LCOV - code coverage report
Current view: directory - layout/base - FrameLayerBuilder.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1004 0 0.0 %
Date: 2012-06-02 Functions: 78 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  * ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Corporation code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Robert O'Callahan <robert@ocallahan.org>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "FrameLayerBuilder.h"
      39                 : 
      40                 : #include "nsDisplayList.h"
      41                 : #include "nsPresContext.h"
      42                 : #include "nsLayoutUtils.h"
      43                 : #include "Layers.h"
      44                 : #include "BasicLayers.h"
      45                 : #include "nsSubDocumentFrame.h"
      46                 : #include "nsCSSRendering.h"
      47                 : #include "nsCSSFrameConstructor.h"
      48                 : #include "gfxUtils.h"
      49                 : #include "nsImageFrame.h"
      50                 : #include "nsRenderingContext.h"
      51                 : 
      52                 : #include "mozilla/Preferences.h"
      53                 : #include "sampler.h"
      54                 : 
      55                 : #ifdef DEBUG
      56                 : #include <stdio.h>
      57                 : #endif
      58                 : 
      59                 : using namespace mozilla::layers;
      60                 : 
      61                 : namespace mozilla {
      62                 : 
      63                 : /**
      64                 :  * This is the userdata we associate with a layer manager.
      65                 :  */
      66                 : class LayerManagerData : public LayerUserData {
      67                 : public:
      68               0 :   LayerManagerData(LayerManager *aManager) :
      69                 :     mInvalidateAllLayers(false),
      70               0 :     mLayerManager(aManager)
      71                 :   {
      72               0 :     MOZ_COUNT_CTOR(LayerManagerData);
      73               0 :     mFramesWithLayers.Init();
      74               0 :   }
      75               0 :   ~LayerManagerData() {
      76                 :     // Remove display item data properties now, since we won't be able
      77                 :     // to find these frames again without mFramesWithLayers.
      78                 :     mFramesWithLayers.EnumerateEntries(
      79               0 :         FrameLayerBuilder::RemoveDisplayItemDataForFrame, nsnull);
      80               0 :     MOZ_COUNT_DTOR(LayerManagerData);
      81               0 :   }
      82                 : 
      83                 :   /**
      84                 :    * Tracks which frames have layers associated with them.
      85                 :    */
      86                 :   nsTHashtable<FrameLayerBuilder::DisplayItemDataEntry> mFramesWithLayers;
      87                 :   bool mInvalidateAllLayers;
      88                 :   /** Layer manager we belong to, we hold a reference to this object. */
      89                 :   nsRefPtr<LayerManager> mLayerManager;
      90                 : };
      91                 : 
      92                 : namespace {
      93                 : 
      94               0 : static void DestroyRegion(void* aPropertyValue)
      95                 : {
      96               0 :   delete static_cast<nsRegion*>(aPropertyValue);
      97               0 : }
      98                 : 
      99                 : /**
     100                 :  * This property represents a region that should be invalidated in every
     101                 :  * ThebesLayer child whose parent ContainerLayer is associated with the
     102                 :  * frame. This is an nsRegion*; the coordinates of the region are
     103                 :  * relative to the top-left of the border-box of the frame the property
     104                 :  * is attached to (which is the frame for the ContainerLayer).
     105                 :  * 
     106                 :  * We add to this region in InvalidateThebesLayerContents. The region
     107                 :  * is propagated to ContainerState in BuildContainerLayerFor, and then
     108                 :  * the region(s) are actually invalidated in CreateOrRecycleThebesLayer.
     109                 :  *
     110                 :  * When the property value is null, the region is infinite --- i.e. all
     111                 :  * areas of the ThebesLayers should be invalidated.
     112                 :  */
     113               0 : NS_DECLARE_FRAME_PROPERTY(ThebesLayerInvalidRegionProperty, DestroyRegion)
     114                 : 
     115               0 : static void DestroyPoint(void* aPropertyValue)
     116                 : {
     117                 :   delete static_cast<nsPoint*>(aPropertyValue);
     118               0 : }
     119                 : 
     120                 : /**
     121                 :  * The valid content in our child ThebesLayers is defined relative to
     122                 :  * the offset from this frame to its active scroll root, mapped back
     123                 :  * by the ThebesLayer's inverse transform.  Since we accumulate the
     124                 :  * region invalidated between last-paint and next-paint, and because
     125                 :  * the offset of this frame to its active root may change during that
     126                 :  * period, we save the offset at last-paint in this property and use
     127                 :  * it to invalidate at next-paint.
     128                 :  */
     129               0 : NS_DECLARE_FRAME_PROPERTY(ThebesLayerLastPaintOffsetProperty, DestroyPoint)
     130                 : 
     131                 : /**
     132                 :  * This is a helper object used to build up the layer children for
     133                 :  * a ContainerLayer.
     134                 :  */
     135               0 : class ContainerState {
     136                 : public:
     137               0 :   ContainerState(nsDisplayListBuilder* aBuilder,
     138                 :                  LayerManager* aManager,
     139                 :                  nsIFrame* aContainerFrame,
     140                 :                  ContainerLayer* aContainerLayer,
     141                 :                  const FrameLayerBuilder::ContainerParameters& aParameters) :
     142                 :     mBuilder(aBuilder), mManager(aManager),
     143                 :     mContainerFrame(aContainerFrame), mContainerLayer(aContainerLayer),
     144                 :     mParameters(aParameters),
     145                 :     mNextFreeRecycledThebesLayer(0), mNextFreeRecycledColorLayer(0),
     146               0 :     mNextFreeRecycledImageLayer(0), mInvalidateAllThebesContent(false)
     147                 :   {
     148               0 :     CollectOldLayers();
     149               0 :   }
     150                 : 
     151               0 :   void SetInvalidThebesContent(const nsIntRegion& aRegion)
     152                 :   {
     153               0 :     mInvalidThebesContent = aRegion;
     154               0 :   }
     155               0 :   void SetInvalidateAllThebesContent()
     156                 :   {
     157               0 :     mInvalidateAllThebesContent = true;
     158               0 :   }
     159                 :   /**
     160                 :    * This is the method that actually walks a display list and builds
     161                 :    * the child layers. We invoke it recursively to process clipped sublists.
     162                 :    * @param aClipRect the clip rect to apply to the list items, or null
     163                 :    * if no clipping is required
     164                 :    */
     165                 :   void ProcessDisplayItems(const nsDisplayList& aList,
     166                 :                            FrameLayerBuilder::Clip& aClip);
     167                 :   /**
     168                 :    * This finalizes all the open ThebesLayers by popping every element off
     169                 :    * mThebesLayerDataStack, then sets the children of the container layer
     170                 :    * to be all the layers in mNewChildLayers in that order and removes any
     171                 :    * layers as children of the container that aren't in mNewChildLayers.
     172                 :    * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA,
     173                 :    * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA
     174                 :    */
     175                 :   void Finish(PRUint32 *aTextContentFlags);
     176                 : 
     177               0 :   nsRect GetChildrenBounds() { return mBounds; }
     178                 : 
     179                 : protected:
     180                 :   /**
     181                 :    * We keep a stack of these to represent the ThebesLayers that are
     182                 :    * currently available to have display items added to.
     183                 :    * We use a stack here because as much as possible we want to
     184                 :    * assign display items to existing ThebesLayers, and to the lowest
     185                 :    * ThebesLayer in z-order. This reduces the number of layers and
     186                 :    * makes it more likely a display item will be rendered to an opaque
     187                 :    * layer, giving us the best chance of getting subpixel AA.
     188                 :    */
     189               0 :   class ThebesLayerData {
     190                 :   public:
     191               0 :     ThebesLayerData() :
     192                 :       mActiveScrolledRoot(nsnull), mLayer(nsnull),
     193                 :       mIsSolidColorInVisibleRegion(false),
     194                 :       mNeedComponentAlpha(false),
     195                 :       mForceTransparentSurface(false),
     196               0 :       mImage(nsnull) {}
     197                 :     /**
     198                 :      * Record that an item has been added to the ThebesLayer, so we
     199                 :      * need to update our regions.
     200                 :      * @param aVisibleRect the area of the item that's visible
     201                 :      * @param aDrawRect the area of the item that would be drawn if it
     202                 :      * was completely visible
     203                 :      * @param aOpaqueRect if non-null, the area of the item that's opaque.
     204                 :      * We pass in a separate opaque rect because the opaque rect can be
     205                 :      * bigger than the visible rect, and we want to have the biggest
     206                 :      * opaque rect that we can.
     207                 :      * @param aSolidColor if non-null, the visible area of the item is
     208                 :      * a constant color given by *aSolidColor
     209                 :      */
     210                 :     void Accumulate(ContainerState* aState,
     211                 :                     nsDisplayItem* aItem,
     212                 :                     const nsIntRect& aVisibleRect,
     213                 :                     const nsIntRect& aDrawRect,
     214                 :                     const FrameLayerBuilder::Clip& aClip);
     215                 :     nsIFrame* GetActiveScrolledRoot() { return mActiveScrolledRoot; }
     216                 : 
     217                 :     /**
     218                 :      * If this represents only a nsDisplayImage, and the image type
     219                 :      * supports being optimized to an ImageLayer (TYPE_RASTER only) returns
     220                 :      * an ImageContainer for the image.
     221                 :      */
     222                 :     already_AddRefed<ImageContainer> CanOptimizeImageLayer();
     223                 : 
     224                 :     /**
     225                 :      * The region of visible content in the layer, relative to the
     226                 :      * container layer (which is at the snapped top-left of the display
     227                 :      * list reference frame).
     228                 :      */
     229                 :     nsIntRegion  mVisibleRegion;
     230                 :     /**
     231                 :      * The region of visible content above the layer and below the
     232                 :      * next ThebesLayerData currently in the stack, if any. Note that not
     233                 :      * all ThebesLayers for the container are in the ThebesLayerData stack.
     234                 :      * Same coordinate system as mVisibleRegion.
     235                 :      * This is a conservative approximation: it contains the true region.
     236                 :      */
     237                 :     nsIntRegion  mVisibleAboveRegion;
     238                 :     /**
     239                 :      * The region containing the bounds of all display items in the layer,
     240                 :      * regardless of visbility.
     241                 :      * Same coordinate system as mVisibleRegion.
     242                 :      * This is a conservative approximation: it contains the true region.
     243                 :      */
     244                 :     nsIntRegion  mDrawRegion;
     245                 :     /**
     246                 :      * The region containing the bounds of all display items (regardless
     247                 :      * of visibility) in the layer and below the next ThebesLayerData
     248                 :      * currently in the stack, if any.
     249                 :      * Note that not all ThebesLayers for the container are in the
     250                 :      * ThebesLayerData stack.
     251                 :      * Same coordinate system as mVisibleRegion.
     252                 :      */
     253                 :     nsIntRegion  mDrawAboveRegion;
     254                 :     /**
     255                 :      * The region of visible content in the layer that is opaque.
     256                 :      * Same coordinate system as mVisibleRegion.
     257                 :      */
     258                 :     nsIntRegion  mOpaqueRegion;
     259                 :     /**
     260                 :      * The "active scrolled root" for all content in the layer. Must
     261                 :      * be non-null; all content in a ThebesLayer must have the same
     262                 :      * active scrolled root.
     263                 :      */
     264                 :     nsIFrame*    mActiveScrolledRoot;
     265                 :     ThebesLayer* mLayer;
     266                 :     /**
     267                 :      * If mIsSolidColorInVisibleRegion is true, this is the color of the visible
     268                 :      * region.
     269                 :      */
     270                 :     nscolor      mSolidColor;
     271                 :     /**
     272                 :      * True if every pixel in mVisibleRegion will have color mSolidColor.
     273                 :      */
     274                 :     bool mIsSolidColorInVisibleRegion;
     275                 :     /**
     276                 :      * True if there is any text visible in the layer that's over
     277                 :      * transparent pixels in the layer.
     278                 :      */
     279                 :     bool mNeedComponentAlpha;
     280                 :     /**
     281                 :      * Set if the layer should be treated as transparent, even if its entire
     282                 :      * area is covered by opaque display items. For example, this needs to
     283                 :      * be set if something is going to "punch holes" in the layer by clearing
     284                 :      * part of its surface.
     285                 :      */
     286                 :     bool mForceTransparentSurface;
     287                 : 
     288                 :     /**
     289                 :      * Stores the pointer to the nsDisplayImage if we want to
     290                 :      * convert this to an ImageLayer.
     291                 :      */
     292                 :     nsDisplayImage* mImage;
     293                 :     /**
     294                 :      * Stores the clip that we need to apply to the image.
     295                 :      */
     296                 :     FrameLayerBuilder::Clip mImageClip;
     297                 :   };
     298                 :   friend class ThebesLayerData;
     299                 : 
     300                 :   /**
     301                 :    * Grab the next recyclable ThebesLayer, or create one if there are no
     302                 :    * more recyclable ThebesLayers. Does any necessary invalidation of
     303                 :    * a recycled ThebesLayer, and sets up the transform on the ThebesLayer
     304                 :    * to account for scrolling.
     305                 :    */
     306                 :   already_AddRefed<ThebesLayer> CreateOrRecycleThebesLayer(nsIFrame* aActiveScrolledRoot);
     307                 :   /**
     308                 :    * Grab the next recyclable ColorLayer, or create one if there are no
     309                 :    * more recyclable ColorLayers.
     310                 :    */
     311                 :   already_AddRefed<ColorLayer> CreateOrRecycleColorLayer();
     312                 :   /**
     313                 :    * Grab the next recyclable ImageLayer, or create one if there are no
     314                 :    * more recyclable ImageLayers.
     315                 :    */
     316                 :   already_AddRefed<ImageLayer> CreateOrRecycleImageLayer();
     317                 :   /**
     318                 :    * Grabs all ThebesLayers and ColorLayers from the ContainerLayer and makes them
     319                 :    * available for recycling.
     320                 :    */
     321                 :   void CollectOldLayers();
     322                 :   /**
     323                 :    * If aItem used to belong to a ThebesLayer, invalidates the area of
     324                 :    * aItem in that layer. If aNewLayer is a ThebesLayer, invalidates the area of
     325                 :    * aItem in that layer.
     326                 :    */
     327                 :   void InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer);
     328                 :   /**
     329                 :    * Try to determine whether the ThebesLayer at aThebesLayerIndex
     330                 :    * has a single opaque color behind it, over the entire bounds of its visible
     331                 :    * region.
     332                 :    * If successful, return that color, otherwise return NS_RGBA(0,0,0,0).
     333                 :    */
     334                 :   nscolor FindOpaqueBackgroundColorFor(PRInt32 aThebesLayerIndex);
     335                 :   /**
     336                 :    * Indicate that we are done adding items to the ThebesLayer at the top of
     337                 :    * mThebesLayerDataStack. Set the final visible region and opaque-content
     338                 :    * flag, and pop it off the stack.
     339                 :    */
     340                 :   void PopThebesLayerData();
     341                 :   /**
     342                 :    * Find the ThebesLayer to which we should assign the next display item.
     343                 :    * We scan the ThebesLayerData stack to find the topmost ThebesLayer
     344                 :    * that is compatible with the display item (i.e., has the same
     345                 :    * active scrolled root), and that has no content from other layers above
     346                 :    * it and intersecting the aVisibleRect.
     347                 :    * Returns the layer, and also updates the ThebesLayerData. Will
     348                 :    * push a new ThebesLayerData onto the stack if no suitable existing
     349                 :    * layer is found. If we choose a ThebesLayer that's already on the
     350                 :    * ThebesLayerData stack, later elements on the stack will be popped off.
     351                 :    * @param aVisibleRect the area of the next display item that's visible
     352                 :    * @param aActiveScrolledRoot the active scrolled root for the next
     353                 :    * display item
     354                 :    * @param aOpaqueRect if non-null, a region of the display item that is opaque
     355                 :    * @param aSolidColor if non-null, indicates that every pixel in aVisibleRect
     356                 :    * will be painted with aSolidColor by the item
     357                 :    */
     358                 :   already_AddRefed<ThebesLayer> FindThebesLayerFor(nsDisplayItem* aItem,
     359                 :                                                    const nsIntRect& aVisibleRect,
     360                 :                                                    const nsIntRect& aDrawRect,
     361                 :                                                    const FrameLayerBuilder::Clip& aClip,
     362                 :                                                    nsIFrame* aActiveScrolledRoot);
     363               0 :   ThebesLayerData* GetTopThebesLayerData()
     364                 :   {
     365               0 :     return mThebesLayerDataStack.IsEmpty() ? nsnull
     366               0 :         : mThebesLayerDataStack[mThebesLayerDataStack.Length() - 1].get();
     367                 :   }
     368                 : 
     369                 :   nsDisplayListBuilder*            mBuilder;
     370                 :   LayerManager*                    mManager;
     371                 :   nsIFrame*                        mContainerFrame;
     372                 :   ContainerLayer*                  mContainerLayer;
     373                 :   FrameLayerBuilder::ContainerParameters mParameters;
     374                 :   /**
     375                 :    * The region of ThebesLayers that should be invalidated every time
     376                 :    * we recycle one.
     377                 :    */
     378                 :   nsIntRegion                      mInvalidThebesContent;
     379                 :   nsRect                           mBounds;
     380                 :   nsAutoTArray<nsAutoPtr<ThebesLayerData>,1>  mThebesLayerDataStack;
     381                 :   /**
     382                 :    * We collect the list of children in here. During ProcessDisplayItems,
     383                 :    * the layers in this array either have mContainerLayer as their parent,
     384                 :    * or no parent.
     385                 :    */
     386                 :   typedef nsAutoTArray<nsRefPtr<Layer>,1> AutoLayersArray;
     387                 :   AutoLayersArray                  mNewChildLayers;
     388                 :   nsTArray<nsRefPtr<ThebesLayer> > mRecycledThebesLayers;
     389                 :   nsTArray<nsRefPtr<ColorLayer> >  mRecycledColorLayers;
     390                 :   nsTArray<nsRefPtr<ImageLayer> >  mRecycledImageLayers;
     391                 :   PRUint32                         mNextFreeRecycledThebesLayer;
     392                 :   PRUint32                         mNextFreeRecycledColorLayer;
     393                 :   PRUint32                         mNextFreeRecycledImageLayer;
     394                 :   bool                             mInvalidateAllThebesContent;
     395                 : };
     396                 : 
     397                 : class ThebesDisplayItemLayerUserData : public LayerUserData
     398               0 : {
     399                 : public:
     400               0 :   ThebesDisplayItemLayerUserData() :
     401                 :     mForcedBackgroundColor(NS_RGBA(0,0,0,0)),
     402                 :     mXScale(1.f), mYScale(1.f),
     403               0 :     mActiveScrolledRootPosition(0, 0) {}
     404                 : 
     405                 :   /**
     406                 :    * A color that should be painted over the bounds of the layer's visible
     407                 :    * region before any other content is painted.
     408                 :    */
     409                 :   nscolor mForcedBackgroundColor;
     410                 :   /**
     411                 :    * The resolution scale used.
     412                 :    */
     413                 :   float mXScale, mYScale;
     414                 :   /**
     415                 :    * We try to make 0,0 of the ThebesLayer be the top-left of the
     416                 :    * border-box of the "active scrolled root" frame (i.e. the nearest ancestor
     417                 :    * frame for the display items that is being actively scrolled). But
     418                 :    * we force the ThebesLayer transform to be an integer translation, and we may
     419                 :    * have a resolution scale, so we have to snap the ThebesLayer transform, so
     420                 :    * 0,0 may not be exactly the top-left of the active scrolled root. Here we
     421                 :    * store the coordinates in ThebesLayer space of the top-left of the
     422                 :    * active scrolled root.
     423                 :    */
     424                 :   gfxPoint mActiveScrolledRootPosition;
     425                 : };
     426                 : 
     427                 : /**
     428                 :  * The address of gThebesDisplayItemLayerUserData is used as the user
     429                 :  * data key for ThebesLayers created by FrameLayerBuilder.
     430                 :  * It identifies ThebesLayers used to draw non-layer content, which are
     431                 :  * therefore eligible for recycling. We want display items to be able to
     432                 :  * create their own dedicated ThebesLayers in BuildLayer, if necessary,
     433                 :  * and we wouldn't want to accidentally recycle those.
     434                 :  * The user data is a ThebesDisplayItemLayerUserData.
     435                 :  */
     436                 : PRUint8 gThebesDisplayItemLayerUserData;
     437                 : /**
     438                 :  * The address of gColorLayerUserData is used as the user
     439                 :  * data key for ColorLayers created by FrameLayerBuilder.
     440                 :  * The user data is null.
     441                 :  */
     442                 : PRUint8 gColorLayerUserData;
     443                 : /**
     444                 :  * The address of gImageLayerUserData is used as the user
     445                 :  * data key for ImageLayers created by FrameLayerBuilder.
     446                 :  * The user data is null.
     447                 :  */
     448                 : PRUint8 gImageLayerUserData;
     449                 : /**
     450                 :  * The address of gLayerManagerUserData is used as the user
     451                 :  * data key for retained LayerManagers managed by FrameLayerBuilder.
     452                 :  * The user data is a LayerManagerData.
     453                 :  */
     454                 : PRUint8 gLayerManagerUserData;
     455                 : 
     456                 : } // anonymous namespace
     457                 : 
     458                 : void
     459               0 : FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder)
     460                 : {
     461               0 :   mRootPresContext = aBuilder->ReferenceFrame()->PresContext()->GetRootPresContext();
     462               0 :   if (mRootPresContext) {
     463               0 :     mInitialDOMGeneration = mRootPresContext->GetDOMGeneration();
     464                 :   }
     465               0 : }
     466                 : 
     467                 : bool
     468               0 : FrameLayerBuilder::DisplayItemDataEntry::HasNonEmptyContainerLayer()
     469                 : {
     470               0 :   for (PRUint32 i = 0; i < mData.Length(); ++i) {
     471               0 :     if (mData[i].mLayer->GetType() == Layer::TYPE_CONTAINER &&
     472               0 :         mData[i].mLayerState != LAYER_ACTIVE_EMPTY)
     473               0 :       return true;
     474                 :   }
     475               0 :   return false;
     476                 : }
     477                 : 
     478                 : void
     479               0 : FrameLayerBuilder::FlashPaint(gfxContext *aContext)
     480                 : {
     481                 :   static bool sPaintFlashingEnabled;
     482                 :   static bool sPaintFlashingPrefCached = false;
     483                 : 
     484               0 :   if (!sPaintFlashingPrefCached) {
     485               0 :     sPaintFlashingPrefCached = true;
     486                 :     mozilla::Preferences::AddBoolVarCache(&sPaintFlashingEnabled, 
     487               0 :                                           "nglayout.debug.paint_flashing");
     488                 :   }
     489                 : 
     490               0 :   if (sPaintFlashingEnabled) {
     491               0 :     float r = float(rand()) / RAND_MAX;
     492               0 :     float g = float(rand()) / RAND_MAX;
     493               0 :     float b = float(rand()) / RAND_MAX;
     494               0 :     aContext->SetColor(gfxRGBA(r, g, b, 0.2));
     495               0 :     aContext->Paint();
     496                 :   }
     497               0 : }
     498                 : 
     499                 : /* static */ nsTArray<FrameLayerBuilder::DisplayItemData>*
     500               0 : FrameLayerBuilder::GetDisplayItemDataArrayForFrame(nsIFrame* aFrame)
     501                 : {
     502               0 :   FrameProperties props = aFrame->Properties();
     503                 :   LayerManagerData *data =
     504               0 :     reinterpret_cast<LayerManagerData*>(props.Get(LayerManagerDataProperty()));
     505               0 :   if (!data)
     506               0 :     return nsnull;
     507                 : 
     508               0 :   DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame);
     509               0 :   NS_ASSERTION(entry, "out of sync?");
     510               0 :   if (!entry)
     511               0 :     return nsnull;
     512                 : 
     513               0 :   return &entry->mData;
     514                 : }
     515                 : 
     516                 : /* static */ void
     517               0 : FrameLayerBuilder::RemoveFrameFromLayerManager(nsIFrame* aFrame,
     518                 :                                                void* aPropertyValue)
     519                 : {
     520               0 :   LayerManagerData *data = reinterpret_cast<LayerManagerData*>(aPropertyValue);
     521               0 :   data->mFramesWithLayers.RemoveEntry(aFrame);
     522               0 :   if (data->mFramesWithLayers.Count() == 0) {
     523               0 :     data->mLayerManager->RemoveUserData(&gLayerManagerUserData);
     524                 :   }
     525               0 : }
     526                 : 
     527                 : void
     528               0 : FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
     529                 : {
     530               0 :   mRetainingManager = aManager;
     531                 :   LayerManagerData* data = static_cast<LayerManagerData*>
     532               0 :     (aManager->GetUserData(&gLayerManagerUserData));
     533               0 :   if (data) {
     534               0 :     mInvalidateAllLayers = data->mInvalidateAllLayers;
     535                 :   }
     536               0 : }
     537                 : 
     538                 : /**
     539                 :  * A helper function to remove the mThebesLayerItems entries for every
     540                 :  * layer in aLayer's subtree.
     541                 :  */
     542                 : void
     543               0 : FrameLayerBuilder::RemoveThebesItemsForLayerSubtree(Layer* aLayer)
     544                 : {
     545               0 :   ThebesLayer* thebes = aLayer->AsThebesLayer();
     546               0 :   if (thebes) {
     547               0 :     mThebesLayerItems.RemoveEntry(thebes);
     548               0 :     return;
     549                 :   }
     550                 : 
     551               0 :   for (Layer* child = aLayer->GetFirstChild(); child;
     552                 :        child = child->GetNextSibling()) {
     553               0 :     RemoveThebesItemsForLayerSubtree(child);
     554                 :   }
     555                 : }
     556                 : 
     557                 : void
     558               0 : FrameLayerBuilder::DidEndTransaction(LayerManager* aManager)
     559                 : {
     560               0 :   if (aManager != mRetainingManager) {
     561               0 :     Layer* root = aManager->GetRoot();
     562               0 :     if (root) {
     563               0 :       RemoveThebesItemsForLayerSubtree(root);
     564                 :     }
     565                 :   }
     566               0 : }
     567                 : 
     568                 : void
     569               0 : FrameLayerBuilder::WillEndTransaction(LayerManager* aManager)
     570                 : {
     571               0 :   if (aManager != mRetainingManager)
     572               0 :     return;
     573                 : 
     574                 :   // We need to save the data we'll need to support retaining. We do this
     575                 :   // before we paint so that invalidation triggered by painting will
     576                 :   // be able to update the ThebesLayerInvalidRegionProperty values
     577                 :   // correctly and the NS_FRAME_HAS_CONTAINER_LAYER bits will be set
     578                 :   // correctly.
     579                 :   LayerManagerData* data = static_cast<LayerManagerData*>
     580               0 :     (mRetainingManager->GetUserData(&gLayerManagerUserData));
     581               0 :   if (data) {
     582                 :     // Update all the frames that used to have layers.
     583               0 :     data->mFramesWithLayers.EnumerateEntries(UpdateDisplayItemDataForFrame, this);
     584                 :   } else {
     585               0 :     data = new LayerManagerData(mRetainingManager);
     586               0 :     mRetainingManager->SetUserData(&gLayerManagerUserData, data);
     587                 :   }
     588                 :   // Now go through all the frames that didn't have any retained
     589                 :   // display items before, and record those retained display items.
     590                 :   // This also empties mNewDisplayItemData.
     591               0 :   mNewDisplayItemData.EnumerateEntries(StoreNewDisplayItemData, data);
     592               0 :   data->mInvalidateAllLayers = false;
     593                 : 
     594               0 :   NS_ASSERTION(data->mFramesWithLayers.Count() > 0,
     595                 :                "Some frame must have a layer!");
     596                 : }
     597                 : 
     598                 : static void
     599               0 : SetHasContainerLayer(nsIFrame* aFrame, nsPoint aOffsetToRoot)
     600                 : {
     601               0 :   aFrame->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER);
     602               0 :   for (nsIFrame* f = aFrame;
     603               0 :        f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
     604                 :        f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
     605               0 :     f->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
     606                 :   }
     607                 : 
     608               0 :   FrameProperties props = aFrame->Properties();
     609                 :   nsPoint* lastPaintOffset = static_cast<nsPoint*>
     610               0 :     (props.Get(ThebesLayerLastPaintOffsetProperty()));
     611               0 :   if (lastPaintOffset) {
     612               0 :     *lastPaintOffset = aOffsetToRoot;
     613                 :   } else {
     614               0 :     props.Set(ThebesLayerLastPaintOffsetProperty(), new nsPoint(aOffsetToRoot));
     615                 :   }
     616               0 : }
     617                 : 
     618                 : static void
     619               0 : SetNoContainerLayer(nsIFrame* aFrame)
     620                 : {
     621               0 :   FrameProperties props = aFrame->Properties();
     622               0 :   props.Delete(ThebesLayerInvalidRegionProperty());
     623               0 :   props.Delete(ThebesLayerLastPaintOffsetProperty());
     624               0 :   aFrame->RemoveStateBits(NS_FRAME_HAS_CONTAINER_LAYER);
     625               0 : }
     626                 : 
     627                 : /* static */ PLDHashOperator
     628               0 : FrameLayerBuilder::UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
     629                 :                                                  void* aUserArg)
     630                 : {
     631               0 :   FrameLayerBuilder* builder = static_cast<FrameLayerBuilder*>(aUserArg);
     632               0 :   nsIFrame* f = aEntry->GetKey();
     633               0 :   FrameProperties props = f->Properties();
     634                 :   DisplayItemDataEntry* newDisplayItems =
     635               0 :     builder ? builder->mNewDisplayItemData.GetEntry(f) : nsnull;
     636               0 :   if (!newDisplayItems) {
     637                 :     // This frame was visible, but isn't anymore.
     638                 :     bool found;
     639               0 :     props.Remove(LayerManagerDataProperty(), &found);
     640               0 :     NS_ASSERTION(found, "How can the frame property be missing?");
     641               0 :     SetNoContainerLayer(f);
     642               0 :     return PL_DHASH_REMOVE;
     643                 :   }
     644                 : 
     645               0 :   if (newDisplayItems->HasNonEmptyContainerLayer()) {
     646                 :     // Reset or create the invalid region now so we can start collecting
     647                 :     // new dirty areas.
     648                 :     // Note that the NS_FRAME_HAS_CONTAINER_LAYER bit is set in
     649                 :     // BuildContainerLayerFor, so we don't need to set it here.
     650                 :     nsRegion* invalidRegion = static_cast<nsRegion*>
     651               0 :       (props.Get(ThebesLayerInvalidRegionProperty()));
     652               0 :     if (invalidRegion) {
     653               0 :       invalidRegion->SetEmpty();
     654                 :     } else {
     655               0 :       props.Set(ThebesLayerInvalidRegionProperty(), new nsRegion());
     656                 :     }
     657                 :   } else {
     658               0 :     SetNoContainerLayer(f);
     659                 :   }
     660                 : 
     661                 :   // Steal the list of display item layers
     662               0 :   aEntry->mData.SwapElements(newDisplayItems->mData);
     663                 :   // Don't need to process this frame again
     664               0 :   builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems);
     665               0 :   return PL_DHASH_NEXT;
     666                 : }
     667                 : 
     668                 : /* static */ PLDHashOperator
     669               0 : FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemDataEntry* aEntry,
     670                 :                                            void* aUserArg)
     671                 : {
     672               0 :   LayerManagerData* data = static_cast<LayerManagerData*>(aUserArg);
     673               0 :   nsIFrame* f = aEntry->GetKey();
     674               0 :   FrameProperties props = f->Properties();
     675                 :   // Remember that this frame has display items in retained layers
     676               0 :   NS_ASSERTION(!data->mFramesWithLayers.GetEntry(f),
     677                 :                "We shouldn't get here if we're already in mFramesWithLayers");
     678               0 :   DisplayItemDataEntry *newEntry = data->mFramesWithLayers.PutEntry(f);
     679               0 :   NS_ASSERTION(!props.Get(LayerManagerDataProperty()),
     680                 :                "mFramesWithLayers out of sync");
     681                 : 
     682               0 :   newEntry->mData.SwapElements(aEntry->mData);
     683               0 :   props.Set(LayerManagerDataProperty(), data);
     684                 : 
     685               0 :   if (f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) {
     686               0 :     props.Set(ThebesLayerInvalidRegionProperty(), new nsRegion());
     687                 :   }
     688               0 :   return PL_DHASH_REMOVE;
     689                 : }
     690                 : 
     691                 : bool
     692               0 : FrameLayerBuilder::HasRetainedLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
     693                 : {
     694               0 :   nsTArray<DisplayItemData> *array = GetDisplayItemDataArrayForFrame(aFrame);
     695               0 :   if (!array)
     696               0 :     return false;
     697                 : 
     698               0 :   for (PRUint32 i = 0; i < array->Length(); ++i) {
     699               0 :     if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
     700               0 :       Layer* layer = array->ElementAt(i).mLayer;
     701               0 :       if (layer->Manager()->GetUserData(&gLayerManagerUserData)) {
     702                 :         // All layer managers with our user data are retained layer managers
     703               0 :         return true;
     704                 :       }
     705                 :     }
     706                 :   }
     707               0 :   return false;
     708                 : }
     709                 : 
     710                 : Layer*
     711               0 : FrameLayerBuilder::GetOldLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
     712                 : {
     713                 :   // If we need to build a new layer tree, then just refuse to recycle
     714                 :   // anything.
     715               0 :   if (!mRetainingManager || mInvalidateAllLayers)
     716               0 :     return nsnull;
     717                 : 
     718               0 :   nsTArray<DisplayItemData> *array = GetDisplayItemDataArrayForFrame(aFrame);
     719               0 :   if (!array)
     720               0 :     return nsnull;
     721                 : 
     722               0 :   for (PRUint32 i = 0; i < array->Length(); ++i) {
     723               0 :     if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
     724               0 :       Layer* layer = array->ElementAt(i).mLayer;
     725               0 :       if (layer->Manager() == mRetainingManager)
     726               0 :         return layer;
     727                 :     }
     728                 :   }
     729               0 :   return nsnull;
     730                 : }
     731                 : 
     732                 : /**
     733                 :  * Invalidate aRegion in aLayer. aLayer is in the coordinate system
     734                 :  * *after* aTranslation has been applied, so we need to
     735                 :  * apply the inverse of that transform before calling InvalidateRegion.
     736                 :  */
     737                 : static void
     738               0 : InvalidatePostTransformRegion(ThebesLayer* aLayer, const nsIntRegion& aRegion,
     739                 :                               const nsIntPoint& aTranslation)
     740                 : {
     741                 :   // Convert the region from the coordinates of the container layer
     742                 :   // (relative to the snapped top-left of the display list reference frame)
     743                 :   // to the ThebesLayer's own coordinates
     744               0 :   nsIntRegion rgn = aRegion;
     745               0 :   rgn.MoveBy(-aTranslation);
     746               0 :   aLayer->InvalidateRegion(rgn);
     747               0 : }
     748                 : 
     749                 : already_AddRefed<ColorLayer>
     750               0 : ContainerState::CreateOrRecycleColorLayer()
     751                 : {
     752               0 :   nsRefPtr<ColorLayer> layer;
     753               0 :   if (mNextFreeRecycledColorLayer < mRecycledColorLayers.Length()) {
     754                 :     // Recycle a layer
     755               0 :     layer = mRecycledColorLayers[mNextFreeRecycledColorLayer];
     756               0 :     ++mNextFreeRecycledColorLayer;
     757                 :     // Clear clip rect so we don't accidentally stay clipped. We will
     758                 :     // reapply any necessary clipping.
     759               0 :     layer->SetClipRect(nsnull);
     760                 :   } else {
     761                 :     // Create a new layer
     762               0 :     layer = mManager->CreateColorLayer();
     763               0 :     if (!layer)
     764               0 :       return nsnull;
     765                 :     // Mark this layer as being used for Thebes-painting display items
     766               0 :     layer->SetUserData(&gColorLayerUserData, nsnull);
     767                 :   }
     768               0 :   return layer.forget();
     769                 : }
     770                 : 
     771                 : already_AddRefed<ImageLayer>
     772               0 : ContainerState::CreateOrRecycleImageLayer()
     773                 : {
     774               0 :   nsRefPtr<ImageLayer> layer;
     775               0 :   if (mNextFreeRecycledImageLayer < mRecycledImageLayers.Length()) {
     776                 :     // Recycle a layer
     777               0 :     layer = mRecycledImageLayers[mNextFreeRecycledImageLayer];
     778               0 :     ++mNextFreeRecycledImageLayer;
     779                 :     // Clear clip rect so we don't accidentally stay clipped. We will
     780                 :     // reapply any necessary clipping.
     781               0 :     layer->SetClipRect(nsnull);
     782                 :   } else {
     783                 :     // Create a new layer
     784               0 :     layer = mManager->CreateImageLayer();
     785               0 :     if (!layer)
     786               0 :       return nsnull;
     787                 :     // Mark this layer as being used for Thebes-painting display items
     788               0 :     layer->SetUserData(&gImageLayerUserData, nsnull);
     789                 :   }
     790               0 :   return layer.forget();
     791                 : }
     792                 : 
     793                 : static nsIntPoint
     794               0 : GetTranslationForThebesLayer(ThebesLayer* aLayer)
     795                 : {
     796               0 :   gfxMatrix transform;
     797               0 :   if (!aLayer->GetTransform().Is2D(&transform) ||
     798               0 :       transform.HasNonIntegerTranslation()) {
     799               0 :     NS_ERROR("ThebesLayers should have integer translations only");
     800               0 :     return nsIntPoint(0, 0);
     801                 :   }
     802               0 :   return nsIntPoint(PRInt32(transform.x0), PRInt32(transform.y0));
     803                 : }
     804                 : 
     805                 : already_AddRefed<ThebesLayer>
     806               0 : ContainerState::CreateOrRecycleThebesLayer(nsIFrame* aActiveScrolledRoot)
     807                 : {
     808                 :   // We need a new thebes layer
     809               0 :   nsRefPtr<ThebesLayer> layer;
     810                 :   ThebesDisplayItemLayerUserData* data;
     811               0 :   if (mNextFreeRecycledThebesLayer < mRecycledThebesLayers.Length()) {
     812                 :     // Recycle a layer
     813               0 :     layer = mRecycledThebesLayers[mNextFreeRecycledThebesLayer];
     814               0 :     ++mNextFreeRecycledThebesLayer;
     815                 :     // Clear clip rect so we don't accidentally stay clipped. We will
     816                 :     // reapply any necessary clipping.
     817               0 :     layer->SetClipRect(nsnull);
     818                 : 
     819                 :     data = static_cast<ThebesDisplayItemLayerUserData*>
     820               0 :         (layer->GetUserData(&gThebesDisplayItemLayerUserData));
     821               0 :     NS_ASSERTION(data, "Recycled ThebesLayers must have user data");
     822                 : 
     823                 :     // This gets called on recycled ThebesLayers that are going to be in the
     824                 :     // final layer tree, so it's a convenient time to invalidate the
     825                 :     // content that changed where we don't know what ThebesLayer it belonged
     826                 :     // to, or if we need to invalidate the entire layer, we can do that.
     827                 :     // This needs to be done before we update the ThebesLayer to its new
     828                 :     // transform. See nsGfxScrollFrame::InvalidateInternal, where
     829                 :     // we ensure that mInvalidThebesContent is updated according to the
     830                 :     // scroll position as of the most recent paint.
     831               0 :     if (mInvalidateAllThebesContent ||
     832                 :         data->mXScale != mParameters.mXScale ||
     833                 :         data->mYScale != mParameters.mYScale) {
     834               0 :       nsIntRect invalidate = layer->GetValidRegion().GetBounds();
     835               0 :       layer->InvalidateRegion(invalidate);
     836                 :     } else {
     837                 :       InvalidatePostTransformRegion(layer, mInvalidThebesContent,
     838               0 :                                     GetTranslationForThebesLayer(layer));
     839                 :     }
     840                 :     // We do not need to Invalidate these areas in the widget because we
     841                 :     // assume the caller of InvalidateThebesLayerContents has ensured
     842                 :     // the area is invalidated in the widget.
     843                 :   } else {
     844                 :     // Create a new thebes layer
     845               0 :     layer = mManager->CreateThebesLayer();
     846               0 :     if (!layer)
     847               0 :       return nsnull;
     848                 :     // Mark this layer as being used for Thebes-painting display items
     849               0 :     data = new ThebesDisplayItemLayerUserData();
     850               0 :     layer->SetUserData(&gThebesDisplayItemLayerUserData, data);
     851                 :   }
     852               0 :   data->mXScale = mParameters.mXScale;
     853               0 :   data->mYScale = mParameters.mYScale;
     854                 :   // If we're in a transformed subtree, but no ancestor transform is actively
     855                 :   // changing, we'll use the residual translation when drawing into the
     856                 :   // ThebesLayer to ensure that snapping exactly matches the ideal transform.
     857                 :   layer->SetAllowResidualTranslation(
     858               0 :       mParameters.mInTransformedSubtree && !mParameters.mInActiveTransformedSubtree);
     859                 : 
     860               0 :   mBuilder->LayerBuilder()->SaveLastPaintOffset(layer);
     861                 : 
     862                 :   // Set up transform so that 0,0 in the Thebes layer corresponds to the
     863                 :   // (pixel-snapped) top-left of the aActiveScrolledRoot.
     864               0 :   nsPoint offset = mBuilder->ToReferenceFrame(aActiveScrolledRoot);
     865               0 :   nscoord appUnitsPerDevPixel = aActiveScrolledRoot->PresContext()->AppUnitsPerDevPixel();
     866                 :   gfxPoint scaledOffset(
     867               0 :       NSAppUnitsToDoublePixels(offset.x, appUnitsPerDevPixel)*mParameters.mXScale,
     868               0 :       NSAppUnitsToDoublePixels(offset.y, appUnitsPerDevPixel)*mParameters.mYScale);
     869               0 :   nsIntPoint pixOffset(NSToIntRoundUp(scaledOffset.x), NSToIntRoundUp(scaledOffset.y));
     870               0 :   gfxMatrix matrix;
     871               0 :   matrix.Translate(gfxPoint(pixOffset.x, pixOffset.y));
     872               0 :   layer->SetTransform(gfx3DMatrix::From2D(matrix));
     873                 : 
     874                 :   // Calculate exact position of the top-left of the active scrolled root.
     875                 :   // This might not be 0,0 due to the snapping in ScaleToNearestPixels.
     876               0 :   gfxPoint activeScrolledRootTopLeft = scaledOffset - matrix.GetTranslation();
     877                 :   // If it has changed, then we need to invalidate the entire layer since the
     878                 :   // pixels in the layer buffer have the content at a (subpixel) offset
     879                 :   // from what we need.
     880               0 :   if (activeScrolledRootTopLeft != data->mActiveScrolledRootPosition) {
     881               0 :     data->mActiveScrolledRootPosition = activeScrolledRootTopLeft;
     882               0 :     nsIntRect invalidate = layer->GetValidRegion().GetBounds();
     883               0 :     layer->InvalidateRegion(invalidate);
     884                 :   }
     885                 : 
     886               0 :   return layer.forget();
     887                 : }
     888                 : 
     889                 : /**
     890                 :  * Returns the appunits per dev pixel for the item's frame. The item must
     891                 :  * have a frame because only nsDisplayClip items don't have a frame,
     892                 :  * and those items are flattened away by ProcessDisplayItems.
     893                 :  */
     894                 : static PRInt32
     895               0 : AppUnitsPerDevPixel(nsDisplayItem* aItem)
     896                 : {
     897                 :   // The underlying frame for zoom items is the root frame of the subdocument.
     898                 :   // But zoom display items report their bounds etc using the parent document's
     899                 :   // APD because zoom items act as a conversion layer between the two different
     900                 :   // APDs.
     901               0 :   if (aItem->GetType() == nsDisplayItem::TYPE_ZOOM) {
     902               0 :     return static_cast<nsDisplayZoom*>(aItem)->GetParentAppUnitsPerDevPixel();
     903                 :   }
     904               0 :   return aItem->GetUnderlyingFrame()->PresContext()->AppUnitsPerDevPixel();
     905                 : }
     906                 : 
     907                 : /**
     908                 :  * Restrict the visible region of aLayer to the region that is actually visible.
     909                 :  * Because we only reduce the visible region here, we don't need to worry
     910                 :  * about whether CONTENT_OPAQUE is set; if layer was opauqe in the old
     911                 :  * visible region, it will still be opaque in the new one.
     912                 :  * @param aItemVisible the visible region of the display item (that is,
     913                 :  * after any layer transform has been applied)
     914                 :  */
     915                 : static void
     916               0 : RestrictVisibleRegionForLayer(Layer* aLayer, const nsIntRect& aItemVisible)
     917                 : {
     918               0 :   gfx3DMatrix transform = aLayer->GetTransform();
     919                 : 
     920                 :   // if 'transform' is not invertible, then nothing will be displayed
     921                 :   // for the layer, so it doesn't really matter what we do here
     922               0 :   gfxRect itemVisible(aItemVisible.x, aItemVisible.y, aItemVisible.width, aItemVisible.height);
     923               0 :   gfxRect layerVisible = transform.Inverse().ProjectRectBounds(itemVisible);
     924               0 :   layerVisible.RoundOut();
     925                 : 
     926               0 :   nsIntRect visibleRect;
     927               0 :   if (!gfxUtils::GfxRectToIntRect(layerVisible, &visibleRect))
     928               0 :     return;
     929                 : 
     930               0 :   nsIntRegion rgn = aLayer->GetVisibleRegion();
     931               0 :   if (!visibleRect.Contains(rgn.GetBounds())) {
     932               0 :     rgn.And(rgn, visibleRect);
     933               0 :     aLayer->SetVisibleRegion(rgn);
     934                 :   }
     935                 : }
     936                 : 
     937                 : nscolor
     938               0 : ContainerState::FindOpaqueBackgroundColorFor(PRInt32 aThebesLayerIndex)
     939                 : {
     940               0 :   ThebesLayerData* target = mThebesLayerDataStack[aThebesLayerIndex];
     941               0 :   for (PRInt32 i = aThebesLayerIndex - 1; i >= 0; --i) {
     942               0 :     ThebesLayerData* candidate = mThebesLayerDataStack[i];
     943               0 :     nsIntRegion visibleAboveIntersection;
     944               0 :     visibleAboveIntersection.And(candidate->mVisibleAboveRegion, target->mVisibleRegion);
     945               0 :     if (!visibleAboveIntersection.IsEmpty()) {
     946                 :       // Some non-Thebes content between target and candidate; this is
     947                 :       // hopeless
     948                 :       break;
     949                 :     }
     950                 : 
     951               0 :     nsIntRegion intersection;
     952               0 :     intersection.And(candidate->mVisibleRegion, target->mVisibleRegion);
     953               0 :     if (intersection.IsEmpty()) {
     954                 :       // The layer doesn't intersect our target, ignore it and move on
     955               0 :       continue;
     956                 :     }
     957                 : 
     958                 :     // The candidate intersects our target. If any layer has a solid-color
     959                 :     // area behind our target, this must be it. Scan its display items.
     960               0 :     nsPresContext* presContext = mContainerFrame->PresContext();
     961               0 :     nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
     962                 :     nsRect rect =
     963               0 :       target->mVisibleRegion.GetBounds().ToAppUnits(appUnitsPerDevPixel);
     964               0 :     rect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale);
     965                 :     return mBuilder->LayerBuilder()->
     966               0 :       FindOpaqueColorCovering(mBuilder, candidate->mLayer, rect);
     967                 :   }
     968               0 :   return NS_RGBA(0,0,0,0);
     969                 : }
     970                 : 
     971                 : already_AddRefed<ImageContainer>
     972               0 : ContainerState::ThebesLayerData::CanOptimizeImageLayer()
     973                 : {
     974               0 :   if (!mImage || !mImageClip.mRoundedClipRects.IsEmpty()) {
     975               0 :     return nsnull;
     976                 :   }
     977                 : 
     978               0 :   return mImage->GetContainer();
     979                 : }
     980                 : 
     981                 : void
     982               0 : ContainerState::PopThebesLayerData()
     983                 : {
     984               0 :   NS_ASSERTION(!mThebesLayerDataStack.IsEmpty(), "Can't pop");
     985                 : 
     986               0 :   PRInt32 lastIndex = mThebesLayerDataStack.Length() - 1;
     987               0 :   ThebesLayerData* data = mThebesLayerDataStack[lastIndex];
     988                 : 
     989               0 :   nsRefPtr<Layer> layer;
     990               0 :   nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(); 
     991                 : 
     992               0 :   if ((data->mIsSolidColorInVisibleRegion || imageContainer) &&
     993               0 :       data->mLayer->GetValidRegion().IsEmpty()) {
     994               0 :     NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer),
     995                 :                  "Can't be a solid color as well as an image!");
     996               0 :     if (imageContainer) {
     997               0 :       nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer();
     998               0 :       imageLayer->SetContainer(imageContainer);
     999               0 :       data->mImage->ConfigureLayer(imageLayer);
    1000               0 :       if (mParameters.mInActiveTransformedSubtree) {
    1001                 :         // The layer's current transform is applied first, then the result is scaled.
    1002               0 :         gfx3DMatrix transform = imageLayer->GetTransform()*
    1003               0 :           gfx3DMatrix::ScalingMatrix(mParameters.mXScale, mParameters.mYScale, 1.0f);
    1004               0 :         imageLayer->SetTransform(transform);
    1005                 :       }
    1006               0 :       NS_ASSERTION(data->mImageClip.mRoundedClipRects.IsEmpty(),
    1007                 :                    "How did we get rounded clip rects here?");
    1008               0 :       if (data->mImageClip.mHaveClipRect) {
    1009               0 :         nsPresContext* presContext = mContainerFrame->PresContext();
    1010               0 :         nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
    1011                 :         nsIntRect clip = data->mImageClip.mClipRect.ScaleToNearestPixels(
    1012               0 :             mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel);
    1013               0 :         imageLayer->IntersectClipRect(clip);
    1014                 :       }
    1015               0 :       layer = imageLayer;
    1016                 :     } else {
    1017               0 :       nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer();
    1018               0 :       colorLayer->SetIsFixedPosition(data->mLayer->GetIsFixedPosition());
    1019               0 :       colorLayer->SetColor(data->mSolidColor);
    1020                 : 
    1021                 :       // Copy transform
    1022               0 :       colorLayer->SetTransform(data->mLayer->GetTransform());
    1023                 :       
    1024                 :       // Clip colorLayer to its visible region, since ColorLayers are
    1025                 :       // allowed to paint outside the visible region. Here we rely on the
    1026                 :       // fact that uniform display items fill rectangles; obviously the
    1027                 :       // area to fill must contain the visible region, and because it's
    1028                 :       // a rectangle, it must therefore contain the visible region's GetBounds.
    1029                 :       // Note that the visible region is already clipped appropriately.
    1030               0 :       nsIntRect visibleRect = data->mVisibleRegion.GetBounds();
    1031               0 :       colorLayer->SetClipRect(&visibleRect);
    1032                 : 
    1033               0 :       layer = colorLayer;
    1034                 :     }
    1035                 : 
    1036               0 :     NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
    1037               0 :     AutoLayersArray::index_type index = mNewChildLayers.IndexOf(data->mLayer);
    1038               0 :     NS_ASSERTION(index != AutoLayersArray::NoIndex, "Thebes layer not found?");
    1039               0 :     mNewChildLayers.InsertElementAt(index + 1, layer);
    1040                 : 
    1041                 :     // Hide the ThebesLayer. We leave it in the layer tree so that we
    1042                 :     // can find and recycle it later.
    1043               0 :     data->mLayer->IntersectClipRect(nsIntRect());
    1044               0 :     data->mLayer->SetVisibleRegion(nsIntRegion());
    1045                 :   } else {
    1046               0 :     layer = data->mLayer;
    1047               0 :     imageContainer = nsnull;
    1048                 :   }
    1049                 : 
    1050               0 :   gfxMatrix transform;
    1051               0 :   if (!layer->GetTransform().Is2D(&transform)) {
    1052               0 :     NS_ERROR("Only 2D transformations currently supported");
    1053                 :   }
    1054                 :   
    1055                 :   // ImageLayers are already configured with a visible region
    1056               0 :   if (!imageContainer) {
    1057               0 :     NS_ASSERTION(!transform.HasNonIntegerTranslation(),
    1058                 :                  "Matrix not just an integer translation?");
    1059                 :     // Convert from relative to the container to relative to the
    1060                 :     // ThebesLayer itself.
    1061               0 :     nsIntRegion rgn = data->mVisibleRegion;
    1062               0 :     rgn.MoveBy(-nsIntPoint(PRInt32(transform.x0), PRInt32(transform.y0)));
    1063               0 :     layer->SetVisibleRegion(rgn);
    1064                 :   }
    1065                 : 
    1066               0 :   nsIntRegion transparentRegion;
    1067               0 :   transparentRegion.Sub(data->mVisibleRegion, data->mOpaqueRegion);
    1068               0 :   bool isOpaque = transparentRegion.IsEmpty();
    1069                 :   // For translucent ThebesLayers, try to find an opaque background
    1070                 :   // color that covers the entire area beneath it so we can pull that
    1071                 :   // color into this layer to make it opaque.
    1072               0 :   if (layer == data->mLayer) {
    1073               0 :     nscolor backgroundColor = NS_RGBA(0,0,0,0);
    1074               0 :     if (!isOpaque) {
    1075               0 :       backgroundColor = FindOpaqueBackgroundColorFor(lastIndex);
    1076               0 :       if (NS_GET_A(backgroundColor) == 255) {
    1077               0 :         isOpaque = true;
    1078                 :       }
    1079                 :     }
    1080                 : 
    1081                 :     // Store the background color
    1082                 :     ThebesDisplayItemLayerUserData* userData =
    1083                 :       static_cast<ThebesDisplayItemLayerUserData*>
    1084               0 :         (data->mLayer->GetUserData(&gThebesDisplayItemLayerUserData));
    1085               0 :     NS_ASSERTION(userData, "where did our user data go?");
    1086               0 :     if (userData->mForcedBackgroundColor != backgroundColor) {
    1087                 :       // Invalidate the entire target ThebesLayer since we're changing
    1088                 :       // the background color
    1089               0 :       data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion());
    1090                 :     }
    1091               0 :     userData->mForcedBackgroundColor = backgroundColor;
    1092                 :   }
    1093                 :   PRUint32 flags;
    1094               0 :   if (isOpaque && !data->mForceTransparentSurface) {
    1095               0 :     flags = Layer::CONTENT_OPAQUE;
    1096               0 :   } else if (data->mNeedComponentAlpha) {
    1097               0 :     flags = Layer::CONTENT_COMPONENT_ALPHA;
    1098                 :   } else {
    1099               0 :     flags = 0;
    1100                 :   }
    1101               0 :   layer->SetContentFlags(flags);
    1102                 : 
    1103               0 :   if (lastIndex > 0) {
    1104                 :     // Since we're going to pop off the last ThebesLayerData, the
    1105                 :     // mVisibleAboveRegion of the second-to-last item will need to include
    1106                 :     // the regions of the last item.
    1107               0 :     ThebesLayerData* nextData = mThebesLayerDataStack[lastIndex - 1];
    1108                 :     nextData->mVisibleAboveRegion.Or(nextData->mVisibleAboveRegion,
    1109               0 :                                      data->mVisibleAboveRegion);
    1110                 :     nextData->mVisibleAboveRegion.Or(nextData->mVisibleAboveRegion,
    1111               0 :                                      data->mVisibleRegion);
    1112               0 :     nextData->mVisibleAboveRegion.SimplifyOutward(4);
    1113                 :     nextData->mDrawAboveRegion.Or(nextData->mDrawAboveRegion,
    1114               0 :                                      data->mDrawAboveRegion);
    1115                 :     nextData->mDrawAboveRegion.Or(nextData->mDrawAboveRegion,
    1116               0 :                                      data->mDrawRegion);
    1117               0 :     nextData->mDrawAboveRegion.SimplifyOutward(4);
    1118                 :   }
    1119                 : 
    1120               0 :   mThebesLayerDataStack.RemoveElementAt(lastIndex);
    1121               0 : }
    1122                 : 
    1123                 : static bool
    1124               0 : SuppressComponentAlpha(nsDisplayListBuilder* aBuilder,
    1125                 :                        nsDisplayItem* aItem,
    1126                 :                        const nsRect& aComponentAlphaBounds)
    1127                 : {
    1128               0 :   const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion();
    1129               0 :   if (!windowTransparentRegion || windowTransparentRegion->IsEmpty())
    1130               0 :     return false;
    1131                 : 
    1132                 :   // Suppress component alpha for items in the toplevel window that are over
    1133                 :   // the window translucent area
    1134               0 :   nsIFrame* f = aItem->GetUnderlyingFrame();
    1135               0 :   nsIFrame* ref = aBuilder->ReferenceFrame();
    1136               0 :   if (f->PresContext() != ref->PresContext())
    1137               0 :     return false;
    1138                 : 
    1139               0 :   for (nsIFrame* t = f; t; t = t->GetParent()) {
    1140               0 :     if (t->IsTransformed())
    1141               0 :       return false;
    1142                 :   }
    1143                 : 
    1144               0 :   return windowTransparentRegion->Intersects(aComponentAlphaBounds);
    1145                 : }
    1146                 : 
    1147                 : static bool
    1148               0 : WindowHasTransparency(nsDisplayListBuilder* aBuilder)
    1149                 : {
    1150               0 :   const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion();
    1151               0 :   return windowTransparentRegion && !windowTransparentRegion->IsEmpty();
    1152                 : }
    1153                 : 
    1154                 : void
    1155               0 : ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
    1156                 :                                             nsDisplayItem* aItem,
    1157                 :                                             const nsIntRect& aVisibleRect,
    1158                 :                                             const nsIntRect& aDrawRect,
    1159                 :                                             const FrameLayerBuilder::Clip& aClip)
    1160                 : {
    1161                 :   nscolor uniformColor;
    1162               0 :   bool isUniform = aItem->IsUniform(aState->mBuilder, &uniformColor);
    1163                 :   
    1164                 :   /* Mark as available for conversion to image layer if this is a nsDisplayImage and
    1165                 :    * we are the first visible item in the ThebesLayerData object.
    1166                 :    */
    1167               0 :   if (aItem->GetType() == nsDisplayItem::TYPE_IMAGE && mVisibleRegion.IsEmpty()) {
    1168               0 :     mImage = static_cast<nsDisplayImage*>(aItem);
    1169               0 :     mImageClip = aClip;
    1170                 :   } else {
    1171               0 :     mImage = nsnull;
    1172                 :   }
    1173                 : 
    1174                 :   // Some display items have to exist (so they can set forceTransparentSurface
    1175                 :   // below) but don't draw anything. They'll return true for isUniform but
    1176                 :   // a color with opacity 0.
    1177               0 :   if (!isUniform || NS_GET_A(uniformColor) > 0) {
    1178               0 :     if (isUniform &&
    1179               0 :         aItem->GetBounds(aState->mBuilder).ScaleToInsidePixels(
    1180                 :             aState->mParameters.mXScale, aState->mParameters.mYScale,
    1181               0 :             AppUnitsPerDevPixel(aItem)).Contains(aVisibleRect)) {
    1182               0 :       if (mVisibleRegion.IsEmpty()) {
    1183                 :         // This color is all we have
    1184               0 :         mSolidColor = uniformColor;
    1185               0 :         mIsSolidColorInVisibleRegion = true;
    1186               0 :       } else if (mIsSolidColorInVisibleRegion &&
    1187               0 :                  mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect))) {
    1188                 :         // we can just blend the colors together
    1189               0 :         mSolidColor = NS_ComposeColors(mSolidColor, uniformColor);
    1190                 :       } else {
    1191               0 :         mIsSolidColorInVisibleRegion = false;
    1192                 :       }
    1193                 :     } else {
    1194               0 :       mIsSolidColorInVisibleRegion = false;
    1195                 :     }
    1196                 : 
    1197               0 :     mVisibleRegion.Or(mVisibleRegion, aVisibleRect);
    1198               0 :     mVisibleRegion.SimplifyOutward(4);
    1199               0 :     mDrawRegion.Or(mDrawRegion, aDrawRect);
    1200               0 :     mDrawRegion.SimplifyOutward(4);
    1201                 :   }
    1202                 :   
    1203               0 :   bool forceTransparentSurface = false;
    1204               0 :   nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &forceTransparentSurface);
    1205               0 :   if (!opaque.IsEmpty()) {
    1206               0 :     nsRegionRectIterator iter(opaque);
    1207               0 :     nscoord appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
    1208               0 :     for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
    1209                 :       // We don't use SimplifyInward here since it's not defined exactly
    1210                 :       // what it will discard. For our purposes the most important case
    1211                 :       // is a large opaque background at the bottom of z-order (e.g.,
    1212                 :       // a canvas background), so we need to make sure that the first rect
    1213                 :       // we see doesn't get discarded.
    1214               0 :       nsIntRect rect = aClip.ApproximateIntersect(*r).ScaleToInsidePixels(
    1215                 :           aState->mParameters.mXScale, aState->mParameters.mYScale,
    1216               0 :           appUnitsPerDevPixel);
    1217               0 :       nsIntRegion tmp;
    1218               0 :       tmp.Or(mOpaqueRegion, rect);
    1219                 :        // Opaque display items in chrome documents whose window is partially
    1220                 :        // transparent are always added to the opaque region. This helps ensure
    1221                 :        // that we get as much subpixel-AA as possible in the chrome.
    1222               0 :        if (tmp.GetNumRects() <= 4 ||
    1223               0 :            (WindowHasTransparency(aState->mBuilder) &&
    1224               0 :             aItem->GetUnderlyingFrame()->PresContext()->IsChrome())) {
    1225               0 :         mOpaqueRegion = tmp;
    1226                 :       }
    1227                 :     }
    1228                 :   }
    1229               0 :   if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
    1230                 :     // Disable component alpha. This is cheaper than calling GetComponentAlphaBounds since for
    1231                 :     // most items this is a single virtual call that does nothing.
    1232                 :     // Note that the transform (if any) on the ThebesLayer is always an integer translation so
    1233                 :     // we don't have to factor that in here.
    1234               0 :     aItem->DisableComponentAlpha();
    1235                 :   } else {
    1236               0 :     nsRect componentAlpha = aItem->GetComponentAlphaBounds(aState->mBuilder);
    1237               0 :     componentAlpha.IntersectRect(componentAlpha, aItem->GetVisibleRect());
    1238               0 :     if (!componentAlpha.IsEmpty()) {
    1239               0 :       nscoord appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
    1240               0 :       if (!mOpaqueRegion.Contains(componentAlpha.ScaleToOutsidePixels(
    1241               0 :           aState->mParameters.mXScale, aState->mParameters.mYScale, appUnitsPerDevPixel))) {
    1242               0 :         if (SuppressComponentAlpha(aState->mBuilder, aItem, componentAlpha)) {
    1243               0 :           aItem->DisableComponentAlpha();
    1244                 :         } else {
    1245               0 :           mNeedComponentAlpha = true;
    1246                 :         }
    1247                 :       }
    1248                 :     }
    1249                 :   }
    1250               0 :   mForceTransparentSurface = mForceTransparentSurface || forceTransparentSurface;
    1251               0 : }
    1252                 : 
    1253                 : already_AddRefed<ThebesLayer>
    1254               0 : ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
    1255                 :                                    const nsIntRect& aVisibleRect,
    1256                 :                                    const nsIntRect& aDrawRect,
    1257                 :                                    const FrameLayerBuilder::Clip& aClip,
    1258                 :                                    nsIFrame* aActiveScrolledRoot)
    1259                 : {
    1260                 :   PRInt32 i;
    1261               0 :   PRInt32 lowestUsableLayerWithScrolledRoot = -1;
    1262               0 :   PRInt32 topmostLayerWithScrolledRoot = -1;
    1263               0 :   for (i = mThebesLayerDataStack.Length() - 1; i >= 0; --i) {
    1264               0 :     ThebesLayerData* data = mThebesLayerDataStack[i];
    1265               0 :     if (data->mDrawAboveRegion.Intersects(aVisibleRect)) {
    1266               0 :       ++i;
    1267               0 :       break;
    1268                 :     }
    1269               0 :     if (data->mActiveScrolledRoot == aActiveScrolledRoot) {
    1270               0 :       lowestUsableLayerWithScrolledRoot = i;
    1271               0 :       if (topmostLayerWithScrolledRoot < 0) {
    1272               0 :         topmostLayerWithScrolledRoot = i;
    1273                 :       }
    1274                 :     }
    1275               0 :     if (data->mDrawRegion.Intersects(aVisibleRect))
    1276               0 :       break;
    1277                 :   }
    1278               0 :   if (topmostLayerWithScrolledRoot < 0) {
    1279               0 :     --i;
    1280               0 :     for (; i >= 0; --i) {
    1281               0 :       ThebesLayerData* data = mThebesLayerDataStack[i];
    1282               0 :       if (data->mActiveScrolledRoot == aActiveScrolledRoot) {
    1283               0 :         topmostLayerWithScrolledRoot = i;
    1284               0 :         break;
    1285                 :       }
    1286                 :     }
    1287                 :   }
    1288                 : 
    1289               0 :   if (topmostLayerWithScrolledRoot >= 0) {
    1290               0 :     while (PRUint32(topmostLayerWithScrolledRoot + 1) < mThebesLayerDataStack.Length()) {
    1291               0 :       PopThebesLayerData();
    1292                 :     }
    1293                 :   }
    1294                 : 
    1295               0 :   nsRefPtr<ThebesLayer> layer;
    1296               0 :   ThebesLayerData* thebesLayerData = nsnull;
    1297               0 :   if (lowestUsableLayerWithScrolledRoot < 0) {
    1298               0 :     layer = CreateOrRecycleThebesLayer(aActiveScrolledRoot);
    1299                 : 
    1300               0 :     NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
    1301               0 :     mNewChildLayers.AppendElement(layer);
    1302                 : 
    1303               0 :     thebesLayerData = new ThebesLayerData();
    1304               0 :     mThebesLayerDataStack.AppendElement(thebesLayerData);
    1305               0 :     thebesLayerData->mLayer = layer;
    1306               0 :     thebesLayerData->mActiveScrolledRoot = aActiveScrolledRoot;
    1307                 :   } else {
    1308               0 :     thebesLayerData = mThebesLayerDataStack[lowestUsableLayerWithScrolledRoot];
    1309               0 :     layer = thebesLayerData->mLayer;
    1310                 :   }
    1311                 : 
    1312               0 :   thebesLayerData->Accumulate(this, aItem, aVisibleRect, aDrawRect, aClip);
    1313               0 :   return layer.forget();
    1314                 : }
    1315                 : 
    1316                 : #ifdef MOZ_DUMP_PAINTING
    1317                 : static void
    1318               0 : DumpPaintedImage(nsDisplayItem* aItem, gfxASurface* aSurf)
    1319                 : {
    1320               0 :   nsCString string(aItem->Name());
    1321               0 :   string.Append("-");
    1322               0 :   string.AppendInt((PRUint64)aItem);
    1323               0 :   fprintf(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
    1324               0 :   aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
    1325               0 :   fprintf(gfxUtils::sDumpPaintFile, "\";");
    1326               0 : }
    1327                 : #endif
    1328                 : 
    1329                 : static void
    1330               0 : PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
    1331                 :                    nsDisplayItem* aItem,
    1332                 :                    gfxContext* aContext)
    1333                 : {
    1334                 :   // This item has an inactive layer. Render it to a ThebesLayer
    1335                 :   // using a temporary BasicLayerManager.
    1336               0 :   PRInt32 appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
    1337                 :   nsIntRect itemVisibleRect =
    1338               0 :     aItem->GetVisibleRect().ToOutsidePixels(appUnitsPerDevPixel);
    1339                 : 
    1340               0 :   nsRefPtr<gfxContext> context = aContext;
    1341                 : #ifdef MOZ_DUMP_PAINTING
    1342               0 :   nsRefPtr<gfxASurface> surf; 
    1343               0 :   if (gfxUtils::sDumpPainting) {
    1344               0 :     surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(itemVisibleRect.Size(), 
    1345               0 :                                                               gfxASurface::CONTENT_COLOR_ALPHA);
    1346               0 :     surf->SetDeviceOffset(-itemVisibleRect.TopLeft());
    1347               0 :     context = new gfxContext(surf);
    1348                 :   }
    1349                 : #endif
    1350                 : 
    1351               0 :   nsRefPtr<BasicLayerManager> tempManager = new BasicLayerManager();
    1352               0 :   tempManager->BeginTransactionWithTarget(context);
    1353                 :   nsRefPtr<Layer> layer =
    1354               0 :     aItem->BuildLayer(aBuilder, tempManager, FrameLayerBuilder::ContainerParameters());
    1355               0 :   if (!layer) {
    1356               0 :     tempManager->EndTransaction(nsnull, nsnull);
    1357                 :     return;
    1358                 :   }
    1359               0 :   RestrictVisibleRegionForLayer(layer, itemVisibleRect);
    1360                 :   
    1361               0 :   tempManager->SetRoot(layer);
    1362               0 :   aBuilder->LayerBuilder()->WillEndTransaction(tempManager);
    1363               0 :   tempManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);
    1364               0 :   aBuilder->LayerBuilder()->DidEndTransaction(tempManager);
    1365                 :  
    1366                 : #ifdef MOZ_DUMP_PAINTING
    1367               0 :   if (gfxUtils::sDumpPainting) {
    1368               0 :     DumpPaintedImage(aItem, surf);
    1369                 :   
    1370               0 :     surf->SetDeviceOffset(gfxPoint(0, 0));
    1371               0 :     aContext->SetSource(surf, itemVisibleRect.TopLeft());
    1372               0 :     aContext->Rectangle(itemVisibleRect);
    1373               0 :     aContext->Fill();
    1374               0 :     aItem->SetPainted();
    1375                 :   }
    1376                 : #endif
    1377                 : }
    1378                 : 
    1379                 : /*
    1380                 :  * Iterate through the non-clip items in aList and its descendants.
    1381                 :  * For each item we compute the effective clip rect. Each item is assigned
    1382                 :  * to a layer. We invalidate the areas in ThebesLayers where an item
    1383                 :  * has moved from one ThebesLayer to another. Also,
    1384                 :  * aState->mInvalidThebesContent is invalidated in every ThebesLayer.
    1385                 :  * We set the clip rect for items that generated their own layer.
    1386                 :  * (ThebesLayers don't need a clip rect on the layer, we clip the items
    1387                 :  * individually when we draw them.)
    1388                 :  * If we have to clip to a rounded rect, we treat any active layer as
    1389                 :  * though it's inactive so that we draw it ourselves into the thebes layer.
    1390                 :  * We set the visible rect for all layers, although the actual setting
    1391                 :  * of visible rects for some ThebesLayers is deferred until the calling
    1392                 :  * of ContainerState::Finish.
    1393                 :  */
    1394                 : void
    1395               0 : ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
    1396                 :                                     FrameLayerBuilder::Clip& aClip)
    1397                 : {
    1398                 :   PRInt32 appUnitsPerDevPixel =
    1399               0 :     mContainerFrame->PresContext()->AppUnitsPerDevPixel();
    1400                 : 
    1401               0 :   for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
    1402               0 :     nsDisplayItem::Type type = item->GetType();
    1403               0 :     if (type == nsDisplayItem::TYPE_CLIP ||
    1404                 :         type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) {
    1405               0 :       FrameLayerBuilder::Clip childClip(aClip, item);
    1406               0 :       ProcessDisplayItems(*item->GetList(), childClip);
    1407               0 :       continue;
    1408                 :     }
    1409                 : 
    1410               0 :     NS_ASSERTION(appUnitsPerDevPixel == AppUnitsPerDevPixel(item),
    1411                 :       "items in a container layer should all have the same app units per dev pixel");
    1412                 : 
    1413                 :     nsIntRect itemVisibleRect =
    1414               0 :       item->GetVisibleRect().ScaleToOutsidePixels(
    1415               0 :           mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel);
    1416               0 :     nsRect itemContent = item->GetBounds(mBuilder);
    1417               0 :     if (aClip.mHaveClipRect) {
    1418               0 :       itemContent.IntersectRect(aClip.mClipRect, itemContent);
    1419                 :     }
    1420               0 :     mBounds.UnionRect(mBounds, itemContent);
    1421                 :     nsIntRect itemDrawRect = itemContent.ScaleToOutsidePixels(
    1422               0 :         mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel);
    1423               0 :     LayerState layerState = item->GetLayerState(mBuilder, mManager);
    1424                 : 
    1425                 :     nsIFrame* activeScrolledRoot =
    1426               0 :       nsLayoutUtils::GetActiveScrolledRootFor(item, mBuilder);
    1427                 : 
    1428                 :     // Assign the item to a layer
    1429               0 :     if (layerState == LAYER_ACTIVE_FORCE ||
    1430                 :         layerState == LAYER_ACTIVE_EMPTY ||
    1431                 :         (layerState == LAYER_ACTIVE &&
    1432               0 :          (aClip.mRoundedClipRects.IsEmpty() ||
    1433                 :           // We can use the visible rect here only because the item has its own
    1434                 :           // layer, like the comment below.
    1435               0 :           !aClip.IsRectClippedByRoundedCorner(item->GetVisibleRect())))) {
    1436                 : 
    1437                 :       // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
    1438                 :       // We should never see an empty layer with any visible content!
    1439               0 :       NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY ||
    1440                 :                    itemVisibleRect.IsEmpty(),
    1441                 :                    "State is LAYER_ACTIVE_EMPTY but visible rect is not.");
    1442                 : 
    1443                 :       // If the item would have its own layer but is invisible, just hide it.
    1444                 :       // Note that items without their own layers can't be skipped this
    1445                 :       // way, since their ThebesLayer may decide it wants to draw them
    1446                 :       // into its buffer even if they're currently covered.
    1447               0 :       if (itemVisibleRect.IsEmpty() && layerState != LAYER_ACTIVE_EMPTY) {
    1448               0 :         InvalidateForLayerChange(item, nsnull);
    1449               0 :         continue;
    1450                 :       }
    1451                 : 
    1452                 :       // Just use its layer.
    1453               0 :       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
    1454               0 :       if (!ownLayer) {
    1455               0 :         InvalidateForLayerChange(item, ownLayer);
    1456               0 :         continue;
    1457                 :       }
    1458                 : 
    1459                 :       // If it's not a ContainerLayer, we need to apply the scale transform
    1460                 :       // ourselves.
    1461               0 :       if (!ownLayer->AsContainerLayer()) {
    1462                 :         // The layer's current transform is applied first, then the result is scaled.
    1463               0 :         gfx3DMatrix transform = ownLayer->GetTransform()*
    1464               0 :             gfx3DMatrix::ScalingMatrix(mParameters.mXScale, mParameters.mYScale, 1.0f);
    1465               0 :         ownLayer->SetTransform(transform);
    1466                 :       }
    1467                 : 
    1468                 :       ownLayer->SetIsFixedPosition(!nsLayoutUtils::ScrolledByViewportScrolling(
    1469               0 :                                       activeScrolledRoot, mBuilder));
    1470                 : 
    1471                 :       // Update that layer's clip and visible rects.
    1472               0 :       NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
    1473               0 :       NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
    1474                 :                    "We shouldn't have a FrameLayerBuilder-managed layer here!");
    1475               0 :       NS_ASSERTION(aClip.mHaveClipRect ||
    1476                 :                      aClip.mRoundedClipRects.IsEmpty(),
    1477                 :                    "If we have rounded rects, we must have a clip rect");
    1478                 :       // It has its own layer. Update that layer's clip and visible rects.
    1479               0 :       if (aClip.mHaveClipRect) {
    1480                 :         ownLayer->IntersectClipRect(
    1481               0 :             aClip.NonRoundedIntersection().ScaleToNearestPixels(
    1482               0 :                 mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel));
    1483                 :       }
    1484               0 :       ThebesLayerData* data = GetTopThebesLayerData();
    1485               0 :       if (data) {
    1486               0 :         data->mVisibleAboveRegion.Or(data->mVisibleAboveRegion, itemVisibleRect);
    1487               0 :         data->mVisibleAboveRegion.SimplifyOutward(4);
    1488                 :         // Add the entire bounds rect to the mDrawAboveRegion.
    1489                 :         // The visible region may be excluding opaque content above the
    1490                 :         // item, and we need to ensure that that content is not placed
    1491                 :         // in a ThebesLayer below the item!
    1492               0 :         data->mDrawAboveRegion.Or(data->mDrawAboveRegion, itemDrawRect);
    1493               0 :         data->mDrawAboveRegion.SimplifyOutward(4);
    1494                 :       }
    1495               0 :       RestrictVisibleRegionForLayer(ownLayer, itemVisibleRect);
    1496               0 :       ContainerLayer* oldContainer = ownLayer->GetParent();
    1497               0 :       if (oldContainer && oldContainer != mContainerLayer) {
    1498               0 :         oldContainer->RemoveChild(ownLayer);
    1499                 :       }
    1500               0 :       NS_ASSERTION(!mNewChildLayers.Contains(ownLayer),
    1501                 :                    "Layer already in list???");
    1502                 : 
    1503               0 :       InvalidateForLayerChange(item, ownLayer);
    1504                 : 
    1505               0 :       mNewChildLayers.AppendElement(ownLayer);
    1506               0 :       mBuilder->LayerBuilder()->AddLayerDisplayItem(ownLayer, item, layerState);
    1507                 :     } else {
    1508                 :       nsRefPtr<ThebesLayer> thebesLayer =
    1509                 :         FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, aClip,
    1510               0 :                            activeScrolledRoot);
    1511                 : 
    1512               0 :       thebesLayer->SetIsFixedPosition(!nsLayoutUtils::ScrolledByViewportScrolling(
    1513               0 :                                          activeScrolledRoot, mBuilder));
    1514                 : 
    1515               0 :       InvalidateForLayerChange(item, thebesLayer);
    1516                 : 
    1517                 :       mBuilder->LayerBuilder()->
    1518                 :         AddThebesDisplayItem(thebesLayer, item, aClip, mContainerFrame,
    1519               0 :                              layerState);
    1520                 :     }
    1521                 :   }
    1522               0 : }
    1523                 : 
    1524                 : void
    1525               0 : ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer)
    1526                 : {
    1527               0 :   nsIFrame* f = aItem->GetUnderlyingFrame();
    1528               0 :   NS_ASSERTION(f, "Display items that render using Thebes must have a frame");
    1529               0 :   PRUint32 key = aItem->GetPerFrameKey();
    1530               0 :   NS_ASSERTION(key, "Display items that render using Thebes must have a key");
    1531               0 :   Layer* oldLayer = mBuilder->LayerBuilder()->GetOldLayerFor(f, key);
    1532               0 :   if (!oldLayer) {
    1533                 :     // Nothing to do here, this item didn't have a layer before
    1534               0 :     return;
    1535                 :   }
    1536               0 :   if (aNewLayer != oldLayer) {
    1537                 :     // The item has changed layers.
    1538                 :     // Invalidate the bounds in the old layer and new layer.
    1539                 :     // The bounds might have changed, but we assume that any difference
    1540                 :     // in the bounds will have been invalidated for all Thebes layers
    1541                 :     // in the container via regular frame invalidation.
    1542               0 :     nsRect bounds = aItem->GetBounds(mBuilder);
    1543               0 :     PRInt32 appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
    1544                 : 
    1545               0 :     ThebesLayer* t = oldLayer->AsThebesLayer();
    1546               0 :     if (t) {
    1547                 :       ThebesDisplayItemLayerUserData* data =
    1548               0 :           static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
    1549                 :       // Note that whenever the layer's scale changes, we invalidate the whole thing,
    1550                 :       // so it doesn't matter whether we are using the old scale at last paint
    1551                 :       // or a new scale here
    1552                 :       InvalidatePostTransformRegion(t,
    1553                 :           bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, appUnitsPerDevPixel),
    1554               0 :           mBuilder->LayerBuilder()->GetLastPaintOffset(t));
    1555                 :     }
    1556               0 :     if (aNewLayer) {
    1557               0 :       ThebesLayer* newLayer = aNewLayer->AsThebesLayer();
    1558               0 :       if (newLayer) {
    1559                 :         ThebesDisplayItemLayerUserData* data =
    1560               0 :             static_cast<ThebesDisplayItemLayerUserData*>(newLayer->GetUserData(&gThebesDisplayItemLayerUserData));
    1561                 :         InvalidatePostTransformRegion(newLayer,
    1562                 :             bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, appUnitsPerDevPixel),
    1563               0 :             GetTranslationForThebesLayer(newLayer));
    1564                 :       }
    1565                 :     }
    1566                 : 
    1567               0 :     NS_ASSERTION(appUnitsPerDevPixel ==
    1568                 :                    mContainerFrame->PresContext()->AppUnitsPerDevPixel(),
    1569                 :                  "app units per dev pixel should be constant in a container");
    1570                 :     mContainerFrame->InvalidateWithFlags(
    1571               0 :         bounds - mBuilder->ToReferenceFrame(mContainerFrame),
    1572                 :         nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
    1573               0 :         nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
    1574                 :   }
    1575                 : }
    1576                 : 
    1577                 : bool
    1578               0 : FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder,
    1579                 :                                                     nsDisplayItem* aItem)
    1580                 : {
    1581               0 :   return !aItem->ShouldFixToViewport(aBuilder) ||
    1582               0 :       !HasRetainedLayerFor(aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey());
    1583                 : }
    1584                 : 
    1585                 : void
    1586               0 : FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
    1587                 :                                         nsDisplayItem* aItem,
    1588                 :                                         const Clip& aClip,
    1589                 :                                         nsIFrame* aContainerLayerFrame,
    1590                 :                                         LayerState aLayerState)
    1591                 : {
    1592               0 :   AddLayerDisplayItem(aLayer, aItem, aLayerState);
    1593                 : 
    1594               0 :   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
    1595               0 :   if (entry) {
    1596               0 :     entry->mContainerLayerFrame = aContainerLayerFrame;
    1597               0 :     NS_ASSERTION(aItem->GetUnderlyingFrame(), "Must have frame");
    1598                 :     ClippedDisplayItem* cdi =
    1599               0 :       entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip));
    1600               0 :     cdi->mInactiveLayer = aLayerState != LAYER_NONE;
    1601                 :   }
    1602               0 : }
    1603                 : 
    1604                 : void
    1605               0 : FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
    1606                 :                                        nsDisplayItem* aItem,
    1607                 :                                        LayerState aLayerState)
    1608                 : {
    1609               0 :   if (aLayer->Manager() != mRetainingManager)
    1610               0 :     return;
    1611                 : 
    1612               0 :   nsIFrame* f = aItem->GetUnderlyingFrame();
    1613               0 :   DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(f);
    1614               0 :   if (entry) {
    1615               0 :     entry->mData.AppendElement(DisplayItemData(aLayer, aItem->GetPerFrameKey(), aLayerState));
    1616                 :   }
    1617                 : }
    1618                 : 
    1619                 : nsIntPoint
    1620               0 : FrameLayerBuilder::GetLastPaintOffset(ThebesLayer* aLayer)
    1621                 : {
    1622               0 :   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
    1623               0 :   if (entry && entry->mHasExplicitLastPaintOffset)
    1624               0 :     return entry->mLastPaintOffset;
    1625               0 :   return GetTranslationForThebesLayer(aLayer);
    1626                 : }
    1627                 : 
    1628                 : void
    1629               0 : FrameLayerBuilder::SaveLastPaintOffset(ThebesLayer* aLayer)
    1630                 : {
    1631               0 :   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
    1632               0 :   if (entry) {
    1633               0 :     entry->mLastPaintOffset = GetTranslationForThebesLayer(aLayer);
    1634               0 :     entry->mHasExplicitLastPaintOffset = true;
    1635                 :   }
    1636               0 : }
    1637                 : 
    1638                 : nscolor
    1639               0 : FrameLayerBuilder::FindOpaqueColorCovering(nsDisplayListBuilder* aBuilder,
    1640                 :                                            ThebesLayer* aLayer,
    1641                 :                                            const nsRect& aRect)
    1642                 : {
    1643               0 :   ThebesLayerItemsEntry* entry = mThebesLayerItems.GetEntry(aLayer);
    1644               0 :   NS_ASSERTION(entry, "Must know about this layer!");
    1645               0 :   for (PRInt32 i = entry->mItems.Length() - 1; i >= 0; --i) {
    1646               0 :     nsDisplayItem* item = entry->mItems[i].mItem;
    1647               0 :     const nsRect& visible = item->GetVisibleRect();
    1648               0 :     if (!visible.Intersects(aRect))
    1649               0 :       continue;
    1650                 : 
    1651                 :     nscolor color;
    1652               0 :     if (visible.Contains(aRect) && item->IsUniform(aBuilder, &color) &&
    1653                 :         NS_GET_A(color) == 255)
    1654               0 :       return color;
    1655               0 :     break;
    1656                 :   }
    1657               0 :   return NS_RGBA(0,0,0,0);
    1658                 : }
    1659                 : 
    1660                 : void
    1661               0 : ContainerState::CollectOldLayers()
    1662                 : {
    1663               0 :   for (Layer* layer = mContainerLayer->GetFirstChild(); layer;
    1664                 :        layer = layer->GetNextSibling()) {
    1665               0 :     if (layer->HasUserData(&gColorLayerUserData)) {
    1666               0 :       mRecycledColorLayers.AppendElement(static_cast<ColorLayer*>(layer));
    1667               0 :     } else if (layer->HasUserData(&gImageLayerUserData)) {
    1668               0 :       mRecycledImageLayers.AppendElement(static_cast<ImageLayer*>(layer));
    1669               0 :     } else if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
    1670               0 :       NS_ASSERTION(layer->AsThebesLayer(), "Wrong layer type");
    1671               0 :       mRecycledThebesLayers.AppendElement(static_cast<ThebesLayer*>(layer));
    1672                 :     }
    1673                 :   }
    1674               0 : }
    1675                 : 
    1676                 : void
    1677               0 : ContainerState::Finish(PRUint32* aTextContentFlags)
    1678                 : {
    1679               0 :   while (!mThebesLayerDataStack.IsEmpty()) {
    1680               0 :     PopThebesLayerData();
    1681                 :   }
    1682                 : 
    1683               0 :   PRUint32 textContentFlags = 0;
    1684                 : 
    1685               0 :   for (PRUint32 i = 0; i <= mNewChildLayers.Length(); ++i) {
    1686                 :     // An invariant of this loop is that the layers in mNewChildLayers
    1687                 :     // with index < i are the first i child layers of mContainerLayer.
    1688                 :     Layer* layer;
    1689               0 :     if (i < mNewChildLayers.Length()) {
    1690               0 :       layer = mNewChildLayers[i];
    1691               0 :       if (!layer->GetVisibleRegion().IsEmpty()) {
    1692               0 :         textContentFlags |= layer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA;
    1693                 :       }
    1694               0 :       if (!layer->GetParent()) {
    1695                 :         // This is not currently a child of the container, so just add it
    1696                 :         // now.
    1697               0 :         Layer* prevChild = i == 0 ? nsnull : mNewChildLayers[i - 1].get();
    1698               0 :         mContainerLayer->InsertAfter(layer, prevChild);
    1699               0 :         continue;
    1700                 :       }
    1701               0 :       NS_ASSERTION(layer->GetParent() == mContainerLayer,
    1702                 :                    "Layer shouldn't be the child of some other container");
    1703                 :     } else {
    1704               0 :       layer = nsnull;
    1705                 :     }
    1706                 : 
    1707                 :     // If layer is non-null, then it's already a child of the container,
    1708                 :     // so scan forward until we find it, removing the other layers we
    1709                 :     // don't want here.
    1710                 :     // If it's null, scan forward until we've removed all the leftover
    1711                 :     // children.
    1712               0 :     Layer* nextOldChild = i == 0 ? mContainerLayer->GetFirstChild() :
    1713               0 :       mNewChildLayers[i - 1]->GetNextSibling();
    1714               0 :     while (nextOldChild != layer) {
    1715               0 :       Layer* tmp = nextOldChild;
    1716               0 :       nextOldChild = nextOldChild->GetNextSibling();
    1717               0 :       mContainerLayer->RemoveChild(tmp);
    1718                 :     }
    1719                 :     // If non-null, 'layer' is now in the right place in the list, so we
    1720                 :     // can just move on to the next one.
    1721                 :   }
    1722                 : 
    1723               0 :   *aTextContentFlags = textContentFlags;
    1724               0 : }
    1725                 : 
    1726                 : static FrameLayerBuilder::ContainerParameters
    1727               0 : ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
    1728                 :                            nsIFrame* aContainerFrame,
    1729                 :                            const gfx3DMatrix* aTransform,
    1730                 :                            const FrameLayerBuilder::ContainerParameters& aIncomingScale,
    1731                 :                            ContainerLayer* aLayer)
    1732                 : {
    1733                 :   gfx3DMatrix transform =
    1734               0 :     gfx3DMatrix::ScalingMatrix(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
    1735               0 :   if (aTransform) {
    1736                 :     // aTransform is applied first, then the scale is applied to the result
    1737               0 :     transform = (*aTransform)*transform;
    1738                 :   }
    1739                 : 
    1740               0 :   gfxMatrix transform2d;
    1741               0 :   bool canDraw2D = transform.CanDraw2D(&transform2d);
    1742               0 :   gfxSize scale;
    1743               0 :   bool isRetained = aLayerBuilder->GetRetainingLayerManager() == aLayer->Manager();
    1744                 :   // Only fiddle with scale factors for the retaining layer manager, since
    1745                 :   // it only matters for retained layers
    1746                 :   // XXX Should we do something for 3D transforms?
    1747               0 :   if (canDraw2D && isRetained) {
    1748                 :     //Scale factors are normalized to a power of 2 to reduce the number of resolution changes
    1749               0 :     scale = transform2d.ScaleFactors(true);
    1750                 :     // For frames with a changing transform that's not just a translation,
    1751                 :     // round scale factors up to nearest power-of-2 boundary so that we don't
    1752                 :     // keep having to redraw the content as it scales up and down. Rounding up to nearest
    1753                 :     // power-of-2 boundary ensures we never scale up, only down --- avoiding
    1754                 :     // jaggies. It also ensures we never scale down by more than a factor of 2,
    1755                 :     // avoiding bad downscaling quality.
    1756               0 :     gfxMatrix frameTransform;
    1757               0 :     if (aContainerFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
    1758                 :         aTransform &&
    1759               0 :         (!aTransform->Is2D(&frameTransform) || frameTransform.HasNonTranslationOrFlip())) {
    1760                 :       // Don't clamp the scale factor when the new desired scale factor matches the old one
    1761                 :       // or it was previously unscaled.
    1762               0 :       bool clamp = true;
    1763               0 :       gfxMatrix oldFrameTransform2d;
    1764               0 :       if (aLayer->GetTransform().Is2D(&oldFrameTransform2d)) {
    1765               0 :         gfxSize oldScale = oldFrameTransform2d.ScaleFactors(true);
    1766               0 :         if (oldScale == scale || oldScale == gfxSize(1.0, 1.0))
    1767               0 :           clamp = false;
    1768                 :       }
    1769               0 :       if (clamp) {
    1770               0 :         scale.width = gfxUtils::ClampToScaleFactor(scale.width);
    1771               0 :         scale.height = gfxUtils::ClampToScaleFactor(scale.height);
    1772                 :       }
    1773                 :     } else {
    1774                 :       // XXX Do we need to move nearly-integer values to integers here?
    1775                 :     }
    1776                 :     // If the scale factors are too small, just use 1.0. The content is being
    1777                 :     // scaled out of sight anyway.
    1778               0 :     if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) {
    1779               0 :       scale.width = scale.height = 1.0;
    1780               0 :     }
    1781                 :   } else {
    1782               0 :     scale = gfxSize(1.0, 1.0);
    1783                 :   }
    1784                 : 
    1785                 :   // Apply the inverse of our resolution-scale before the rest of our transform
    1786               0 :   transform = gfx3DMatrix::ScalingMatrix(1.0/scale.width, 1.0/scale.height, 1.0)*transform;
    1787               0 :   aLayer->SetTransform(transform);
    1788                 : 
    1789                 :   FrameLayerBuilder::ContainerParameters
    1790               0 :     result(scale.width, scale.height, aIncomingScale);
    1791               0 :   if (aTransform) {
    1792               0 :     result.mInTransformedSubtree = true;
    1793               0 :     if (aContainerFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
    1794               0 :       result.mInActiveTransformedSubtree = true;
    1795                 :     }
    1796                 :   }
    1797               0 :   if (isRetained && (!canDraw2D || transform2d.HasNonIntegerTranslation())) {
    1798               0 :     result.mDisableSubpixelAntialiasingInDescendants = true;
    1799                 :   }
    1800                 :   return result;
    1801                 : }
    1802                 : 
    1803                 : already_AddRefed<ContainerLayer>
    1804               0 : FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
    1805                 :                                           LayerManager* aManager,
    1806                 :                                           nsIFrame* aContainerFrame,
    1807                 :                                           nsDisplayItem* aContainerItem,
    1808                 :                                           const nsDisplayList& aChildren,
    1809                 :                                           const ContainerParameters& aParameters,
    1810                 :                                           const gfx3DMatrix* aTransform)
    1811                 : {
    1812               0 :   FrameProperties props = aContainerFrame->Properties();
    1813                 :   PRUint32 containerDisplayItemKey =
    1814               0 :     aContainerItem ? aContainerItem->GetPerFrameKey() : 0;
    1815               0 :   NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
    1816               0 :   NS_ASSERTION(!aContainerItem ||
    1817                 :                aContainerItem->GetUnderlyingFrame() == aContainerFrame,
    1818                 :                "Container display item must match given frame");
    1819                 : 
    1820               0 :   nsRefPtr<ContainerLayer> containerLayer;
    1821               0 :   if (aManager == mRetainingManager) {
    1822               0 :     Layer* oldLayer = GetOldLayerFor(aContainerFrame, containerDisplayItemKey);
    1823               0 :     if (oldLayer) {
    1824               0 :       NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager");
    1825               0 :       if (oldLayer->HasUserData(&gThebesDisplayItemLayerUserData)) {
    1826                 :         // The old layer for this item is actually our ThebesLayer
    1827                 :         // because we rendered its layer into that ThebesLayer. So we
    1828                 :         // don't actually have a retained container layer.
    1829                 :       } else {
    1830               0 :         NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER,
    1831                 :                      "Wrong layer type");
    1832               0 :         containerLayer = static_cast<ContainerLayer*>(oldLayer);
    1833                 :         // Clear clip rect; the caller will set it if necessary.
    1834               0 :         containerLayer->SetClipRect(nsnull);
    1835                 :       }
    1836                 :     }
    1837                 :   }
    1838               0 :   if (!containerLayer) {
    1839                 :     // No suitable existing layer was found.
    1840               0 :     containerLayer = aManager->CreateContainerLayer();
    1841               0 :     if (!containerLayer)
    1842               0 :       return nsnull;
    1843                 :   }
    1844                 : 
    1845               0 :   if (aContainerItem &&
    1846               0 :       aContainerItem->GetLayerState(aBuilder, aManager) == LAYER_ACTIVE_EMPTY) {
    1847                 :     // Empty layers only have metadata and should never have display items. We
    1848                 :     // early exit because later, invalidation will walk up the frame tree to
    1849                 :     // determine which thebes layer gets invalidated. Since an empty layer
    1850                 :     // should never have anything to paint, it should never be invalidated.
    1851               0 :     NS_ASSERTION(aChildren.IsEmpty(), "Should have no children");
    1852               0 :     return containerLayer.forget();
    1853                 :   }
    1854                 : 
    1855                 :   ContainerParameters scaleParameters =
    1856                 :     ChooseScaleAndSetTransform(this, aContainerFrame, aTransform, aParameters,
    1857               0 :                                containerLayer);
    1858                 :   ContainerState state(aBuilder, aManager, aContainerFrame, containerLayer,
    1859               0 :                        scaleParameters);
    1860               0 :   nscoord appUnitsPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
    1861                 : 
    1862               0 :   if (aManager == mRetainingManager) {
    1863               0 :     DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aContainerFrame);
    1864               0 :     if (entry) {
    1865                 :       entry->mData.AppendElement(
    1866               0 :           DisplayItemData(containerLayer, containerDisplayItemKey, LAYER_ACTIVE));
    1867                 :     }
    1868                 : 
    1869                 :     nsPoint* offsetAtLastPaint = static_cast<nsPoint*>
    1870               0 :       (props.Get(ThebesLayerLastPaintOffsetProperty()));
    1871               0 :     nsPoint currentOffset = aBuilder->ToReferenceFrame(aContainerFrame);
    1872                 : 
    1873                 :     nsRegion* invalidThebesContent(static_cast<nsRegion*>
    1874               0 :       (props.Get(ThebesLayerInvalidRegionProperty())));
    1875               0 :     if (invalidThebesContent) {
    1876               0 :       nsPoint offset = offsetAtLastPaint ? *offsetAtLastPaint : currentOffset;
    1877               0 :       invalidThebesContent->MoveBy(offset);
    1878                 :       state.SetInvalidThebesContent(invalidThebesContent->
    1879                 :         ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
    1880               0 :                              appUnitsPerDevPixel));
    1881                 :       // We have to preserve the current contents of invalidThebesContent
    1882                 :       // because there might be multiple container layers for the same
    1883                 :       // frame and we need to invalidate the ThebesLayer children of all
    1884                 :       // of them.
    1885               0 :       invalidThebesContent->MoveBy(-offset);
    1886                 :     } else {
    1887                 :       // The region was deleted to indicate that everything should be
    1888                 :       // invalidated.
    1889               0 :       state.SetInvalidateAllThebesContent();
    1890                 :     }
    1891               0 :     SetHasContainerLayer(aContainerFrame, currentOffset);
    1892                 :   }
    1893                 : 
    1894               0 :   Clip clip;
    1895               0 :   state.ProcessDisplayItems(aChildren, clip);
    1896                 : 
    1897                 :   // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
    1898                 :   // This is suboptimal ... a child could have text that's over transparent
    1899                 :   // pixels in its own layer, but over opaque parts of previous siblings.
    1900                 :   PRUint32 flags;
    1901               0 :   state.Finish(&flags);
    1902                 : 
    1903               0 :   nsRect bounds = state.GetChildrenBounds();
    1904               0 :   NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds");
    1905                 :   nsIntRect pixBounds =
    1906                 :     bounds.ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
    1907               0 :                                 appUnitsPerDevPixel);
    1908               0 :   containerLayer->SetVisibleRegion(pixBounds);
    1909                 :   // Make sure that rounding the visible region out didn't add any area
    1910                 :   // we won't paint
    1911               0 :   if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) {
    1912               0 :     bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
    1913               0 :     if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) {
    1914                 :       // Clear CONTENT_COMPONENT_ALPHA
    1915               0 :       flags = Layer::CONTENT_OPAQUE;
    1916                 :     }
    1917                 :   }
    1918               0 :   containerLayer->SetContentFlags(flags);
    1919                 : 
    1920               0 :   return containerLayer.forget();
    1921                 : }
    1922                 : 
    1923                 : Layer*
    1924               0 : FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
    1925                 :                                    LayerManager* aManager,
    1926                 :                                    nsDisplayItem* aItem)
    1927                 : {
    1928               0 :   if (aManager != mRetainingManager)
    1929               0 :     return nsnull;
    1930                 : 
    1931               0 :   nsIFrame* f = aItem->GetUnderlyingFrame();
    1932               0 :   NS_ASSERTION(f, "Can only call GetLeafLayerFor on items that have a frame");
    1933               0 :   Layer* layer = GetOldLayerFor(f, aItem->GetPerFrameKey());
    1934               0 :   if (!layer)
    1935               0 :     return nsnull;
    1936               0 :   if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
    1937                 :     // This layer was created to render Thebes-rendered content for this
    1938                 :     // display item. The display item should not use it for its own
    1939                 :     // layer rendering.
    1940               0 :     return nsnull;
    1941                 :   }
    1942                 :   // Clear clip rect; the caller is responsible for setting it.
    1943               0 :   layer->SetClipRect(nsnull);
    1944               0 :   return layer;
    1945                 : }
    1946                 : 
    1947                 : /* static */ void
    1948               0 : FrameLayerBuilder::InvalidateThebesLayerContents(nsIFrame* aFrame,
    1949                 :                                                  const nsRect& aRect)
    1950                 : {
    1951                 :   nsRegion* invalidThebesContent = static_cast<nsRegion*>
    1952               0 :     (aFrame->Properties().Get(ThebesLayerInvalidRegionProperty()));
    1953               0 :   if (!invalidThebesContent)
    1954               0 :     return;
    1955               0 :   invalidThebesContent->Or(*invalidThebesContent, aRect);
    1956               0 :   invalidThebesContent->SimplifyOutward(20);
    1957                 : }
    1958                 : 
    1959                 : /**
    1960                 :  * Returns true if we find a descendant with a container layer
    1961                 :  */
    1962                 : static bool
    1963               0 : InternalInvalidateThebesLayersInSubtree(nsIFrame* aFrame)
    1964                 : {
    1965               0 :   if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT))
    1966               0 :     return false;
    1967                 : 
    1968               0 :   bool foundContainerLayer = false;
    1969               0 :   if (aFrame->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) {
    1970                 :     // Delete the invalid region to indicate that all Thebes contents
    1971                 :     // need to be invalidated
    1972               0 :     aFrame->Properties().Delete(ThebesLayerInvalidRegionProperty());
    1973               0 :     foundContainerLayer = true;
    1974                 :   }
    1975                 : 
    1976               0 :   nsAutoTArray<nsIFrame::ChildList,4> childListArray;
    1977               0 :   if (!aFrame->GetFirstPrincipalChild()) {
    1978               0 :     nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(aFrame);
    1979               0 :     if (subdocumentFrame) {
    1980                 :       // Descend into the subdocument
    1981               0 :       nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
    1982               0 :       if (root) {
    1983                 :         childListArray.AppendElement(nsIFrame::ChildList(
    1984               0 :           nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
    1985               0 :           nsIFrame::kPrincipalList));
    1986                 :       }
    1987                 :     }
    1988                 :   }
    1989                 : 
    1990               0 :   aFrame->GetChildLists(&childListArray);
    1991               0 :   nsIFrame::ChildListArrayIterator lists(childListArray);
    1992               0 :   for (; !lists.IsDone(); lists.Next()) {
    1993               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    1994               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    1995               0 :       if (InternalInvalidateThebesLayersInSubtree(childFrames.get())) {
    1996               0 :         foundContainerLayer = true;
    1997                 :       }
    1998                 :     }
    1999                 :   }
    2000                 : 
    2001               0 :   if (!foundContainerLayer) {
    2002               0 :     aFrame->RemoveStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
    2003                 :   }
    2004               0 :   return foundContainerLayer;
    2005                 : }
    2006                 : 
    2007                 : /* static */ void
    2008               0 : FrameLayerBuilder::InvalidateThebesLayersInSubtree(nsIFrame* aFrame)
    2009                 : {
    2010               0 :   InternalInvalidateThebesLayersInSubtree(aFrame);
    2011               0 : }
    2012                 : 
    2013                 : /* static */ void
    2014               0 : FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager)
    2015                 : {
    2016                 :   LayerManagerData* data = static_cast<LayerManagerData*>
    2017               0 :     (aManager->GetUserData(&gLayerManagerUserData));
    2018               0 :   if (data) {
    2019               0 :     data->mInvalidateAllLayers = true;
    2020                 :   }
    2021               0 : }
    2022                 : 
    2023                 : /* static */
    2024                 : Layer*
    2025               0 : FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
    2026                 : {
    2027               0 :   nsTArray<DisplayItemData>* array = GetDisplayItemDataArrayForFrame(aFrame);
    2028               0 :   if (!array)
    2029               0 :     return nsnull;
    2030                 : 
    2031               0 :   for (PRUint32 i = 0; i < array->Length(); ++i) {
    2032               0 :     if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
    2033               0 :       Layer* layer = array->ElementAt(i).mLayer;
    2034               0 :       if (!layer->HasUserData(&gColorLayerUserData) &&
    2035               0 :           !layer->HasUserData(&gImageLayerUserData) &&
    2036               0 :           !layer->HasUserData(&gThebesDisplayItemLayerUserData))
    2037               0 :         return layer;
    2038                 :     }
    2039                 :   }
    2040               0 :   return nsnull;
    2041                 : }
    2042                 : 
    2043                 : #ifdef MOZ_DUMP_PAINTING
    2044               0 : static void DebugPaintItem(nsRenderingContext* aDest, nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder)
    2045                 : {
    2046               0 :   nsRect appUnitBounds = aItem->GetBounds(aBuilder);
    2047               0 :   gfxRect bounds(appUnitBounds.x, appUnitBounds.y, appUnitBounds.width, appUnitBounds.height);
    2048               0 :   bounds.ScaleInverse(aDest->AppUnitsPerDevPixel());
    2049                 : 
    2050                 :   nsRefPtr<gfxASurface> surf = 
    2051               0 :     gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), 
    2052               0 :                                                        gfxASurface::CONTENT_COLOR_ALPHA);
    2053               0 :   surf->SetDeviceOffset(-bounds.TopLeft());
    2054               0 :   nsRefPtr<gfxContext> context = new gfxContext(surf);
    2055               0 :   nsRefPtr<nsRenderingContext> ctx = new nsRenderingContext();
    2056               0 :   ctx->Init(aDest->DeviceContext(), context);
    2057                 : 
    2058               0 :   aItem->Paint(aBuilder, ctx);
    2059               0 :   DumpPaintedImage(aItem, surf);
    2060               0 :   aItem->SetPainted();
    2061                 :     
    2062               0 :   surf->SetDeviceOffset(gfxPoint(0, 0));
    2063               0 :   aDest->ThebesContext()->SetSource(surf, bounds.TopLeft());
    2064               0 :   aDest->ThebesContext()->Rectangle(bounds);
    2065               0 :   aDest->ThebesContext()->Fill();
    2066               0 : }
    2067                 : #endif
    2068                 : 
    2069                 : /*
    2070                 :  * A note on residual transforms:
    2071                 :  *
    2072                 :  * In a transformed subtree we sometimes apply the ThebesLayer's
    2073                 :  * "residual transform" when drawing content into the ThebesLayer.
    2074                 :  * This is a translation by components in the range [-0.5,0.5) provided
    2075                 :  * by the layer system; applying the residual transform followed by the
    2076                 :  * transforms used by layer compositing ensures that the subpixel alignment
    2077                 :  * of the content of the ThebesLayer exactly matches what it would be if
    2078                 :  * we used cairo/Thebes to draw directly to the screen without going through
    2079                 :  * retained layer buffers.
    2080                 :  *
    2081                 :  * The visible and valid regions of the ThebesLayer are computed without
    2082                 :  * knowing the residual transform (because we don't know what the residual
    2083                 :  * transform is going to be until we've built the layer tree!). So we have to
    2084                 :  * consider whether content painted in the range [x, xmost) might be painted
    2085                 :  * outside the visible region we computed for that content. The visible region
    2086                 :  * would be [floor(x), ceil(xmost)). The content would be rendered at
    2087                 :  * [x + r, xmost + r), where -0.5 <= r < 0.5. So some half-rendered pixels could
    2088                 :  * indeed fall outside the computed visible region, which is not a big deal;
    2089                 :  * similar issues already arise when we snap cliprects to nearest pixels.
    2090                 :  * Note that if the rendering of the content is snapped to nearest pixels ---
    2091                 :  * which it often is --- then the content is actually rendered at
    2092                 :  * [snap(x + r), snap(xmost + r)). It turns out that floor(x) <= snap(x + r)
    2093                 :  * and ceil(xmost) >= snap(xmost + r), so the rendering of snapped content
    2094                 :  * always falls within the visible region we computed.
    2095                 :  */
    2096                 : 
    2097                 : /* static */ void
    2098               0 : FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
    2099                 :                                    gfxContext* aContext,
    2100                 :                                    const nsIntRegion& aRegionToDraw,
    2101                 :                                    const nsIntRegion& aRegionToInvalidate,
    2102                 :                                    void* aCallbackData)
    2103                 : {
    2104               0 :   SAMPLE_LABEL("gfx", "DrawThebesLayer");
    2105                 : 
    2106                 :   nsDisplayListBuilder* builder = static_cast<nsDisplayListBuilder*>
    2107               0 :     (aCallbackData);
    2108                 : 
    2109               0 :   if (builder->LayerBuilder()->CheckDOMModified())
    2110                 :     return;
    2111                 : 
    2112               0 :   nsTArray<ClippedDisplayItem> items;
    2113                 :   nsIFrame* containerLayerFrame;
    2114                 :   {
    2115                 :     ThebesLayerItemsEntry* entry =
    2116               0 :       builder->LayerBuilder()->mThebesLayerItems.GetEntry(aLayer);
    2117               0 :     NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!");
    2118               0 :     items.SwapElements(entry->mItems);
    2119               0 :     containerLayerFrame = entry->mContainerLayerFrame;
    2120                 :     // Later after this point, due to calls to DidEndTransaction
    2121                 :     // for temporary layer managers, mThebesLayerItems can change,
    2122                 :     // so 'entry' could become invalid.
    2123                 :   }
    2124                 : 
    2125                 :   ThebesDisplayItemLayerUserData* userData =
    2126                 :     static_cast<ThebesDisplayItemLayerUserData*>
    2127               0 :       (aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
    2128               0 :   NS_ASSERTION(userData, "where did our user data go?");
    2129               0 :   if (NS_GET_A(userData->mForcedBackgroundColor) > 0) {
    2130               0 :     nsIntRect r = aLayer->GetVisibleRegion().GetBounds();
    2131               0 :     aContext->NewPath();
    2132               0 :     aContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height));
    2133               0 :     aContext->SetColor(gfxRGBA(userData->mForcedBackgroundColor));
    2134               0 :     aContext->Fill();
    2135                 :   }
    2136                 : 
    2137                 :   // make the origin of the context coincide with the origin of the
    2138                 :   // ThebesLayer
    2139               0 :   gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
    2140               0 :   nsIntPoint offset = GetTranslationForThebesLayer(aLayer);
    2141                 :   // Apply the residual transform if it has been enabled, to ensure that
    2142                 :   // snapping when we draw into aContext exactly matches the ideal transform.
    2143                 :   // See above for why this is OK.
    2144               0 :   aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y));
    2145               0 :   aContext->Scale(userData->mXScale, userData->mYScale);
    2146                 : 
    2147               0 :   nsPresContext* presContext = containerLayerFrame->PresContext();
    2148               0 :   PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
    2149               0 :   if (!aRegionToInvalidate.IsEmpty()) {
    2150                 :     nsRect r = (aRegionToInvalidate.GetBounds() + offset).
    2151               0 :       ToAppUnits(appUnitsPerDevPixel);
    2152               0 :     r.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
    2153                 :     containerLayerFrame->InvalidateWithFlags(r,
    2154                 :         nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
    2155               0 :         nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
    2156                 :   }
    2157                 : 
    2158                 :   PRUint32 i;
    2159                 :   // Update visible regions. We need perform visibility analysis again
    2160                 :   // because we may be asked to draw into part of a ThebesLayer that
    2161                 :   // isn't actually visible in the window (e.g., because a ThebesLayer
    2162                 :   // expanded its visible region to a rectangle internally), in which
    2163                 :   // case the mVisibleRect stored in the display item may be wrong.
    2164               0 :   nsRegion visible = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel);
    2165                 :   visible.MoveBy(NSIntPixelsToAppUnits(offset.x, appUnitsPerDevPixel),
    2166               0 :                  NSIntPixelsToAppUnits(offset.y, appUnitsPerDevPixel));
    2167               0 :   visible.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
    2168                 : 
    2169               0 :   for (i = items.Length(); i > 0; --i) {
    2170               0 :     ClippedDisplayItem* cdi = &items[i - 1];
    2171                 : 
    2172               0 :     NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == appUnitsPerDevPixel,
    2173                 :                  "a thebes layer should contain items only at the same zoom");
    2174                 : 
    2175               0 :     NS_ABORT_IF_FALSE(cdi->mClip.mHaveClipRect ||
    2176                 :                       cdi->mClip.mRoundedClipRects.IsEmpty(),
    2177                 :                       "If we have rounded rects, we must have a clip rect");
    2178                 : 
    2179               0 :     if (!cdi->mClip.mHaveClipRect ||
    2180               0 :         (cdi->mClip.mRoundedClipRects.IsEmpty() &&
    2181               0 :          cdi->mClip.mClipRect.Contains(visible.GetBounds()))) {
    2182               0 :       cdi->mItem->RecomputeVisibility(builder, &visible);
    2183               0 :       continue;
    2184                 :     }
    2185                 : 
    2186                 :     // Do a little dance to account for the fact that we're clipping
    2187                 :     // to cdi->mClipRect
    2188               0 :     nsRegion clipped;
    2189               0 :     clipped.And(visible, cdi->mClip.mClipRect);
    2190               0 :     nsRegion finalClipped = clipped;
    2191               0 :     cdi->mItem->RecomputeVisibility(builder, &finalClipped);
    2192                 :     // If we have rounded clip rects, don't subtract from the visible
    2193                 :     // region since we aren't displaying everything inside the rect.
    2194               0 :     if (cdi->mClip.mRoundedClipRects.IsEmpty()) {
    2195               0 :       nsRegion removed;
    2196               0 :       removed.Sub(clipped, finalClipped);
    2197               0 :       nsRegion newVisible;
    2198               0 :       newVisible.Sub(visible, removed);
    2199                 :       // Don't let the visible region get too complex.
    2200               0 :       if (newVisible.GetNumRects() <= 15) {
    2201               0 :         visible = newVisible;
    2202                 :       }
    2203                 :     }
    2204               0 :     if (!cdi->mClip.IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) {
    2205               0 :       cdi->mClip.RemoveRoundedCorners();
    2206                 :     }
    2207                 :   }
    2208                 : 
    2209               0 :   nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
    2210               0 :   rc->Init(presContext->DeviceContext(), aContext);
    2211                 : 
    2212               0 :   Clip currentClip;
    2213               0 :   bool setClipRect = false;
    2214                 : 
    2215               0 :   for (i = 0; i < items.Length(); ++i) {
    2216               0 :     ClippedDisplayItem* cdi = &items[i];
    2217                 : 
    2218               0 :     if (cdi->mItem->GetVisibleRect().IsEmpty())
    2219               0 :       continue;
    2220                 : 
    2221                 :     // If the new desired clip state is different from the current state,
    2222                 :     // update the clip.
    2223               0 :     if (setClipRect != cdi->mClip.mHaveClipRect ||
    2224               0 :         (cdi->mClip.mHaveClipRect && cdi->mClip != currentClip)) {
    2225               0 :       if (setClipRect) {
    2226               0 :         aContext->Restore();
    2227                 :       }
    2228               0 :       setClipRect = cdi->mClip.mHaveClipRect;
    2229               0 :       if (setClipRect) {
    2230               0 :         currentClip = cdi->mClip;
    2231               0 :         aContext->Save();
    2232               0 :         currentClip.ApplyTo(aContext, presContext);
    2233                 :       }
    2234                 :     }
    2235                 : 
    2236               0 :     if (cdi->mInactiveLayer) {
    2237               0 :       PaintInactiveLayer(builder, cdi->mItem, aContext);
    2238                 :     } else {
    2239               0 :       nsIFrame* frame = cdi->mItem->GetUnderlyingFrame();
    2240               0 :       if (frame) {
    2241               0 :         frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
    2242                 :       }
    2243                 : #ifdef MOZ_DUMP_PAINTING
    2244                 : 
    2245               0 :       if (gfxUtils::sDumpPainting) {
    2246               0 :         DebugPaintItem(rc, cdi->mItem, builder);
    2247                 :       } else {
    2248                 : #else
    2249                 :       {
    2250                 : #endif
    2251               0 :         cdi->mItem->Paint(builder, rc);
    2252                 :       }
    2253                 :     }
    2254                 : 
    2255               0 :     if (builder->LayerBuilder()->CheckDOMModified())
    2256               0 :       break;
    2257                 :   }
    2258                 : 
    2259               0 :   if (setClipRect) {
    2260               0 :     aContext->Restore();
    2261                 :   }
    2262                 : 
    2263               0 :   FlashPaint(aContext);
    2264                 : }
    2265                 : 
    2266                 : bool
    2267               0 : FrameLayerBuilder::CheckDOMModified()
    2268                 : {
    2269               0 :   if (!mRootPresContext ||
    2270               0 :       mInitialDOMGeneration == mRootPresContext->GetDOMGeneration())
    2271               0 :     return false;
    2272               0 :   if (mDetectedDOMModification) {
    2273                 :     // Don't spam the console with extra warnings
    2274               0 :     return true;
    2275                 :   }
    2276               0 :   mDetectedDOMModification = true;
    2277                 :   // Painting is not going to complete properly. There's not much
    2278                 :   // we can do here though. Invalidating the window to get another repaint
    2279                 :   // is likely to lead to an infinite repaint loop.
    2280               0 :   NS_WARNING("Detected DOM modification during paint, bailing out!");
    2281               0 :   return true;
    2282                 : }
    2283                 : 
    2284                 : #ifdef MOZ_DUMP_PAINTING
    2285                 : void
    2286               0 : FrameLayerBuilder::DumpRetainedLayerTree(FILE* aFile)
    2287                 : {
    2288               0 :   if (mRetainingManager) {
    2289               0 :     mRetainingManager->Dump(aFile);
    2290                 :   }
    2291               0 : }
    2292                 : #endif
    2293                 : 
    2294               0 : FrameLayerBuilder::Clip::Clip(const Clip& aOther, nsDisplayItem* aClipItem)
    2295                 :   : mRoundedClipRects(aOther.mRoundedClipRects),
    2296               0 :     mHaveClipRect(true)
    2297                 : {
    2298               0 :   nsDisplayItem::Type type = aClipItem->GetType();
    2299               0 :   NS_ABORT_IF_FALSE(type == nsDisplayItem::TYPE_CLIP ||
    2300                 :                     type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT,
    2301                 :                     "unexpected display item type");
    2302               0 :   nsDisplayClip* item = static_cast<nsDisplayClip*>(aClipItem);
    2303                 :   // Always intersect with mClipRect, even if we're going to add a
    2304                 :   // rounded rect.
    2305               0 :   if (aOther.mHaveClipRect) {
    2306               0 :     mClipRect.IntersectRect(aOther.mClipRect, item->GetClipRect());
    2307                 :   } else {
    2308               0 :     mClipRect = item->GetClipRect();
    2309                 :   }
    2310                 : 
    2311               0 :   if (type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) {
    2312               0 :     RoundedRect *rr = mRoundedClipRects.AppendElement();
    2313               0 :     if (rr) {
    2314               0 :       rr->mRect = item->GetClipRect();
    2315               0 :       static_cast<nsDisplayClipRoundedRect*>(item)->GetRadii(rr->mRadii);
    2316                 :     }
    2317                 :   }
    2318                 : 
    2319                 :   // FIXME: Optimize away excess rounded rectangles due to the new addition.
    2320               0 : }
    2321                 : 
    2322                 : void
    2323               0 : FrameLayerBuilder::Clip::ApplyTo(gfxContext* aContext,
    2324                 :                                  nsPresContext* aPresContext)
    2325                 : {
    2326               0 :   aContext->NewPath();
    2327               0 :   PRInt32 A2D = aPresContext->AppUnitsPerDevPixel();
    2328               0 :   gfxRect clip = nsLayoutUtils::RectToGfxRect(mClipRect, A2D);
    2329               0 :   aContext->Rectangle(clip, true);
    2330               0 :   aContext->Clip();
    2331                 : 
    2332               0 :   for (PRUint32 i = 0, iEnd = mRoundedClipRects.Length();
    2333                 :        i < iEnd; ++i) {
    2334               0 :     const Clip::RoundedRect &rr = mRoundedClipRects[i];
    2335                 : 
    2336               0 :     gfxCornerSizes pixelRadii;
    2337               0 :     nsCSSRendering::ComputePixelRadii(rr.mRadii, A2D, &pixelRadii);
    2338                 : 
    2339               0 :     clip = nsLayoutUtils::RectToGfxRect(rr.mRect, A2D);
    2340               0 :     clip.Round();
    2341               0 :     clip.Condition();
    2342                 :     // REVIEW: This might make clip empty.  Is that OK?
    2343                 : 
    2344               0 :     aContext->NewPath();
    2345               0 :     aContext->RoundedRectangle(clip, pixelRadii);
    2346               0 :     aContext->Clip();
    2347                 :   }
    2348               0 : }
    2349                 : 
    2350                 : nsRect
    2351               0 : FrameLayerBuilder::Clip::ApproximateIntersect(const nsRect& aRect) const
    2352                 : {
    2353               0 :   nsRect r = aRect;
    2354               0 :   if (mHaveClipRect) {
    2355               0 :     r.IntersectRect(r, mClipRect);
    2356                 :   }
    2357               0 :   for (PRUint32 i = 0, iEnd = mRoundedClipRects.Length();
    2358                 :        i < iEnd; ++i) {
    2359               0 :     const Clip::RoundedRect &rr = mRoundedClipRects[i];
    2360               0 :     nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(rr.mRect, rr.mRadii, r);
    2361               0 :     r = rgn.GetLargestRectangle();
    2362                 :   }
    2363                 :   return r;
    2364                 : }
    2365                 : 
    2366                 : // Test if (aXPoint, aYPoint) is in the ellipse with center (aXCenter, aYCenter)
    2367                 : // and radii aXRadius, aYRadius.
    2368               0 : bool IsInsideEllipse(nscoord aXRadius, nscoord aXCenter, nscoord aXPoint,
    2369                 :                      nscoord aYRadius, nscoord aYCenter, nscoord aYPoint)
    2370                 : {
    2371               0 :   float scaledX = float(aXPoint - aXCenter) / float(aXRadius);
    2372               0 :   float scaledY = float(aYPoint - aYCenter) / float(aYRadius);
    2373               0 :   return scaledX * scaledX + scaledY * scaledY < 1.0f;
    2374                 : }
    2375                 : 
    2376                 : bool
    2377               0 : FrameLayerBuilder::Clip::IsRectClippedByRoundedCorner(const nsRect& aRect) const
    2378                 : {
    2379               0 :   if (mRoundedClipRects.IsEmpty())
    2380               0 :     return false;
    2381                 : 
    2382               0 :   nsRect rect;
    2383               0 :   rect.IntersectRect(aRect, NonRoundedIntersection());
    2384               0 :   for (PRUint32 i = 0, iEnd = mRoundedClipRects.Length();
    2385                 :        i < iEnd; ++i) {
    2386               0 :     const Clip::RoundedRect &rr = mRoundedClipRects[i];
    2387                 :     // top left
    2388               0 :     if (rect.x < rr.mRect.x + rr.mRadii[NS_CORNER_TOP_LEFT_X] &&
    2389               0 :         rect.y < rr.mRect.y + rr.mRadii[NS_CORNER_TOP_LEFT_Y]) {
    2390               0 :       if (!IsInsideEllipse(rr.mRadii[NS_CORNER_TOP_LEFT_X],
    2391               0 :                            rr.mRect.x + rr.mRadii[NS_CORNER_TOP_LEFT_X],
    2392                 :                            rect.x,
    2393                 :                            rr.mRadii[NS_CORNER_TOP_LEFT_Y],
    2394               0 :                            rr.mRect.y + rr.mRadii[NS_CORNER_TOP_LEFT_Y],
    2395               0 :                            rect.y)) {
    2396               0 :         return true;
    2397                 :       }
    2398                 :     }
    2399                 :     // top right
    2400               0 :     if (rect.XMost() > rr.mRect.XMost() - rr.mRadii[NS_CORNER_TOP_RIGHT_X] &&
    2401               0 :         rect.y < rr.mRect.y + rr.mRadii[NS_CORNER_TOP_RIGHT_Y]) {
    2402               0 :       if (!IsInsideEllipse(rr.mRadii[NS_CORNER_TOP_RIGHT_X],
    2403               0 :                            rr.mRect.XMost() - rr.mRadii[NS_CORNER_TOP_RIGHT_X],
    2404                 :                            rect.XMost(),
    2405                 :                            rr.mRadii[NS_CORNER_TOP_RIGHT_Y],
    2406               0 :                            rr.mRect.y + rr.mRadii[NS_CORNER_TOP_RIGHT_Y],
    2407               0 :                            rect.y)) {
    2408               0 :         return true;
    2409                 :       }
    2410                 :     }
    2411                 :     // bottom left
    2412               0 :     if (rect.x < rr.mRect.x + rr.mRadii[NS_CORNER_BOTTOM_LEFT_X] &&
    2413               0 :         rect.YMost() > rr.mRect.YMost() - rr.mRadii[NS_CORNER_BOTTOM_LEFT_Y]) {
    2414               0 :       if (!IsInsideEllipse(rr.mRadii[NS_CORNER_BOTTOM_LEFT_X],
    2415               0 :                            rr.mRect.x + rr.mRadii[NS_CORNER_BOTTOM_LEFT_X],
    2416                 :                            rect.x,
    2417                 :                            rr.mRadii[NS_CORNER_BOTTOM_LEFT_Y],
    2418               0 :                            rr.mRect.YMost() - rr.mRadii[NS_CORNER_BOTTOM_LEFT_Y],
    2419               0 :                            rect.YMost())) {
    2420               0 :         return true;
    2421                 :       }
    2422                 :     }
    2423                 :     // bottom right
    2424               0 :     if (rect.XMost() > rr.mRect.XMost() - rr.mRadii[NS_CORNER_BOTTOM_RIGHT_X] &&
    2425               0 :         rect.YMost() > rr.mRect.YMost() - rr.mRadii[NS_CORNER_BOTTOM_RIGHT_Y]) {
    2426               0 :       if (!IsInsideEllipse(rr.mRadii[NS_CORNER_BOTTOM_RIGHT_X],
    2427               0 :                            rr.mRect.XMost() - rr.mRadii[NS_CORNER_BOTTOM_RIGHT_X],
    2428                 :                            rect.XMost(),
    2429                 :                            rr.mRadii[NS_CORNER_BOTTOM_RIGHT_Y],
    2430               0 :                            rr.mRect.YMost() - rr.mRadii[NS_CORNER_BOTTOM_RIGHT_Y],
    2431               0 :                            rect.YMost())) {
    2432               0 :         return true;
    2433                 :       }
    2434                 :     }
    2435                 :   }
    2436               0 :   return false;
    2437                 : }
    2438                 : 
    2439                 : nsRect
    2440               0 : FrameLayerBuilder::Clip::NonRoundedIntersection() const
    2441                 : {
    2442               0 :   nsRect result = mClipRect;
    2443               0 :   for (PRUint32 i = 0, iEnd = mRoundedClipRects.Length();
    2444                 :        i < iEnd; ++i) {
    2445               0 :     result.IntersectRect(result, mRoundedClipRects[i].mRect);
    2446                 :   }
    2447                 :   return result;
    2448                 : }
    2449                 : 
    2450                 : void
    2451               0 : FrameLayerBuilder::Clip::RemoveRoundedCorners()
    2452                 : {
    2453               0 :   if (mRoundedClipRects.IsEmpty())
    2454               0 :     return;
    2455                 : 
    2456               0 :   mClipRect = NonRoundedIntersection();
    2457               0 :   mRoundedClipRects.Clear();
    2458                 : }
    2459                 : 
    2460                 : } // namespace mozilla

Generated by: LCOV version 1.7