<commit_before>/*************************************************************************
 *
 *  $RCSfile: bitmapaction.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2004-11-26 20:54:03 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <bitmapaction.hxx>
#include <outdevstate.hxx>

#ifndef _RTL_LOGFILE_HXX_
#include <rtl/logfile.hxx>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_XBITMAP_HPP__
#include <drafts/com/sun/star/rendering/XBitmap.hpp>
#endif

#ifndef _SV_BITMAPEX_HXX
#include <vcl/bitmapex.hxx>
#endif
#ifndef _SV_GEN_HXX
#include <tools/gen.hxx>
#endif
#ifndef _VCL_CANVASTOOLS_HXX
#include <vcl/canvastools.hxx>
#endif

#ifndef _CANVAS_CANVASTOOLS_HXX
#include <canvas/canvastools.hxx>
#endif

#ifndef _BGFX_MATRIX_B2DHOMMATRIX_HXX
#include <basegfx/matrix/b2dhommatrix.hxx>
#endif
#ifndef _BGFX_TOOLS_CANVASTOOLS_HXX
#include <basegfx/tools/canvastools.hxx>
#endif

#include <mtftools.hxx>

using namespace ::com::sun::star;
using namespace ::drafts::com::sun::star;

namespace cppcanvas
{
    namespace internal
    {
        // free support functions
        // ======================
        namespace
        {
            /** Setup transformation such that the next render call is
                moved rPoint away.
            */
            void implSetupTransform( rendering::RenderState&    rRenderState,
                                     const Point&               rPoint          )
            {
                ::basegfx::B2DHomMatrix aLocalTransformation;

                aLocalTransformation.translate( rPoint.X(),
                                                rPoint.Y() );
                ::canvas::tools::appendToRenderState( rRenderState,
                                                      aLocalTransformation );
            }

            /** Setup transformation such that the next render call is
                moved rPoint away, and scaled according to the ratio
                given by src and dst size.
            */
            void implSetupTransform( rendering::RenderState&    rRenderState,
                                     const Point&               rPoint,
                                     const Size&                rSrcSize,
                                     const Size&                rDstSize        )
            {
                ::basegfx::B2DHomMatrix aLocalTransformation;

                aLocalTransformation.scale( static_cast<double>(rDstSize.Width()) / rSrcSize.Width(),
                                            static_cast<double>(rDstSize.Height()) / rSrcSize.Height() );
                aLocalTransformation.translate( rPoint.X(),
                                                rPoint.Y() );
                ::canvas::tools::appendToRenderState( rRenderState,
                                                      aLocalTransformation );
            }

            /** Setup transformation such that the next render call
                paints the content given by the src area into the dst
                area. No clipping is set whatsoever.
            */
            void implSetupTransform( rendering::RenderState&    rRenderState,
                                     const Point&               rSrcPoint,
                                     const Size&                rSrcSize,
                                     const Point&               rDstPoint,
                                     const Size&                rDstSize        )
            {
                ::basegfx::B2DHomMatrix aLocalTransformation;

                aLocalTransformation.scale( static_cast<double>(rDstSize.Width()) / rSrcSize.Width(),
                                            static_cast<double>(rDstSize.Height()) / rSrcSize.Height() );
                aLocalTransformation.translate( rDstPoint.X() - rSrcPoint.X(),
                                                rDstPoint.Y() - rSrcPoint.Y() );
                ::canvas::tools::appendToRenderState( rRenderState,
                                                      aLocalTransformation );
            }
        }

        BitmapAction::BitmapAction( const ::BitmapEx&       rBmpEx,
                                    const ::Point&          rDstPoint,
                                    const CanvasSharedPtr&  rCanvas,
                                    const OutDevState&      rState ) :
            mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(),
                                                            rBmpEx ) ),
            mpCanvas( rCanvas ),
            maState()
        {
            tools::initRenderState(maState,rState);
            implSetupTransform( maState, rDstPoint );
        }

        BitmapAction::BitmapAction( const ::BitmapEx&       rBmpEx,
                                    const ::Point&          rDstPoint,
                                    const ::Size&           rDstSize,
                                    const CanvasSharedPtr&  rCanvas,
                                    const OutDevState&      rState      ) :
            mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(),
                                                            rBmpEx ) ),
            mpCanvas( rCanvas ),
            maState()
        {
            tools::initRenderState(maState,rState);
            implSetupTransform( maState, rDstPoint, rBmpEx.GetSizePixel(), rDstSize );
        }

        BitmapAction::BitmapAction( const ::BitmapEx&       rBmpEx,
                                    const ::Point&          rSrcPoint,
                                    const ::Size&           rSrcSize,
                                    const ::Point&          rDstPoint,
                                    const ::Size&           rDstSize,
                                    const CanvasSharedPtr&  rCanvas,
                                    const OutDevState&      rState      ) :
            mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(),
                                                            rBmpEx ) ),
            mpCanvas( rCanvas ),
            maState()
        {
            tools::initRenderState(maState,rState);

            // TODO(F2): setup clipping/extract only part of the bitmap
            implSetupTransform( maState, rSrcPoint, rSrcSize, rDstPoint, rDstSize );
        }

        BitmapAction::~BitmapAction()
        {
        }

        bool BitmapAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
        {
            RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::BitmapAction::render()" );
            RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::BitmapAction: 0x%X", this );

            rendering::RenderState aLocalState( maState );
            ::canvas::tools::prependToRenderState(aLocalState, rTransformation);

            mpCanvas->getUNOCanvas()->drawBitmap( mxBitmap,
                                                  mpCanvas->getViewState(),
                                                  aLocalState );

            return true;
        }

    }
}
<commit_msg>INTEGRATION: CWS presfixes01 (1.3.6); FILE MERGED 2005/02/16 11:14:26 fs 1.3.6.1: #i42558# drafts.com.sun.star.drawing/rendering/geometry moved to com.sun.star.*<commit_after>/*************************************************************************
 *
 *  $RCSfile: bitmapaction.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-10 13:23:37 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <bitmapaction.hxx>
#include <outdevstate.hxx>

#ifndef _RTL_LOGFILE_HXX_
#include <rtl/logfile.hxx>
#endif
#ifndef _COM_SUN_STAR_RENDERING_XBITMAP_HPP__
#include <com/sun/star/rendering/XBitmap.hpp>
#endif

#ifndef _SV_BITMAPEX_HXX
#include <vcl/bitmapex.hxx>
#endif
#ifndef _SV_GEN_HXX
#include <tools/gen.hxx>
#endif
#ifndef _VCL_CANVASTOOLS_HXX
#include <vcl/canvastools.hxx>
#endif

#ifndef _CANVAS_CANVASTOOLS_HXX
#include <canvas/canvastools.hxx>
#endif

#ifndef _BGFX_MATRIX_B2DHOMMATRIX_HXX
#include <basegfx/matrix/b2dhommatrix.hxx>
#endif
#ifndef _BGFX_TOOLS_CANVASTOOLS_HXX
#include <basegfx/tools/canvastools.hxx>
#endif

#include <mtftools.hxx>

using namespace ::com::sun::star;

namespace cppcanvas
{
    namespace internal
    {
        // free support functions
        // ======================
        namespace
        {
            /** Setup transformation such that the next render call is
                moved rPoint away.
            */
            void implSetupTransform( rendering::RenderState&    rRenderState,
                                     const Point&               rPoint          )
            {
                ::basegfx::B2DHomMatrix aLocalTransformation;

                aLocalTransformation.translate( rPoint.X(),
                                                rPoint.Y() );
                ::canvas::tools::appendToRenderState( rRenderState,
                                                      aLocalTransformation );
            }

            /** Setup transformation such that the next render call is
                moved rPoint away, and scaled according to the ratio
                given by src and dst size.
            */
            void implSetupTransform( rendering::RenderState&    rRenderState,
                                     const Point&               rPoint,
                                     const Size&                rSrcSize,
                                     const Size&                rDstSize        )
            {
                ::basegfx::B2DHomMatrix aLocalTransformation;

                aLocalTransformation.scale( static_cast<double>(rDstSize.Width()) / rSrcSize.Width(),
                                            static_cast<double>(rDstSize.Height()) / rSrcSize.Height() );
                aLocalTransformation.translate( rPoint.X(),
                                                rPoint.Y() );
                ::canvas::tools::appendToRenderState( rRenderState,
                                                      aLocalTransformation );
            }

            /** Setup transformation such that the next render call
                paints the content given by the src area into the dst
                area. No clipping is set whatsoever.
            */
            void implSetupTransform( rendering::RenderState&    rRenderState,
                                     const Point&               rSrcPoint,
                                     const Size&                rSrcSize,
                                     const Point&               rDstPoint,
                                     const Size&                rDstSize        )
            {
                ::basegfx::B2DHomMatrix aLocalTransformation;

                aLocalTransformation.scale( static_cast<double>(rDstSize.Width()) / rSrcSize.Width(),
                                            static_cast<double>(rDstSize.Height()) / rSrcSize.Height() );
                aLocalTransformation.translate( rDstPoint.X() - rSrcPoint.X(),
                                                rDstPoint.Y() - rSrcPoint.Y() );
                ::canvas::tools::appendToRenderState( rRenderState,
                                                      aLocalTransformation );
            }
        }

        BitmapAction::BitmapAction( const ::BitmapEx&       rBmpEx,
                                    const ::Point&          rDstPoint,
                                    const CanvasSharedPtr&  rCanvas,
                                    const OutDevState&      rState ) :
            mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(),
                                                            rBmpEx ) ),
            mpCanvas( rCanvas ),
            maState()
        {
            tools::initRenderState(maState,rState);
            implSetupTransform( maState, rDstPoint );
        }

        BitmapAction::BitmapAction( const ::BitmapEx&       rBmpEx,
                                    const ::Point&          rDstPoint,
                                    const ::Size&           rDstSize,
                                    const CanvasSharedPtr&  rCanvas,
                                    const OutDevState&      rState      ) :
            mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(),
                                                            rBmpEx ) ),
            mpCanvas( rCanvas ),
            maState()
        {
            tools::initRenderState(maState,rState);
            implSetupTransform( maState, rDstPoint, rBmpEx.GetSizePixel(), rDstSize );
        }

        BitmapAction::BitmapAction( const ::BitmapEx&       rBmpEx,
                                    const ::Point&          rSrcPoint,
                                    const ::Size&           rSrcSize,
                                    const ::Point&          rDstPoint,
                                    const ::Size&           rDstSize,
                                    const CanvasSharedPtr&  rCanvas,
                                    const OutDevState&      rState      ) :
            mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(),
                                                            rBmpEx ) ),
            mpCanvas( rCanvas ),
            maState()
        {
            tools::initRenderState(maState,rState);

            // TODO(F2): setup clipping/extract only part of the bitmap
            implSetupTransform( maState, rSrcPoint, rSrcSize, rDstPoint, rDstSize );
        }

        BitmapAction::~BitmapAction()
        {
        }

        bool BitmapAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
        {
            RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::BitmapAction::render()" );
            RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::BitmapAction: 0x%X", this );

            rendering::RenderState aLocalState( maState );
            ::canvas::tools::prependToRenderState(aLocalState, rTransformation);

            mpCanvas->getUNOCanvas()->drawBitmap( mxBitmap,
                                                  mpCanvas->getViewState(),
                                                  aLocalState );

            return true;
        }

    }
}
<|endoftext|>


<commit_before><commit_msg>use LanguageTag<commit_after><|endoftext|>


<commit_before>// @(#)root/gfal:$Name:  $:$Id: TGFALFile.cxx,v 1.4 2006/04/18 14:23:20 rdm Exp $
// Author: Fons Rademakers   8/12/2005

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGFALFile                                                            //
//                                                                      //
// A TGFALFile is like a normal TFile except that it reads and writes   //
// its data via the underlaying Grid access mechanism.                  //
// TGFALFile file names are either a logical file name, a guid, an      //
// SURL or a TURL, like:                                                //
//                                                                      //
//    gfal:/lfn/user/r/rdm/galice.root                                  //
//                                                                      //
// Grid storage interactions today require using several existing       //
// software components:                                                 //
//  - The replica catalog services to locate valid replicas of          //
//    files.                                                            //
//  - The SRM software to ensure:                                       //
//     - files  exist on disk (they are recalled from mass              //
//       storage if necessary) or                                       //
//     - space is allocated on disk for new files (they are possibly    //
//       migrated to mass storage later)                                //
//  - A file access mechanism to access files from the storage          //
//    system on the worker node.                                        //
//                                                                      //
// The GFAL library hides these interactions and presents a Posix       //
// interface for the I/O operations. The currently supported protocols  //
// are: file for local access, dcap, gsidcap and kdcap (dCache access   //
// protocol) and rfio (CASTOR access protocol).                         //
//                                                                      //
// File naming convention:                                              //
// A file name can be a Logical File Name (LFN), a Grid Unique          //
// IDentifier (GUID), a file replica (SURL) or a Transport file         //
// name (TURL):                                                         //
//                                                                      //
//     an LFN starts with lfn:                                          //
//        for example lfn:baud/testgfal15                               //
//                                                                      //
//     a GUID starts with guid:                                         //
//        for example guid:2cd59291-7ae7-4778-af6d-b1f423719441         //
//                                                                      //
//     an SURL starts with srm://                                       //
//         for example srm://wacdr002d.cern.ch:8443/castor/             //
//                    cern.ch/user/b/baud/testgfal15                    //
//                                                                      //
//      a TURL starts with a protocol name:                             //
//          for example rfio:///castor/cern.ch/user/b/baud/testgfal15   //
//                                                                      //
// Note that for the TGFALFile plugin to work, all these pathnames      //
// should be prepended by gfal:.                                        //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGFALFile.h"
#include "TROOT.h"
#include "TUrl.h"

extern "C" {
#include <gfal_api.h>
}

ClassImp(TGFALFile)
ClassImp(TGFALSystem)

//______________________________________________________________________________
TGFALFile::TGFALFile(const char *url, Option_t *option, const char *ftitle,
                     Int_t compress)
         : TFile(url, "NET", ftitle, compress)
{
   // Create a GFAL file object. A GFAL file is the same as a TFile
   // except that it is being accessed via the underlaying Grid access
   // mechanism. The url argument must be of the form: gfal:/lfn/file.root
   // If the file specified in the URL does not exist, is not accessable
   // or can not be created the kZombie bit will be set in the TGFALFile
   // object. Use IsZombie() to see if the file is accessable.
   // For a description of the option and other arguments see the TFile ctor.
   // The preferred interface to this constructor is via TFile::Open().

   fOption = option;
   fOption.ToUpper();

   if (fOption == "NEW")
      fOption = "CREATE";

   Bool_t create   = (fOption == "CREATE") ? kTRUE : kFALSE;
   Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
   Bool_t update   = (fOption == "UPDATE") ? kTRUE : kFALSE;
   Bool_t read     = (fOption == "READ") ? kTRUE : kFALSE;
   if (!create && !recreate && !update && !read) {
      read    = kTRUE;
      fOption = "READ";
   }

   TString stmp;
   char *fname;
   if ((fname = gSystem->ExpandPathName(fUrl.GetFile()))) {
      stmp = fname;
      delete [] fname;
      fname = (char *)stmp.Data();
   } else {
      Error("TGFALFile", "error expanding path %s", fUrl.GetFile());
      goto zombie;
   }

   if (recreate) {
      if (::gfal_access(fname, kFileExists) == 0)
         ::gfal_unlink(fname);
      recreate = kFALSE;
      create   = kTRUE;
      fOption  = "CREATE";
   }
   if (create && ::gfal_access(fname, kFileExists) == 0) {
      Error("TGFALFile", "file %s already exists", fname);
      goto zombie;
   }
   if (update) {
      if (::gfal_access(fname, kFileExists) != 0) {
         update = kFALSE;
         create = kTRUE;
      }
      if (update && ::gfal_access(fname, kWritePermission) != 0) {
         Error("TGFALFile", "no write permission, could not open file %s", fname);
         goto zombie;
      }
   }
   if (read) {
      if (::gfal_access(fname, kFileExists) != 0) {
         Error("TGFALFile", "file %s does not exist", fname);
         goto zombie;
      }
      if (::gfal_access(fname, kReadPermission) != 0) {
         Error("TGFALFile", "no read permission, could not open file %s", fname);
         goto zombie;
      }
   }

   // Connect to file system stream
   fRealName = fname;

   if (create || update) {
#ifndef WIN32
      fD = SysOpen(fname, O_RDWR | O_CREAT, 0644);
#else
      fD = SysOpen(fname, O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
#endif
      if (fD == -1) {
         SysError("TGFALFile", "file %s can not be opened", fname);
         goto zombie;
      }
      fWritable = kTRUE;
   } else {
#ifndef WIN32
      fD = SysOpen(fname, O_RDONLY, 0644);
#else
      fD = SysOpen(fname, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
#endif
      if (fD == -1) {
         SysError("TGFALFile", "file %s can not be opened for reading", fname);
         goto zombie;
      }
      fWritable = kFALSE;
   }

   Init(create);

   return;

zombie:
   // error in file opening occured, make this object a zombie
   MakeZombie();
   gDirectory = gROOT;
}

//______________________________________________________________________________
TGFALFile::~TGFALFile()
{
   // GFAL file dtor. Close and flush directory structure.

   Close();
}

//______________________________________________________________________________
Int_t TGFALFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
{
   // Interface to system open. All arguments like in POSIX open.

   Int_t ret = ::gfal_open64(pathname, flags, (Int_t) mode);

   return ret;
}

//______________________________________________________________________________
Int_t TGFALFile::SysClose(Int_t fd)
{
   // Interface to system close. All arguments like in POSIX close.

   Int_t ret = ::gfal_close(fd);

   return ret;
}

//______________________________________________________________________________
Int_t TGFALFile::SysRead(Int_t fd, void *buf, Int_t len)
{
   // Interface to system read. All arguments like in POSIX read.

   fOffset += len;
   Int_t ret = ::gfal_read(fd, buf, len);

   return ret;
}

//______________________________________________________________________________
Int_t TGFALFile::SysWrite(Int_t fd, const void *buf, Int_t len)
{
   // Interface to system write. All arguments like in POSIX write.

   fOffset += len;
   Int_t ret = ::gfal_write(fd, buf, len);

   return ret;
}

//______________________________________________________________________________
Long64_t TGFALFile::SysSeek(Int_t fd, Long64_t offset, Int_t whence)
{
   // Interface to system lseek. All arguments like in POSIX lseek
   // except that the offset and return value are Long_t to be able to
   // handle 64 bit file systems.

   if (whence == SEEK_SET && offset == fOffset) return offset;

   Long64_t ret = ::gfal_lseek64(fd, offset, whence);

   if (ret >= 0)
      fOffset = ret;

   return ret;
}

//______________________________________________________________________________
Int_t TGFALFile::SysStat(Int_t /*fd*/, Long_t *id, Long64_t *size, Long_t *flags,
                         Long_t *modtime)
{
   // Interface to TSystem:GetPathInfo(). Generally implemented via
   // stat() or fstat().

   struct stat64 &statbuf = fStatBuffer;

   if (fOption != "READ" || !fStatCached) {
      // We are not in read mode, or the file status information is not yet
      // in the cache. Update or read the status information with gfal_stat().

      if (::gfal_stat64(fRealName, &statbuf) >= 0)
         fStatCached = kTRUE;
   }

   if (fStatCached) {
      if (id)
         *id = (statbuf.st_dev << 24) + statbuf.st_ino;
      if (size)
         *size = statbuf.st_size;
      if (modtime)
         *modtime = statbuf.st_mtime;
      if (flags) {
         *flags = 0;
         if (statbuf.st_mode & ((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6)))
            *flags |= 1;
         if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
            *flags |= 2;
         if ((statbuf.st_mode & S_IFMT) != S_IFREG &&
             (statbuf.st_mode & S_IFMT) != S_IFDIR)
            *flags |= 4;
      }
      return 0;
   }

   return 1;
}

//______________________________________________________________________________
Bool_t TGFALFile::ReadBuffer(char *buf, Int_t len)
{
   // Read specified byte range from remote file via GFAL.
   // Returns kTRUE in case of error.

   Int_t st;
   if ((st = ReadBufferViaCache(buf, len))) {
      if (st == 2)
         return kTRUE;
      return kFALSE;
   }

   return TFile::ReadBuffer(buf, len);
}

//______________________________________________________________________________
Bool_t TGFALFile::WriteBuffer(const char *buf, Int_t len)
{
   // Write specified byte range to remote file via GFAL.
   // Returns kTRUE in case of error.

   if (!IsOpen() || !fWritable) return kTRUE;

   Int_t st;
   if ((st = WriteBufferViaCache(buf, len))) {
      if (st == 2)
         return kTRUE;
      return kFALSE;
   }

   return TFile::WriteBuffer(buf, len);
}

//______________________________________________________________________________
TGFALSystem::TGFALSystem() : TSystem("-gfal", "GFAL Helper System")
{
   // Create helper class that allows directory access via GFAL.

   // name must start with '-' to bypass the TSystem singleton check
   SetName("gfal");

   fDirp = 0;
}

//______________________________________________________________________________
Int_t TGFALSystem::MakeDirectory(const char *dir)
{
   // Make a directory via GFAL.

   TUrl url(dir);

   Int_t ret = ::gfal_mkdir(url.GetFile(), 0755);

   return ret;
}

//______________________________________________________________________________
void *TGFALSystem::OpenDirectory(const char *dir)
{
   // Open a directory via GFAL. Returns an opaque pointer to a dir
   // structure. Returns 0 in case of error.

   if (fDirp) {
      Error("OpenDirectory", "invalid directory pointer (should never happen)");
      fDirp = 0;
   }

   TUrl url(dir);

   struct stat64 finfo;

   if (::gfal_stat64(url.GetFile(), &finfo) < 0)
      return 0;

   if ((finfo.st_mode & S_IFMT) != S_IFDIR)
      return 0;

   fDirp = (void*) ::gfal_opendir(url.GetFile());

   return fDirp;
}

//______________________________________________________________________________
void TGFALSystem::FreeDirectory(void *dirp)
{
   // Free directory via GFAL.

   if (dirp != fDirp) {
      Error("FreeDirectory", "invalid directory pointer (should never happen)");
      return;
   }

   if (dirp)
      ::gfal_closedir((DIR*)dirp);

   fDirp = 0;
}

//______________________________________________________________________________
const char *TGFALSystem::GetDirEntry(void *dirp)
{
   // Get directory entry via GFAL. Returns 0 in case no more entries.

   if (dirp != fDirp) {
      Error("GetDirEntry", "invalid directory pointer (should never happen)");
      return 0;
   }

   struct dirent64 *dp;

   if (dirp) {
      dp = ::gfal_readdir64((DIR*)dirp);
      if (!dp)
         return 0;
      return dp->d_name;
   }
   return 0;
}

//______________________________________________________________________________
Int_t TGFALSystem::GetPathInfo(const char *path, FileStat_t &buf)
{
   // Get info about a file. Info is returned in the form of a FileStat_t
   // structure (see TSystem.h).
   // The function returns 0 in case of success and 1 if the file could
   // not be stat'ed.

   TUrl url(path);

   struct stat64 sbuf;

   if (path && ::gfal_stat64(url.GetFile(), &sbuf) >= 0) {

      buf.fDev    = sbuf.st_dev;
      buf.fIno    = sbuf.st_ino;
      buf.fMode   = sbuf.st_mode;
      buf.fUid    = sbuf.st_uid;
      buf.fGid    = sbuf.st_gid;
      buf.fSize   = sbuf.st_size;
      buf.fMtime  = sbuf.st_mtime;
      buf.fIsLink = kFALSE;

      return 0;
   }
   return 1;
}

//______________________________________________________________________________
Bool_t TGFALSystem::AccessPathName(const char *path, EAccessMode mode)
{
   // Returns FALSE if one can access a file using the specified access mode.
   // Mode is the same as for the Unix access(2) function.
   // Attention, bizarre convention of return value!!

   TUrl url(path);

   if (::gfal_access(url.GetFile(), mode) == 0)
      return kFALSE;

   return kTRUE;
}
<commit_msg>From Hubert Degaudenzi: comment out calls to broken gfal_access().<commit_after>// @(#)root/gfal:$Name:  $:$Id: TGFALFile.cxx,v 1.5 2006/05/01 16:36:40 rdm Exp $
// Author: Fons Rademakers   8/12/2005

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGFALFile                                                            //
//                                                                      //
// A TGFALFile is like a normal TFile except that it reads and writes   //
// its data via the underlaying Grid access mechanism.                  //
// TGFALFile file names are either a logical file name, a guid, an      //
// SURL or a TURL, like:                                                //
//                                                                      //
//    gfal:/lfn/user/r/rdm/galice.root                                  //
//                                                                      //
// Grid storage interactions today require using several existing       //
// software components:                                                 //
//  - The replica catalog services to locate valid replicas of          //
//    files.                                                            //
//  - The SRM software to ensure:                                       //
//     - files  exist on disk (they are recalled from mass              //
//       storage if necessary) or                                       //
//     - space is allocated on disk for new files (they are possibly    //
//       migrated to mass storage later)                                //
//  - A file access mechanism to access files from the storage          //
//    system on the worker node.                                        //
//                                                                      //
// The GFAL library hides these interactions and presents a Posix       //
// interface for the I/O operations. The currently supported protocols  //
// are: file for local access, dcap, gsidcap and kdcap (dCache access   //
// protocol) and rfio (CASTOR access protocol).                         //
//                                                                      //
// File naming convention:                                              //
// A file name can be a Logical File Name (LFN), a Grid Unique          //
// IDentifier (GUID), a file replica (SURL) or a Transport file         //
// name (TURL):                                                         //
//                                                                      //
//     an LFN starts with lfn:                                          //
//        for example lfn:baud/testgfal15                               //
//                                                                      //
//     a GUID starts with guid:                                         //
//        for example guid:2cd59291-7ae7-4778-af6d-b1f423719441         //
//                                                                      //
//     an SURL starts with srm://                                       //
//         for example srm://wacdr002d.cern.ch:8443/castor/             //
//                    cern.ch/user/b/baud/testgfal15                    //
//                                                                      //
//      a TURL starts with a protocol name:                             //
//          for example rfio:///castor/cern.ch/user/b/baud/testgfal15   //
//                                                                      //
// Note that for the TGFALFile plugin to work, all these pathnames      //
// should be prepended by gfal:.                                        //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGFALFile.h"
#include "TROOT.h"
#include "TUrl.h"

extern "C" {
#include <gfal_api.h>
}

ClassImp(TGFALFile)
ClassImp(TGFALSystem)

//______________________________________________________________________________
TGFALFile::TGFALFile(const char *url, Option_t *option, const char *ftitle,
                     Int_t compress)
         : TFile(url, "NET", ftitle, compress)
{
   // Create a GFAL file object. A GFAL file is the same as a TFile
   // except that it is being accessed via the underlaying Grid access
   // mechanism. The url argument must be of the form: gfal:/lfn/file.root
   // If the file specified in the URL does not exist, is not accessable
   // or can not be created the kZombie bit will be set in the TGFALFile
   // object. Use IsZombie() to see if the file is accessable.
   // For a description of the option and other arguments see the TFile ctor.
   // The preferred interface to this constructor is via TFile::Open().

   fOption = option;
   fOption.ToUpper();

   if (fOption == "NEW")
      fOption = "CREATE";

   Bool_t create   = (fOption == "CREATE") ? kTRUE : kFALSE;
   Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
   Bool_t update   = (fOption == "UPDATE") ? kTRUE : kFALSE;
   Bool_t read     = (fOption == "READ") ? kTRUE : kFALSE;
   if (!create && !recreate && !update && !read) {
      read    = kTRUE;
      fOption = "READ";
   }

   TString stmp;
   char *fname;
   if ((fname = gSystem->ExpandPathName(fUrl.GetFile()))) {
      stmp = fname;
      delete [] fname;
      fname = (char *)stmp.Data();
   } else {
      Error("TGFALFile", "error expanding path %s", fUrl.GetFile());
      goto zombie;
   }

   if (recreate) {
      if (::gfal_access(fname, kFileExists) == 0)
         ::gfal_unlink(fname);
      recreate = kFALSE;
      create   = kTRUE;
      fOption  = "CREATE";
   }
   if (create && ::gfal_access(fname, kFileExists) == 0) {
      Error("TGFALFile", "file %s already exists", fname);
      goto zombie;
   }
   if (update) {
      if (::gfal_access(fname, kFileExists) != 0) {
         update = kFALSE;
         create = kTRUE;
      }
      if (update && ::gfal_access(fname, kWritePermission) != 0) {
         Error("TGFALFile", "no write permission, could not open file %s", fname);
         goto zombie;
      }
   }
   if (read) {
#ifdef GFAL_ACCESS_FIXED
      if (::gfal_access(fname, kFileExists) != 0) {
         Error("TGFALFile", "file %s does not exist", fname);
         goto zombie;
      }
      if (::gfal_access(fname, kReadPermission) != 0) {
         Error("TGFALFile", "no read permission, could not open file %s", fname);
         goto zombie;
      }
#endif
   }

   // Connect to file system stream
   fRealName = fname;

   if (create || update) {
#ifndef WIN32
      fD = SysOpen(fname, O_RDWR | O_CREAT, 0644);
#else
      fD = SysOpen(fname, O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
#endif
      if (fD == -1) {
         SysError("TGFALFile", "file %s can not be opened", fname);
         goto zombie;
      }
      fWritable = kTRUE;
   } else {
#ifndef WIN32
      fD = SysOpen(fname, O_RDONLY, 0644);
#else
      fD = SysOpen(fname, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
#endif
      if (fD == -1) {
         SysError("TGFALFile", "file %s can not be opened for reading", fname);
         goto zombie;
      }
      fWritable = kFALSE;
   }

   Init(create);

   return;

zombie:
   // error in file opening occured, make this object a zombie
   MakeZombie();
   gDirectory = gROOT;
}

//______________________________________________________________________________
TGFALFile::~TGFALFile()
{
   // GFAL file dtor. Close and flush directory structure.

   Close();
}

//______________________________________________________________________________
Int_t TGFALFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
{
   // Interface to system open. All arguments like in POSIX open.

   Int_t ret = ::gfal_open64(pathname, flags, (Int_t) mode);

   return ret;
}

//______________________________________________________________________________
Int_t TGFALFile::SysClose(Int_t fd)
{
   // Interface to system close. All arguments like in POSIX close.

   Int_t ret = ::gfal_close(fd);

   return ret;
}

//______________________________________________________________________________
Int_t TGFALFile::SysRead(Int_t fd, void *buf, Int_t len)
{
   // Interface to system read. All arguments like in POSIX read.

   fOffset += len;
   Int_t ret = ::gfal_read(fd, buf, len);

   return ret;
}

//______________________________________________________________________________
Int_t TGFALFile::SysWrite(Int_t fd, const void *buf, Int_t len)
{
   // Interface to system write. All arguments like in POSIX write.

   fOffset += len;
   Int_t ret = ::gfal_write(fd, buf, len);

   return ret;
}

//______________________________________________________________________________
Long64_t TGFALFile::SysSeek(Int_t fd, Long64_t offset, Int_t whence)
{
   // Interface to system lseek. All arguments like in POSIX lseek
   // except that the offset and return value are Long_t to be able to
   // handle 64 bit file systems.

   if (whence == SEEK_SET && offset == fOffset) return offset;

   Long64_t ret = ::gfal_lseek64(fd, offset, whence);

   if (ret >= 0)
      fOffset = ret;

   return ret;
}

//______________________________________________________________________________
Int_t TGFALFile::SysStat(Int_t /*fd*/, Long_t *id, Long64_t *size, Long_t *flags,
                         Long_t *modtime)
{
   // Interface to TSystem:GetPathInfo(). Generally implemented via
   // stat() or fstat().

   struct stat64 &statbuf = fStatBuffer;

   if (fOption != "READ" || !fStatCached) {
      // We are not in read mode, or the file status information is not yet
      // in the cache. Update or read the status information with gfal_stat().

      if (::gfal_stat64(fRealName, &statbuf) >= 0)
         fStatCached = kTRUE;
   }

   if (fStatCached) {
      if (id)
         *id = (statbuf.st_dev << 24) + statbuf.st_ino;
      if (size)
         *size = statbuf.st_size;
      if (modtime)
         *modtime = statbuf.st_mtime;
      if (flags) {
         *flags = 0;
         if (statbuf.st_mode & ((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6)))
            *flags |= 1;
         if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
            *flags |= 2;
         if ((statbuf.st_mode & S_IFMT) != S_IFREG &&
             (statbuf.st_mode & S_IFMT) != S_IFDIR)
            *flags |= 4;
      }
      return 0;
   }

   return 1;
}

//______________________________________________________________________________
Bool_t TGFALFile::ReadBuffer(char *buf, Int_t len)
{
   // Read specified byte range from remote file via GFAL.
   // Returns kTRUE in case of error.

   Int_t st;
   if ((st = ReadBufferViaCache(buf, len))) {
      if (st == 2)
         return kTRUE;
      return kFALSE;
   }

   return TFile::ReadBuffer(buf, len);
}

//______________________________________________________________________________
Bool_t TGFALFile::WriteBuffer(const char *buf, Int_t len)
{
   // Write specified byte range to remote file via GFAL.
   // Returns kTRUE in case of error.

   if (!IsOpen() || !fWritable) return kTRUE;

   Int_t st;
   if ((st = WriteBufferViaCache(buf, len))) {
      if (st == 2)
         return kTRUE;
      return kFALSE;
   }

   return TFile::WriteBuffer(buf, len);
}

//______________________________________________________________________________
TGFALSystem::TGFALSystem() : TSystem("-gfal", "GFAL Helper System")
{
   // Create helper class that allows directory access via GFAL.

   // name must start with '-' to bypass the TSystem singleton check
   SetName("gfal");

   fDirp = 0;
}

//______________________________________________________________________________
Int_t TGFALSystem::MakeDirectory(const char *dir)
{
   // Make a directory via GFAL.

   TUrl url(dir);

   Int_t ret = ::gfal_mkdir(url.GetFile(), 0755);

   return ret;
}

//______________________________________________________________________________
void *TGFALSystem::OpenDirectory(const char *dir)
{
   // Open a directory via GFAL. Returns an opaque pointer to a dir
   // structure. Returns 0 in case of error.

   if (fDirp) {
      Error("OpenDirectory", "invalid directory pointer (should never happen)");
      fDirp = 0;
   }

   TUrl url(dir);

   struct stat64 finfo;

   if (::gfal_stat64(url.GetFile(), &finfo) < 0)
      return 0;

   if ((finfo.st_mode & S_IFMT) != S_IFDIR)
      return 0;

   fDirp = (void*) ::gfal_opendir(url.GetFile());

   return fDirp;
}

//______________________________________________________________________________
void TGFALSystem::FreeDirectory(void *dirp)
{
   // Free directory via GFAL.

   if (dirp != fDirp) {
      Error("FreeDirectory", "invalid directory pointer (should never happen)");
      return;
   }

   if (dirp)
      ::gfal_closedir((DIR*)dirp);

   fDirp = 0;
}

//______________________________________________________________________________
const char *TGFALSystem::GetDirEntry(void *dirp)
{
   // Get directory entry via GFAL. Returns 0 in case no more entries.

   if (dirp != fDirp) {
      Error("GetDirEntry", "invalid directory pointer (should never happen)");
      return 0;
   }

   struct dirent64 *dp;

   if (dirp) {
      dp = ::gfal_readdir64((DIR*)dirp);
      if (!dp)
         return 0;
      return dp->d_name;
   }
   return 0;
}

//______________________________________________________________________________
Int_t TGFALSystem::GetPathInfo(const char *path, FileStat_t &buf)
{
   // Get info about a file. Info is returned in the form of a FileStat_t
   // structure (see TSystem.h).
   // The function returns 0 in case of success and 1 if the file could
   // not be stat'ed.

   TUrl url(path);

   struct stat64 sbuf;

   if (path && ::gfal_stat64(url.GetFile(), &sbuf) >= 0) {

      buf.fDev    = sbuf.st_dev;
      buf.fIno    = sbuf.st_ino;
      buf.fMode   = sbuf.st_mode;
      buf.fUid    = sbuf.st_uid;
      buf.fGid    = sbuf.st_gid;
      buf.fSize   = sbuf.st_size;
      buf.fMtime  = sbuf.st_mtime;
      buf.fIsLink = kFALSE;

      return 0;
   }
   return 1;
}

//______________________________________________________________________________
Bool_t TGFALSystem::AccessPathName(const char *path, EAccessMode mode)
{
   // Returns FALSE if one can access a file using the specified access mode.
   // Mode is the same as for the Unix access(2) function.
   // Attention, bizarre convention of return value!!

   TUrl url(path);

   if (::gfal_access(url.GetFile(), mode) == 0)
      return kFALSE;

   return kTRUE;
}
<|endoftext|>


<commit_before>#include "introspection.h"

#include "argumentlist.h"
#include "stringtools.h"

#include <tinyxml2.h>

#include <cassert>
#include <cstring> // for strcmp...
#include <memory> // for auto_ptr - yes it sucks in general, but it's suitable here

namespace tx2 = tinyxml2;

// strcmp()'s return value is easy to misinterpret, especially for equality...
static bool strequal(const char *c1, const char *c2)
{
    return !strcmp(c1, c2);
}

IntrospectionTree::IntrospectionTree()
   : m_rootNode(new IntrospectionNode)
{
    m_rootNode->parent = 0;
    // name stays empty for the root
}

IntrospectionTree::~IntrospectionTree()
{
    delete m_rootNode;
    m_rootNode = 0;
}

bool IntrospectionTree::mergeXml(const char *xmlData, const char *_path)
{
    // TODO use path to replace an empty root node name in the XML document
    // TODO is it OK to add interfaces to the root node? if so, review/test the code to ensure that it works!
    // TODO what about adding interfaces to other existing nodes? (this is not taken care of in current code!)
    // TODO check the path names (absolute / relative according to spec)
    // If things turn out to be complicated, it might be better to first create a detached tree from the XML
    // document, then check if it can be merged without conflicts, then merge it. That requires not rollback.
    tx2::XMLDocument doc;
    if (doc.Parse(xmlData) != tx2::XML_SUCCESS) {
        return false;
    }
    tx2::XMLElement *el = doc.RootElement();
    if (!el || !strequal(el->Name(), "node")) {
        return false;
    }
    std::string path = _path;
    const tx2::XMLAttribute *attr = el->FirstAttribute();
    if (attr && strequal(attr->Name(), "name"))  {
        std::string intrinsicPath = attr->Value();
        if (!path.empty() && path != intrinsicPath) {
            return false;
        }
        path = intrinsicPath;
    }

    // ### Should we do this? if (path.empty()) { path = "/"; }

    std::string leafName;
    IntrospectionNode *parent = findOrCreateParent(path.c_str(), &leafName);
    if (!parent || parent->children.count(leafName)) {
        // the second condition makes sure that we don't overwrite existing nodes
        return false;
    }

    if (!addNode(parent, el)) {
        // TODO undo creation of parent nodes by findOrCreateParent() here

        return false;
    }
    return true;
}

IntrospectionNode *IntrospectionTree::findOrCreateParent(const char *path, std::string *leafName)
{
    cstring csPath(path);
    if (!ArgumentList::isObjectPathValid(csPath)) {
        return 0;
    }
    std::string strPath(path, csPath.length); // prevent another strlen()
    std::vector<std::string> elements = split(strPath, '/', false);

    IntrospectionNode *node = m_rootNode;
    // the leaf node is to be created later, hence we omit the last path element
    for (int i = 0; i < elements.size() - 1; i++) {
        std::map<std::string, IntrospectionNode *>::iterator it = node->children.find(elements[i]);
        if (it != node->children.end()) {
            node = it->second;
        } else {
            IntrospectionNode *newNode = new IntrospectionNode;
            newNode->name = elements[i];
            node->children[elements[i]] = newNode;
            node = newNode;
        }
    }
    if (leafName) {
        if (elements.empty()) {
            leafName->clear();
        } else {
            *leafName = elements.back();
        }
    }
    return node;
}

// careful with this one when not calling it from findOrCreateParent() or mergeXml() - if applied to a node
// that was created earlier, it might delete children that shouldn't be deleted.
void IntrospectionTree::pruneBranch(IntrospectionNode *node)
{
    IntrospectionNode *const parent = node->parent;
    // remove the node itself, including any children
    removeNode(node);

    // remove all now empty parents (except the root node)
    for (node = parent; node != m_rootNode; ) {
        assert(node->parent->children.count(node->name) == 1);
        if (node->children.size() == 1 && node->interfaces.empty()) {
            // we must have deleted that child while ascending; just remove the current node
            IntrospectionNode *exNode = node;
            node = node->parent;
            delete exNode;
        } else {
            // this node has other children, so we are going to keep it and update its children map
            // (we want to do this for the root node, too, so break here and do it after the loop)
            break;
        }
    }
}

void IntrospectionTree::removeNode(IntrospectionNode *node)
{
    std::map<std::string, IntrospectionNode *>::iterator it = node->children.begin();
    for (; it != node->children.end(); ++it) {
        removeNode(it->second);
    }
    delete node;
}

bool IntrospectionTree::addNode(IntrospectionNode *parent, const tx2::XMLElement *el)
{
    const tx2::XMLAttribute *attr = el->FirstAttribute();
    if (!attr || !strequal(attr->Name(), "name") || attr->Next())  {
        return false;
    }

    const bool isRootOfDocument = el == el->GetDocument()->RootElement();

    std::auto_ptr<IntrospectionNode> node(new IntrospectionNode);
    node->parent = parent;
    node->name = attr->Value();

    for (const tx2::XMLElement *child = el->FirstChildElement(); child; child = child->NextSiblingElement()) {
        if (strequal(child->Name(), "node")) {
            if (!addNode(node.get(), child)) {
                return false;
            }
        } else if (strequal(child->Name(), "interface")) {
            if (!addInterface(node.get(), child)) {
                return false;
            }
        }
    }
    parent->children[node->name] = node.release();
    return true;
}

bool IntrospectionTree::addInterface(IntrospectionNode *node, const tx2::XMLElement *el)
{
    const tx2::XMLAttribute *attr = el->FirstAttribute();
    if (!attr || !strequal(attr->Name(), "name") || attr->Next())  {
        return false;
    }

    Interface iface;
    iface.name = attr->Value();

    for (const tx2::XMLElement *child = el->FirstChildElement(); child; child = child->NextSiblingElement()) {
        if (strequal(child->Name(), "method")) {
            if (!addMethod(&iface, child, Message::MethodCallMessage)) {
                return false;
            }
        } else if (strequal(child->Name(), "signal")) {
            if (!addMethod(&iface, child, Message::SignalMessage)) {
                return false;
            }
        } else if (strequal(child->Name(), "property")) {
            if (!addProperty(&iface, child)) {
                return false;
            }
        } else {
            return false;
        }
    }
    node->interfaces[iface.name] = iface;
    return true;
}

bool IntrospectionTree::addMethod(Interface *iface, const tx2::XMLElement *el, Message::Type messageType)
{
    const tx2::XMLAttribute *attr = el->FirstAttribute();
    if (!attr || !strequal(attr->Name(), "name") || attr->Next())  {
        return false;
    }

    Method method;
    method.type = messageType;
    method.name = attr->Value();

    for (const tx2::XMLElement *child = el->FirstChildElement(); child; child = child->NextSiblingElement()) {
        if (strequal(child->Name(), "arg")) {
            if (!addArgument(&method, child, messageType)) {
                return false;
            }
        } else if (strequal(child->Name(), "annotation")) {
            // annotations are allowed, but we don't use them
            continue;
        } else {
            return false;
        }
    }
    iface->methods[method.name] = method;
    return true;
}

bool IntrospectionTree::addArgument(Method *method, const tx2::XMLElement *el, Message::Type messageType)
{
    Argument arg;
    arg.isDirectionOut = messageType == Message::SignalMessage;
    for (const tx2::XMLAttribute *attr = el->FirstAttribute(); attr; attr = attr->Next()) {
        if (strequal(attr->Name(), "name")) {
            arg.name = attr->Value();
        } else if (strequal(attr->Name(), "type")) {
            arg.type = attr->Value();
            // TODO validate (single complete type!)
        } else if (strequal(attr->Name(), "direction")) {
            if (strequal(attr->Value(), "in")) {
                if (messageType == Message::SignalMessage) {
                    return false;
                }
                arg.isDirectionOut = false;
            } else if (strequal(attr->Value(), "out")) {
                arg.isDirectionOut = true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    if (arg.type.empty()) {
        return false;
    }
    method->arguments.push_back(arg);
    return true;
}

bool IntrospectionTree::addProperty(Interface *iface, const tx2::XMLElement *el)
{
    Property prop;
    prop.access = Property::Invalid;
    for (const tx2::XMLAttribute *attr = el->FirstAttribute(); attr; attr = attr->Next()) {
        if (strequal(attr->Name(), "name")) {
            // TODO validate
            prop.name = attr->Value();
        } else if (strequal(attr->Name(), "type")) {
            // TODO validate - don't forget to check it's a single complete type
            prop.type = attr->Value();
        } else if (strequal(attr->Name(), "access")) {
            if (strequal(attr->Value(), "readwrite")) {
                prop.access = Property::ReadWrite;
            } else if (strequal(attr->Value(), "read")) {
                prop.access = Property::Read;
            } else if (strequal(attr->Value(), "write")) {
                prop.access = Property::Write;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    if (prop.name.empty() || prop.type.empty() || prop.access == Property::Invalid) {
        return false;
    }
    iface->properties[prop.name] = prop;
    return true;
}
<commit_msg>Implement IntrospectionNode::path().<commit_after>#include "introspection.h"

#include "argumentlist.h"
#include "stringtools.h"

#include <tinyxml2.h>

#include <cassert>
#include <cstring> // for strcmp...
#include <memory> // for auto_ptr - yes it sucks in general, but it's suitable here

namespace tx2 = tinyxml2;

// strcmp()'s return value is easy to misinterpret, especially for equality...
static bool strequal(const char *c1, const char *c2)
{
    return !strcmp(c1, c2);
}

// This function exists to avoid making the many copies that a naive recursive implementation would make.
// That it makes it possible to reserve() is just a nice extra.
static void introspectionNodePathHelper(const IntrospectionNode *node, int length,  std::string *out)
{
    if (node->parent) {
        introspectionNodePathHelper(node->parent, length + 1 + node->name.length(), out);
        *out += '/';
        *out += node->name;
    } else {
        // root node; reserve just enough room in output string before we start filling it in
        out->reserve(length);
    }
}

std::string IntrospectionNode::path() const
{
    if (!parent) {
        return std::string("/");
    }
    std::string ret;
    introspectionNodePathHelper(this, 0, &ret);
    return ret;
}

IntrospectionTree::IntrospectionTree()
   : m_rootNode(new IntrospectionNode)
{
    m_rootNode->parent = 0;
    // name stays empty for the root
}

IntrospectionTree::~IntrospectionTree()
{
    delete m_rootNode;
    m_rootNode = 0;
}

bool IntrospectionTree::mergeXml(const char *xmlData, const char *_path)
{
    // TODO use path to replace an empty root node name in the XML document
    // TODO is it OK to add interfaces to the root node? if so, review/test the code to ensure that it works!
    // TODO what about adding interfaces to other existing nodes? (this is not taken care of in current code!)
    // TODO check the path names (absolute / relative according to spec)
    // If things turn out to be complicated, it might be better to first create a detached tree from the XML
    // document, then check if it can be merged without conflicts, then merge it. That requires not rollback.
    tx2::XMLDocument doc;
    if (doc.Parse(xmlData) != tx2::XML_SUCCESS) {
        return false;
    }
    tx2::XMLElement *el = doc.RootElement();
    if (!el || !strequal(el->Name(), "node")) {
        return false;
    }
    std::string path = _path;
    const tx2::XMLAttribute *attr = el->FirstAttribute();
    if (attr && strequal(attr->Name(), "name"))  {
        std::string intrinsicPath = attr->Value();
        if (!path.empty() && path != intrinsicPath) {
            return false;
        }
        path = intrinsicPath;
    }

    // ### Should we do this? if (path.empty()) { path = "/"; }

    std::string leafName;
    IntrospectionNode *parent = findOrCreateParent(path.c_str(), &leafName);
    if (!parent || parent->children.count(leafName)) {
        // the second condition makes sure that we don't overwrite existing nodes
        return false;
    }

    if (!addNode(parent, el)) {
        // TODO undo creation of parent nodes by findOrCreateParent() here

        return false;
    }
    return true;
}

IntrospectionNode *IntrospectionTree::findOrCreateParent(const char *path, std::string *leafName)
{
    cstring csPath(path);
    if (!ArgumentList::isObjectPathValid(csPath)) {
        return 0;
    }
    std::string strPath(path, csPath.length); // prevent another strlen()
    std::vector<std::string> elements = split(strPath, '/', false);

    IntrospectionNode *node = m_rootNode;
    // the leaf node is to be created later, hence we omit the last path element
    for (int i = 0; i < elements.size() - 1; i++) {
        std::map<std::string, IntrospectionNode *>::iterator it = node->children.find(elements[i]);
        if (it != node->children.end()) {
            node = it->second;
        } else {
            IntrospectionNode *newNode = new IntrospectionNode;
            newNode->name = elements[i];
            node->children[elements[i]] = newNode;
            node = newNode;
        }
    }
    if (leafName) {
        if (elements.empty()) {
            leafName->clear();
        } else {
            *leafName = elements.back();
        }
    }
    return node;
}

// careful with this one when not calling it from findOrCreateParent() or mergeXml() - if applied to a node
// that was created earlier, it might delete children that shouldn't be deleted.
void IntrospectionTree::pruneBranch(IntrospectionNode *node)
{
    IntrospectionNode *const parent = node->parent;
    // remove the node itself, including any children
    removeNode(node);

    // remove all now empty parents (except the root node)
    for (node = parent; node != m_rootNode; ) {
        assert(node->parent->children.count(node->name) == 1);
        if (node->children.size() == 1 && node->interfaces.empty()) {
            // we must have deleted that child while ascending; just remove the current node
            IntrospectionNode *exNode = node;
            node = node->parent;
            delete exNode;
        } else {
            // this node has other children, so we are going to keep it and update its children map
            // (we want to do this for the root node, too, so break here and do it after the loop)
            break;
        }
    }
}

void IntrospectionTree::removeNode(IntrospectionNode *node)
{
    std::map<std::string, IntrospectionNode *>::iterator it = node->children.begin();
    for (; it != node->children.end(); ++it) {
        removeNode(it->second);
    }
    delete node;
}

bool IntrospectionTree::addNode(IntrospectionNode *parent, const tx2::XMLElement *el)
{
    const tx2::XMLAttribute *attr = el->FirstAttribute();
    if (!attr || !strequal(attr->Name(), "name") || attr->Next())  {
        return false;
    }

    const bool isRootOfDocument = el == el->GetDocument()->RootElement();

    std::auto_ptr<IntrospectionNode> node(new IntrospectionNode);
    node->parent = parent;
    node->name = attr->Value();

    for (const tx2::XMLElement *child = el->FirstChildElement(); child; child = child->NextSiblingElement()) {
        if (strequal(child->Name(), "node")) {
            if (!addNode(node.get(), child)) {
                return false;
            }
        } else if (strequal(child->Name(), "interface")) {
            if (!addInterface(node.get(), child)) {
                return false;
            }
        }
    }
    parent->children[node->name] = node.release();
    return true;
}

bool IntrospectionTree::addInterface(IntrospectionNode *node, const tx2::XMLElement *el)
{
    const tx2::XMLAttribute *attr = el->FirstAttribute();
    if (!attr || !strequal(attr->Name(), "name") || attr->Next())  {
        return false;
    }

    Interface iface;
    iface.name = attr->Value();

    for (const tx2::XMLElement *child = el->FirstChildElement(); child; child = child->NextSiblingElement()) {
        if (strequal(child->Name(), "method")) {
            if (!addMethod(&iface, child, Message::MethodCallMessage)) {
                return false;
            }
        } else if (strequal(child->Name(), "signal")) {
            if (!addMethod(&iface, child, Message::SignalMessage)) {
                return false;
            }
        } else if (strequal(child->Name(), "property")) {
            if (!addProperty(&iface, child)) {
                return false;
            }
        } else {
            return false;
        }
    }
    node->interfaces[iface.name] = iface;
    return true;
}

bool IntrospectionTree::addMethod(Interface *iface, const tx2::XMLElement *el, Message::Type messageType)
{
    const tx2::XMLAttribute *attr = el->FirstAttribute();
    if (!attr || !strequal(attr->Name(), "name") || attr->Next())  {
        return false;
    }

    Method method;
    method.type = messageType;
    method.name = attr->Value();

    for (const tx2::XMLElement *child = el->FirstChildElement(); child; child = child->NextSiblingElement()) {
        if (strequal(child->Name(), "arg")) {
            if (!addArgument(&method, child, messageType)) {
                return false;
            }
        } else if (strequal(child->Name(), "annotation")) {
            // annotations are allowed, but we don't use them
            continue;
        } else {
            return false;
        }
    }
    iface->methods[method.name] = method;
    return true;
}

bool IntrospectionTree::addArgument(Method *method, const tx2::XMLElement *el, Message::Type messageType)
{
    Argument arg;
    arg.isDirectionOut = messageType == Message::SignalMessage;
    for (const tx2::XMLAttribute *attr = el->FirstAttribute(); attr; attr = attr->Next()) {
        if (strequal(attr->Name(), "name")) {
            arg.name = attr->Value();
        } else if (strequal(attr->Name(), "type")) {
            arg.type = attr->Value();
            // TODO validate (single complete type!)
        } else if (strequal(attr->Name(), "direction")) {
            if (strequal(attr->Value(), "in")) {
                if (messageType == Message::SignalMessage) {
                    return false;
                }
                arg.isDirectionOut = false;
            } else if (strequal(attr->Value(), "out")) {
                arg.isDirectionOut = true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    if (arg.type.empty()) {
        return false;
    }
    method->arguments.push_back(arg);
    return true;
}

bool IntrospectionTree::addProperty(Interface *iface, const tx2::XMLElement *el)
{
    Property prop;
    prop.access = Property::Invalid;
    for (const tx2::XMLAttribute *attr = el->FirstAttribute(); attr; attr = attr->Next()) {
        if (strequal(attr->Name(), "name")) {
            // TODO validate
            prop.name = attr->Value();
        } else if (strequal(attr->Name(), "type")) {
            // TODO validate - don't forget to check it's a single complete type
            prop.type = attr->Value();
        } else if (strequal(attr->Name(), "access")) {
            if (strequal(attr->Value(), "readwrite")) {
                prop.access = Property::ReadWrite;
            } else if (strequal(attr->Value(), "read")) {
                prop.access = Property::Read;
            } else if (strequal(attr->Value(), "write")) {
                prop.access = Property::Write;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    if (prop.name.empty() || prop.type.empty() || prop.access == Property::Invalid) {
        return false;
    }
    iface->properties[prop.name] = prop;
    return true;
}
<|endoftext|>


<commit_before>#include <atomic>
#include <chrono>
#include <iostream>
#include <memory>
#include <random>
#include <vector>

#include "MultiQueuedTaskSystem.h"
#include "OracleTaskSystem.h"
#include "TaskStealingTaskSystem.h"

#ifdef MY_DEBUG
std::atomic<int> NOT_USED;
std::atomic<int> task_count{0};
std::mutex mutex;
#endif

template <typename TaskSystemType>
void AddTasks(TaskSystemType &ts, std::vector<uint64_t> &runningTimes) {
  for (auto runningTime: runningTimes) {
    ts.async([runningTimeInNs = runningTime]() {
      auto start = std::chrono::steady_clock::now();
      auto running_time = std::chrono::steady_clock::duration(runningTimeInNs);
      auto result = runningTimeInNs;
      while ((std::chrono::steady_clock::now() - start) < running_time) {
        result *= runningTimeInNs;
        result %= 43;
        result *= runningTimeInNs;
        result %= 53;
        result *= runningTimeInNs;
        result %= 73;
      }
#ifdef MY_DEBUG
      NOT_USED.fetch_add(result, std::memory_order::memory_order_relaxed);
      task_count.fetch_add(1, std::memory_order::memory_order_relaxed);
#endif
    });
  }
}

template <typename TaskSystemType>
std::chrono::high_resolution_clock::duration MeasureTaskSystem(std::vector<uint64_t> &runningTimes) {
  auto ts = std::make_unique<TaskSystemType>();
  auto start = std::chrono::high_resolution_clock::now();
  AddTasks(*ts, runningTimes);
  ts = nullptr;
  auto end = std::chrono::high_resolution_clock::now();
  return end - start;
}

int main(int argc, char **argv) {
  if (argc < 5) {
    std::cerr << "Please add 4 number as arguments!\n";
    return -1;
  }
  char **endPtr = nullptr;
  const uint64_t distMin = std::strtoull(argv[1], endPtr, 10);
  const uint64_t distMax = std::strtoull(argv[2], endPtr, 10);
  const uint64_t nrTasks = std::strtoull(argv[3], endPtr, 10);
  const uint64_t testCase = std::strtoull(argv[4], endPtr, 10);
  std::random_device dev;
  std::mt19937_64 rng(dev());
  std::uniform_int_distribution<std::mt19937_64::result_type> dist(distMin, distMax);

  std::vector<uint64_t> runningTimes;
  runningTimes.reserve(nrTasks);
  for (auto i = 0u; i < nrTasks; ++i) {
    runningTimes.push_back(dist(rng));
  }

  std::chrono::high_resolution_clock::duration elapsedTime;
  if (testCase == 0u) {
    elapsedTime = MeasureTaskSystem<OracleTaskSystem>(runningTimes);
  } else if (testCase == 1u) {
    elapsedTime = MeasureTaskSystem<MultiQueuedTaskSystem>(runningTimes);
  } else if (testCase == 2u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<1>>(runningTimes);
  } else if (testCase == 3u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<5>>(runningTimes);
  } else if (testCase == 4u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<10>>(runningTimes);
  } else if (testCase == 5u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<50>>(runningTimes);
  } else if (testCase == 6u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<100>>(runningTimes);
  }
#ifdef MY_DEBUG
  std::cout << "NOT_USED: " << NOT_USED << "\n";
  std::cout << "Runned tasks: " << task_count << "\n";
#endif

  std::cout << "Running time: " << std::chrono::duration_cast<std::chrono::milliseconds>(elapsedTime).count() << "ms\n";
}<commit_msg>Fix warning in debug<commit_after>#include <atomic>
#include <chrono>
#include <iostream>
#include <memory>
#include <random>
#include <vector>

#include "MultiQueuedTaskSystem.h"
#include "OracleTaskSystem.h"
#include "TaskStealingTaskSystem.h"

#ifdef MY_DEBUG
std::atomic<uint64_t> NOT_USED;
std::atomic<int> task_count{0};
std::mutex mutex;
#endif

template <typename TaskSystemType>
void AddTasks(TaskSystemType &ts, std::vector<uint64_t> &runningTimes) {
  for (auto runningTime: runningTimes) {
    ts.async([runningTimeInNs = runningTime]() {
      auto start = std::chrono::steady_clock::now();
      auto running_time = std::chrono::steady_clock::duration(runningTimeInNs);
      auto result = runningTimeInNs;
      while ((std::chrono::steady_clock::now() - start) < running_time) {
        result *= runningTimeInNs;
        result %= 43;
        result *= runningTimeInNs;
        result %= 53;
        result *= runningTimeInNs;
        result %= 73;
      }
#ifdef MY_DEBUG
      NOT_USED.fetch_add(result, std::memory_order::memory_order_relaxed);
      task_count.fetch_add(1, std::memory_order::memory_order_relaxed);
#endif
    });
  }
}

template <typename TaskSystemType>
std::chrono::high_resolution_clock::duration MeasureTaskSystem(std::vector<uint64_t> &runningTimes) {
  auto ts = std::make_unique<TaskSystemType>();
  auto start = std::chrono::high_resolution_clock::now();
  AddTasks(*ts, runningTimes);
  ts = nullptr;
  auto end = std::chrono::high_resolution_clock::now();
  return end - start;
}

int main(int argc, char **argv) {
  if (argc < 5) {
    std::cerr << "Please add 4 number as arguments!\n";
    return -1;
  }
  char **endPtr = nullptr;
  const uint64_t distMin = std::strtoull(argv[1], endPtr, 10);
  const uint64_t distMax = std::strtoull(argv[2], endPtr, 10);
  const uint64_t nrTasks = std::strtoull(argv[3], endPtr, 10);
  const uint64_t testCase = std::strtoull(argv[4], endPtr, 10);
  std::random_device dev;
  std::mt19937_64 rng(dev());
  std::uniform_int_distribution<std::mt19937_64::result_type> dist(distMin, distMax);

  std::vector<uint64_t> runningTimes;
  runningTimes.reserve(nrTasks);
  for (auto i = 0u; i < nrTasks; ++i) {
    runningTimes.push_back(dist(rng));
  }

  std::chrono::high_resolution_clock::duration elapsedTime;
  if (testCase == 0u) {
    elapsedTime = MeasureTaskSystem<OracleTaskSystem>(runningTimes);
  } else if (testCase == 1u) {
    elapsedTime = MeasureTaskSystem<MultiQueuedTaskSystem>(runningTimes);
  } else if (testCase == 2u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<1>>(runningTimes);
  } else if (testCase == 3u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<5>>(runningTimes);
  } else if (testCase == 4u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<10>>(runningTimes);
  } else if (testCase == 5u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<50>>(runningTimes);
  } else if (testCase == 6u) {
    elapsedTime = MeasureTaskSystem<TaskStealingTaskSystem<100>>(runningTimes);
  }
#ifdef MY_DEBUG
  std::cout << "NOT_USED: " << NOT_USED << "\n";
  std::cout << "Runned tasks: " << task_count << "\n";
#endif

  std::cout << "Running time: " << std::chrono::duration_cast<std::chrono::milliseconds>(elapsedTime).count() << "ms\n";
}<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/compact_location_bar_host.h"

#include <algorithm>

#include "app/slide_animation.h"
#include "base/keyboard_codes.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/compact_location_bar_view.h"
#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/bookmark_bar_view.h"
#include "chrome/browser/views/find_bar_view.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/tabs/tab.h"
#include "chrome/browser/views/tabs/tab_strip.h"
#include "chrome/browser/views/toolbar_star_toggle.h"
#include "views/controls/scrollbar/native_scroll_bar.h"
#include "views/focus/external_focus_tracker.h"
#include "views/focus/view_storage.h"
#include "views/widget/root_view.h"
#include "views/widget/widget.h"

namespace chromeos {
const int kDefaultLocationBarWidth = 300;
const int kHideTimeoutInSeconds = 2;

// An mouse event observer to detect a mouse click on
// BrowserView's content area and hide the location bar.
class MouseObserver : public MessageLoopForUI::Observer {
 public:
  MouseObserver(CompactLocationBarHost* host, ::BrowserView* view)
      : host_(host),
        browser_view_(view) {
    top_level_window_ = browser_view_->GetWidget()->GetNativeView()->window;
  }

  // MessageLoopForUI::Observer overrides.
  virtual void WillProcessEvent(GdkEvent* event) {}
  virtual void DidProcessEvent(GdkEvent* event) {
    // Hide the location bar iff the mouse is pressed on the
    // BrowserView's content area.
    if (top_level_window_ == gdk_window_get_toplevel(event->any.window) &&
        event->type == GDK_BUTTON_PRESS &&
        HitContentArea(event)) {
      host_->Hide(true);
    }
  }

 private:
  // Tests if the event occured on the content area, using
  // root window's coordinates.
  bool HitContentArea(GdkEvent* event) {
    gfx::Point p(event->button.x_root, event->button.y_root);
    // First, exclude the location bar as it's shown on top of
    // content area.
    if (HitOnScreen(host_->GetClbView(), p)) {
      return false;
    }
    // Treat the bookmark as a content area when it in detached mode.
    if (browser_view_->GetBookmarkBarView()->IsDetached() &&
        browser_view_->IsBookmarkBarVisible() &&
        HitOnScreen(browser_view_->GetBookmarkBarView(), p)) {
      return true;
    }
    if (HitOnScreen(browser_view_->GetContentsView(),
                    p)) {
      return true;
    }
    return false;
  }

  // Tests if |p| in the root window's coordinate is within the |view|'s bound.
  bool HitOnScreen(const views::View* view, const gfx::Point& p) {
    gfx::Point origin(0, 0);
    views::View::ConvertPointToScreen(view, &origin);
    gfx::Rect new_bounds(origin, view->size());
    return new_bounds.Contains(p);
  }

  CompactLocationBarHost* host_;
  ::BrowserView* browser_view_;
  GdkWindow* top_level_window_;

  DISALLOW_COPY_AND_ASSIGN(MouseObserver);
};

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost, public:

CompactLocationBarHost::CompactLocationBarHost(::BrowserView* browser_view)
    : DropdownBarHost(browser_view),
      current_tab_index_(-1) {
  auto_hide_timer_.reset(new base::OneShotTimer<CompactLocationBarHost>());
  mouse_observer_.reset(new MouseObserver(this, browser_view));
  Init(new CompactLocationBarView(this));
}

CompactLocationBarHost::~CompactLocationBarHost() {
  browser_view()->browser()->tabstrip_model()->RemoveObserver(this);
  MessageLoopForUI::current()->RemoveObserver(mouse_observer_.get());
}

void CompactLocationBarHost::StartAutoHideTimer() {
  if (!host()->IsVisible())
    return;
  if (auto_hide_timer_->IsRunning()) {
    // Restart the timer.
    auto_hide_timer_->Reset();
  } else {
    auto_hide_timer_->Start(base::TimeDelta::FromSeconds(kHideTimeoutInSeconds),
                            this, &CompactLocationBarHost::HideCallback);
  }
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost, views::AcceleratorTarget implementation:

bool CompactLocationBarHost::AcceleratorPressed(
    const views::Accelerator& accelerator) {
  Hide(true);
  return false;
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost, views::DropdownBarHost implementation:

gfx::Rect CompactLocationBarHost::GetDialogPosition(
    gfx::Rect avoid_overlapping_rect) {
  DCHECK_GE(current_tab_index_, 0);
  gfx::Rect new_pos = GetBoundsUnderTab(current_tab_index_);

  if (animation_offset() > 0)
    new_pos.Offset(0, std::min(0, -animation_offset()));
  return new_pos;
}

void CompactLocationBarHost::SetDialogPosition(const gfx::Rect& new_pos,
                                               bool no_redraw) {
  if (new_pos.IsEmpty())
    return;

  // Make sure the window edges are clipped to just the visible region. We need
  // to do this before changing position, so that when we animate the closure
  // of it it doesn't look like the window crumbles into the toolbar.
  UpdateWindowEdges(new_pos);

  // TODO(oshima): Animate the window clipping like find-bar.
  SetWidgetPositionNative(new_pos, no_redraw);
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost, views::TabStripModelObserver implementation:

void CompactLocationBarHost::TabInsertedAt(TabContents* contents,
                                           int index,
                                           bool foreground) {
  Hide(false);
  // TODO(oshima): Consult UX team if we should show the location bar.
}

void CompactLocationBarHost::TabClosingAt(TabContents* contents, int index) {
  if (IsCurrentTabIndex(index)) {
    Hide(false);
  } else {
    // TODO(oshima): We need to relocate the compact navigation bar here,
    // but the tabstrip does not have the ideal location yet
    // because the tabs are animating at this time. Need to investigate
    // the best way to handle this case.
  }
}

void CompactLocationBarHost::TabSelectedAt(TabContents* old_contents,
                                           TabContents* new_contents,
                                           int index,
                                           bool user_gesture) {
  if (user_gesture) {
    // Show the compact location bar only when a user selected the tab.
    Update(index, false);
  } else {
    Hide(false);
  }
}

void CompactLocationBarHost::TabMoved(TabContents* contents,
                                      int from_index,
                                      int to_index) {
  Update(to_index, false);
}

void CompactLocationBarHost::TabChangedAt(TabContents* contents, int index,
                                          TabChangeType change_type) {
  if (IsCurrentTabIndex(index) && IsVisible()) {
    GetClbView()->Update(contents);
  }
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost public:

gfx::Rect CompactLocationBarHost::GetBoundsUnderTab(int index) const {
  // Get the position of the left-bottom corner of the tab on the
  // widget.  The widget of the tab is same as the widget of the
  // BrowserView which is the parent of the host.
  TabStrip* tabstrip = browser_view()->tabstrip()->AsTabStrip();
  gfx::Rect bounds = tabstrip->GetIdealBounds(index);
  gfx::Point tab_left_bottom(bounds.x(), bounds.height());
  views::View::ConvertPointToWidget(tabstrip, &tab_left_bottom);

  // The compact location bar must be smaller than browser_width.
  gfx::Size pref_size = view()->GetPreferredSize();
  int width = std::min(browser_view()->width(), pref_size.width());

  // Try to center around the tab, or align to the left of the window.
  // TODO(oshima): handle RTL
  int x = std::max(tab_left_bottom.x() - ((width - bounds.width()) / 2), 0);
  int y;
  if (browser_view()->IsBookmarkBarVisible() &&
      !browser_view()->GetBookmarkBarView()->IsDetached()) {
    // Adjust the location to create the illusion that the compact location bar
    // is a part of boolmark bar.
    // TODO(oshima): compact location bar does not have right background
    // image yet, so -2 is tentative. Fix this once UI is settled.
    y = browser_view()->GetBookmarkBarView()->bounds().bottom() - 2;
  } else {
    y  = tab_left_bottom.y();
  }
  return gfx::Rect(x, y, width, pref_size.height());
}

void CompactLocationBarHost::Update(int index, bool animate_x) {
  DCHECK_GE(index, 0);
  if (IsCurrentTabIndex(index) && IsVisible()) {
    return;
  }
  current_tab_index_ = index;
  // Don't aminate if the bar is already shown.
  bool animate = !animation()->IsShowing();
  Hide(false);
  GetClbView()->Update(browser_view()->browser()->GetSelectedTabContents());
  GetClbView()->SetFocusAndSelection();
  Show(animate && animate_x);
}

void CompactLocationBarHost::CancelAutoHideTimer() {
  auto_hide_timer_->Stop();
}

void CompactLocationBarHost::SetEnabled(bool enabled) {
  if (enabled) {
    browser_view()->browser()->tabstrip_model()->AddObserver(this);
  } else {
    browser_view()->browser()->tabstrip_model()->RemoveObserver(this);
  }
}

ToolbarStarToggle* CompactLocationBarHost::GetStarButton() {
  return GetClbView()->star_button();
}

void CompactLocationBarHost::Show(bool a) {
  MessageLoopForUI::current()->AddObserver(mouse_observer_.get());
  DropdownBarHost::Show(a);
}

void CompactLocationBarHost::Hide(bool a) {
  MessageLoopForUI::current()->RemoveObserver(mouse_observer_.get());
  DropdownBarHost::Hide(a);
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost private:

CompactLocationBarView* CompactLocationBarHost::GetClbView() {
  return static_cast<CompactLocationBarView*>(view());
}

bool CompactLocationBarHost::IsCurrentTabIndex(int index) {
  return current_tab_index_ == index;
}

}  // namespace chromeos
<commit_msg>Support RTL for compact navbar mode location bar.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/compact_location_bar_host.h"

#include <algorithm>

#include "app/l10n_util.h"
#include "app/slide_animation.h"
#include "base/keyboard_codes.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/compact_location_bar_view.h"
#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/bookmark_bar_view.h"
#include "chrome/browser/views/find_bar_view.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/tabs/tab.h"
#include "chrome/browser/views/tabs/tab_strip.h"
#include "chrome/browser/views/toolbar_star_toggle.h"
#include "views/controls/scrollbar/native_scroll_bar.h"
#include "views/focus/external_focus_tracker.h"
#include "views/focus/view_storage.h"
#include "views/widget/root_view.h"
#include "views/widget/widget.h"

namespace chromeos {
const int kDefaultLocationBarWidth = 300;
const int kHideTimeoutInSeconds = 2;

// An mouse event observer to detect a mouse click on
// BrowserView's content area and hide the location bar.
class MouseObserver : public MessageLoopForUI::Observer {
 public:
  MouseObserver(CompactLocationBarHost* host, ::BrowserView* view)
      : host_(host),
        browser_view_(view) {
    top_level_window_ = browser_view_->GetWidget()->GetNativeView()->window;
  }

  // MessageLoopForUI::Observer overrides.
  virtual void WillProcessEvent(GdkEvent* event) {}
  virtual void DidProcessEvent(GdkEvent* event) {
    // Hide the location bar iff the mouse is pressed on the
    // BrowserView's content area.
    if (top_level_window_ == gdk_window_get_toplevel(event->any.window) &&
        event->type == GDK_BUTTON_PRESS &&
        HitContentArea(event)) {
      host_->Hide(true);
    }
  }

 private:
  // Tests if the event occured on the content area, using
  // root window's coordinates.
  bool HitContentArea(GdkEvent* event) {
    gfx::Point p(event->button.x_root, event->button.y_root);
    // First, exclude the location bar as it's shown on top of
    // content area.
    if (HitOnScreen(host_->GetClbView(), p)) {
      return false;
    }
    // Treat the bookmark as a content area when it in detached mode.
    if (browser_view_->GetBookmarkBarView()->IsDetached() &&
        browser_view_->IsBookmarkBarVisible() &&
        HitOnScreen(browser_view_->GetBookmarkBarView(), p)) {
      return true;
    }
    if (HitOnScreen(browser_view_->GetContentsView(),
                    p)) {
      return true;
    }
    return false;
  }

  // Tests if |p| in the root window's coordinate is within the |view|'s bound.
  bool HitOnScreen(const views::View* view, const gfx::Point& p) {
    gfx::Point origin(0, 0);
    views::View::ConvertPointToScreen(view, &origin);
    gfx::Rect new_bounds(origin, view->size());
    return new_bounds.Contains(p);
  }

  CompactLocationBarHost* host_;
  ::BrowserView* browser_view_;
  GdkWindow* top_level_window_;

  DISALLOW_COPY_AND_ASSIGN(MouseObserver);
};

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost, public:

CompactLocationBarHost::CompactLocationBarHost(::BrowserView* browser_view)
    : DropdownBarHost(browser_view),
      current_tab_index_(-1) {
  auto_hide_timer_.reset(new base::OneShotTimer<CompactLocationBarHost>());
  mouse_observer_.reset(new MouseObserver(this, browser_view));
  Init(new CompactLocationBarView(this));
}

CompactLocationBarHost::~CompactLocationBarHost() {
  browser_view()->browser()->tabstrip_model()->RemoveObserver(this);
  MessageLoopForUI::current()->RemoveObserver(mouse_observer_.get());
}

void CompactLocationBarHost::StartAutoHideTimer() {
  if (!host()->IsVisible())
    return;
  if (auto_hide_timer_->IsRunning()) {
    // Restart the timer.
    auto_hide_timer_->Reset();
  } else {
    auto_hide_timer_->Start(base::TimeDelta::FromSeconds(kHideTimeoutInSeconds),
                            this, &CompactLocationBarHost::HideCallback);
  }
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost, views::AcceleratorTarget implementation:

bool CompactLocationBarHost::AcceleratorPressed(
    const views::Accelerator& accelerator) {
  Hide(true);
  return false;
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost, views::DropdownBarHost implementation:

gfx::Rect CompactLocationBarHost::GetDialogPosition(
    gfx::Rect avoid_overlapping_rect) {
  DCHECK_GE(current_tab_index_, 0);
  gfx::Rect new_pos = GetBoundsUnderTab(current_tab_index_);

  if (animation_offset() > 0)
    new_pos.Offset(0, std::min(0, -animation_offset()));
  return new_pos;
}

void CompactLocationBarHost::SetDialogPosition(const gfx::Rect& new_pos,
                                               bool no_redraw) {
  if (new_pos.IsEmpty())
    return;

  // Make sure the window edges are clipped to just the visible region. We need
  // to do this before changing position, so that when we animate the closure
  // of it it doesn't look like the window crumbles into the toolbar.
  UpdateWindowEdges(new_pos);

  // TODO(oshima): Animate the window clipping like find-bar.
  SetWidgetPositionNative(new_pos, no_redraw);
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost, views::TabStripModelObserver implementation:

void CompactLocationBarHost::TabInsertedAt(TabContents* contents,
                                           int index,
                                           bool foreground) {
  Hide(false);
  // TODO(oshima): Consult UX team if we should show the location bar.
}

void CompactLocationBarHost::TabClosingAt(TabContents* contents, int index) {
  if (IsCurrentTabIndex(index)) {
    Hide(false);
  } else {
    // TODO(oshima): We need to relocate the compact navigation bar here,
    // but the tabstrip does not have the ideal location yet
    // because the tabs are animating at this time. Need to investigate
    // the best way to handle this case.
  }
}

void CompactLocationBarHost::TabSelectedAt(TabContents* old_contents,
                                           TabContents* new_contents,
                                           int index,
                                           bool user_gesture) {
  if (user_gesture) {
    // Show the compact location bar only when a user selected the tab.
    Update(index, false);
  } else {
    Hide(false);
  }
}

void CompactLocationBarHost::TabMoved(TabContents* contents,
                                      int from_index,
                                      int to_index) {
  Update(to_index, false);
}

void CompactLocationBarHost::TabChangedAt(TabContents* contents, int index,
                                          TabChangeType change_type) {
  if (IsCurrentTabIndex(index) && IsVisible()) {
    GetClbView()->Update(contents);
  }
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost public:

gfx::Rect CompactLocationBarHost::GetBoundsUnderTab(int index) const {
  // Get the position of the left-bottom corner of the tab on the
  // widget.  The widget of the tab is same as the widget of the
  // BrowserView which is the parent of the host.
  TabStrip* tabstrip = browser_view()->tabstrip()->AsTabStrip();
  gfx::Rect bounds = tabstrip->GetIdealBounds(index);
  gfx::Rect navbar_bounds(gfx::Point(bounds.x(), bounds.height()),
                          view()->GetPreferredSize());

  // For RTL case x() defines tab right corner.
  if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) {
    navbar_bounds.set_x(navbar_bounds.x() + bounds.width());
  }
  navbar_bounds.set_x(navbar_bounds.x() + tabstrip->x());
  navbar_bounds.set_y(navbar_bounds.y() + tabstrip->y());

  // The compact location bar must be smaller than browser_width.
  int width = std::min(browser_view()->width(),
                       view()->GetPreferredSize().width());

  // Try to center around the tab.
  navbar_bounds.set_x(browser_view()->MirroredXCoordinateInsideView(
      navbar_bounds.x()) - ((width - bounds.width()) / 2));

  if (browser_view()->IsBookmarkBarVisible() &&
      !browser_view()->GetBookmarkBarView()->IsDetached()) {
    // Adjust the location to create the illusion that the compact location bar
    // is a part of boolmark bar.
    // TODO(oshima): compact location bar does not have right background
    // image yet, so -2 is tentative. Fix this once UI is settled.
    navbar_bounds.set_y(
        browser_view()->GetBookmarkBarView()->bounds().bottom() - 2);
  }
  return navbar_bounds.AdjustToFit(browser_view()->bounds());
}

void CompactLocationBarHost::Update(int index, bool animate_x) {
  DCHECK_GE(index, 0);
  if (IsCurrentTabIndex(index) && IsVisible()) {
    return;
  }
  current_tab_index_ = index;
  // Don't aminate if the bar is already shown.
  bool animate = !animation()->IsShowing();
  Hide(false);
  GetClbView()->Update(browser_view()->browser()->GetSelectedTabContents());
  GetClbView()->SetFocusAndSelection();
  Show(animate && animate_x);
}

void CompactLocationBarHost::CancelAutoHideTimer() {
  auto_hide_timer_->Stop();
}

void CompactLocationBarHost::SetEnabled(bool enabled) {
  if (enabled) {
    browser_view()->browser()->tabstrip_model()->AddObserver(this);
  } else {
    browser_view()->browser()->tabstrip_model()->RemoveObserver(this);
  }
}

ToolbarStarToggle* CompactLocationBarHost::GetStarButton() {
  return GetClbView()->star_button();
}

void CompactLocationBarHost::Show(bool a) {
  MessageLoopForUI::current()->AddObserver(mouse_observer_.get());
  DropdownBarHost::Show(a);
}

void CompactLocationBarHost::Hide(bool a) {
  MessageLoopForUI::current()->RemoveObserver(mouse_observer_.get());
  DropdownBarHost::Hide(a);
}

////////////////////////////////////////////////////////////////////////////////
// CompactLocationBarHost private:

CompactLocationBarView* CompactLocationBarHost::GetClbView() {
  return static_cast<CompactLocationBarView*>(view());
}

bool CompactLocationBarHost::IsCurrentTabIndex(int index) {
  return current_tab_index_ == index;
}

}  // namespace chromeos
<|endoftext|>