2010-05-20 20:20:48 -07:00
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2012-05-21 04:12:37 -07:00
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/. */
2010-05-20 20:20:48 -07:00
2012-12-14 15:58:45 -08:00
# include "mozilla/DebugOnly.h"
2010-05-20 20:20:48 -07:00
# include "FrameLayerBuilder.h"
# include "nsDisplayList.h"
# include "nsPresContext.h"
# include "nsLayoutUtils.h"
2010-07-15 14:07:51 -07:00
# include "Layers.h"
2010-07-15 14:08:05 -07:00
# include "BasicLayers.h"
2010-08-30 17:49:07 -07:00
# include "nsSubDocumentFrame.h"
2010-09-09 08:21:46 -07:00
# include "nsCSSRendering.h"
2010-09-17 12:09:08 -07:00
# include "nsCSSFrameConstructor.h"
2010-11-24 01:35:21 -08:00
# include "gfxUtils.h"
2011-04-07 18:04:40 -07:00
# include "nsRenderingContext.h"
2012-06-25 19:43:30 -07:00
# include "MaskLayerImageCache.h"
2012-08-16 16:40:10 -07:00
# include "nsIScrollableFrame.h"
2012-08-28 22:47:15 -07:00
# include "nsPrintfCString.h"
2012-08-28 22:47:18 -07:00
# include "LayerTreeInvalidation.h"
# include "nsSVGIntegrationUtils.h"
2010-07-15 14:07:51 -07:00
2011-11-14 20:59:03 -08:00
# include "mozilla/Preferences.h"
2011-12-02 14:05:33 -08:00
# include "sampler.h"
2012-10-01 21:00:09 -07:00
# include "mozilla/gfx/Tools.h"
2011-11-14 20:59:03 -08:00
2012-07-31 10:28:21 -07:00
# include "nsAnimationManager.h"
# include "nsTransitionManager.h"
2013-01-15 04:22:03 -08:00
# include <algorithm>
2012-07-31 10:28:21 -07:00
2010-07-15 14:07:51 -07:00
# ifdef DEBUG
# include <stdio.h>
2012-08-28 22:47:15 -07:00
//#define DEBUG_INVALIDATIONS
2012-10-11 16:38:25 -07:00
//#define DEBUG_DISPLAY_ITEM_DATA
2010-07-15 14:07:51 -07:00
# endif
2010-05-20 20:20:48 -07:00
using namespace mozilla : : layers ;
2012-10-01 21:00:09 -07:00
using namespace mozilla : : gfx ;
2010-05-20 20:20:48 -07:00
namespace mozilla {
2012-10-11 19:39:46 -07:00
FrameLayerBuilder : : DisplayItemData : : DisplayItemData ( LayerManagerData * aParent , uint32_t aKey ,
2012-10-11 16:38:24 -07:00
Layer * aLayer , LayerState aLayerState , uint32_t aGeneration )
: mParent ( aParent )
, mLayer ( aLayer )
2012-08-20 21:06:46 -07:00
, mDisplayItemKey ( aKey )
, mContainerLayerGeneration ( aGeneration )
, mLayerState ( aLayerState )
2012-10-11 19:39:46 -07:00
, mUsed ( true )
2012-11-06 14:04:53 -08:00
, mIsInvalid ( false )
2012-10-11 16:38:24 -07:00
{
}
2012-08-20 21:06:46 -07:00
2012-08-28 22:47:15 -07:00
FrameLayerBuilder : : DisplayItemData : : DisplayItemData ( DisplayItemData & toCopy )
{
// This isn't actually a copy-constructor; notice that it steals toCopy's
// mGeometry pointer. Be careful.
2012-10-11 16:38:24 -07:00
mParent = toCopy . mParent ;
2012-08-28 22:47:15 -07:00
mLayer = toCopy . mLayer ;
mInactiveManager = toCopy . mInactiveManager ;
mFrameList = toCopy . mFrameList ;
mGeometry = toCopy . mGeometry ;
mDisplayItemKey = toCopy . mDisplayItemKey ;
2012-10-11 16:38:24 -07:00
mClip = toCopy . mClip ;
2012-08-28 22:47:15 -07:00
mContainerLayerGeneration = toCopy . mContainerLayerGeneration ;
mLayerState = toCopy . mLayerState ;
mUsed = toCopy . mUsed ;
2012-10-11 16:38:24 -07:00
}
void
2012-10-11 19:39:46 -07:00
FrameLayerBuilder : : DisplayItemData : : AddFrame ( nsIFrame * aFrame )
2012-10-11 16:38:24 -07:00
{
2012-10-11 19:39:46 -07:00
mFrameList . AppendElement ( aFrame ) ;
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aFrame - > Properties ( ) . Get ( FrameLayerBuilder : : LayerManagerDataProperty ( ) ) ) ;
if ( ! array ) {
array = new nsTArray < DisplayItemData * > ( ) ;
aFrame - > Properties ( ) . Set ( FrameLayerBuilder : : LayerManagerDataProperty ( ) , array ) ;
2012-10-11 16:38:24 -07:00
}
2012-10-11 19:39:46 -07:00
array - > AppendElement ( this ) ;
2012-08-28 22:47:15 -07:00
}
2012-10-11 16:38:24 -07:00
void
2012-10-15 18:23:07 -07:00
FrameLayerBuilder : : DisplayItemData : : RemoveFrame ( nsIFrame * aFrame )
{
DebugOnly < bool > result = mFrameList . RemoveElement ( aFrame ) ;
NS_ASSERTION ( result , " Can't remove a frame that wasn't added! " ) ;
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aFrame - > Properties ( ) . Get ( FrameLayerBuilder : : LayerManagerDataProperty ( ) ) ) ;
NS_ASSERTION ( array , " Must be already stored on the frame! " ) ;
array - > RemoveElement ( this ) ;
}
void
FrameLayerBuilder : : DisplayItemData : : UpdateContents ( Layer * aLayer , LayerState aState ,
uint32_t aContainerLayerGeneration ,
nsDisplayItem * aItem /* = nullptr */ )
2012-10-11 16:38:24 -07:00
{
2012-10-11 19:39:46 -07:00
mLayer = aLayer ;
mOptLayer = nullptr ;
mInactiveManager = nullptr ;
mLayerState = aState ;
mContainerLayerGeneration = aContainerLayerGeneration ;
mGeometry = nullptr ;
mClip . mHaveClipRect = false ;
mClip . mRoundedClipRects . Clear ( ) ;
mUsed = true ;
2012-10-15 18:23:07 -07:00
if ( ! aItem ) {
return ;
}
2012-12-18 17:16:06 -08:00
nsAutoTArray < nsIFrame * , 4 > copy ( mFrameList ) ;
2012-10-15 18:23:07 -07:00
if ( ! copy . RemoveElement ( aItem - > GetUnderlyingFrame ( ) ) ) {
AddFrame ( aItem - > GetUnderlyingFrame ( ) ) ;
}
nsAutoTArray < nsIFrame * , 4 > mergedFrames ;
aItem - > GetMergedFrames ( & mergedFrames ) ;
for ( uint32_t i = 0 ; i < mergedFrames . Length ( ) ; + + i ) {
if ( ! copy . RemoveElement ( mergedFrames [ i ] ) ) {
AddFrame ( mergedFrames [ i ] ) ;
}
}
for ( uint32_t i = 0 ; i < copy . Length ( ) ; i + + ) {
RemoveFrame ( copy [ i ] ) ;
}
2012-10-11 16:38:24 -07:00
}
static nsIFrame * sDestroyedFrame = NULL ;
2012-08-20 21:06:46 -07:00
FrameLayerBuilder : : DisplayItemData : : ~ DisplayItemData ( )
2012-10-11 16:38:24 -07:00
{
for ( uint32_t i = 0 ; i < mFrameList . Length ( ) ; i + + ) {
2012-10-11 19:39:46 -07:00
nsIFrame * frame = mFrameList [ i ] ;
if ( frame = = sDestroyedFrame ) {
2012-10-11 16:38:24 -07:00
continue ;
}
nsTArray < DisplayItemData * > * array =
2012-10-11 19:39:46 -07:00
reinterpret_cast < nsTArray < DisplayItemData * > * > ( frame - > Properties ( ) . Get ( LayerManagerDataProperty ( ) ) ) ;
array - > RemoveElement ( this ) ;
2012-10-11 16:38:24 -07:00
}
}
2012-08-20 21:06:46 -07:00
2012-10-15 18:23:07 -07:00
void
FrameLayerBuilder : : DisplayItemData : : GetFrameListChanges ( nsDisplayItem * aOther ,
nsTArray < nsIFrame * > & aOut )
2012-08-28 22:47:15 -07:00
{
2012-10-15 18:23:07 -07:00
aOut = mFrameList ;
nsAutoTArray < nsIFrame * , 4 > added ;
if ( ! aOut . RemoveElement ( aOther - > GetUnderlyingFrame ( ) ) ) {
added . AppendElement ( aOther - > GetUnderlyingFrame ( ) ) ;
2012-08-28 22:47:15 -07:00
}
2012-10-11 16:38:24 -07:00
2012-08-28 22:47:15 -07:00
nsAutoTArray < nsIFrame * , 4 > mergedFrames ;
aOther - > GetMergedFrames ( & mergedFrames ) ;
for ( uint32_t i = 0 ; i < mergedFrames . Length ( ) ; + + i ) {
2012-10-15 18:23:07 -07:00
if ( ! aOut . RemoveElement ( mergedFrames [ i ] ) ) {
added . AppendElement ( mergedFrames [ i ] ) ;
2012-08-28 22:47:15 -07:00
}
}
2012-10-15 18:23:07 -07:00
aOut . AppendElements ( added ) ;
2012-08-28 22:47:15 -07:00
}
2010-05-20 20:20:48 -07:00
/**
2010-07-15 14:07:51 -07:00
* This is the userdata we associate with a layer manager .
2010-05-20 20:20:48 -07:00
*/
2010-09-02 02:18:39 -07:00
class LayerManagerData : public LayerUserData {
2010-05-20 20:20:48 -07:00
public :
2012-10-11 16:38:24 -07:00
LayerManagerData ( LayerManager * aManager )
: mLayerManager ( aManager )
2012-10-11 19:39:46 -07:00
# ifdef DEBUG_DISPLAY_ITEM_DATA
2012-10-11 16:38:24 -07:00
, mParent ( nullptr )
2012-10-11 19:39:46 -07:00
# endif
2012-10-11 16:38:24 -07:00
, mInvalidateAllLayers ( false )
2010-05-20 20:20:48 -07:00
{
2010-09-02 02:18:39 -07:00
MOZ_COUNT_CTOR ( LayerManagerData ) ;
2012-10-11 16:38:24 -07:00
mDisplayItems . Init ( ) ;
2010-05-20 20:20:48 -07:00
}
2010-09-02 02:18:39 -07:00
~ LayerManagerData ( ) {
2012-08-28 22:48:41 -07:00
MOZ_COUNT_DTOR ( LayerManagerData ) ;
2010-09-02 02:18:39 -07:00
}
2012-10-11 16:38:25 -07:00
# ifdef DEBUG_DISPLAY_ITEM_DATA
void Dump ( const char * aPrefix = " " ) {
printf ( " %sLayerManagerData %p \n " , aPrefix , this ) ;
nsAutoCString prefix ;
prefix + = aPrefix ;
prefix + = " " ;
mDisplayItems . EnumerateEntries (
FrameLayerBuilder : : DumpDisplayItemDataForFrame , ( void * ) prefix . get ( ) ) ;
}
# endif
2010-07-15 14:07:51 -07:00
/**
* Tracks which frames have layers associated with them .
*/
2012-10-11 16:38:24 -07:00
LayerManager * mLayerManager ;
2012-10-11 19:39:46 -07:00
# ifdef DEBUG_DISPLAY_ITEM_DATA
2012-10-11 16:38:24 -07:00
LayerManagerData * mParent ;
2012-10-11 19:39:46 -07:00
# endif
2012-10-11 16:38:24 -07:00
nsTHashtable < nsRefPtrHashKey < FrameLayerBuilder : : DisplayItemData > > mDisplayItems ;
2011-09-28 23:19:26 -07:00
bool mInvalidateAllLayers ;
2010-07-15 14:07:51 -07:00
} ;
2012-08-28 22:48:41 -07:00
/* static */ void
FrameLayerBuilder : : DestroyDisplayItemDataFor ( nsIFrame * aFrame )
{
FrameProperties props = aFrame - > Properties ( ) ;
props . Delete ( LayerManagerDataProperty ( ) ) ;
}
2011-10-06 14:35:08 -07:00
namespace {
2012-06-25 19:43:30 -07:00
// a global cache of image containers used for mask layers
2012-07-30 07:20:58 -07:00
static MaskLayerImageCache * gMaskLayerImageCache = nullptr ;
2012-06-25 19:43:30 -07:00
static inline MaskLayerImageCache * GetMaskLayerImageCache ( )
{
if ( ! gMaskLayerImageCache ) {
gMaskLayerImageCache = new MaskLayerImageCache ( ) ;
}
return gMaskLayerImageCache ;
}
2010-07-15 14:07:51 -07:00
/**
* This is a helper object used to build up the layer children for
* a ContainerLayer .
*/
class ContainerState {
public :
ContainerState ( nsDisplayListBuilder * aBuilder ,
LayerManager * aManager ,
2012-07-17 10:03:51 -07:00
FrameLayerBuilder * aLayerBuilder ,
2010-07-15 14:07:51 -07:00
nsIFrame * aContainerFrame ,
2012-09-28 04:19:39 -07:00
nsDisplayItem * aContainerItem ,
2011-06-22 05:11:27 -07:00
ContainerLayer * aContainerLayer ,
const FrameLayerBuilder : : ContainerParameters & aParameters ) :
2010-07-15 14:07:51 -07:00
mBuilder ( aBuilder ) , mManager ( aManager ) ,
2012-07-17 10:03:51 -07:00
mLayerBuilder ( aLayerBuilder ) ,
2012-09-28 04:19:39 -07:00
mContainerFrame ( aContainerFrame ) ,
mContainerLayer ( aContainerLayer ) ,
2011-06-22 05:11:27 -07:00
mParameters ( aParameters ) ,
2012-08-28 22:47:15 -07:00
mNextFreeRecycledThebesLayer ( 0 )
2010-05-20 20:20:48 -07:00
{
2012-04-10 04:24:18 -07:00
nsPresContext * presContext = aContainerFrame - > PresContext ( ) ;
mAppUnitsPerDevPixel = presContext - > AppUnitsPerDevPixel ( ) ;
2012-10-15 18:10:48 -07:00
mContainerReferenceFrame = aContainerItem ? aContainerItem - > ReferenceFrameForChildren ( ) :
2012-09-28 04:19:39 -07:00
mBuilder - > FindReferenceFrameFor ( mContainerFrame ) ;
2012-04-10 04:24:18 -07:00
// When AllowResidualTranslation is false, display items will be drawn
// scaled with a translation by integer pixels, so we know how the snapping
// will work.
mSnappingEnabled = aManager - > IsSnappingEffectiveTransforms ( ) & &
! mParameters . AllowResidualTranslation ( ) ;
2012-02-07 14:26:40 -08:00
mRecycledMaskImageLayers . Init ( ) ;
2010-07-15 14:08:03 -07:00
CollectOldLayers ( ) ;
2010-05-20 20:20:48 -07:00
}
2010-07-15 14:07:51 -07:00
2012-07-22 20:00:36 -07:00
enum ProcessDisplayItemsFlags {
NO_COMPONENT_ALPHA = 0x01 ,
} ;
2010-07-15 14:07:51 -07:00
/**
* This is the method that actually walks a display list and builds
* the child layers . We invoke it recursively to process clipped sublists .
* @ param aClipRect the clip rect to apply to the list items , or null
* if no clipping is required
*/
void ProcessDisplayItems ( const nsDisplayList & aList ,
2012-07-22 20:00:36 -07:00
FrameLayerBuilder : : Clip & aClip ,
2012-12-11 12:36:22 -08:00
uint32_t aFlags ,
const nsIFrame * aForceActiveScrolledRoot = nullptr ) ;
2010-07-15 14:07:51 -07:00
/**
* This finalizes all the open ThebesLayers by popping every element off
* mThebesLayerDataStack , then sets the children of the container layer
* to be all the layers in mNewChildLayers in that order and removes any
* layers as children of the container that aren ' t in mNewChildLayers .
2010-12-19 17:26:14 -08:00
* @ param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA ,
* set * aTextContentFlags to CONTENT_COMPONENT_ALPHA
2010-07-15 14:07:51 -07:00
*/
2012-08-28 22:47:15 -07:00
void Finish ( uint32_t * aTextContentFlags , LayerManagerData * aData ) ;
2010-07-15 14:07:51 -07:00
2011-02-22 21:38:09 -08:00
nsRect GetChildrenBounds ( ) { return mBounds ; }
2012-04-10 04:24:18 -07:00
nscoord GetAppUnitsPerDevPixel ( ) { return mAppUnitsPerDevPixel ; }
nsIntRect ScaleToNearestPixels ( const nsRect & aRect )
{
return aRect . ScaleToNearestPixels ( mParameters . mXScale , mParameters . mYScale ,
mAppUnitsPerDevPixel ) ;
}
2012-07-22 20:00:36 -07:00
nsIntRegion ScaleRegionToNearestPixels ( const nsRegion & aRegion )
{
return aRegion . ScaleToNearestPixels ( mParameters . mXScale , mParameters . mYScale ,
mAppUnitsPerDevPixel ) ;
}
2012-04-10 04:24:18 -07:00
nsIntRect ScaleToOutsidePixels ( const nsRect & aRect , bool aSnap )
{
if ( aSnap & & mSnappingEnabled ) {
return ScaleToNearestPixels ( aRect ) ;
}
return aRect . ScaleToOutsidePixels ( mParameters . mXScale , mParameters . mYScale ,
mAppUnitsPerDevPixel ) ;
}
nsIntRect ScaleToInsidePixels ( const nsRect & aRect , bool aSnap )
{
if ( aSnap & & mSnappingEnabled ) {
return ScaleToNearestPixels ( aRect ) ;
}
return aRect . ScaleToInsidePixels ( mParameters . mXScale , mParameters . mYScale ,
mAppUnitsPerDevPixel ) ;
}
2012-07-22 20:00:36 -07:00
nsIntRegion ScaleRegionToInsidePixels ( const nsRegion & aRegion , bool aSnap )
{
if ( aSnap & & mSnappingEnabled ) {
return ScaleRegionToNearestPixels ( aRegion ) ;
}
return aRegion . ScaleToInsidePixels ( mParameters . mXScale , mParameters . mYScale ,
mAppUnitsPerDevPixel ) ;
}
2010-07-15 14:07:51 -07:00
protected :
/**
* We keep a stack of these to represent the ThebesLayers that are
* currently available to have display items added to .
* We use a stack here because as much as possible we want to
* assign display items to existing ThebesLayers , and to the lowest
* ThebesLayer in z - order . This reduces the number of layers and
* makes it more likely a display item will be rendered to an opaque
* layer , giving us the best chance of getting subpixel AA .
*/
class ThebesLayerData {
public :
2010-07-15 14:08:03 -07:00
ThebesLayerData ( ) :
2012-07-30 07:20:58 -07:00
mActiveScrolledRoot ( nullptr ) , mLayer ( nullptr ) ,
2011-10-17 07:59:28 -07:00
mIsSolidColorInVisibleRegion ( false ) ,
mNeedComponentAlpha ( false ) ,
mForceTransparentSurface ( false ) ,
2012-07-30 07:20:58 -07:00
mImage ( nullptr ) ,
2012-02-07 14:27:44 -08:00
mCommonClipCount ( - 1 ) { }
2010-07-15 14:07:51 -07:00
/**
* Record that an item has been added to the ThebesLayer , so we
* need to update our regions .
2010-07-15 14:08:11 -07:00
* @ param aVisibleRect the area of the item that ' s visible
2010-08-01 20:06:58 -07:00
* @ param aDrawRect the area of the item that would be drawn if it
* was completely visible
2010-07-15 14:08:11 -07:00
* @ param aOpaqueRect if non - null , the area of the item that ' s opaque .
* We pass in a separate opaque rect because the opaque rect can be
* bigger than the visible rect , and we want to have the biggest
* opaque rect that we can .
* @ param aSolidColor if non - null , the visible area of the item is
* a constant color given by * aSolidColor
2010-07-15 14:07:51 -07:00
*/
2011-06-22 05:11:27 -07:00
void Accumulate ( ContainerState * aState ,
2010-09-02 02:18:39 -07:00
nsDisplayItem * aItem ,
const nsIntRect & aVisibleRect ,
2011-01-02 17:48:09 -08:00
const nsIntRect & aDrawRect ,
const FrameLayerBuilder : : Clip & aClip ) ;
2012-09-12 17:32:53 -07:00
const nsIFrame * GetActiveScrolledRoot ( ) { return mActiveScrolledRoot ; }
2010-07-15 14:07:51 -07:00
2011-01-17 13:47:18 -08:00
/**
* If this represents only a nsDisplayImage , and the image type
* supports being optimized to an ImageLayer ( TYPE_RASTER only ) returns
* an ImageContainer for the image .
*/
2012-11-18 19:28:18 -08:00
already_AddRefed < ImageContainer > CanOptimizeImageLayer ( nsDisplayListBuilder * aBuilder ) ;
2011-01-17 13:47:18 -08:00
2010-07-15 14:07:51 -07:00
/**
* The region of visible content in the layer , relative to the
* container layer ( which is at the snapped top - left of the display
* list reference frame ) .
*/
nsIntRegion mVisibleRegion ;
/**
* The region of visible content above the layer and below the
* next ThebesLayerData currently in the stack , if any . Note that not
* all ThebesLayers for the container are in the ThebesLayerData stack .
* Same coordinate system as mVisibleRegion .
2012-01-11 03:26:33 -08:00
* This is a conservative approximation : it contains the true region .
2010-07-15 14:07:51 -07:00
*/
nsIntRegion mVisibleAboveRegion ;
2010-08-01 20:06:58 -07:00
/**
* The region containing the bounds of all display items in the layer ,
* regardless of visbility .
* Same coordinate system as mVisibleRegion .
2012-01-11 03:26:33 -08:00
* This is a conservative approximation : it contains the true region .
2010-08-01 20:06:58 -07:00
*/
nsIntRegion mDrawRegion ;
/**
* The region containing the bounds of all display items ( regardless
* of visibility ) in the layer and below the next ThebesLayerData
* currently in the stack , if any .
* Note that not all ThebesLayers for the container are in the
* ThebesLayerData stack .
* Same coordinate system as mVisibleRegion .
*/
nsIntRegion mDrawAboveRegion ;
2010-07-15 14:07:51 -07:00
/**
* The region of visible content in the layer that is opaque .
* Same coordinate system as mVisibleRegion .
*/
nsIntRegion mOpaqueRegion ;
/**
* The " active scrolled root " for all content in the layer . Must
* be non - null ; all content in a ThebesLayer must have the same
* active scrolled root .
*/
2012-09-28 04:19:39 -07:00
const nsIFrame * mActiveScrolledRoot ;
2010-07-15 14:07:51 -07:00
ThebesLayer * mLayer ;
2010-07-15 14:08:03 -07:00
/**
* If mIsSolidColorInVisibleRegion is true , this is the color of the visible
* region .
*/
nscolor mSolidColor ;
/**
* True if every pixel in mVisibleRegion will have color mSolidColor .
*/
2011-09-28 23:19:26 -07:00
bool mIsSolidColorInVisibleRegion ;
2010-09-02 02:18:40 -07:00
/**
* True if there is any text visible in the layer that ' s over
* transparent pixels in the layer .
*/
2011-09-28 23:19:26 -07:00
bool mNeedComponentAlpha ;
2010-10-19 10:02:25 -07:00
/**
* Set if the layer should be treated as transparent , even if its entire
* area is covered by opaque display items . For example , this needs to
* be set if something is going to " punch holes " in the layer by clearing
* part of its surface .
*/
2011-09-28 23:19:26 -07:00
bool mForceTransparentSurface ;
2011-01-17 13:47:18 -08:00
/**
* Stores the pointer to the nsDisplayImage if we want to
* convert this to an ImageLayer .
*/
2012-09-24 13:29:14 -07:00
nsDisplayImageContainer * mImage ;
2011-03-31 14:33:46 -07:00
/**
2012-02-07 14:27:44 -08:00
* Stores the clip that we need to apply to the image or , if there is no
* image , a clip for SOME item in the layer . There is no guarantee which
* item ' s clip will be stored here and mItemClip should not be used to clip
* the whole layer - only some part of the clip should be used , as determined
* by ThebesDisplayItemLayerUserData : : GetCommonClipCount ( ) - which may even be
* no part at all .
2011-03-31 14:33:46 -07:00
*/
2012-02-07 14:27:44 -08:00
FrameLayerBuilder : : Clip mItemClip ;
/**
* The first mCommonClipCount rounded rectangle clips are identical for
* all items in the layer .
* - 1 if there are no items in the layer ; must be > = 0 by the time that this
* data is popped from the stack .
*/
2012-08-22 08:56:38 -07:00
int32_t mCommonClipCount ;
2012-02-07 14:27:44 -08:00
/*
* Updates mCommonClipCount by checking for rounded rect clips in common
* between the clip on a new item ( aCurrentClip ) and the common clips
* on items already in the layer ( the first mCommonClipCount rounded rects
* in mItemClip ) .
*/
void UpdateCommonClipCount ( const FrameLayerBuilder : : Clip & aCurrentClip ) ;
2010-05-20 20:20:48 -07:00
} ;
2011-06-22 05:11:27 -07:00
friend class ThebesLayerData ;
2010-05-20 20:20:48 -07:00
2010-07-15 14:07:51 -07:00
/**
* Grab the next recyclable ThebesLayer , or create one if there are no
* more recyclable ThebesLayers . Does any necessary invalidation of
* a recycled ThebesLayer , and sets up the transform on the ThebesLayer
2010-07-15 14:08:03 -07:00
* to account for scrolling .
2010-07-15 14:07:51 -07:00
*/
2012-09-28 04:19:39 -07:00
already_AddRefed < ThebesLayer > CreateOrRecycleThebesLayer ( const nsIFrame * aActiveScrolledRoot ,
const nsIFrame * aReferenceFrame ,
const nsPoint & aTopLeft ) ;
2010-07-15 14:07:51 -07:00
/**
2010-07-15 14:08:03 -07:00
* Grab the next recyclable ColorLayer , or create one if there are no
* more recyclable ColorLayers .
*/
2012-08-20 03:00:49 -07:00
already_AddRefed < ColorLayer > CreateOrRecycleColorLayer ( ThebesLayer * aThebes ) ;
2011-01-17 13:47:18 -08:00
/**
* Grab the next recyclable ImageLayer , or create one if there are no
* more recyclable ImageLayers .
*/
2012-08-20 03:00:49 -07:00
already_AddRefed < ImageLayer > CreateOrRecycleImageLayer ( ThebesLayer * aThebes ) ;
2012-02-07 14:26:40 -08:00
/**
* Grab a recyclable ImageLayer for use as a mask layer for aLayer ( that is a
* mask layer which has been used for aLayer before ) , or create one if such
* a layer doesn ' t exist .
*/
already_AddRefed < ImageLayer > CreateOrRecycleMaskImageLayerFor ( Layer * aLayer ) ;
2010-07-15 14:08:03 -07:00
/**
* Grabs all ThebesLayers and ColorLayers from the ContainerLayer and makes them
2010-07-15 14:07:51 -07:00
* available for recycling .
*/
2010-07-15 14:08:03 -07:00
void CollectOldLayers ( ) ;
2010-07-15 14:08:05 -07:00
/**
* If aItem used to belong to a ThebesLayer , invalidates the area of
* aItem in that layer . If aNewLayer is a ThebesLayer , invalidates the area of
* aItem in that layer .
*/
2012-08-28 22:47:15 -07:00
void InvalidateForLayerChange ( nsDisplayItem * aItem ,
2012-08-28 22:48:43 -07:00
Layer * aNewLayer ,
const FrameLayerBuilder : : Clip & aClip ,
2012-10-11 16:38:24 -07:00
const nsPoint & aTopLeft ,
nsDisplayItemGeometry * aGeometry ) ;
2010-09-02 02:18:39 -07:00
/**
* Try to determine whether the ThebesLayer at aThebesLayerIndex
2011-01-04 02:35:57 -08:00
* has a single opaque color behind it , over the entire bounds of its visible
* region .
2010-09-02 02:18:39 -07:00
* If successful , return that color , otherwise return NS_RGBA ( 0 , 0 , 0 , 0 ) .
*/
2012-08-22 08:56:38 -07:00
nscolor FindOpaqueBackgroundColorFor ( int32_t aThebesLayerIndex ) ;
2010-07-15 14:07:51 -07:00
/**
* Indicate that we are done adding items to the ThebesLayer at the top of
* mThebesLayerDataStack . Set the final visible region and opaque - content
* flag , and pop it off the stack .
*/
void PopThebesLayerData ( ) ;
/**
* Find the ThebesLayer to which we should assign the next display item .
2010-08-01 20:06:58 -07:00
* We scan the ThebesLayerData stack to find the topmost ThebesLayer
* that is compatible with the display item ( i . e . , has the same
* active scrolled root ) , and that has no content from other layers above
* it and intersecting the aVisibleRect .
2010-07-15 14:07:51 -07:00
* Returns the layer , and also updates the ThebesLayerData . Will
2010-08-01 20:06:58 -07:00
* push a new ThebesLayerData onto the stack if no suitable existing
* layer is found . If we choose a ThebesLayer that ' s already on the
* ThebesLayerData stack , later elements on the stack will be popped off .
2010-07-15 14:07:51 -07:00
* @ param aVisibleRect the area of the next display item that ' s visible
* @ param aActiveScrolledRoot the active scrolled root for the next
* display item
2010-07-15 14:08:11 -07:00
* @ param aOpaqueRect if non - null , a region of the display item that is opaque
2010-07-15 14:08:03 -07:00
* @ param aSolidColor if non - null , indicates that every pixel in aVisibleRect
* will be painted with aSolidColor by the item
2010-07-15 14:07:51 -07:00
*/
2012-02-07 14:27:44 -08:00
ThebesLayerData * FindThebesLayerFor ( nsDisplayItem * aItem ,
2010-09-02 02:18:39 -07:00
const nsIntRect & aVisibleRect ,
2010-08-01 20:06:58 -07:00
const nsIntRect & aDrawRect ,
2011-01-02 17:48:09 -08:00
const FrameLayerBuilder : : Clip & aClip ,
2012-09-28 04:19:39 -07:00
const nsIFrame * aActiveScrolledRoot ,
const nsPoint & aTopLeft ) ;
2010-07-15 14:07:51 -07:00
ThebesLayerData * GetTopThebesLayerData ( )
2010-05-20 20:20:48 -07:00
{
2012-07-30 07:20:58 -07:00
return mThebesLayerDataStack . IsEmpty ( ) ? nullptr
2010-07-15 14:07:51 -07:00
: mThebesLayerDataStack [ mThebesLayerDataStack . Length ( ) - 1 ] . get ( ) ;
2010-05-20 20:20:48 -07:00
}
2012-02-07 14:27:44 -08:00
/* Build a mask layer to represent the clipping region. Will return null if
* there is no clipping specified or a mask layer cannot be built .
* Builds an ImageLayer for the appropriate backend ; the mask is relative to
* aLayer ' s visible region .
* aLayer is the layer to be clipped .
* aRoundedRectClipCount is used when building mask layers for ThebesLayers ,
* SetupMaskLayer will build a mask layer for only the first
* aRoundedRectClipCount rounded rects in aClip
*/
void SetupMaskLayer ( Layer * aLayer , const FrameLayerBuilder : : Clip & aClip ,
2012-09-27 23:57:33 -07:00
uint32_t aRoundedRectClipCount = UINT32_MAX ) ;
2012-02-07 14:27:44 -08:00
2012-12-11 12:36:22 -08:00
bool ChooseActiveScrolledRoot ( const nsDisplayList & aList ,
const nsIFrame * * aActiveScrolledRoot ) ;
2010-07-15 14:07:51 -07:00
nsDisplayListBuilder * mBuilder ;
LayerManager * mManager ;
2012-07-17 10:03:51 -07:00
FrameLayerBuilder * mLayerBuilder ;
2010-07-15 14:07:51 -07:00
nsIFrame * mContainerFrame ;
2012-09-28 04:19:39 -07:00
const nsIFrame * mContainerReferenceFrame ;
2010-07-15 14:07:51 -07:00
ContainerLayer * mContainerLayer ;
2011-06-22 05:11:27 -07:00
FrameLayerBuilder : : ContainerParameters mParameters ;
2010-07-15 14:07:51 -07:00
/**
* The region of ThebesLayers that should be invalidated every time
* we recycle one .
*/
nsIntRegion mInvalidThebesContent ;
2011-02-22 21:38:09 -08:00
nsRect mBounds ;
2010-07-15 14:07:51 -07:00
nsAutoTArray < nsAutoPtr < ThebesLayerData > , 1 > mThebesLayerDataStack ;
/**
* We collect the list of children in here . During ProcessDisplayItems ,
* the layers in this array either have mContainerLayer as their parent ,
* or no parent .
*/
2010-11-08 18:48:59 -08:00
typedef nsAutoTArray < nsRefPtr < Layer > , 1 > AutoLayersArray ;
AutoLayersArray mNewChildLayers ;
2010-07-15 14:07:51 -07:00
nsTArray < nsRefPtr < ThebesLayer > > mRecycledThebesLayers ;
2012-02-07 14:26:40 -08:00
nsDataHashtable < nsPtrHashKey < Layer > , nsRefPtr < ImageLayer > >
mRecycledMaskImageLayers ;
2012-08-22 08:56:38 -07:00
uint32_t mNextFreeRecycledThebesLayer ;
2012-04-10 04:24:18 -07:00
nscoord mAppUnitsPerDevPixel ;
bool mSnappingEnabled ;
2010-05-20 20:20:48 -07:00
} ;
2010-09-02 02:18:39 -07:00
class ThebesDisplayItemLayerUserData : public LayerUserData
{
public :
ThebesDisplayItemLayerUserData ( ) :
2012-09-05 21:07:53 -07:00
mMaskClipCount ( 0 ) ,
2011-06-22 05:11:28 -07:00
mForcedBackgroundColor ( NS_RGBA ( 0 , 0 , 0 , 0 ) ) ,
mXScale ( 1.f ) , mYScale ( 1.f ) ,
2012-08-28 22:47:15 -07:00
mAppUnitsPerDevPixel ( 0 ) ,
2012-09-16 15:25:33 -07:00
mTranslation ( 0 , 0 ) ,
2011-06-22 05:11:28 -07:00
mActiveScrolledRootPosition ( 0 , 0 ) { }
2010-09-02 02:18:39 -07:00
2012-09-03 18:02:56 -07:00
/**
* Record the number of clips in the Thebes layer ' s mask layer .
* Should not be reset when the layer is recycled since it is used to track
* changes in the use of mask layers .
*/
uint32_t mMaskClipCount ;
2011-01-04 02:35:57 -08:00
/**
* A color that should be painted over the bounds of the layer ' s visible
* region before any other content is painted .
*/
2010-09-02 02:18:39 -07:00
nscolor mForcedBackgroundColor ;
2012-09-03 18:02:56 -07:00
2011-06-22 05:11:27 -07:00
/**
* The resolution scale used .
*/
float mXScale , mYScale ;
2012-02-07 14:27:44 -08:00
2012-08-28 22:47:15 -07:00
/**
* The appunits per dev pixel for the items in this layer .
*/
nscoord mAppUnitsPerDevPixel ;
2012-09-16 15:25:33 -07:00
/**
* The offset from the ThebesLayer ' s 0 , 0 to the
* reference frame . This isn ' t necessarily the same as the transform
* set on the ThebesLayer since we might also be applying an extra
* offset specified by the parent ContainerLayer /
*/
nsIntPoint mTranslation ;
2011-06-22 05:11:28 -07:00
/**
* We try to make 0 , 0 of the ThebesLayer be the top - left of the
* border - box of the " active scrolled root " frame ( i . e . the nearest ancestor
* frame for the display items that is being actively scrolled ) . But
* we force the ThebesLayer transform to be an integer translation , and we may
* have a resolution scale , so we have to snap the ThebesLayer transform , so
* 0 , 0 may not be exactly the top - left of the active scrolled root . Here we
* store the coordinates in ThebesLayer space of the top - left of the
* active scrolled root .
*/
gfxPoint mActiveScrolledRootPosition ;
2012-08-20 03:00:49 -07:00
2012-08-28 22:47:15 -07:00
nsIntRegion mRegionToInvalidate ;
2012-09-28 04:19:39 -07:00
// The offset between the active scrolled root of this layer
// and the root of the container for the previous and current
// paints respectively.
2012-08-28 22:47:15 -07:00
nsPoint mLastActiveScrolledRootOrigin ;
nsPoint mActiveScrolledRootOrigin ;
2012-08-20 03:00:49 -07:00
nsRefPtr < ColorLayer > mColorLayer ;
nsRefPtr < ImageLayer > mImageLayer ;
2010-09-02 02:18:39 -07:00
} ;
2012-02-07 14:26:33 -08:00
/*
* User data for layers which will be used as masks .
*/
struct MaskLayerUserData : public LayerUserData
{
2012-07-30 07:20:58 -07:00
MaskLayerUserData ( ) : mImageKey ( nullptr ) { }
2012-06-25 19:43:30 -07:00
bool
operator = = ( const MaskLayerUserData & aOther ) const
{
return mRoundedClipRects = = aOther . mRoundedClipRects & &
mScaleX = = aOther . mScaleX & &
mScaleY = = aOther . mScaleY ;
}
nsRefPtr < const MaskLayerImageCache : : MaskLayerImageKey > mImageKey ;
2012-02-07 14:26:33 -08:00
// properties of the mask layer; the mask layer may be re-used if these
// remain unchanged.
nsTArray < FrameLayerBuilder : : Clip : : RoundedRect > mRoundedClipRects ;
2012-06-25 19:43:30 -07:00
// scale from the masked layer which is applied to the mask
float mScaleX , mScaleY ;
2012-02-07 14:26:33 -08:00
} ;
2010-05-20 20:20:48 -07:00
/**
2010-07-15 14:07:51 -07:00
* The address of gThebesDisplayItemLayerUserData is used as the user
2010-09-02 02:18:39 -07:00
* data key for ThebesLayers created by FrameLayerBuilder .
2010-07-15 14:07:51 -07:00
* It identifies ThebesLayers used to draw non - layer content , which are
* therefore eligible for recycling . We want display items to be able to
* create their own dedicated ThebesLayers in BuildLayer , if necessary ,
* and we wouldn ' t want to accidentally recycle those .
2010-09-02 02:18:39 -07:00
* The user data is a ThebesDisplayItemLayerUserData .
2010-05-20 20:20:48 -07:00
*/
2012-08-22 08:56:38 -07:00
uint8_t gThebesDisplayItemLayerUserData ;
2010-07-15 14:08:03 -07:00
/**
* The address of gColorLayerUserData is used as the user
2010-09-02 02:18:39 -07:00
* data key for ColorLayers created by FrameLayerBuilder .
* The user data is null .
2010-07-15 14:08:03 -07:00
*/
2012-08-22 08:56:38 -07:00
uint8_t gColorLayerUserData ;
2011-01-17 13:47:18 -08:00
/**
* The address of gImageLayerUserData is used as the user
* data key for ImageLayers created by FrameLayerBuilder .
* The user data is null .
*/
2012-08-22 08:56:38 -07:00
uint8_t gImageLayerUserData ;
2010-09-02 02:18:39 -07:00
/**
* The address of gLayerManagerUserData is used as the user
* data key for retained LayerManagers managed by FrameLayerBuilder .
* The user data is a LayerManagerData .
*/
2012-08-22 08:56:38 -07:00
uint8_t gLayerManagerUserData ;
2012-02-07 14:26:33 -08:00
/**
* The address of gMaskLayerUserData is used as the user
* data key for mask layers managed by FrameLayerBuilder .
* The user data is a MaskLayerUserData .
*/
2012-08-22 08:56:38 -07:00
uint8_t gMaskLayerUserData ;
2010-07-15 14:07:51 -07:00
2012-02-07 14:27:44 -08:00
/**
* Helper functions for getting user data and casting it to the correct type .
* aLayer is the layer where the user data is stored .
*/
MaskLayerUserData * GetMaskLayerUserData ( Layer * aLayer )
{
return static_cast < MaskLayerUserData * > ( aLayer - > GetUserData ( & gMaskLayerUserData ) ) ;
}
ThebesDisplayItemLayerUserData * GetThebesDisplayItemLayerUserData ( Layer * aLayer )
{
return static_cast < ThebesDisplayItemLayerUserData * > (
aLayer - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
}
2010-07-15 14:07:51 -07:00
} // anonymous namespace
2012-06-25 19:43:30 -07:00
/* static */ void
FrameLayerBuilder : : Shutdown ( )
{
if ( gMaskLayerImageCache ) {
delete gMaskLayerImageCache ;
2012-07-30 07:20:58 -07:00
gMaskLayerImageCache = nullptr ;
2012-06-25 19:43:30 -07:00
}
}
2010-09-17 12:09:08 -07:00
void
2012-08-20 21:06:46 -07:00
FrameLayerBuilder : : Init ( nsDisplayListBuilder * aBuilder , LayerManager * aManager )
2010-09-17 12:09:08 -07:00
{
2012-08-28 22:47:15 -07:00
mDisplayListBuilder = aBuilder ;
2012-09-16 03:32:59 -07:00
mRootPresContext = aBuilder - > RootReferenceFrame ( ) - > PresContext ( ) - > GetRootPresContext ( ) ;
2010-09-17 12:09:08 -07:00
if ( mRootPresContext ) {
mInitialDOMGeneration = mRootPresContext - > GetDOMGeneration ( ) ;
}
2012-08-28 22:48:15 -07:00
aManager - > SetUserData ( & gLayerManagerLayerBuilder , this ) ;
2010-09-17 12:09:08 -07:00
}
2011-11-14 20:59:03 -08:00
void
FrameLayerBuilder : : FlashPaint ( gfxContext * aContext )
{
static bool sPaintFlashingEnabled ;
static bool sPaintFlashingPrefCached = false ;
if ( ! sPaintFlashingPrefCached ) {
sPaintFlashingPrefCached = true ;
2012-07-31 10:28:21 -07:00
mozilla : : Preferences : : AddBoolVarCache ( & sPaintFlashingEnabled ,
2011-11-14 20:59:03 -08:00
" nglayout.debug.paint_flashing " ) ;
}
if ( sPaintFlashingEnabled ) {
float r = float ( rand ( ) ) / RAND_MAX ;
float g = float ( rand ( ) ) / RAND_MAX ;
float b = float ( rand ( ) ) / RAND_MAX ;
aContext - > SetColor ( gfxRGBA ( r , g , b , 0.2 ) ) ;
aContext - > Paint ( ) ;
}
}
2012-10-11 16:38:24 -07:00
FrameLayerBuilder : : DisplayItemData *
FrameLayerBuilder : : GetDisplayItemData ( nsIFrame * aFrame , uint32_t aKey )
{
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aFrame - > Properties ( ) . Get ( LayerManagerDataProperty ( ) ) ) ;
if ( array ) {
for ( uint32_t i = 0 ; i < array - > Length ( ) ; i + + ) {
DisplayItemData * item = array - > ElementAt ( i ) ;
if ( item - > mDisplayItemKey = = aKey & &
item - > mLayer - > Manager ( ) = = mRetainingManager ) {
return item ;
}
}
2012-08-28 22:47:15 -07:00
}
2012-10-11 16:38:24 -07:00
return nullptr ;
2010-07-15 14:07:51 -07:00
}
2012-08-28 22:47:15 -07:00
nsACString &
AppendToString ( nsACString & s , const nsIntRect & r ,
const char * pfx = " " , const char * sfx = " " )
{
s + = pfx ;
s + = nsPrintfCString (
" (x=%d, y=%d, w=%d, h=%d) " ,
r . x , r . y , r . width , r . height ) ;
return s + = sfx ;
}
nsACString &
AppendToString ( nsACString & s , const nsIntRegion & r ,
const char * pfx = " " , const char * sfx = " " )
{
s + = pfx ;
nsIntRegionRectIterator it ( r ) ;
s + = " < " ;
while ( const nsIntRect * sr = it . Next ( ) ) {
AppendToString ( s , * sr ) + = " ; " ;
}
s + = " > " ;
return s + = sfx ;
}
/**
* Invalidate aRegion in aLayer . aLayer is in the coordinate system
* * after * aTranslation has been applied , so we need to
* apply the inverse of that transform before calling InvalidateRegion .
*/
static void
InvalidatePostTransformRegion ( ThebesLayer * aLayer , const nsIntRegion & aRegion ,
const nsIntPoint & aTranslation )
{
// Convert the region from the coordinates of the container layer
// (relative to the snapped top-left of the display list reference frame)
// to the ThebesLayer's own coordinates
nsIntRegion rgn = aRegion ;
rgn . MoveBy ( - aTranslation ) ;
aLayer - > InvalidateRegion ( rgn ) ;
# ifdef DEBUG_INVALIDATIONS
nsAutoCString str ;
AppendToString ( str , rgn ) ;
printf ( " Invalidating layer %p: %s \n " , aLayer , str . get ( ) ) ;
# endif
}
2012-10-15 18:10:43 -07:00
static void
InvalidatePostTransformRegion ( ThebesLayer * aLayer , const nsRect & aRect ,
const FrameLayerBuilder : : Clip & aClip ,
const nsIntPoint & aTranslation )
{
ThebesDisplayItemLayerUserData * data =
static_cast < ThebesDisplayItemLayerUserData * > ( aLayer - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
nsRect rect = aClip . ApplyNonRoundedIntersection ( aRect ) ;
nsIntRect pixelRect = rect . ScaleToOutsidePixels ( data - > mXScale , data - > mYScale , data - > mAppUnitsPerDevPixel ) ;
InvalidatePostTransformRegion ( aLayer , pixelRect , aTranslation ) ;
}
2012-08-28 22:47:15 -07:00
static nsIntPoint
GetTranslationForThebesLayer ( ThebesLayer * aLayer )
{
ThebesDisplayItemLayerUserData * data =
static_cast < ThebesDisplayItemLayerUserData * >
( aLayer - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
NS_ASSERTION ( data , " Must be a tracked thebes layer! " ) ;
return data - > mTranslation ;
}
/**
* Some frames can have multiple , nested , retaining layer managers
* associated with them ( normal manager , inactive managers , SVG effects ) .
* In these cases we store the ' outermost ' LayerManager data property
* on the frame since we can walk down the chain from there .
*
* If one of these frames has just been destroyed , we will free the inner
* layer manager when removing the entry from mFramesWithLayers . Destroying
* the layer manager destroys the LayerManagerData and calls into
2012-10-11 19:39:46 -07:00
* the DisplayItemData destructor . If the inner layer manager had any
2012-08-28 22:47:15 -07:00
* items with the same frame , then we attempt to retrieve properties
* from the deleted frame .
*
* Cache the destroyed frame pointer here so we can avoid crashing in this case .
*/
2010-07-15 14:07:51 -07:00
/* static */ void
2011-10-06 14:35:08 -07:00
FrameLayerBuilder : : RemoveFrameFromLayerManager ( nsIFrame * aFrame ,
void * aPropertyValue )
2010-07-15 14:07:51 -07:00
{
2012-10-11 16:38:24 -07:00
sDestroyedFrame = aFrame ;
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aPropertyValue ) ;
// Hold a reference to all the items so that they don't get
// deleted from under us.
nsTArray < nsRefPtr < DisplayItemData > > arrayCopy ;
for ( uint32_t i = 0 ; i < array - > Length ( ) ; + + i ) {
arrayCopy . AppendElement ( array - > ElementAt ( i ) ) ;
}
2012-08-28 22:47:15 -07:00
2012-10-11 16:38:25 -07:00
# ifdef DEBUG_DISPLAY_ITEM_DATA
if ( array - > Length ( ) ) {
LayerManagerData * rootData = array - > ElementAt ( 0 ) - > mParent ;
while ( rootData - > mParent ) {
rootData = rootData - > mParent ;
}
printf ( " Removing frame %p - dumping display data \n " , aFrame ) ;
rootData - > Dump ( ) ;
}
# endif
2012-10-11 16:38:24 -07:00
for ( uint32_t i = 0 ; i < array - > Length ( ) ; + + i ) {
DisplayItemData * data = array - > ElementAt ( i ) ;
ThebesLayer * t = data - > mLayer - > AsThebesLayer ( ) ;
2012-08-28 22:47:15 -07:00
if ( t ) {
2012-10-11 16:38:24 -07:00
ThebesDisplayItemLayerUserData * thebesData =
2012-08-28 22:47:15 -07:00
static_cast < ThebesDisplayItemLayerUserData * > ( t - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
2012-10-11 16:38:24 -07:00
if ( thebesData ) {
nsRegion old = data - > mGeometry - > ComputeInvalidationRegion ( ) ;
nsIntRegion rgn = old . ScaleToOutsidePixels ( thebesData - > mXScale , thebesData - > mYScale , thebesData - > mAppUnitsPerDevPixel ) ;
2012-08-28 22:47:15 -07:00
rgn . MoveBy ( - GetTranslationForThebesLayer ( t ) ) ;
2012-10-11 16:38:24 -07:00
thebesData - > mRegionToInvalidate . Or ( thebesData - > mRegionToInvalidate , rgn ) ;
2013-03-02 09:21:00 -08:00
thebesData - > mRegionToInvalidate . SimplifyOutward ( 8 ) ;
2012-08-28 22:47:15 -07:00
}
}
2012-10-11 16:38:24 -07:00
data - > mParent - > mDisplayItems . RemoveEntry ( data ) ;
2012-09-27 08:34:46 -07:00
}
2012-09-28 04:19:39 -07:00
2012-10-11 16:38:24 -07:00
arrayCopy . Clear ( ) ;
delete array ;
2012-08-28 22:47:15 -07:00
sDestroyedFrame = NULL ;
2010-07-15 14:07:51 -07:00
}
void
2011-01-19 00:27:54 -08:00
FrameLayerBuilder : : DidBeginRetainedLayerTransaction ( LayerManager * aManager )
2010-07-15 14:07:51 -07:00
{
mRetainingManager = aManager ;
LayerManagerData * data = static_cast < LayerManagerData * >
2010-09-02 02:18:39 -07:00
( aManager - > GetUserData ( & gLayerManagerUserData ) ) ;
2010-07-15 14:07:51 -07:00
if ( data ) {
mInvalidateAllLayers = data - > mInvalidateAllLayers ;
2012-08-28 22:48:41 -07:00
} else {
2012-10-11 16:38:24 -07:00
data = new LayerManagerData ( aManager ) ;
2012-08-28 22:48:41 -07:00
aManager - > SetUserData ( & gLayerManagerUserData , data ) ;
2010-05-20 20:20:48 -07:00
}
2010-07-15 14:07:51 -07:00
}
2010-05-20 20:20:48 -07:00
2012-09-24 13:31:30 -07:00
void
2012-10-11 19:39:46 -07:00
FrameLayerBuilder : : StoreOptimizedLayerForFrame ( nsDisplayItem * aItem , Layer * aLayer )
2012-09-24 13:31:30 -07:00
{
2012-10-11 19:39:46 -07:00
if ( ! mRetainingManager ) {
2012-09-24 13:31:30 -07:00
return ;
2012-10-11 19:39:46 -07:00
}
2012-09-24 13:31:30 -07:00
2012-10-11 19:39:46 -07:00
DisplayItemData * data = GetDisplayItemDataForManager ( aItem , aLayer - > Manager ( ) ) ;
NS_ASSERTION ( data , " Must have already stored data for this item! " ) ;
data - > mOptLayer = aLayer ;
2012-09-24 13:31:30 -07:00
}
2010-07-15 14:07:51 -07:00
void
2012-08-28 22:47:15 -07:00
FrameLayerBuilder : : DidEndTransaction ( )
2010-07-15 14:07:51 -07:00
{
2012-06-25 19:43:30 -07:00
GetMaskLayerImageCache ( ) - > Sweep ( ) ;
2010-07-15 14:08:11 -07:00
}
void
2012-08-28 22:47:15 -07:00
FrameLayerBuilder : : WillEndTransaction ( )
2010-07-15 14:08:11 -07:00
{
2012-08-28 22:47:15 -07:00
if ( ! mRetainingManager ) {
2010-07-15 14:08:11 -07:00
return ;
2012-08-28 22:47:15 -07:00
}
2010-05-20 20:20:48 -07:00
2012-08-28 22:47:15 -07:00
// We need to save the data we'll need to support retaining.
2010-07-15 14:07:51 -07:00
LayerManagerData * data = static_cast < LayerManagerData * >
2010-09-02 02:18:39 -07:00
( mRetainingManager - > GetUserData ( & gLayerManagerUserData ) ) ;
2012-08-28 22:48:41 -07:00
NS_ASSERTION ( data , " Must have data! " ) ;
// Update all the frames that used to have layers.
2012-12-12 12:47:05 -08:00
data - > mDisplayItems . EnumerateEntries ( ProcessRemovedDisplayItems , this ) ;
2011-10-17 07:59:28 -07:00
data - > mInvalidateAllLayers = false ;
2012-09-27 08:34:46 -07:00
}
2012-08-28 22:47:15 -07:00
/* static */ PLDHashOperator
2012-10-11 16:38:24 -07:00
FrameLayerBuilder : : ProcessRemovedDisplayItems ( nsRefPtrHashKey < DisplayItemData > * aEntry ,
2012-08-28 22:47:15 -07:00
void * aUserArg )
2010-05-20 20:20:48 -07:00
{
2012-10-11 16:38:24 -07:00
DisplayItemData * data = aEntry - > GetKey ( ) ;
2012-10-11 19:39:46 -07:00
if ( ! data - > mUsed ) {
2012-10-11 16:38:24 -07:00
// This item was visible, but isn't anymore.
2012-12-12 12:47:05 -08:00
FrameLayerBuilder * layerBuilder = static_cast < FrameLayerBuilder * > ( aUserArg ) ;
ThebesLayer * t = data - > mLayer - > AsThebesLayer ( ) ;
if ( t ) {
# ifdef DEBUG_INVALIDATIONS
printf ( " Invalidating unused display item (%i) belonging to frame %p from layer %p \n " , data - > mDisplayItemKey , data - > mFrameList [ 0 ] , t ) ;
# endif
InvalidatePostTransformRegion ( t ,
data - > mGeometry - > ComputeInvalidationRegion ( ) ,
data - > mClip ,
layerBuilder - > GetLastPaintOffset ( t ) ) ;
}
2010-07-15 14:07:51 -07:00
return PL_DHASH_REMOVE ;
}
2012-10-11 19:39:46 -07:00
data - > mUsed = false ;
2012-11-06 14:04:53 -08:00
data - > mIsInvalid = false ;
2010-07-15 14:07:51 -07:00
return PL_DHASH_NEXT ;
}
2012-08-28 22:47:15 -07:00
2012-10-11 16:38:25 -07:00
/* static */ PLDHashOperator
FrameLayerBuilder : : DumpDisplayItemDataForFrame ( nsRefPtrHashKey < DisplayItemData > * aEntry ,
void * aClosure )
{
# ifdef DEBUG_DISPLAY_ITEM_DATA
DisplayItemData * data = aEntry - > GetKey ( ) ;
nsAutoCString prefix ;
prefix + = static_cast < const char * > ( aClosure ) ;
const char * layerState ;
switch ( data - > mLayerState ) {
case LAYER_NONE :
layerState = " LAYER_NONE " ; break ;
case LAYER_INACTIVE :
layerState = " LAYER_INACTIVE " ; break ;
case LAYER_ACTIVE :
layerState = " LAYER_ACTIVE " ; break ;
case LAYER_ACTIVE_FORCE :
layerState = " LAYER_ACTIVE_FORCE " ; break ;
case LAYER_ACTIVE_EMPTY :
layerState = " LAYER_ACTIVE_EMPTY " ; break ;
case LAYER_SVG_EFFECTS :
layerState = " LAYER_SVG_EFFECTS " ; break ;
}
uint32_t mask = ( 1 < < nsDisplayItem : : TYPE_BITS ) - 1 ;
nsAutoCString str ;
str + = prefix ;
str + = nsPrintfCString ( " Frame %p " , data - > mFrameList [ 0 ] ) ;
str + = nsDisplayItem : : DisplayItemTypeName ( static_cast < nsDisplayItem : : Type > ( data - > mDisplayItemKey & mask ) ) ;
if ( ( data - > mDisplayItemKey > > nsDisplayItem : : TYPE_BITS ) ) {
str + = nsPrintfCString ( " (%i) " , data - > mDisplayItemKey > > nsDisplayItem : : TYPE_BITS ) ;
}
str + = nsPrintfCString ( " , %s, Layer %p " , layerState , data - > mLayer . get ( ) ) ;
if ( data - > mOptLayer ) {
str + = nsPrintfCString ( " , OptLayer %p " , data - > mOptLayer . get ( ) ) ;
}
if ( data - > mInactiveManager ) {
str + = nsPrintfCString ( " , InactiveLayerManager %p " , data - > mInactiveManager . get ( ) ) ;
}
str + = " \n " ;
printf ( " %s " , str . get ( ) ) ;
if ( data - > mInactiveManager ) {
prefix + = " " ;
printf ( " %sDumping inactive layer info: \n " , prefix . get ( ) ) ;
LayerManagerData * lmd = static_cast < LayerManagerData * >
( data - > mInactiveManager - > GetUserData ( & gLayerManagerUserData ) ) ;
lmd - > Dump ( prefix . get ( ) ) ;
}
# endif
return PL_DHASH_NEXT ;
}
2012-08-28 22:48:45 -07:00
/* static */ FrameLayerBuilder : : DisplayItemData *
FrameLayerBuilder : : GetDisplayItemDataForManager ( nsDisplayItem * aItem ,
LayerManager * aManager )
2012-08-28 22:47:15 -07:00
{
2012-10-11 16:38:24 -07:00
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aItem - > GetUnderlyingFrame ( ) - > Properties ( ) . Get ( LayerManagerDataProperty ( ) ) ) ;
if ( array ) {
for ( uint32_t i = 0 ; i < array - > Length ( ) ; i + + ) {
DisplayItemData * item = array - > ElementAt ( i ) ;
if ( item - > mDisplayItemKey = = aItem - > GetPerFrameKey ( ) & &
2012-10-15 18:23:07 -07:00
item - > mLayer - > Manager ( ) = = aManager ) {
2012-10-11 16:38:24 -07:00
return item ;
}
2012-08-28 22:47:15 -07:00
}
}
return nullptr ;
}
2012-08-28 22:48:45 -07:00
bool
2012-12-13 14:51:00 -08:00
FrameLayerBuilder : : HasRetainedDataFor ( nsIFrame * aFrame , uint32_t aDisplayItemKey )
2012-08-28 22:48:45 -07:00
{
2012-10-11 16:38:24 -07:00
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aFrame - > Properties ( ) . Get ( LayerManagerDataProperty ( ) ) ) ;
if ( array ) {
for ( uint32_t i = 0 ; i < array - > Length ( ) ; i + + ) {
2012-12-13 14:51:00 -08:00
if ( array - > ElementAt ( i ) - > mDisplayItemKey = = aDisplayItemKey ) {
2012-10-11 16:38:24 -07:00
return true ;
}
}
2012-08-28 22:48:45 -07:00
}
return false ;
}
2012-11-06 14:04:53 -08:00
void
2012-12-13 14:50:57 -08:00
FrameLayerBuilder : : IterateRetainedDataFor ( nsIFrame * aFrame , DisplayItemDataCallback aCallback )
2012-11-06 14:04:53 -08:00
{
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aFrame - > Properties ( ) . Get ( LayerManagerDataProperty ( ) ) ) ;
if ( ! array ) {
return ;
}
for ( uint32_t i = 0 ; i < array - > Length ( ) ; i + + ) {
2012-11-19 02:54:50 -08:00
DisplayItemData * data = array - > ElementAt ( i ) ;
2012-12-13 14:50:57 -08:00
if ( data - > mDisplayItemKey ! = nsDisplayItem : : TYPE_ZERO ) {
2012-11-19 02:54:50 -08:00
aCallback ( aFrame , data ) ;
}
2012-11-06 14:04:53 -08:00
}
}
2012-08-28 22:47:15 -07:00
FrameLayerBuilder : : DisplayItemData *
2012-08-29 03:53:27 -07:00
FrameLayerBuilder : : GetOldLayerForFrame ( nsIFrame * aFrame , uint32_t aDisplayItemKey )
2010-07-15 14:07:51 -07:00
{
// If we need to build a new layer tree, then just refuse to recycle
// anything.
if ( ! mRetainingManager | | mInvalidateAllLayers )
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-07-15 14:07:51 -07:00
2012-10-11 16:38:24 -07:00
DisplayItemData * data = GetDisplayItemData ( aFrame , aDisplayItemKey ) ;
2010-07-15 14:07:51 -07:00
2012-10-11 16:38:24 -07:00
if ( data & & data - > mLayer - > Manager ( ) = = mRetainingManager ) {
return data ;
2010-05-20 20:20:48 -07:00
}
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-05-20 20:20:48 -07:00
}
2012-08-29 03:53:27 -07:00
Layer *
2012-10-15 18:23:07 -07:00
FrameLayerBuilder : : GetOldLayerFor ( nsDisplayItem * aItem ,
nsDisplayItemGeometry * * aOldGeometry ,
Clip * * aOldClip ,
2012-11-06 14:04:53 -08:00
nsTArray < nsIFrame * > * aChangedFrames ,
bool * aIsInvalid )
2012-08-29 03:53:27 -07:00
{
uint32_t key = aItem - > GetPerFrameKey ( ) ;
nsIFrame * frame = aItem - > GetUnderlyingFrame ( ) ;
if ( frame ) {
2012-08-28 22:47:15 -07:00
DisplayItemData * oldData = GetOldLayerForFrame ( frame , key ) ;
2012-10-15 18:23:07 -07:00
if ( oldData ) {
2012-08-28 22:47:15 -07:00
if ( aOldGeometry ) {
* aOldGeometry = oldData - > mGeometry . get ( ) ;
}
2012-08-28 22:48:43 -07:00
if ( aOldClip ) {
* aOldClip = & oldData - > mClip ;
}
2012-10-15 18:23:07 -07:00
if ( aChangedFrames ) {
oldData - > GetFrameListChanges ( aItem , * aChangedFrames ) ;
}
2012-11-06 14:04:53 -08:00
if ( aIsInvalid ) {
* aIsInvalid = oldData - > mIsInvalid ;
}
2012-08-28 22:47:15 -07:00
return oldData - > mLayer ;
2012-08-29 03:53:27 -07:00
}
}
return nullptr ;
2012-08-28 22:47:15 -07:00
}
2012-08-29 03:53:27 -07:00
2012-07-17 10:03:51 -07:00
/* static */ Layer *
2012-08-22 08:56:38 -07:00
FrameLayerBuilder : : GetDebugOldLayerFor ( nsIFrame * aFrame , uint32_t aDisplayItemKey )
2012-07-17 10:03:51 -07:00
{
2012-10-11 16:38:24 -07:00
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aFrame - > Properties ( ) . Get ( LayerManagerDataProperty ( ) ) ) ;
2012-07-17 10:03:51 -07:00
2012-10-11 16:38:24 -07:00
if ( ! array ) {
2012-07-30 07:20:58 -07:00
return nullptr ;
2012-07-17 10:03:51 -07:00
}
2012-10-11 16:38:24 -07:00
for ( uint32_t i = 0 ; i < array - > Length ( ) ; i + + ) {
DisplayItemData * data = array - > ElementAt ( i ) ;
2012-08-28 22:47:15 -07:00
2012-10-11 16:38:24 -07:00
if ( data - > mDisplayItemKey = = aDisplayItemKey ) {
return data - > mLayer ;
2012-08-28 22:47:15 -07:00
}
}
2012-10-11 16:38:24 -07:00
return nullptr ;
2010-07-15 14:07:51 -07:00
}
2010-07-15 14:08:03 -07:00
already_AddRefed < ColorLayer >
2012-08-20 03:00:49 -07:00
ContainerState : : CreateOrRecycleColorLayer ( ThebesLayer * aThebes )
2010-07-15 14:08:03 -07:00
{
2012-08-20 03:00:49 -07:00
ThebesDisplayItemLayerUserData * data =
static_cast < ThebesDisplayItemLayerUserData * > ( aThebes - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
nsRefPtr < ColorLayer > layer = data - > mColorLayer ;
if ( layer ) {
2012-07-30 07:20:58 -07:00
layer - > SetClipRect ( nullptr ) ;
layer - > SetMaskLayer ( nullptr ) ;
2010-07-15 14:08:03 -07:00
} else {
// Create a new layer
layer = mManager - > CreateColorLayer ( ) ;
if ( ! layer )
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-07-15 14:08:03 -07:00
// Mark this layer as being used for Thebes-painting display items
2012-08-20 03:00:49 -07:00
data - > mColorLayer = layer ;
2012-07-30 07:20:58 -07:00
layer - > SetUserData ( & gColorLayerUserData , nullptr ) ;
2012-08-20 03:00:49 -07:00
// Remove other layer types we might have stored for this ThebesLayer
data - > mImageLayer = nullptr ;
2010-07-15 14:08:03 -07:00
}
return layer . forget ( ) ;
}
2011-01-17 13:47:18 -08:00
already_AddRefed < ImageLayer >
2012-08-20 03:00:49 -07:00
ContainerState : : CreateOrRecycleImageLayer ( ThebesLayer * aThebes )
2011-01-17 13:47:18 -08:00
{
2012-08-20 03:00:49 -07:00
ThebesDisplayItemLayerUserData * data =
static_cast < ThebesDisplayItemLayerUserData * > ( aThebes - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
nsRefPtr < ImageLayer > layer = data - > mImageLayer ;
if ( layer ) {
2012-07-30 07:20:58 -07:00
layer - > SetClipRect ( nullptr ) ;
layer - > SetMaskLayer ( nullptr ) ;
2011-01-17 13:47:18 -08:00
} else {
// Create a new layer
layer = mManager - > CreateImageLayer ( ) ;
if ( ! layer )
2012-07-30 07:20:58 -07:00
return nullptr ;
2011-01-17 13:47:18 -08:00
// Mark this layer as being used for Thebes-painting display items
2012-08-20 03:00:49 -07:00
data - > mImageLayer = layer ;
2012-07-30 07:20:58 -07:00
layer - > SetUserData ( & gImageLayerUserData , nullptr ) ;
2012-08-20 03:00:49 -07:00
// Remove other layer types we might have stored for this ThebesLayer
data - > mColorLayer = nullptr ;
2011-01-17 13:47:18 -08:00
}
return layer . forget ( ) ;
}
2012-02-07 14:26:40 -08:00
already_AddRefed < ImageLayer >
ContainerState : : CreateOrRecycleMaskImageLayerFor ( Layer * aLayer )
{
nsRefPtr < ImageLayer > result = mRecycledMaskImageLayers . Get ( aLayer ) ;
if ( result ) {
mRecycledMaskImageLayers . Remove ( aLayer ) ;
2012-06-25 19:43:30 -07:00
// XXX if we use clip on mask layers, null it out here
2012-02-07 14:26:40 -08:00
} else {
// Create a new layer
result = mManager - > CreateImageLayer ( ) ;
if ( ! result )
2012-07-30 07:20:58 -07:00
return nullptr ;
2012-02-07 14:26:40 -08:00
result - > SetUserData ( & gMaskLayerUserData , new MaskLayerUserData ( ) ) ;
2012-05-22 16:14:03 -07:00
result - > SetForceSingleTile ( true ) ;
2012-02-07 14:26:40 -08:00
}
2012-07-30 11:36:12 -07:00
2012-02-07 14:26:40 -08:00
return result . forget ( ) ;
}
2012-05-09 22:24:20 -07:00
static const double SUBPIXEL_OFFSET_EPSILON = 0.02 ;
/**
* This normally computes NSToIntRoundUp ( aValue ) . However , if that would
* give a residual near 0.5 while aOldResidual is near - 0.5 , or
* it would give a residual near - 0.5 while aOldResidual is near 0.5 , then
* instead we return the integer in the other direction so that the residual
* is close to aOldResidual .
*/
2012-08-22 08:56:38 -07:00
static int32_t
2012-05-09 22:24:20 -07:00
RoundToMatchResidual ( double aValue , double aOldResidual )
{
2012-08-22 08:56:38 -07:00
int32_t v = NSToIntRoundUp ( aValue ) ;
2012-05-09 22:24:20 -07:00
double residual = aValue - v ;
if ( aOldResidual < 0 ) {
if ( residual > 0 & & fabs ( residual - 1.0 - aOldResidual ) < SUBPIXEL_OFFSET_EPSILON ) {
// Round up instead
2012-08-22 08:56:38 -07:00
return int32_t ( ceil ( aValue ) ) ;
2012-05-09 22:24:20 -07:00
}
} else if ( aOldResidual > 0 ) {
if ( residual < 0 & & fabs ( residual + 1.0 - aOldResidual ) < SUBPIXEL_OFFSET_EPSILON ) {
// Round down instead
2012-08-22 08:56:38 -07:00
return int32_t ( floor ( aValue ) ) ;
2012-05-09 22:24:20 -07:00
}
}
return v ;
2012-05-09 22:24:18 -07:00
}
2012-08-16 16:40:10 -07:00
static void
ResetScrollPositionForLayerPixelAlignment ( const nsIFrame * aActiveScrolledRoot )
{
nsIScrollableFrame * sf = nsLayoutUtils : : GetScrollableFrameFor ( aActiveScrolledRoot ) ;
if ( sf ) {
sf - > ResetScrollPositionForLayerPixelAlignment ( ) ;
}
}
static void
InvalidateEntireThebesLayer ( ThebesLayer * aLayer , const nsIFrame * aActiveScrolledRoot )
{
2012-08-28 22:47:15 -07:00
# ifdef DEBUG_INVALIDATIONS
2012-08-28 22:47:18 -07:00
printf ( " Invalidating entire layer %p \n " , aLayer ) ;
2012-08-28 22:47:15 -07:00
# endif
2012-08-16 16:40:10 -07:00
nsIntRect invalidate = aLayer - > GetValidRegion ( ) . GetBounds ( ) ;
aLayer - > InvalidateRegion ( invalidate ) ;
ResetScrollPositionForLayerPixelAlignment ( aActiveScrolledRoot ) ;
}
2010-07-15 14:07:51 -07:00
already_AddRefed < ThebesLayer >
2012-09-28 04:19:39 -07:00
ContainerState : : CreateOrRecycleThebesLayer ( const nsIFrame * aActiveScrolledRoot ,
const nsIFrame * aReferenceFrame ,
const nsPoint & aTopLeft )
2010-07-15 14:07:51 -07:00
{
// We need a new thebes layer
nsRefPtr < ThebesLayer > layer ;
2011-06-22 05:11:27 -07:00
ThebesDisplayItemLayerUserData * data ;
2012-11-30 08:06:37 -08:00
# ifndef MOZ_ANDROID_OMTC
2012-08-16 16:40:10 -07:00
bool didResetScrollPositionForLayerPixelAlignment = false ;
2012-11-30 08:06:37 -08:00
# endif
2010-07-15 14:08:03 -07:00
if ( mNextFreeRecycledThebesLayer < mRecycledThebesLayers . Length ( ) ) {
2010-07-15 14:07:51 -07:00
// Recycle a layer
layer = mRecycledThebesLayers [ mNextFreeRecycledThebesLayer ] ;
+ + mNextFreeRecycledThebesLayer ;
2012-02-07 14:26:40 -08:00
// Clear clip rect and mask layer so we don't accidentally stay clipped.
// We will reapply any necessary clipping.
2012-07-30 07:20:58 -07:00
layer - > SetClipRect ( nullptr ) ;
layer - > SetMaskLayer ( nullptr ) ;
2010-07-15 14:07:51 -07:00
2011-06-22 05:11:27 -07:00
data = static_cast < ThebesDisplayItemLayerUserData * >
( layer - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
NS_ASSERTION ( data , " Recycled ThebesLayers must have user data " ) ;
2010-07-15 14:07:51 -07:00
// This gets called on recycled ThebesLayers that are going to be in the
// final layer tree, so it's a convenient time to invalidate the
// content that changed where we don't know what ThebesLayer it belonged
// to, or if we need to invalidate the entire layer, we can do that.
// This needs to be done before we update the ThebesLayer to its new
// transform. See nsGfxScrollFrame::InvalidateInternal, where
// we ensure that mInvalidThebesContent is updated according to the
// scroll position as of the most recent paint.
2012-10-01 21:00:09 -07:00
if ( ! FuzzyEqual ( data - > mXScale , mParameters . mXScale , 0.00001 ) | |
2012-10-15 18:10:51 -07:00
! FuzzyEqual ( data - > mYScale , mParameters . mYScale , 0.00001 ) | |
data - > mAppUnitsPerDevPixel ! = mAppUnitsPerDevPixel ) {
2012-08-16 16:40:10 -07:00
InvalidateEntireThebesLayer ( layer , aActiveScrolledRoot ) ;
2012-11-30 08:06:37 -08:00
# ifndef MOZ_ANDROID_OMTC
2012-08-16 16:40:10 -07:00
didResetScrollPositionForLayerPixelAlignment = true ;
2012-11-30 08:06:37 -08:00
# endif
2010-07-15 14:07:51 -07:00
}
2012-08-28 22:47:15 -07:00
if ( ! data - > mRegionToInvalidate . IsEmpty ( ) ) {
# ifdef DEBUG_INVALIDATIONS
printf ( " Invalidating deleted frame content from layer %p \n " , layer . get ( ) ) ;
# endif
layer - > InvalidateRegion ( data - > mRegionToInvalidate ) ;
# ifdef DEBUG_INVALIDATIONS
nsAutoCString str ;
AppendToString ( str , data - > mRegionToInvalidate ) ;
printf ( " Invalidating layer %p: %s \n " , layer . get ( ) , str . get ( ) ) ;
# endif
data - > mRegionToInvalidate . SetEmpty ( ) ;
}
2010-07-15 14:07:51 -07:00
// We do not need to Invalidate these areas in the widget because we
2011-02-10 15:21:07 -08:00
// assume the caller of InvalidateThebesLayerContents has ensured
2010-07-15 14:07:51 -07:00
// the area is invalidated in the widget.
} else {
// Create a new thebes layer
layer = mManager - > CreateThebesLayer ( ) ;
if ( ! layer )
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-07-15 14:07:51 -07:00
// Mark this layer as being used for Thebes-painting display items
2011-06-22 05:11:27 -07:00
data = new ThebesDisplayItemLayerUserData ( ) ;
layer - > SetUserData ( & gThebesDisplayItemLayerUserData , data ) ;
2012-08-16 16:40:10 -07:00
ResetScrollPositionForLayerPixelAlignment ( aActiveScrolledRoot ) ;
2012-11-30 08:06:37 -08:00
# ifndef MOZ_ANDROID_OMTC
2012-08-16 16:40:10 -07:00
didResetScrollPositionForLayerPixelAlignment = true ;
2012-11-30 08:06:37 -08:00
# endif
2010-07-15 14:07:51 -07:00
}
2011-06-22 05:11:27 -07:00
data - > mXScale = mParameters . mXScale ;
data - > mYScale = mParameters . mYScale ;
2012-08-28 22:47:15 -07:00
data - > mLastActiveScrolledRootOrigin = data - > mActiveScrolledRootOrigin ;
2012-09-28 04:19:39 -07:00
data - > mActiveScrolledRootOrigin = aTopLeft ;
2012-08-28 22:47:15 -07:00
data - > mAppUnitsPerDevPixel = mAppUnitsPerDevPixel ;
2012-04-10 04:24:18 -07:00
layer - > SetAllowResidualTranslation ( mParameters . AllowResidualTranslation ( ) ) ;
2010-07-15 14:07:51 -07:00
2012-07-17 10:03:51 -07:00
mLayerBuilder - > SaveLastPaintOffset ( layer ) ;
2011-05-16 16:05:56 -07:00
2010-07-15 14:07:51 -07:00
// Set up transform so that 0,0 in the Thebes layer corresponds to the
// (pixel-snapped) top-left of the aActiveScrolledRoot.
2012-09-16 03:32:59 -07:00
nsPoint offset = aActiveScrolledRoot - > GetOffsetToCrossDoc ( aReferenceFrame ) ;
2011-06-22 05:11:28 -07:00
nscoord appUnitsPerDevPixel = aActiveScrolledRoot - > PresContext ( ) - > AppUnitsPerDevPixel ( ) ;
gfxPoint scaledOffset (
NSAppUnitsToDoublePixels ( offset . x , appUnitsPerDevPixel ) * mParameters . mXScale ,
NSAppUnitsToDoublePixels ( offset . y , appUnitsPerDevPixel ) * mParameters . mYScale ) ;
2012-05-09 22:24:20 -07:00
// We call RoundToMatchResidual here so that the residual after rounding
// is close to data->mActiveScrolledRootPosition if possible.
nsIntPoint pixOffset ( RoundToMatchResidual ( scaledOffset . x , data - > mActiveScrolledRootPosition . x ) ,
RoundToMatchResidual ( scaledOffset . y , data - > mActiveScrolledRootPosition . y ) ) ;
2012-09-16 15:25:33 -07:00
data - > mTranslation = pixOffset ;
pixOffset + = mParameters . mOffset ;
2010-07-15 14:07:51 -07:00
gfxMatrix matrix ;
matrix . Translate ( gfxPoint ( pixOffset . x , pixOffset . y ) ) ;
2012-07-30 19:20:00 -07:00
layer - > SetBaseTransform ( gfx3DMatrix : : From2D ( matrix ) ) ;
2010-07-15 14:07:51 -07:00
2012-03-13 09:57:31 -07:00
// FIXME: Temporary workaround for bug 681192 and bug 724786.
2012-10-01 13:01:35 -07:00
# ifndef MOZ_ANDROID_OMTC
2011-06-22 05:11:28 -07:00
// Calculate exact position of the top-left of the active scrolled root.
// This might not be 0,0 due to the snapping in ScaleToNearestPixels.
2012-11-21 21:33:37 -08:00
gfxPoint activeScrolledRootTopLeft = scaledOffset - matrix . GetTranslation ( ) + mParameters . mOffset ;
2011-06-22 05:11:28 -07:00
// If it has changed, then we need to invalidate the entire layer since the
// pixels in the layer buffer have the content at a (subpixel) offset
// from what we need.
2012-08-16 16:40:10 -07:00
if ( ! activeScrolledRootTopLeft . WithinEpsilonOf ( data - > mActiveScrolledRootPosition , SUBPIXEL_OFFSET_EPSILON ) ) {
data - > mActiveScrolledRootPosition = activeScrolledRootTopLeft ;
InvalidateEntireThebesLayer ( layer , aActiveScrolledRoot ) ;
} else if ( didResetScrollPositionForLayerPixelAlignment ) {
2011-06-22 05:11:28 -07:00
data - > mActiveScrolledRootPosition = activeScrolledRootTopLeft ;
}
2012-02-07 22:21:38 -08:00
# endif
2011-06-22 05:11:28 -07:00
2010-07-15 14:07:51 -07:00
return layer . forget ( ) ;
}
2012-10-15 11:56:11 -07:00
# ifdef MOZ_DUMP_PAINTING
2010-07-15 14:07:51 -07:00
/**
* Returns the appunits per dev pixel for the item ' s frame . The item must
* have a frame because only nsDisplayClip items don ' t have a frame ,
* and those items are flattened away by ProcessDisplayItems .
*/
2012-08-22 08:56:38 -07:00
static int32_t
2010-07-15 14:07:51 -07:00
AppUnitsPerDevPixel ( nsDisplayItem * aItem )
{
2010-08-08 11:49:06 -07:00
// The underlying frame for zoom items is the root frame of the subdocument.
// But zoom display items report their bounds etc using the parent document's
// APD because zoom items act as a conversion layer between the two different
// APDs.
if ( aItem - > GetType ( ) = = nsDisplayItem : : TYPE_ZOOM ) {
return static_cast < nsDisplayZoom * > ( aItem ) - > GetParentAppUnitsPerDevPixel ( ) ;
}
2010-07-15 14:07:51 -07:00
return aItem - > GetUnderlyingFrame ( ) - > PresContext ( ) - > AppUnitsPerDevPixel ( ) ;
}
2012-10-09 22:00:05 -07:00
# endif
2010-07-15 14:07:51 -07:00
/**
2011-02-22 21:38:09 -08:00
* Restrict the visible region of aLayer to the region that is actually visible .
* Because we only reduce the visible region here , we don ' t need to worry
* about whether CONTENT_OPAQUE is set ; if layer was opauqe in the old
* visible region , it will still be opaque in the new one .
* @ param aItemVisible the visible region of the display item ( that is ,
* after any layer transform has been applied )
2010-07-15 14:07:51 -07:00
*/
static void
2011-02-22 21:38:09 -08:00
RestrictVisibleRegionForLayer ( Layer * aLayer , const nsIntRect & aItemVisible )
2010-07-15 14:07:51 -07:00
{
2011-08-02 20:04:21 -07:00
gfx3DMatrix transform = aLayer - > GetTransform ( ) ;
2011-02-22 21:38:09 -08:00
// if 'transform' is not invertible, then nothing will be displayed
// for the layer, so it doesn't really matter what we do here
gfxRect itemVisible ( aItemVisible . x , aItemVisible . y , aItemVisible . width , aItemVisible . height ) ;
2011-08-02 20:04:21 -07:00
gfxRect layerVisible = transform . Inverse ( ) . ProjectRectBounds ( itemVisible ) ;
2011-02-22 21:38:09 -08:00
layerVisible . RoundOut ( ) ;
nsIntRect visibleRect ;
if ( ! gfxUtils : : GfxRectToIntRect ( layerVisible , & visibleRect ) )
return ;
nsIntRegion rgn = aLayer - > GetVisibleRegion ( ) ;
if ( ! visibleRect . Contains ( rgn . GetBounds ( ) ) ) {
rgn . And ( rgn , visibleRect ) ;
aLayer - > SetVisibleRegion ( rgn ) ;
2010-07-15 14:07:51 -07:00
}
}
2010-09-02 02:18:39 -07:00
nscolor
2012-08-22 08:56:38 -07:00
ContainerState : : FindOpaqueBackgroundColorFor ( int32_t aThebesLayerIndex )
2010-09-02 02:18:39 -07:00
{
ThebesLayerData * target = mThebesLayerDataStack [ aThebesLayerIndex ] ;
2012-08-22 08:56:38 -07:00
for ( int32_t i = aThebesLayerIndex - 1 ; i > = 0 ; - - i ) {
2010-09-02 02:18:39 -07:00
ThebesLayerData * candidate = mThebesLayerDataStack [ i ] ;
nsIntRegion visibleAboveIntersection ;
visibleAboveIntersection . And ( candidate - > mVisibleAboveRegion , target - > mVisibleRegion ) ;
if ( ! visibleAboveIntersection . IsEmpty ( ) ) {
// Some non-Thebes content between target and candidate; this is
// hopeless
break ;
}
nsIntRegion intersection ;
intersection . And ( candidate - > mVisibleRegion , target - > mVisibleRegion ) ;
if ( intersection . IsEmpty ( ) ) {
// The layer doesn't intersect our target, ignore it and move on
continue ;
}
2011-06-22 05:11:27 -07:00
2010-09-02 02:18:39 -07:00
// The candidate intersects our target. If any layer has a solid-color
// area behind our target, this must be it. Scan its display items.
2012-12-04 18:53:17 -08:00
nsIntRect deviceRect = target - > mVisibleRegion . GetBounds ( ) ;
nsRect appUnitRect = deviceRect . ToAppUnits ( mAppUnitsPerDevPixel ) ;
appUnitRect . ScaleInverseRoundOut ( mParameters . mXScale , mParameters . mYScale ) ;
FrameLayerBuilder : : ThebesLayerItemsEntry * entry =
mLayerBuilder - > GetThebesLayerItemsEntry ( candidate - > mLayer ) ;
NS_ASSERTION ( entry , " Must know about this layer! " ) ;
for ( int32_t j = entry - > mItems . Length ( ) - 1 ; j > = 0 ; - - j ) {
nsDisplayItem * item = entry - > mItems [ j ] . mItem ;
bool snap ;
nsRect bounds = item - > GetBounds ( mBuilder , & snap ) ;
if ( snap & & mSnappingEnabled ) {
nsIntRect snappedBounds = ScaleToNearestPixels ( bounds ) ;
if ( ! snappedBounds . Intersects ( deviceRect ) )
continue ;
if ( ! snappedBounds . Contains ( deviceRect ) )
break ;
} else {
// The layer's visible rect is already (close enough to) pixel
// aligned, so no need to round out and in here.
if ( ! bounds . Intersects ( appUnitRect ) )
continue ;
if ( ! bounds . Contains ( appUnitRect ) )
break ;
}
nscolor color ;
if ( item - > IsUniform ( mBuilder , & color ) & & NS_GET_A ( color ) = = 255 )
return color ;
break ;
}
break ;
2010-09-02 02:18:39 -07:00
}
return NS_RGBA ( 0 , 0 , 0 , 0 ) ;
}
2012-02-07 14:27:44 -08:00
void
ContainerState : : ThebesLayerData : : UpdateCommonClipCount (
const FrameLayerBuilder : : Clip & aCurrentClip )
{
if ( mCommonClipCount > = 0 ) {
2013-01-15 04:22:03 -08:00
int32_t end = std : : min < int32_t > ( aCurrentClip . mRoundedClipRects . Length ( ) ,
2012-02-07 14:27:44 -08:00
mCommonClipCount ) ;
2012-08-22 08:56:38 -07:00
int32_t clipCount = 0 ;
2012-02-07 14:27:44 -08:00
for ( ; clipCount < end ; + + clipCount ) {
if ( mItemClip . mRoundedClipRects [ clipCount ] ! =
aCurrentClip . mRoundedClipRects [ clipCount ] ) {
break ;
}
}
mCommonClipCount = clipCount ;
2012-08-22 08:56:38 -07:00
NS_ASSERTION ( mItemClip . mRoundedClipRects . Length ( ) > = uint32_t ( mCommonClipCount ) ,
2012-02-07 14:27:44 -08:00
" Inconsistent common clip count. " ) ;
} else {
// first item in the layer
mCommonClipCount = aCurrentClip . mRoundedClipRects . Length ( ) ;
2012-07-31 10:28:21 -07:00
}
2012-02-07 14:27:44 -08:00
}
2012-01-29 21:16:54 -08:00
already_AddRefed < ImageContainer >
2012-11-18 19:28:18 -08:00
ContainerState : : ThebesLayerData : : CanOptimizeImageLayer ( nsDisplayListBuilder * aBuilder )
2011-01-17 13:47:18 -08:00
{
2012-02-07 14:27:44 -08:00
if ( ! mImage ) {
2012-07-30 07:20:58 -07:00
return nullptr ;
2011-01-17 13:47:18 -08:00
}
2012-11-27 18:34:45 -08:00
return mImage - > GetContainer ( mLayer - > Manager ( ) , aBuilder ) ;
2011-01-17 13:47:18 -08:00
}
2010-07-15 14:07:51 -07:00
void
ContainerState : : PopThebesLayerData ( )
{
NS_ASSERTION ( ! mThebesLayerDataStack . IsEmpty ( ) , " Can't pop " ) ;
2012-08-22 08:56:38 -07:00
int32_t lastIndex = mThebesLayerDataStack . Length ( ) - 1 ;
2010-07-15 14:07:51 -07:00
ThebesLayerData * data = mThebesLayerDataStack [ lastIndex ] ;
2011-01-17 13:47:18 -08:00
nsRefPtr < Layer > layer ;
2012-11-18 19:28:18 -08:00
nsRefPtr < ImageContainer > imageContainer = data - > CanOptimizeImageLayer ( mBuilder ) ;
2011-01-17 13:47:18 -08:00
2012-02-15 20:17:20 -08:00
if ( ( data - > mIsSolidColorInVisibleRegion | | imageContainer ) & &
data - > mLayer - > GetValidRegion ( ) . IsEmpty ( ) ) {
2011-01-17 13:47:18 -08:00
NS_ASSERTION ( ! ( data - > mIsSolidColorInVisibleRegion & & imageContainer ) ,
" Can't be a solid color as well as an image! " ) ;
if ( imageContainer ) {
2012-08-20 03:00:49 -07:00
nsRefPtr < ImageLayer > imageLayer = CreateOrRecycleImageLayer ( data - > mLayer ) ;
2011-01-17 13:47:18 -08:00
imageLayer - > SetContainer ( imageContainer ) ;
2012-09-16 15:25:33 -07:00
data - > mImage - > ConfigureLayer ( imageLayer , mParameters . mOffset ) ;
2012-08-03 14:29:22 -07:00
imageLayer - > SetPostScale ( mParameters . mXScale ,
mParameters . mYScale ) ;
2012-02-07 14:27:44 -08:00
if ( data - > mItemClip . mHaveClipRect ) {
nsIntRect clip = ScaleToNearestPixels ( data - > mItemClip . mClipRect ) ;
2012-09-23 19:56:39 -07:00
clip . MoveBy ( mParameters . mOffset ) ;
2011-06-22 05:11:27 -07:00
imageLayer - > IntersectClipRect ( clip ) ;
2011-03-31 14:33:46 -07:00
}
2011-01-17 13:47:18 -08:00
layer = imageLayer ;
2012-10-11 19:39:46 -07:00
mLayerBuilder - > StoreOptimizedLayerForFrame ( data - > mImage ,
2012-09-24 13:31:30 -07:00
imageLayer ) ;
2011-01-17 13:47:18 -08:00
} else {
2012-08-20 03:00:49 -07:00
nsRefPtr < ColorLayer > colorLayer = CreateOrRecycleColorLayer ( data - > mLayer ) ;
2011-04-05 22:00:25 -07:00
colorLayer - > SetIsFixedPosition ( data - > mLayer - > GetIsFixedPosition ( ) ) ;
2011-01-17 13:47:18 -08:00
colorLayer - > SetColor ( data - > mSolidColor ) ;
2012-07-30 11:36:12 -07:00
// Copy transform
2012-07-30 19:20:00 -07:00
colorLayer - > SetBaseTransform ( data - > mLayer - > GetBaseTransform ( ) ) ;
2012-08-03 14:29:22 -07:00
colorLayer - > SetPostScale ( data - > mLayer - > GetPostXScale ( ) , data - > mLayer - > GetPostYScale ( ) ) ;
2011-01-17 13:47:18 -08:00
// Clip colorLayer to its visible region, since ColorLayers are
// allowed to paint outside the visible region. Here we rely on the
// fact that uniform display items fill rectangles; obviously the
// area to fill must contain the visible region, and because it's
// a rectangle, it must therefore contain the visible region's GetBounds.
// Note that the visible region is already clipped appropriately.
nsIntRect visibleRect = data - > mVisibleRegion . GetBounds ( ) ;
2012-09-16 15:25:33 -07:00
visibleRect . MoveBy ( mParameters . mOffset ) ;
2011-01-17 13:47:18 -08:00
colorLayer - > SetClipRect ( & visibleRect ) ;
layer = colorLayer ;
}
2010-07-15 14:08:03 -07:00
2011-01-17 13:47:18 -08:00
NS_ASSERTION ( ! mNewChildLayers . Contains ( layer ) , " Layer already in list??? " ) ;
2010-11-08 18:48:59 -08:00
AutoLayersArray : : index_type index = mNewChildLayers . IndexOf ( data - > mLayer ) ;
NS_ASSERTION ( index ! = AutoLayersArray : : NoIndex , " Thebes layer not found? " ) ;
2011-01-17 13:47:18 -08:00
mNewChildLayers . InsertElementAt ( index + 1 , layer ) ;
2010-07-15 14:08:03 -07:00
// Hide the ThebesLayer. We leave it in the layer tree so that we
// can find and recycle it later.
data - > mLayer - > IntersectClipRect ( nsIntRect ( ) ) ;
data - > mLayer - > SetVisibleRegion ( nsIntRegion ( ) ) ;
} else {
layer = data - > mLayer ;
2012-07-30 07:20:58 -07:00
imageContainer = nullptr ;
2010-07-15 14:08:03 -07:00
}
2010-07-15 14:07:51 -07:00
gfxMatrix transform ;
2011-01-17 13:47:18 -08:00
if ( ! layer - > GetTransform ( ) . Is2D ( & transform ) ) {
NS_ERROR ( " Only 2D transformations currently supported " ) ;
}
2012-07-31 10:28:21 -07:00
2012-03-19 00:26:39 -07:00
// ImageLayers are already configured with a visible region
2011-01-17 13:47:18 -08:00
if ( ! imageContainer ) {
2010-07-15 14:07:51 -07:00
NS_ASSERTION ( ! transform . HasNonIntegerTranslation ( ) ,
" Matrix not just an integer translation? " ) ;
// Convert from relative to the container to relative to the
// ThebesLayer itself.
nsIntRegion rgn = data - > mVisibleRegion ;
2012-09-16 15:25:33 -07:00
rgn . MoveBy ( - GetTranslationForThebesLayer ( data - > mLayer ) ) ;
2010-07-15 14:08:03 -07:00
layer - > SetVisibleRegion ( rgn ) ;
2010-07-15 14:07:51 -07:00
}
nsIntRegion transparentRegion ;
transparentRegion . Sub ( data - > mVisibleRegion , data - > mOpaqueRegion ) ;
2011-09-28 23:19:26 -07:00
bool isOpaque = transparentRegion . IsEmpty ( ) ;
2010-09-02 02:18:39 -07:00
// For translucent ThebesLayers, try to find an opaque background
// color that covers the entire area beneath it so we can pull that
// color into this layer to make it opaque.
if ( layer = = data - > mLayer ) {
nscolor backgroundColor = NS_RGBA ( 0 , 0 , 0 , 0 ) ;
if ( ! isOpaque ) {
backgroundColor = FindOpaqueBackgroundColorFor ( lastIndex ) ;
if ( NS_GET_A ( backgroundColor ) = = 255 ) {
2011-10-17 07:59:28 -07:00
isOpaque = true ;
2010-09-02 02:18:39 -07:00
}
}
// Store the background color
ThebesDisplayItemLayerUserData * userData =
2012-02-07 14:27:44 -08:00
GetThebesDisplayItemLayerUserData ( data - > mLayer ) ;
2010-09-02 02:18:39 -07:00
NS_ASSERTION ( userData , " where did our user data go? " ) ;
if ( userData - > mForcedBackgroundColor ! = backgroundColor ) {
// Invalidate the entire target ThebesLayer since we're changing
// the background color
data - > mLayer - > InvalidateRegion ( data - > mLayer - > GetValidRegion ( ) ) ;
}
userData - > mForcedBackgroundColor = backgroundColor ;
2012-02-07 14:27:44 -08:00
// use a mask layer for rounded rect clipping
2012-08-22 08:56:38 -07:00
int32_t commonClipCount = data - > mCommonClipCount ;
2012-02-07 14:27:44 -08:00
NS_ASSERTION ( commonClipCount > = 0 , " Inconsistent clip count. " ) ;
SetupMaskLayer ( layer , data - > mItemClip , commonClipCount ) ;
// copy commonClipCount to the entry
2012-07-17 10:03:51 -07:00
FrameLayerBuilder : : ThebesLayerItemsEntry * entry = mLayerBuilder - >
2012-02-07 14:27:44 -08:00
GetThebesLayerItemsEntry ( static_cast < ThebesLayer * > ( layer . get ( ) ) ) ;
entry - > mCommonClipCount = commonClipCount ;
} else {
// mask layer for image and color layers
SetupMaskLayer ( layer , data - > mItemClip ) ;
2010-09-02 02:18:39 -07:00
}
2012-08-22 08:56:38 -07:00
uint32_t flags ;
2010-12-19 17:26:14 -08:00
if ( isOpaque & & ! data - > mForceTransparentSurface ) {
flags = Layer : : CONTENT_OPAQUE ;
} else if ( data - > mNeedComponentAlpha ) {
flags = Layer : : CONTENT_COMPONENT_ALPHA ;
} else {
flags = 0 ;
}
2010-09-02 02:18:40 -07:00
layer - > SetContentFlags ( flags ) ;
2010-09-02 02:18:39 -07:00
if ( lastIndex > 0 ) {
// Since we're going to pop off the last ThebesLayerData, the
// mVisibleAboveRegion of the second-to-last item will need to include
// the regions of the last item.
ThebesLayerData * nextData = mThebesLayerDataStack [ lastIndex - 1 ] ;
nextData - > mVisibleAboveRegion . Or ( nextData - > mVisibleAboveRegion ,
data - > mVisibleAboveRegion ) ;
nextData - > mVisibleAboveRegion . Or ( nextData - > mVisibleAboveRegion ,
data - > mVisibleRegion ) ;
2012-01-11 03:26:33 -08:00
nextData - > mVisibleAboveRegion . SimplifyOutward ( 4 ) ;
2010-09-02 02:18:39 -07:00
nextData - > mDrawAboveRegion . Or ( nextData - > mDrawAboveRegion ,
data - > mDrawAboveRegion ) ;
nextData - > mDrawAboveRegion . Or ( nextData - > mDrawAboveRegion ,
data - > mDrawRegion ) ;
2012-01-11 03:26:33 -08:00
nextData - > mDrawAboveRegion . SimplifyOutward ( 4 ) ;
2010-09-02 02:18:39 -07:00
}
2010-07-15 14:07:51 -07:00
mThebesLayerDataStack . RemoveElementAt ( lastIndex ) ;
}
2011-09-28 23:19:26 -07:00
static bool
2011-01-02 17:48:09 -08:00
SuppressComponentAlpha ( nsDisplayListBuilder * aBuilder ,
2011-01-02 17:48:09 -08:00
nsDisplayItem * aItem ,
const nsRect & aComponentAlphaBounds )
2011-01-02 17:48:09 -08:00
{
const nsRegion * windowTransparentRegion = aBuilder - > GetFinalTransparentRegion ( ) ;
if ( ! windowTransparentRegion | | windowTransparentRegion - > IsEmpty ( ) )
2011-10-17 07:59:28 -07:00
return false ;
2011-01-02 17:48:09 -08:00
// Suppress component alpha for items in the toplevel window that are over
// the window translucent area
nsIFrame * f = aItem - > GetUnderlyingFrame ( ) ;
2012-09-16 03:32:59 -07:00
nsIFrame * ref = aBuilder - > RootReferenceFrame ( ) ;
2011-01-02 17:48:09 -08:00
if ( f - > PresContext ( ) ! = ref - > PresContext ( ) )
2011-10-17 07:59:28 -07:00
return false ;
2011-01-02 17:48:09 -08:00
for ( nsIFrame * t = f ; t ; t = t - > GetParent ( ) ) {
if ( t - > IsTransformed ( ) )
2011-10-17 07:59:28 -07:00
return false ;
2011-01-02 17:48:09 -08:00
}
2011-01-02 17:48:09 -08:00
return windowTransparentRegion - > Intersects ( aComponentAlphaBounds ) ;
2011-01-02 17:48:09 -08:00
}
2011-09-28 23:19:26 -07:00
static bool
2011-01-02 17:48:09 -08:00
WindowHasTransparency ( nsDisplayListBuilder * aBuilder )
{
const nsRegion * windowTransparentRegion = aBuilder - > GetFinalTransparentRegion ( ) ;
return windowTransparentRegion & & ! windowTransparentRegion - > IsEmpty ( ) ;
}
2010-07-15 14:07:51 -07:00
void
2011-06-22 05:11:27 -07:00
ContainerState : : ThebesLayerData : : Accumulate ( ContainerState * aState ,
2010-09-02 02:18:39 -07:00
nsDisplayItem * aItem ,
const nsIntRect & aVisibleRect ,
2011-01-02 17:48:09 -08:00
const nsIntRect & aDrawRect ,
const FrameLayerBuilder : : Clip & aClip )
2010-07-15 14:07:51 -07:00
{
2012-05-02 21:29:05 -07:00
if ( aState - > mBuilder - > NeedToForceTransparentSurfaceForItem ( aItem ) ) {
mForceTransparentSurface = true ;
}
2012-05-02 21:29:05 -07:00
if ( aState - > mParameters . mDisableSubpixelAntialiasingInDescendants ) {
// Disable component alpha.
// Note that the transform (if any) on the ThebesLayer is always an integer translation so
// we don't have to factor that in here.
aItem - > DisableComponentAlpha ( ) ;
}
2012-05-02 21:29:05 -07:00
2011-10-25 20:24:58 -07:00
/* Mark as available for conversion to image layer if this is a nsDisplayImage and
* we are the first visible item in the ThebesLayerData object .
*/
2012-09-24 13:29:14 -07:00
if ( mVisibleRegion . IsEmpty ( ) & &
2012-11-18 19:28:18 -08:00
aItem - > SupportsOptimizingToImage ( ) ) {
2012-09-24 13:29:14 -07:00
mImage = static_cast < nsDisplayImageContainer * > ( aItem ) ;
2011-10-25 20:24:58 -07:00
} else {
2012-07-30 07:20:58 -07:00
mImage = nullptr ;
2011-10-25 20:24:58 -07:00
}
2012-02-07 14:27:44 -08:00
mItemClip = aClip ;
2011-10-25 20:24:58 -07:00
2012-05-02 21:29:05 -07:00
if ( ! mIsSolidColorInVisibleRegion & & mOpaqueRegion . Contains ( aDrawRect ) & &
mVisibleRegion . Contains ( aVisibleRect ) ) {
// A very common case! Most pages have a ThebesLayer with the page
// background (opaque) visible and most or all of the page content over the
// top of that background.
// The rest of this method won't do anything. mVisibleRegion, mOpaqueRegion
// and mDrawRegion don't need updating. mVisibleRegion contains aVisibleRect
// already, mOpaqueRegion contains aDrawRect and therefore whatever
// the opaque region of the item is. mDrawRegion must contain mOpaqueRegion
// and therefore aDrawRect.
NS_ASSERTION ( mDrawRegion . Contains ( aDrawRect ) , " Draw region not covered " ) ;
return ;
}
nscolor uniformColor ;
bool isUniform = aItem - > IsUniform ( aState - > mBuilder , & uniformColor ) ;
2011-01-16 02:38:45 -08:00
// Some display items have to exist (so they can set forceTransparentSurface
// below) but don't draw anything. They'll return true for isUniform but
// a color with opacity 0.
if ( ! isUniform | | NS_GET_A ( uniformColor ) > 0 ) {
2012-04-10 04:24:18 -07:00
// Make sure that the visible area is covered by uniform pixels. In
// particular this excludes cases where the edges of the item are not
// pixel-aligned (thus the item will not be truly uniform).
if ( isUniform ) {
bool snap ;
nsRect bounds = aItem - > GetBounds ( aState - > mBuilder , & snap ) ;
if ( ! aState - > ScaleToInsidePixels ( bounds , snap ) . Contains ( aVisibleRect ) ) {
isUniform = false ;
}
}
2012-04-26 17:24:53 -07:00
if ( isUniform & & aClip . mRoundedClipRects . IsEmpty ( ) ) {
2011-01-16 02:38:45 -08:00
if ( mVisibleRegion . IsEmpty ( ) ) {
// This color is all we have
mSolidColor = uniformColor ;
2011-10-17 07:59:28 -07:00
mIsSolidColorInVisibleRegion = true ;
2011-01-16 02:38:45 -08:00
} else if ( mIsSolidColorInVisibleRegion & &
mVisibleRegion . IsEqual ( nsIntRegion ( aVisibleRect ) ) ) {
// we can just blend the colors together
mSolidColor = NS_ComposeColors ( mSolidColor , uniformColor ) ;
} else {
2011-10-17 07:59:28 -07:00
mIsSolidColorInVisibleRegion = false ;
2011-01-16 02:38:45 -08:00
}
2010-07-15 14:08:03 -07:00
} else {
2011-10-17 07:59:28 -07:00
mIsSolidColorInVisibleRegion = false ;
2010-07-15 14:08:03 -07:00
}
2011-01-16 02:38:45 -08:00
mVisibleRegion . Or ( mVisibleRegion , aVisibleRect ) ;
mVisibleRegion . SimplifyOutward ( 4 ) ;
mDrawRegion . Or ( mDrawRegion , aDrawRect ) ;
mDrawRegion . SimplifyOutward ( 4 ) ;
}
2011-01-17 13:47:18 -08:00
2012-04-10 04:24:18 -07:00
bool snap ;
2012-05-02 21:29:05 -07:00
nsRegion opaque = aItem - > GetOpaqueRegion ( aState - > mBuilder , & snap ) ;
2011-01-02 17:48:09 -08:00
if ( ! opaque . IsEmpty ( ) ) {
2012-07-22 20:00:36 -07:00
nsRegion opaqueClipped ;
2011-01-02 17:48:09 -08:00
nsRegionRectIterator iter ( opaque ) ;
for ( const nsRect * r = iter . Next ( ) ; r ; r = iter . Next ( ) ) {
2012-12-13 14:50:57 -08:00
opaqueClipped . Or ( opaqueClipped , aClip . ApproximateIntersect ( * r ) ) ;
2012-07-22 20:00:36 -07:00
}
nsIntRegion opaquePixels = aState - > ScaleRegionToInsidePixels ( opaqueClipped , snap ) ;
nsIntRegionRectIterator iter2 ( opaquePixels ) ;
for ( const nsIntRect * r = iter2 . Next ( ) ; r ; r = iter2 . Next ( ) ) {
2011-01-02 17:48:09 -08:00
// We don't use SimplifyInward here since it's not defined exactly
// what it will discard. For our purposes the most important case
// is a large opaque background at the bottom of z-order (e.g.,
// a canvas background), so we need to make sure that the first rect
// we see doesn't get discarded.
nsIntRegion tmp ;
2012-07-22 20:00:36 -07:00
tmp . Or ( mOpaqueRegion , * r ) ;
2011-01-02 17:48:09 -08:00
// Opaque display items in chrome documents whose window is partially
// transparent are always added to the opaque region. This helps ensure
// that we get as much subpixel-AA as possible in the chrome.
if ( tmp . GetNumRects ( ) < = 4 | |
2011-06-22 05:11:27 -07:00
( WindowHasTransparency ( aState - > mBuilder ) & &
2011-01-02 17:48:09 -08:00
aItem - > GetUnderlyingFrame ( ) - > PresContext ( ) - > IsChrome ( ) ) ) {
2011-01-02 17:48:09 -08:00
mOpaqueRegion = tmp ;
}
2010-07-15 14:08:11 -07:00
}
2011-01-02 17:48:09 -08:00
}
2012-05-02 21:29:05 -07:00
if ( ! aState - > mParameters . mDisableSubpixelAntialiasingInDescendants ) {
2012-01-11 03:26:33 -08:00
nsRect componentAlpha = aItem - > GetComponentAlphaBounds ( aState - > mBuilder ) ;
if ( ! componentAlpha . IsEmpty ( ) ) {
2012-04-10 04:24:18 -07:00
nsIntRect componentAlphaRect =
aState - > ScaleToOutsidePixels ( componentAlpha , false ) . Intersect ( aVisibleRect ) ;
if ( ! mOpaqueRegion . Contains ( componentAlphaRect ) ) {
2012-01-11 03:26:33 -08:00
if ( SuppressComponentAlpha ( aState - > mBuilder , aItem , componentAlpha ) ) {
aItem - > DisableComponentAlpha ( ) ;
} else {
mNeedComponentAlpha = true ;
}
2011-01-02 17:48:09 -08:00
}
2010-09-02 02:18:40 -07:00
}
2010-07-15 14:07:51 -07:00
}
}
2012-02-07 14:27:44 -08:00
ContainerState : : ThebesLayerData *
2010-09-02 02:18:39 -07:00
ContainerState : : FindThebesLayerFor ( nsDisplayItem * aItem ,
const nsIntRect & aVisibleRect ,
2010-08-01 20:06:58 -07:00
const nsIntRect & aDrawRect ,
2011-01-02 17:48:09 -08:00
const FrameLayerBuilder : : Clip & aClip ,
2012-09-28 04:19:39 -07:00
const nsIFrame * aActiveScrolledRoot ,
const nsPoint & aTopLeft )
2010-07-15 14:07:51 -07:00
{
2012-08-22 08:56:38 -07:00
int32_t i ;
int32_t lowestUsableLayerWithScrolledRoot = - 1 ;
int32_t topmostLayerWithScrolledRoot = - 1 ;
2010-07-15 14:07:51 -07:00
for ( i = mThebesLayerDataStack . Length ( ) - 1 ; i > = 0 ; - - i ) {
ThebesLayerData * data = mThebesLayerDataStack [ i ] ;
2010-08-01 20:06:58 -07:00
if ( data - > mDrawAboveRegion . Intersects ( aVisibleRect ) ) {
2010-07-15 14:07:51 -07:00
+ + i ;
break ;
}
if ( data - > mActiveScrolledRoot = = aActiveScrolledRoot ) {
lowestUsableLayerWithScrolledRoot = i ;
if ( topmostLayerWithScrolledRoot < 0 ) {
topmostLayerWithScrolledRoot = i ;
2010-05-20 20:20:48 -07:00
}
}
2010-08-01 20:06:58 -07:00
if ( data - > mDrawRegion . Intersects ( aVisibleRect ) )
2010-07-15 14:07:51 -07:00
break ;
}
if ( topmostLayerWithScrolledRoot < 0 ) {
- - i ;
for ( ; i > = 0 ; - - i ) {
ThebesLayerData * data = mThebesLayerDataStack [ i ] ;
if ( data - > mActiveScrolledRoot = = aActiveScrolledRoot ) {
topmostLayerWithScrolledRoot = i ;
break ;
}
}
}
2010-05-20 20:20:48 -07:00
2010-07-15 14:07:51 -07:00
if ( topmostLayerWithScrolledRoot > = 0 ) {
2012-08-22 08:56:38 -07:00
while ( uint32_t ( topmostLayerWithScrolledRoot + 1 ) < mThebesLayerDataStack . Length ( ) ) {
2010-07-15 14:07:51 -07:00
PopThebesLayerData ( ) ;
2010-05-20 20:20:48 -07:00
}
}
2010-07-15 14:07:51 -07:00
nsRefPtr < ThebesLayer > layer ;
2012-07-30 07:20:58 -07:00
ThebesLayerData * thebesLayerData = nullptr ;
2010-07-15 14:07:51 -07:00
if ( lowestUsableLayerWithScrolledRoot < 0 ) {
2012-09-28 04:19:39 -07:00
layer = CreateOrRecycleThebesLayer ( aActiveScrolledRoot , aItem - > ReferenceFrame ( ) , aTopLeft ) ;
2010-07-15 14:08:03 -07:00
NS_ASSERTION ( ! mNewChildLayers . Contains ( layer ) , " Layer already in list??? " ) ;
mNewChildLayers . AppendElement ( layer ) ;
2010-07-15 14:07:51 -07:00
thebesLayerData = new ThebesLayerData ( ) ;
mThebesLayerDataStack . AppendElement ( thebesLayerData ) ;
thebesLayerData - > mLayer = layer ;
thebesLayerData - > mActiveScrolledRoot = aActiveScrolledRoot ;
} else {
thebesLayerData = mThebesLayerDataStack [ lowestUsableLayerWithScrolledRoot ] ;
layer = thebesLayerData - > mLayer ;
}
2012-09-03 18:02:56 -07:00
// check to see if the new item has rounded rect clips in common with
// other items in the layer
thebesLayerData - > UpdateCommonClipCount ( aClip ) ;
2011-06-22 05:11:27 -07:00
thebesLayerData - > Accumulate ( this , aItem , aVisibleRect , aDrawRect , aClip ) ;
2012-02-07 14:27:44 -08:00
return thebesLayerData ;
2010-07-15 14:07:51 -07:00
}
2012-03-05 10:09:05 -08:00
# ifdef MOZ_DUMP_PAINTING
static void
DumpPaintedImage ( nsDisplayItem * aItem , gfxASurface * aSurf )
{
nsCString string ( aItem - > Name ( ) ) ;
string . Append ( " - " ) ;
2012-08-22 08:56:38 -07:00
string . AppendInt ( ( uint64_t ) aItem ) ;
2012-03-05 10:09:05 -08:00
fprintf ( gfxUtils : : sDumpPaintFile , " array[ \" %s \" ]= \" " , string . BeginReading ( ) ) ;
aSurf - > DumpAsDataURL ( gfxUtils : : sDumpPaintFile ) ;
fprintf ( gfxUtils : : sDumpPaintFile , " \" ; " ) ;
}
# endif
2011-02-10 00:58:11 -08:00
static void
PaintInactiveLayer ( nsDisplayListBuilder * aBuilder ,
2012-08-28 22:47:15 -07:00
LayerManager * aManager ,
2011-02-10 00:58:11 -08:00
nsDisplayItem * aItem ,
2012-07-17 10:03:51 -07:00
gfxContext * aContext ,
2012-08-28 22:47:15 -07:00
nsRenderingContext * aCtx )
2010-08-02 20:33:24 -07:00
{
2011-02-10 00:58:11 -08:00
// This item has an inactive layer. Render it to a ThebesLayer
// using a temporary BasicLayerManager.
2012-08-28 22:47:15 -07:00
BasicLayerManager * basic = static_cast < BasicLayerManager * > ( aManager ) ;
nsRefPtr < gfxContext > context = aContext ;
# ifdef MOZ_DUMP_PAINTING
2012-08-22 08:56:38 -07:00
int32_t appUnitsPerDevPixel = AppUnitsPerDevPixel ( aItem ) ;
2012-03-05 10:09:05 -08:00
nsIntRect itemVisibleRect =
aItem - > GetVisibleRect ( ) . ToOutsidePixels ( appUnitsPerDevPixel ) ;
2012-07-31 10:28:21 -07:00
nsRefPtr < gfxASurface > surf ;
2012-03-05 10:09:05 -08:00
if ( gfxUtils : : sDumpPainting ) {
2012-07-31 10:28:21 -07:00
surf = gfxPlatform : : GetPlatform ( ) - > CreateOffscreenSurface ( itemVisibleRect . Size ( ) ,
2012-03-05 10:09:05 -08:00
gfxASurface : : CONTENT_COLOR_ALPHA ) ;
surf - > SetDeviceOffset ( - itemVisibleRect . TopLeft ( ) ) ;
context = new gfxContext ( surf ) ;
}
# endif
2012-08-28 22:47:15 -07:00
basic - > SetTarget ( context ) ;
2012-03-05 10:09:05 -08:00
2012-07-17 10:03:51 -07:00
if ( aItem - > GetType ( ) = = nsDisplayItem : : TYPE_SVG_EFFECTS ) {
2012-08-28 22:47:15 -07:00
static_cast < nsDisplaySVGEffects * > ( aItem ) - > PaintAsLayer ( aBuilder , aCtx , basic ) ;
if ( basic - > InTransaction ( ) ) {
basic - > AbortTransaction ( ) ;
2012-07-19 21:53:55 -07:00
}
2012-07-17 10:03:51 -07:00
} else {
2012-08-28 22:47:15 -07:00
basic - > EndTransaction ( FrameLayerBuilder : : DrawThebesLayer , aBuilder ) ;
}
FrameLayerBuilder * builder = static_cast < FrameLayerBuilder * > ( basic - > GetUserData ( & gLayerManagerLayerBuilder ) ) ;
if ( builder ) {
builder - > DidEndTransaction ( ) ;
2012-07-17 10:03:51 -07:00
}
2012-10-23 04:05:14 -07:00
2012-11-08 22:01:24 -08:00
basic - > SetTarget ( nullptr ) ;
2012-03-05 10:09:05 -08:00
# ifdef MOZ_DUMP_PAINTING
if ( gfxUtils : : sDumpPainting ) {
DumpPaintedImage ( aItem , surf ) ;
2012-07-31 10:28:21 -07:00
2012-03-05 10:09:05 -08:00
surf - > SetDeviceOffset ( gfxPoint ( 0 , 0 ) ) ;
aContext - > SetSource ( surf , itemVisibleRect . TopLeft ( ) ) ;
aContext - > Rectangle ( itemVisibleRect ) ;
aContext - > Fill ( ) ;
aItem - > SetPainted ( ) ;
}
# endif
2010-08-02 20:33:24 -07:00
}
2012-12-03 22:05:22 -08:00
/**
* Chooses a single active scrolled root for the entire display list , used
* when we are flattening layers .
*/
2012-12-11 12:36:22 -08:00
bool
ContainerState : : ChooseActiveScrolledRoot ( const nsDisplayList & aList ,
const nsIFrame * * aActiveScrolledRoot )
2012-12-03 22:05:22 -08:00
{
for ( nsDisplayItem * item = aList . GetBottom ( ) ; item ; item = item - > GetAbove ( ) ) {
nsDisplayItem : : Type type = item - > GetType ( ) ;
if ( type = = nsDisplayItem : : TYPE_CLIP | |
type = = nsDisplayItem : : TYPE_CLIP_ROUNDED_RECT ) {
2012-12-11 12:36:22 -08:00
if ( ChooseActiveScrolledRoot ( * item - > GetSameCoordinateSystemChildren ( ) ,
aActiveScrolledRoot ) ) {
return true ;
2012-12-03 22:05:22 -08:00
}
continue ;
}
2012-12-11 12:36:22 -08:00
LayerState layerState = item - > GetLayerState ( mBuilder , mManager , mParameters ) ;
// Don't use an item that won't be part of any ThebesLayers to pick the
// active scrolled root.
if ( layerState = = LAYER_ACTIVE_FORCE ) {
continue ;
}
// Try using the actual active scrolled root of the backmost item, as that
// should result in the least invalidation when scrolling.
mBuilder - > IsFixedItem ( item , aActiveScrolledRoot ) ;
if ( * aActiveScrolledRoot ) {
return true ;
2012-12-03 22:05:22 -08:00
}
}
2012-12-11 12:36:22 -08:00
return false ;
2012-12-03 22:05:22 -08:00
}
2010-07-15 14:07:51 -07:00
/*
* Iterate through the non - clip items in aList and its descendants .
* For each item we compute the effective clip rect . Each item is assigned
* to a layer . We invalidate the areas in ThebesLayers where an item
* has moved from one ThebesLayer to another . Also ,
* aState - > mInvalidThebesContent is invalidated in every ThebesLayer .
2012-02-07 14:27:44 -08:00
* We set the clip rect for items that generated their own layer , and
* create a mask layer to do any rounded rect clipping .
2010-07-15 14:07:51 -07:00
* ( ThebesLayers don ' t need a clip rect on the layer , we clip the items
* individually when we draw them . )
* We set the visible rect for all layers , although the actual setting
* of visible rects for some ThebesLayers is deferred until the calling
* of ContainerState : : Finish .
*/
void
ContainerState : : ProcessDisplayItems ( const nsDisplayList & aList ,
2012-07-22 20:00:36 -07:00
FrameLayerBuilder : : Clip & aClip ,
2012-12-11 12:36:22 -08:00
uint32_t aFlags ,
const nsIFrame * aForceActiveScrolledRoot )
2010-07-15 14:07:51 -07:00
{
2012-04-16 11:37:59 -07:00
SAMPLE_LABEL ( " ContainerState " , " ProcessDisplayItems " ) ;
2012-10-11 16:38:25 -07:00
const nsIFrame * lastActiveScrolledRoot = nullptr ;
nsPoint topLeft ;
2012-12-03 22:05:22 -08:00
// When NO_COMPONENT_ALPHA is set, items will be flattened into a single
// layer, so we need to choose which active scrolled root to use for all
// items.
if ( aFlags & NO_COMPONENT_ALPHA ) {
2012-12-11 12:36:22 -08:00
if ( aForceActiveScrolledRoot ) {
lastActiveScrolledRoot = aForceActiveScrolledRoot ;
} else if ( ! ChooseActiveScrolledRoot ( aList , & lastActiveScrolledRoot ) ) {
2012-12-03 22:05:22 -08:00
lastActiveScrolledRoot = mContainerReferenceFrame ;
}
topLeft = lastActiveScrolledRoot - > GetOffsetToCrossDoc ( mContainerReferenceFrame ) ;
}
2010-07-15 14:07:51 -07:00
for ( nsDisplayItem * item = aList . GetBottom ( ) ; item ; item = item - > GetAbove ( ) ) {
2010-09-09 08:21:46 -07:00
nsDisplayItem : : Type type = item - > GetType ( ) ;
if ( type = = nsDisplayItem : : TYPE_CLIP | |
type = = nsDisplayItem : : TYPE_CLIP_ROUNDED_RECT ) {
FrameLayerBuilder : : Clip childClip ( aClip , item ) ;
2012-12-11 12:36:22 -08:00
ProcessDisplayItems ( * item - > GetSameCoordinateSystemChildren ( ) , childClip , aFlags , lastActiveScrolledRoot ) ;
2010-07-15 14:07:51 -07:00
continue ;
2010-05-20 20:20:48 -07:00
}
2012-04-10 04:24:18 -07:00
NS_ASSERTION ( mAppUnitsPerDevPixel = = AppUnitsPerDevPixel ( item ) ,
2010-08-08 11:49:07 -07:00
" items in a container layer should all have the same app units per dev pixel " ) ;
2011-10-25 19:55:51 -07:00
nsIntRect itemVisibleRect =
2012-04-10 04:24:18 -07:00
ScaleToOutsidePixels ( item - > GetVisibleRect ( ) , false ) ;
bool snap ;
nsRect itemContent = item - > GetBounds ( mBuilder , & snap ) ;
2012-04-13 04:44:05 -07:00
nsIntRect itemDrawRect = ScaleToOutsidePixels ( itemContent , snap ) ;
2010-09-09 08:21:46 -07:00
if ( aClip . mHaveClipRect ) {
2012-04-13 04:44:05 -07:00
itemContent . IntersectRect ( itemContent , aClip . mClipRect ) ;
nsIntRect clipRect = ScaleToNearestPixels ( aClip . mClipRect ) ;
itemDrawRect . IntersectRect ( itemDrawRect , clipRect ) ;
2010-08-01 20:06:58 -07:00
}
2011-02-22 21:38:09 -08:00
mBounds . UnionRect ( mBounds , itemContent ) ;
2012-04-10 04:24:18 -07:00
itemVisibleRect . IntersectRect ( itemVisibleRect , itemDrawRect ) ;
2012-05-03 07:05:55 -07:00
LayerState layerState = item - > GetLayerState ( mBuilder , mManager , mParameters ) ;
2012-11-22 15:29:05 -08:00
if ( layerState = = LAYER_INACTIVE & &
nsDisplayItem : : ForceActiveLayers ( ) ) {
layerState = LAYER_ACTIVE ;
}
2010-07-15 14:08:05 -07:00
2012-09-13 03:34:34 -07:00
bool isFixed ;
bool forceInactive ;
2012-09-12 17:32:53 -07:00
const nsIFrame * activeScrolledRoot ;
2012-07-22 20:00:36 -07:00
if ( aFlags & NO_COMPONENT_ALPHA ) {
forceInactive = true ;
2012-12-03 22:05:22 -08:00
activeScrolledRoot = lastActiveScrolledRoot ;
2012-09-13 03:34:34 -07:00
isFixed = mBuilder - > IsFixedItem ( item , nullptr , activeScrolledRoot ) ;
2012-07-22 20:00:36 -07:00
} else {
2012-09-13 03:34:34 -07:00
forceInactive = false ;
isFixed = mBuilder - > IsFixedItem ( item , & activeScrolledRoot ) ;
2012-10-11 16:38:25 -07:00
if ( activeScrolledRoot ! = lastActiveScrolledRoot ) {
lastActiveScrolledRoot = activeScrolledRoot ;
topLeft = activeScrolledRoot - > GetOffsetToCrossDoc ( mContainerReferenceFrame ) ;
}
2012-07-22 20:00:36 -07:00
}
2011-04-05 22:00:25 -07:00
2010-07-15 14:07:51 -07:00
// Assign the item to a layer
2011-03-15 16:20:19 -07:00
if ( layerState = = LAYER_ACTIVE_FORCE | |
2012-11-13 14:22:21 -08:00
( layerState = = LAYER_INACTIVE & & ! mManager - > IsWidgetLayerManager ( ) ) | |
2012-07-22 20:00:36 -07:00
( ! forceInactive & &
( layerState = = LAYER_ACTIVE_EMPTY | |
layerState = = LAYER_ACTIVE ) ) ) {
2011-04-13 14:12:22 -07:00
// LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
// We should never see an empty layer with any visible content!
NS_ASSERTION ( layerState ! = LAYER_ACTIVE_EMPTY | |
2011-10-25 19:55:51 -07:00
itemVisibleRect . IsEmpty ( ) ,
2011-04-13 14:12:22 -07:00
" State is LAYER_ACTIVE_EMPTY but visible rect is not. " ) ;
2012-10-11 19:39:46 -07:00
// As long as the new layer isn't going to be a ThebesLayer,
// InvalidateForLayerChange doesn't need the new layer pointer.
// We also need to check the old data now, because BuildLayer
// can overwrite it.
2012-10-17 01:00:00 -07:00
InvalidateForLayerChange ( item , nullptr , aClip , topLeft , nullptr ) ;
2012-10-11 19:39:46 -07:00
2010-07-15 14:08:09 -07:00
// If the item would have its own layer but is invisible, just hide it.
// Note that items without their own layers can't be skipped this
// way, since their ThebesLayer may decide it wants to draw them
// into its buffer even if they're currently covered.
2011-10-25 19:55:51 -07:00
if ( itemVisibleRect . IsEmpty ( ) & & layerState ! = LAYER_ACTIVE_EMPTY ) {
2010-07-15 14:08:09 -07:00
continue ;
}
2010-07-15 14:08:05 -07:00
// Just use its layer.
2011-06-22 05:11:27 -07:00
nsRefPtr < Layer > ownLayer = item - > BuildLayer ( mBuilder , mManager , mParameters ) ;
2010-07-15 14:08:05 -07:00
if ( ! ownLayer ) {
continue ;
}
2012-10-11 19:39:46 -07:00
NS_ASSERTION ( ! ownLayer - > AsThebesLayer ( ) ,
" Should never have created a dedicated Thebes layer! " ) ;
2012-08-28 22:48:45 -07:00
nsRect invalid ;
if ( item - > IsInvalid ( invalid ) ) {
2012-08-28 22:47:18 -07:00
ownLayer - > SetInvalidRectToVisibleRegion ( ) ;
}
2011-06-22 05:11:27 -07:00
// If it's not a ContainerLayer, we need to apply the scale transform
// ourselves.
if ( ! ownLayer - > AsContainerLayer ( ) ) {
2012-08-03 14:29:22 -07:00
ownLayer - > SetPostScale ( mParameters . mXScale ,
mParameters . mYScale ) ;
2011-06-22 05:11:27 -07:00
}
2013-01-12 12:48:55 -08:00
// If a transform layer is marked as fixed then the shadow transform gets
// overwritten by CompositorParent when doing scroll compensation on
// fixed layers. This means we need to make sure transform layers are not
// marked as fixed.
ownLayer - > SetIsFixedPosition ( isFixed & & type ! = nsDisplayItem : : TYPE_TRANSFORM ) ;
2011-04-05 22:00:25 -07:00
2010-07-15 14:08:05 -07:00
// Update that layer's clip and visible rects.
2010-07-15 14:07:51 -07:00
NS_ASSERTION ( ownLayer - > Manager ( ) = = mManager , " Wrong manager " ) ;
2010-09-02 02:18:39 -07:00
NS_ASSERTION ( ! ownLayer - > HasUserData ( & gLayerManagerUserData ) ,
2010-07-15 14:07:51 -07:00
" We shouldn't have a FrameLayerBuilder-managed layer here! " ) ;
2012-02-21 05:53:11 -08:00
NS_ASSERTION ( aClip . mHaveClipRect | |
aClip . mRoundedClipRects . IsEmpty ( ) ,
2012-01-19 12:21:41 -08:00
" If we have rounded rects, we must have a clip rect " ) ;
2010-07-15 14:07:51 -07:00
// It has its own layer. Update that layer's clip and visible rects.
2010-09-09 08:21:46 -07:00
if ( aClip . mHaveClipRect ) {
2012-09-16 15:25:33 -07:00
nsIntRect clip = ScaleToNearestPixels ( aClip . NonRoundedIntersection ( ) ) ;
clip . MoveBy ( mParameters . mOffset ) ;
ownLayer - > IntersectClipRect ( clip ) ;
2010-05-20 20:20:48 -07:00
}
2010-07-15 14:07:51 -07:00
ThebesLayerData * data = GetTopThebesLayerData ( ) ;
if ( data ) {
2011-10-25 19:55:51 -07:00
data - > mVisibleAboveRegion . Or ( data - > mVisibleAboveRegion , itemVisibleRect ) ;
2012-01-11 03:26:33 -08:00
data - > mVisibleAboveRegion . SimplifyOutward ( 4 ) ;
2010-08-01 20:06:58 -07:00
// Add the entire bounds rect to the mDrawAboveRegion.
// The visible region may be excluding opaque content above the
// item, and we need to ensure that that content is not placed
// in a ThebesLayer below the item!
data - > mDrawAboveRegion . Or ( data - > mDrawAboveRegion , itemDrawRect ) ;
2012-01-11 03:26:33 -08:00
data - > mDrawAboveRegion . SimplifyOutward ( 4 ) ;
2010-07-15 14:07:51 -07:00
}
2012-09-16 15:25:33 -07:00
itemVisibleRect . MoveBy ( mParameters . mOffset ) ;
2011-10-25 19:55:51 -07:00
RestrictVisibleRegionForLayer ( ownLayer , itemVisibleRect ) ;
2012-02-07 14:27:44 -08:00
// rounded rectangle clipping using mask layers
// (must be done after visible rect is set on layer)
if ( aClip . IsRectClippedByRoundedCorner ( itemContent ) ) {
SetupMaskLayer ( ownLayer , aClip ) ;
}
2010-07-15 14:07:51 -07:00
ContainerLayer * oldContainer = ownLayer - > GetParent ( ) ;
if ( oldContainer & & oldContainer ! = mContainerLayer ) {
oldContainer - > RemoveChild ( ownLayer ) ;
}
NS_ASSERTION ( ! mNewChildLayers . Contains ( ownLayer ) ,
" Layer already in list??? " ) ;
2010-07-15 14:08:05 -07:00
2010-07-15 14:07:51 -07:00
mNewChildLayers . AppendElement ( ownLayer ) ;
2012-10-17 01:00:00 -07:00
/**
* No need to allocate geometry for items that aren ' t
* part of a ThebesLayer .
*/
nsAutoPtr < nsDisplayItemGeometry > dummy ;
2012-08-28 22:47:15 -07:00
mLayerBuilder - > AddLayerDisplayItem ( ownLayer , item ,
2012-08-28 22:48:43 -07:00
aClip , layerState ,
2012-10-11 16:38:24 -07:00
topLeft , nullptr ,
2012-10-17 01:00:00 -07:00
dummy ) ;
2010-05-20 20:20:48 -07:00
} else {
2012-02-07 14:27:44 -08:00
ThebesLayerData * data =
2011-10-25 19:55:51 -07:00
FindThebesLayerFor ( item , itemVisibleRect , itemDrawRect , aClip ,
2012-09-28 04:19:39 -07:00
activeScrolledRoot , topLeft ) ;
2010-07-15 14:08:05 -07:00
2012-09-13 03:34:34 -07:00
data - > mLayer - > SetIsFixedPosition ( isFixed ) ;
2011-04-05 22:00:25 -07:00
2012-10-17 01:00:00 -07:00
nsAutoPtr < nsDisplayItemGeometry > geometry ( item - > AllocateGeometry ( mBuilder ) ) ;
2012-10-11 16:38:24 -07:00
InvalidateForLayerChange ( item , data - > mLayer , aClip , topLeft , geometry ) ;
2012-02-07 14:27:44 -08:00
2012-07-17 10:03:51 -07:00
mLayerBuilder - > AddThebesDisplayItem ( data - > mLayer , item , aClip ,
mContainerFrame ,
2012-10-11 16:38:24 -07:00
layerState , topLeft ,
geometry ) ;
2010-07-15 14:07:51 -07:00
2012-02-07 14:27:44 -08:00
// check to see if the new item has rounded rect clips in common with
// other items in the layer
data - > UpdateCommonClipCount ( aClip ) ;
2010-05-20 20:20:48 -07:00
}
}
}
2012-10-15 18:10:43 -07:00
/**
* Combine two clips and returns true if clipping
* needs to be applied .
*
* @ param aClip Current clip
* @ param aOldClip Optional clip from previous paint .
* @ param aShift Offet to apply to aOldClip
* @ param aCombined Outparam - Computed clip region
* @ return True if the clip should be applied , false
* otherwise .
*/
static bool ComputeCombinedClip ( const FrameLayerBuilder : : Clip & aClip ,
FrameLayerBuilder : : Clip * aOldClip ,
const nsPoint & aShift ,
nsRegion & aCombined )
{
if ( ! aClip . mHaveClipRect | |
( aOldClip & & ! aOldClip - > mHaveClipRect ) ) {
return false ;
}
if ( aOldClip ) {
aCombined = aOldClip - > NonRoundedIntersection ( ) ;
aCombined . MoveBy ( aShift ) ;
aCombined . Or ( aCombined , aClip . NonRoundedIntersection ( ) ) ;
} else {
aCombined = aClip . NonRoundedIntersection ( ) ;
}
return true ;
}
2010-07-15 14:08:05 -07:00
void
2012-08-28 22:47:15 -07:00
ContainerState : : InvalidateForLayerChange ( nsDisplayItem * aItem ,
2012-08-28 22:48:43 -07:00
Layer * aNewLayer ,
const FrameLayerBuilder : : Clip & aClip ,
2012-10-11 16:38:24 -07:00
const nsPoint & aTopLeft ,
nsDisplayItemGeometry * aGeometry )
2010-07-15 14:08:05 -07:00
{
2012-10-09 22:00:05 -07:00
NS_ASSERTION ( aItem - > GetUnderlyingFrame ( ) ,
" Display items that render using Thebes must have a frame " ) ;
NS_ASSERTION ( aItem - > GetPerFrameKey ( ) ,
" Display items that render using Thebes must have a key " ) ;
2012-08-28 22:47:15 -07:00
nsDisplayItemGeometry * oldGeometry = NULL ;
2012-08-28 22:48:43 -07:00
FrameLayerBuilder : : Clip * oldClip = NULL ;
2012-10-15 18:23:07 -07:00
nsAutoTArray < nsIFrame * , 4 > changedFrames ;
2012-11-06 14:04:53 -08:00
bool isInvalid = false ;
Layer * oldLayer = mLayerBuilder - > GetOldLayerFor ( aItem , & oldGeometry , & oldClip , & changedFrames , & isInvalid ) ;
2012-08-28 22:47:15 -07:00
if ( aNewLayer ! = oldLayer & & oldLayer ) {
2010-07-15 14:08:05 -07:00
// The item has changed layers.
2012-09-28 04:19:39 -07:00
// Invalidate the old bounds in the old layer and new bounds in the new layer.
2010-07-15 14:08:05 -07:00
ThebesLayer * t = oldLayer - > AsThebesLayer ( ) ;
if ( t ) {
2011-06-22 05:11:27 -07:00
// Note that whenever the layer's scale changes, we invalidate the whole thing,
// so it doesn't matter whether we are using the old scale at last paint
// or a new scale here
2012-08-28 22:47:15 -07:00
# ifdef DEBUG_INVALIDATIONS
2012-10-11 16:38:24 -07:00
printf ( " Display item type %s(%p) changed layers %p to %p! \n " , aItem - > Name ( ) , aItem - > GetUnderlyingFrame ( ) , t , aNewLayer ) ;
2012-08-28 22:47:15 -07:00
# endif
2011-06-22 05:11:27 -07:00
InvalidatePostTransformRegion ( t ,
2012-10-15 18:10:43 -07:00
oldGeometry - > ComputeInvalidationRegion ( ) ,
* oldClip ,
2012-07-17 10:03:51 -07:00
mLayerBuilder - > GetLastPaintOffset ( t ) ) ;
2010-07-15 14:08:05 -07:00
}
if ( aNewLayer ) {
2012-08-28 22:47:15 -07:00
ThebesLayer * newThebesLayer = aNewLayer - > AsThebesLayer ( ) ;
if ( newThebesLayer ) {
InvalidatePostTransformRegion ( newThebesLayer ,
2012-10-15 18:10:43 -07:00
aGeometry - > ComputeInvalidationRegion ( ) ,
aClip ,
2012-08-28 22:47:15 -07:00
GetTranslationForThebesLayer ( newThebesLayer ) ) ;
2010-07-15 14:08:05 -07:00
}
}
2012-12-09 21:34:31 -08:00
aItem - > NotifyRenderingChanged ( ) ;
2012-08-28 22:47:15 -07:00
return ;
}
if ( ! aNewLayer ) {
return ;
}
2010-07-15 14:08:05 -07:00
2012-08-28 22:47:15 -07:00
ThebesLayer * newThebesLayer = aNewLayer - > AsThebesLayer ( ) ;
2012-08-28 22:47:18 -07:00
if ( ! newThebesLayer ) {
2012-08-28 22:47:15 -07:00
return ;
}
ThebesDisplayItemLayerUserData * data =
static_cast < ThebesDisplayItemLayerUserData * > ( newThebesLayer - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
2012-08-28 22:48:45 -07:00
// If the frame is marked as invalidated, and didn't specify a rect to invalidate then we want to
// invalidate both the old and new bounds, otherwise we only want to invalidate the changed areas.
// If we do get an invalid rect, then we want to add this on top of the change areas.
nsRect invalid ;
2012-08-28 22:47:15 -07:00
nsRegion combined ;
2012-10-15 18:10:43 -07:00
nsPoint shift = aTopLeft - data - > mLastActiveScrolledRootOrigin ;
2012-08-28 22:47:15 -07:00
if ( ! oldLayer ) {
2012-08-28 22:48:43 -07:00
// This item is being added for the first time, invalidate its entire area.
2012-08-28 22:47:15 -07:00
//TODO: We call GetGeometry again in AddThebesDisplayItem, we should reuse this.
2012-10-15 18:10:43 -07:00
combined = aClip . ApplyNonRoundedIntersection ( aGeometry - > ComputeInvalidationRegion ( ) ) ;
2012-08-28 22:47:15 -07:00
# ifdef DEBUG_INVALIDATIONS
2012-10-11 16:38:24 -07:00
printf ( " Display item type %s(%p) added to layer %p! \n " , aItem - > Name ( ) , aItem - > GetUnderlyingFrame ( ) , aNewLayer ) ;
2012-08-28 22:47:15 -07:00
# endif
2012-11-06 14:04:53 -08:00
} else if ( isInvalid | | ( aItem - > IsInvalid ( invalid ) & & invalid . IsEmpty ( ) ) ) {
2012-08-28 22:48:44 -07:00
// Either layout marked item as needing repainting, invalidate the entire old and new areas.
2012-10-15 18:10:43 -07:00
combined = oldClip - > ApplyNonRoundedIntersection ( oldGeometry - > ComputeInvalidationRegion ( ) ) ;
combined . MoveBy ( shift ) ;
combined . Or ( combined , aClip . ApplyNonRoundedIntersection ( aGeometry - > ComputeInvalidationRegion ( ) ) ) ;
2012-08-28 22:47:15 -07:00
# ifdef DEBUG_INVALIDATIONS
2012-10-11 16:38:24 -07:00
printf ( " Display item type %s(%p) (in layer %p) belongs to an invalidated frame! \n " , aItem - > Name ( ) , aItem - > GetUnderlyingFrame ( ) , aNewLayer ) ;
2012-08-28 22:47:15 -07:00
# endif
} else {
2012-08-28 22:48:44 -07:00
// Let the display item check for geometry changes and decide what needs to be
2012-08-28 22:48:43 -07:00
// repainted.
2012-08-28 22:47:15 -07:00
oldGeometry - > MoveBy ( shift ) ;
aItem - > ComputeInvalidationRegion ( mBuilder , oldGeometry , & combined ) ;
2012-08-28 22:48:44 -07:00
oldClip - > AddOffsetAndComputeDifference ( shift , oldGeometry - > ComputeInvalidationRegion ( ) ,
2012-10-11 16:38:24 -07:00
aClip , aGeometry - > ComputeInvalidationRegion ( ) ,
2012-08-28 22:48:44 -07:00
& combined ) ;
2012-08-28 22:48:45 -07:00
// Add in any rect that the frame specified
2012-10-15 18:10:43 -07:00
combined . Or ( combined , invalid ) ;
2012-10-15 18:23:07 -07:00
for ( uint32_t i = 0 ; i < changedFrames . Length ( ) ; i + + ) {
combined . Or ( combined , changedFrames [ i ] - > GetVisualOverflowRect ( ) ) ;
}
2012-10-15 18:10:43 -07:00
// Restrict invalidation to the clipped region
nsRegion clip ;
if ( ComputeCombinedClip ( aClip , oldClip , shift , clip ) ) {
combined . And ( combined , clip ) ;
}
2012-08-28 22:47:15 -07:00
# ifdef DEBUG_INVALIDATIONS
if ( ! combined . IsEmpty ( ) ) {
2012-10-11 16:38:24 -07:00
printf ( " Display item type %s(%p) (in layer %p) changed geometry! \n " , aItem - > Name ( ) , aItem - > GetUnderlyingFrame ( ) , aNewLayer ) ;
2012-08-28 22:47:15 -07:00
}
# endif
}
if ( ! combined . IsEmpty ( ) ) {
2012-12-09 21:34:31 -08:00
aItem - > NotifyRenderingChanged ( ) ;
2012-08-28 22:47:15 -07:00
InvalidatePostTransformRegion ( newThebesLayer ,
combined . ScaleToOutsidePixels ( data - > mXScale , data - > mYScale , mAppUnitsPerDevPixel ) ,
GetTranslationForThebesLayer ( newThebesLayer ) ) ;
2010-07-15 14:08:05 -07:00
}
}
2010-07-15 14:07:51 -07:00
void
FrameLayerBuilder : : AddThebesDisplayItem ( ThebesLayer * aLayer ,
nsDisplayItem * aItem ,
2010-09-09 08:21:46 -07:00
const Clip & aClip ,
2010-07-15 14:08:05 -07:00
nsIFrame * aContainerLayerFrame ,
2012-08-28 22:47:15 -07:00
LayerState aLayerState ,
2012-10-11 16:38:24 -07:00
const nsPoint & aTopLeft ,
nsAutoPtr < nsDisplayItemGeometry > aGeometry )
2010-07-15 14:07:51 -07:00
{
2012-10-15 18:10:43 -07:00
ThebesDisplayItemLayerUserData * thebesData =
static_cast < ThebesDisplayItemLayerUserData * > ( aLayer - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
2012-08-28 22:47:15 -07:00
nsRefPtr < LayerManager > tempManager ;
2012-10-15 18:10:43 -07:00
nsIntRect intClip ;
bool hasClip = false ;
2012-08-28 22:47:15 -07:00
if ( aLayerState ! = LAYER_NONE ) {
DisplayItemData * data = GetDisplayItemDataForManager ( aItem , aLayer - > Manager ( ) ) ;
if ( data ) {
tempManager = data - > mInactiveManager ;
}
if ( ! tempManager ) {
tempManager = new BasicLayerManager ( ) ;
}
2012-10-23 04:05:14 -07:00
2012-10-15 18:10:43 -07:00
// We need to grab these before calling AddLayerDisplayItem because it will overwrite them.
nsRegion clip ;
FrameLayerBuilder : : Clip * oldClip = nullptr ;
GetOldLayerFor ( aItem , nullptr , & oldClip ) ;
hasClip = ComputeCombinedClip ( aClip , oldClip ,
aTopLeft - thebesData - > mLastActiveScrolledRootOrigin ,
clip ) ;
if ( hasClip ) {
intClip = clip . GetBounds ( ) . ScaleToOutsidePixels ( thebesData - > mXScale ,
thebesData - > mYScale ,
thebesData - > mAppUnitsPerDevPixel ) ;
}
2012-08-28 22:47:15 -07:00
}
2012-12-13 14:50:57 -08:00
AddLayerDisplayItem ( aLayer , aItem , aClip , aLayerState , aTopLeft , tempManager , aGeometry ) ;
2010-07-15 14:07:51 -07:00
ThebesLayerItemsEntry * entry = mThebesLayerItems . PutEntry ( aLayer ) ;
if ( entry ) {
entry - > mContainerLayerFrame = aContainerLayerFrame ;
2012-09-11 14:17:26 -07:00
if ( entry - > mContainerLayerGeneration = = 0 ) {
entry - > mContainerLayerGeneration = mContainerLayerGeneration ;
}
2010-07-15 14:07:51 -07:00
NS_ASSERTION ( aItem - > GetUnderlyingFrame ( ) , " Must have frame " ) ;
2012-08-28 22:47:15 -07:00
if ( tempManager ) {
FrameLayerBuilder * layerBuilder = new FrameLayerBuilder ( ) ;
layerBuilder - > Init ( mDisplayListBuilder , tempManager ) ;
tempManager - > BeginTransaction ( ) ;
if ( mRetainingManager ) {
layerBuilder - > DidBeginRetainedLayerTransaction ( tempManager ) ;
}
2012-08-28 22:47:18 -07:00
nsAutoPtr < LayerProperties > props ( LayerProperties : : CloneFrom ( tempManager - > GetRoot ( ) ) ) ;
2012-08-28 22:47:15 -07:00
nsRefPtr < Layer > layer =
aItem - > BuildLayer ( mDisplayListBuilder , tempManager , FrameLayerBuilder : : ContainerParameters ( ) ) ;
// We have no easy way of detecting if this transaction will ever actually get finished.
// For now, I've just silenced the warning with nested transactions in BasicLayers.cpp
if ( ! layer ) {
tempManager - > EndTransaction ( nullptr , nullptr ) ;
tempManager - > SetUserData ( & gLayerManagerLayerBuilder , nullptr ) ;
return ;
}
// If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been
// stored in layerBuilder. Manually add it now.
2012-10-11 16:38:24 -07:00
if ( mRetainingManager ) {
2012-10-11 19:39:46 -07:00
# ifdef DEBUG_DISPLAY_ITEM_DATA
2012-10-11 16:38:24 -07:00
LayerManagerData * parentLmd = static_cast < LayerManagerData * >
( aLayer - > Manager ( ) - > GetUserData ( & gLayerManagerUserData ) ) ;
LayerManagerData * lmd = static_cast < LayerManagerData * >
( tempManager - > GetUserData ( & gLayerManagerUserData ) ) ;
lmd - > mParent = parentLmd ;
2012-10-11 19:39:46 -07:00
# endif
layerBuilder - > StoreDataForFrame ( aItem , layer , LAYER_ACTIVE ) ;
2012-10-11 16:38:24 -07:00
}
2012-08-28 22:47:15 -07:00
tempManager - > SetRoot ( layer ) ;
layerBuilder - > WillEndTransaction ( ) ;
2012-09-16 15:57:22 -07:00
nsIntPoint offset = GetLastPaintOffset ( aLayer ) - GetTranslationForThebesLayer ( aLayer ) ;
props - > MoveBy ( - offset ) ;
2012-11-12 10:31:15 -08:00
nsIntRegion invalid = props - > ComputeDifferences ( layer , nullptr ) ;
2012-08-28 22:47:18 -07:00
if ( aLayerState = = LAYER_SVG_EFFECTS ) {
2012-11-27 20:06:07 -08:00
invalid = nsSVGIntegrationUtils : : AdjustInvalidAreaForSVGEffects ( aItem - > GetUnderlyingFrame ( ) ,
aItem - > ToReferenceFrame ( ) ,
invalid . GetBounds ( ) ) ;
2012-08-28 22:47:18 -07:00
}
if ( ! invalid . IsEmpty ( ) ) {
# ifdef DEBUG_INVALIDATIONS
printf ( " Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p \n " , tempManager . get ( ) , aItem - > Name ( ) , aItem - > GetUnderlyingFrame ( ) , aLayer ) ;
# endif
2012-10-15 18:10:43 -07:00
if ( hasClip ) {
2012-11-12 10:31:15 -08:00
invalid . And ( invalid , intClip ) ;
2012-10-15 18:10:43 -07:00
}
invalid . ScaleRoundOut ( thebesData - > mXScale , thebesData - > mYScale ) ;
2012-08-28 22:47:18 -07:00
InvalidatePostTransformRegion ( aLayer , invalid ,
GetTranslationForThebesLayer ( aLayer ) ) ;
}
2012-08-28 22:47:15 -07:00
}
2010-07-15 14:08:05 -07:00
ClippedDisplayItem * cdi =
2012-12-13 14:50:57 -08:00
entry - > mItems . AppendElement ( ClippedDisplayItem ( aItem , aClip ,
2012-07-22 20:00:36 -07:00
mContainerLayerGeneration ) ) ;
2012-10-23 04:05:14 -07:00
cdi - > mInactiveLayerManager = tempManager ;
2010-07-15 14:07:51 -07:00
}
}
2012-10-11 19:39:46 -07:00
FrameLayerBuilder : : DisplayItemData *
FrameLayerBuilder : : StoreDataForFrame ( nsDisplayItem * aItem , Layer * aLayer , LayerState aState )
2012-08-29 03:53:27 -07:00
{
2012-10-11 19:39:46 -07:00
DisplayItemData * oldData = GetDisplayItemDataForManager ( aItem , mRetainingManager ) ;
if ( oldData ) {
if ( ! oldData - > mUsed ) {
2012-10-18 21:36:00 -07:00
oldData - > UpdateContents ( aLayer , aState , mContainerLayerGeneration , aItem ) ;
2012-10-11 19:39:46 -07:00
}
return oldData ;
2012-10-11 16:38:24 -07:00
}
2012-10-11 19:39:46 -07:00
LayerManagerData * lmd = static_cast < LayerManagerData * >
( mRetainingManager - > GetUserData ( & gLayerManagerUserData ) ) ;
nsRefPtr < DisplayItemData > data =
new DisplayItemData ( lmd , aItem - > GetPerFrameKey ( ) ,
aLayer , aState , mContainerLayerGeneration ) ;
data - > AddFrame ( aItem - > GetUnderlyingFrame ( ) ) ;
2012-10-11 16:38:24 -07:00
nsAutoTArray < nsIFrame * , 4 > mergedFrames ;
aItem - > GetMergedFrames ( & mergedFrames ) ;
for ( uint32_t i = 0 ; i < mergedFrames . Length ( ) ; + + i ) {
2012-10-11 19:39:46 -07:00
data - > AddFrame ( mergedFrames [ i ] ) ;
2012-08-28 22:47:15 -07:00
}
2012-10-11 19:39:46 -07:00
lmd - > mDisplayItems . PutEntry ( data ) ;
return data ;
}
void
FrameLayerBuilder : : StoreDataForFrame ( nsIFrame * aFrame ,
uint32_t aDisplayItemKey ,
Layer * aLayer ,
LayerState aState )
{
DisplayItemData * oldData = GetDisplayItemData ( aFrame , aDisplayItemKey ) ;
if ( oldData & & oldData - > mFrameList . Length ( ) = = 1 ) {
oldData - > UpdateContents ( aLayer , aState , mContainerLayerGeneration ) ;
return ;
}
LayerManagerData * lmd = static_cast < LayerManagerData * >
( mRetainingManager - > GetUserData ( & gLayerManagerUserData ) ) ;
nsRefPtr < DisplayItemData > data =
new DisplayItemData ( lmd , aDisplayItemKey , aLayer ,
aState , mContainerLayerGeneration ) ;
data - > AddFrame ( aFrame ) ;
lmd - > mDisplayItems . PutEntry ( data ) ;
2012-08-28 22:47:15 -07:00
}
FrameLayerBuilder : : ClippedDisplayItem : : ~ ClippedDisplayItem ( )
{
2012-10-23 04:05:14 -07:00
if ( mInactiveLayerManager ) {
2012-08-28 22:47:15 -07:00
// We always start a transaction during layer construction for all inactive
// layers, but we don't necessarily call EndTransaction during painting.
// If the transaaction is still open, end it to avoid assertions.
2012-10-23 04:05:14 -07:00
BasicLayerManager * basic = static_cast < BasicLayerManager * > ( mInactiveLayerManager . get ( ) ) ;
2012-08-28 22:47:15 -07:00
if ( basic - > InTransaction ( ) ) {
basic - > EndTransaction ( nullptr , nullptr ) ;
}
basic - > SetUserData ( & gLayerManagerLayerBuilder , nullptr ) ;
2012-08-29 03:53:27 -07:00
}
}
2012-12-13 14:50:57 -08:00
void
2010-07-15 14:07:51 -07:00
FrameLayerBuilder : : AddLayerDisplayItem ( Layer * aLayer ,
2011-05-18 15:54:31 -07:00
nsDisplayItem * aItem ,
2012-08-28 22:48:43 -07:00
const Clip & aClip ,
2012-08-28 22:47:15 -07:00
LayerState aLayerState ,
const nsPoint & aTopLeft ,
2012-10-11 16:38:24 -07:00
LayerManager * aManager ,
nsAutoPtr < nsDisplayItemGeometry > aGeometry )
2010-07-15 14:07:51 -07:00
{
if ( aLayer - > Manager ( ) ! = mRetainingManager )
2012-12-13 14:50:57 -08:00
return ;
2012-10-11 16:38:24 -07:00
2012-10-11 19:39:46 -07:00
DisplayItemData * data = StoreDataForFrame ( aItem , aLayer , aLayerState ) ;
2012-08-28 22:47:15 -07:00
ThebesLayer * t = aLayer - > AsThebesLayer ( ) ;
if ( t ) {
2012-10-11 16:38:24 -07:00
data - > mGeometry = aGeometry ;
2012-08-28 22:48:43 -07:00
data - > mClip = aClip ;
2012-08-28 22:47:15 -07:00
}
data - > mInactiveManager = aManager ;
2010-07-15 14:07:51 -07:00
}
2011-05-17 22:48:43 -07:00
nsIntPoint
FrameLayerBuilder : : GetLastPaintOffset ( ThebesLayer * aLayer )
2011-05-16 16:05:56 -07:00
{
ThebesLayerItemsEntry * entry = mThebesLayerItems . PutEntry ( aLayer ) ;
2012-07-22 20:00:36 -07:00
if ( entry ) {
2012-09-11 14:17:26 -07:00
if ( entry - > mContainerLayerGeneration = = 0 ) {
entry - > mContainerLayerGeneration = mContainerLayerGeneration ;
}
2012-07-22 20:00:36 -07:00
if ( entry - > mHasExplicitLastPaintOffset )
return entry - > mLastPaintOffset ;
}
2011-05-17 22:48:43 -07:00
return GetTranslationForThebesLayer ( aLayer ) ;
2011-05-16 16:05:56 -07:00
}
void
2011-05-17 22:48:43 -07:00
FrameLayerBuilder : : SaveLastPaintOffset ( ThebesLayer * aLayer )
2011-05-16 16:05:56 -07:00
{
ThebesLayerItemsEntry * entry = mThebesLayerItems . PutEntry ( aLayer ) ;
if ( entry ) {
2012-09-11 14:17:26 -07:00
if ( entry - > mContainerLayerGeneration = = 0 ) {
entry - > mContainerLayerGeneration = mContainerLayerGeneration ;
}
2011-05-17 22:48:43 -07:00
entry - > mLastPaintOffset = GetTranslationForThebesLayer ( aLayer ) ;
2011-10-17 07:59:28 -07:00
entry - > mHasExplicitLastPaintOffset = true ;
2011-05-16 16:05:56 -07:00
}
}
2010-07-15 14:07:51 -07:00
void
2010-07-15 14:08:03 -07:00
ContainerState : : CollectOldLayers ( )
2010-07-15 14:07:51 -07:00
{
for ( Layer * layer = mContainerLayer - > GetFirstChild ( ) ; layer ;
layer = layer - > GetNextSibling ( ) ) {
2012-02-07 14:26:40 -08:00
NS_ASSERTION ( ! layer - > HasUserData ( & gMaskLayerUserData ) ,
" Mask layer in layer tree; could not be recycled. " ) ;
2012-08-20 03:00:49 -07:00
if ( layer - > HasUserData ( & gThebesDisplayItemLayerUserData ) ) {
2010-07-15 14:08:03 -07:00
NS_ASSERTION ( layer - > AsThebesLayer ( ) , " Wrong layer type " ) ;
mRecycledThebesLayers . AppendElement ( static_cast < ThebesLayer * > ( layer ) ) ;
2010-07-15 14:07:51 -07:00
}
2012-02-07 14:26:40 -08:00
if ( Layer * maskLayer = layer - > GetMaskLayer ( ) ) {
NS_ASSERTION ( maskLayer - > GetType ( ) = = Layer : : TYPE_IMAGE ,
" Could not recycle mask layer, unsupported layer type. " ) ;
mRecycledMaskImageLayers . Put ( layer , static_cast < ImageLayer * > ( maskLayer ) ) ;
}
2010-07-15 14:07:51 -07:00
}
}
void
2012-08-28 22:47:15 -07:00
ContainerState : : Finish ( uint32_t * aTextContentFlags , LayerManagerData * aData )
2010-07-15 14:07:51 -07:00
{
while ( ! mThebesLayerDataStack . IsEmpty ( ) ) {
PopThebesLayerData ( ) ;
}
2012-10-11 16:38:24 -07:00
2012-08-22 08:56:38 -07:00
uint32_t textContentFlags = 0 ;
2010-12-19 17:26:14 -08:00
2012-08-29 03:53:06 -07:00
// Make sure that current/existing layers are added to the parent and are
// in the correct order.
Layer * layer = nullptr ;
for ( uint32_t i = 0 ; i < mNewChildLayers . Length ( ) ; + + i ) {
Layer * prevChild = i = = 0 ? nullptr : mNewChildLayers [ i - 1 ] . get ( ) ;
layer = mNewChildLayers [ i ] ;
2012-10-11 16:38:24 -07:00
2012-08-29 03:53:06 -07:00
if ( ! layer - > GetVisibleRegion ( ) . IsEmpty ( ) ) {
textContentFlags | = layer - > GetContentFlags ( ) & Layer : : CONTENT_COMPONENT_ALPHA ;
2010-07-15 14:07:51 -07:00
}
2012-08-29 03:53:06 -07:00
if ( ! layer - > GetParent ( ) ) {
// This is not currently a child of the container, so just add it
// now.
mContainerLayer - > InsertAfter ( layer , prevChild ) ;
continue ;
2010-07-15 14:07:51 -07:00
}
2012-08-29 03:53:06 -07:00
NS_ASSERTION ( layer - > GetParent ( ) = = mContainerLayer ,
" Layer shouldn't be the child of some other container " ) ;
mContainerLayer - > RepositionChild ( layer , prevChild ) ;
}
// Remove old layers that have become unused.
if ( ! layer ) {
layer = mContainerLayer - > GetFirstChild ( ) ;
} else {
layer = layer - > GetNextSibling ( ) ;
}
while ( layer ) {
Layer * layerToRemove = layer ;
layer = layer - > GetNextSibling ( ) ;
mContainerLayer - > RemoveChild ( layerToRemove ) ;
2010-07-15 14:07:51 -07:00
}
2010-12-19 17:26:14 -08:00
* aTextContentFlags = textContentFlags ;
2010-07-15 14:07:51 -07:00
}
2010-05-20 20:20:48 -07:00
2011-06-22 05:11:27 -07:00
static FrameLayerBuilder : : ContainerParameters
ChooseScaleAndSetTransform ( FrameLayerBuilder * aLayerBuilder ,
2012-09-16 15:25:33 -07:00
nsDisplayListBuilder * aDisplayListBuilder ,
2011-06-22 05:11:27 -07:00
nsIFrame * aContainerFrame ,
const gfx3DMatrix * aTransform ,
const FrameLayerBuilder : : ContainerParameters & aIncomingScale ,
2012-09-16 15:25:33 -07:00
ContainerLayer * aLayer ,
LayerState aState )
2011-06-22 05:11:27 -07:00
{
2012-09-16 15:25:33 -07:00
nsIntPoint offset ;
2011-06-22 05:11:27 -07:00
gfx3DMatrix transform =
2011-08-26 17:06:03 -07:00
gfx3DMatrix : : ScalingMatrix ( aIncomingScale . mXScale , aIncomingScale . mYScale , 1.0 ) ;
2011-06-22 05:11:27 -07:00
if ( aTransform ) {
// aTransform is applied first, then the scale is applied to the result
transform = ( * aTransform ) * transform ;
2012-08-24 21:41:46 -07:00
// Set any matrix entries close to integers to be those exact integers.
// This protects against floating-point inaccuracies causing problems
// in the checks below.
transform . NudgeToIntegers ( ) ;
2012-12-03 22:04:20 -08:00
}
gfxMatrix transform2d ;
if ( aContainerFrame & &
aState = = LAYER_INACTIVE & &
( ! aTransform | | ( aTransform - > Is2D ( & transform2d ) & &
! transform2d . HasNonTranslation ( ) ) ) ) {
2012-09-16 15:25:33 -07:00
// When we have an inactive ContainerLayer, translate the container by the offset to the
// reference frame (and offset all child layers by the reverse) so that the coordinate
// space of the child layers isn't affected by scrolling.
2012-12-03 22:04:20 -08:00
// This gets confusing for complicated transform (since we'd have to compute the scale
// factors for the matrix), so we don't bother. Any frames that are building an nsDisplayTransform
// for a css transform would have 0,0 as their offset to the reference frame, so this doesn't
// matter.
2012-09-16 15:25:33 -07:00
nsPoint appUnitOffset = aDisplayListBuilder - > ToReferenceFrame ( aContainerFrame ) ;
nscoord appUnitsPerDevPixel = aContainerFrame - > PresContext ( ) - > AppUnitsPerDevPixel ( ) ;
offset = nsIntPoint (
int32_t ( NSAppUnitsToDoublePixels ( appUnitOffset . x , appUnitsPerDevPixel ) * aIncomingScale . mXScale ) ,
int32_t ( NSAppUnitsToDoublePixels ( appUnitOffset . y , appUnitsPerDevPixel ) * aIncomingScale . mYScale ) ) ;
}
2012-12-17 21:58:44 -08:00
transform = transform * gfx3DMatrix : : Translation ( offset . x + aIncomingScale . mOffset . x , offset . y + aIncomingScale . mOffset . y , 0 ) ;
2012-12-03 22:04:20 -08:00
2011-06-22 05:11:27 -07:00
2012-02-23 10:03:27 -08:00
bool canDraw2D = transform . CanDraw2D ( & transform2d ) ;
2011-06-22 05:11:27 -07:00
gfxSize scale ;
2012-11-13 14:22:21 -08:00
bool isRetained = aLayer - > Manager ( ) - > IsWidgetLayerManager ( ) ;
2011-06-22 05:11:27 -07:00
// Only fiddle with scale factors for the retaining layer manager, since
// it only matters for retained layers
2012-01-11 03:26:33 -08:00
// XXX Should we do something for 3D transforms?
2012-02-23 10:03:27 -08:00
if ( canDraw2D & & isRetained ) {
2012-12-21 13:58:17 -08:00
// If the container's transform is animated off main thread, then use the
// maximum scale.
if ( aContainerFrame - > GetContent ( ) & &
nsLayoutUtils : : HasAnimationsForCompositor (
aContainerFrame - > GetContent ( ) , eCSSProperty_transform ) ) {
scale = nsLayoutUtils : : GetMaximumAnimatedScale ( aContainerFrame - > GetContent ( ) ) ;
} else {
//Scale factors are normalized to a power of 2 to reduce the number of resolution changes
scale = transform2d . ScaleFactors ( true ) ;
// For frames with a changing transform that's not just a translation,
// round scale factors up to nearest power-of-2 boundary so that we don't
// keep having to redraw the content as it scales up and down. Rounding up to nearest
// power-of-2 boundary ensures we never scale up, only down --- avoiding
// jaggies. It also ensures we never scale down by more than a factor of 2,
// avoiding bad downscaling quality.
gfxMatrix frameTransform ;
if ( aContainerFrame - > AreLayersMarkedActive ( nsChangeHint_UpdateTransformLayer ) & &
aTransform & &
( ! aTransform - > Is2D ( & frameTransform ) | | frameTransform . HasNonTranslationOrFlip ( ) ) ) {
// Don't clamp the scale factor when the new desired scale factor matches the old one
// or it was previously unscaled.
bool clamp = true ;
gfxMatrix oldFrameTransform2d ;
if ( aLayer - > GetBaseTransform ( ) . Is2D ( & oldFrameTransform2d ) ) {
gfxSize oldScale = oldFrameTransform2d . ScaleFactors ( true ) ;
if ( oldScale = = scale | | oldScale = = gfxSize ( 1.0 , 1.0 ) ) {
clamp = false ;
}
2012-12-06 15:58:12 -08:00
}
2012-12-21 13:58:17 -08:00
if ( clamp ) {
scale . width = gfxUtils : : ClampToScaleFactor ( scale . width ) ;
scale . height = gfxUtils : : ClampToScaleFactor ( scale . height ) ;
}
} else {
// XXX Do we need to move nearly-integer values to integers here?
2011-12-07 15:12:41 -08:00
}
2011-06-22 05:11:27 -07:00
}
// If the scale factors are too small, just use 1.0. The content is being
// scaled out of sight anyway.
2011-06-22 05:11:28 -07:00
if ( fabs ( scale . width ) < 1e-8 | | fabs ( scale . height ) < 1e-8 ) {
2012-04-29 14:41:13 -07:00
scale = gfxSize ( 1.0 , 1.0 ) ;
2011-06-22 05:11:27 -07:00
}
} else {
scale = gfxSize ( 1.0 , 1.0 ) ;
}
2012-08-03 14:29:22 -07:00
// Store the inverse of our resolution-scale on the layer
2012-07-30 19:20:00 -07:00
aLayer - > SetBaseTransform ( transform ) ;
2012-08-03 14:29:22 -07:00
aLayer - > SetPreScale ( 1.0f / float ( scale . width ) ,
1.0f / float ( scale . height ) ) ;
2013-01-08 01:39:12 -08:00
aLayer - > SetInheritedScale ( aIncomingScale . mXScale ,
aIncomingScale . mYScale ) ;
2011-06-22 05:11:28 -07:00
FrameLayerBuilder : : ContainerParameters
2012-09-16 15:25:33 -07:00
result ( scale . width , scale . height , - offset , aIncomingScale ) ;
2011-06-22 05:11:28 -07:00
if ( aTransform ) {
result . mInTransformedSubtree = true ;
if ( aContainerFrame - > AreLayersMarkedActive ( nsChangeHint_UpdateTransformLayer ) ) {
result . mInActiveTransformedSubtree = true ;
}
}
2012-02-23 10:03:27 -08:00
if ( isRetained & & ( ! canDraw2D | | transform2d . HasNonIntegerTranslation ( ) ) ) {
2012-01-11 03:26:33 -08:00
result . mDisableSubpixelAntialiasingInDescendants = true ;
}
2011-06-22 05:11:28 -07:00
return result ;
2011-06-22 05:11:27 -07:00
}
2012-07-22 20:00:36 -07:00
/* static */ PLDHashOperator
2012-10-11 19:39:46 -07:00
FrameLayerBuilder : : RestoreDisplayItemData ( nsRefPtrHashKey < DisplayItemData > * aEntry , void * aUserArg )
2012-07-22 20:00:36 -07:00
{
2012-10-11 19:39:46 -07:00
DisplayItemData * data = aEntry - > GetKey ( ) ;
2012-08-22 08:56:38 -07:00
uint32_t * generation = static_cast < uint32_t * > ( aUserArg ) ;
2012-07-22 20:00:36 -07:00
2012-10-11 19:39:46 -07:00
if ( data - > mUsed & & data - > mContainerLayerGeneration > = * generation ) {
2012-07-22 20:00:36 -07:00
return PL_DHASH_REMOVE ;
}
return PL_DHASH_NEXT ;
}
/* static */ PLDHashOperator
FrameLayerBuilder : : RestoreThebesLayerItemEntries ( ThebesLayerItemsEntry * aEntry , void * aUserArg )
{
2012-08-22 08:56:38 -07:00
uint32_t * generation = static_cast < uint32_t * > ( aUserArg ) ;
2012-07-22 20:00:36 -07:00
if ( aEntry - > mContainerLayerGeneration > = * generation ) {
2012-10-11 19:39:46 -07:00
// We can just remove these items rather than attempting to revert them
// because we're going to want to invalidate everything when transitioning
// to component alpha flattening.
2012-07-22 20:00:36 -07:00
return PL_DHASH_REMOVE ;
}
2012-08-22 08:56:38 -07:00
for ( uint32_t i = 0 ; i < aEntry - > mItems . Length ( ) ; i + + ) {
2012-07-22 20:00:36 -07:00
if ( aEntry - > mItems [ i ] . mContainerLayerGeneration > = * generation ) {
aEntry - > mItems . TruncateLength ( i ) ;
return PL_DHASH_NEXT ;
}
}
return PL_DHASH_NEXT ;
}
2010-09-03 13:10:45 -07:00
already_AddRefed < ContainerLayer >
2010-07-15 14:07:51 -07:00
FrameLayerBuilder : : BuildContainerLayerFor ( nsDisplayListBuilder * aBuilder ,
LayerManager * aManager ,
nsIFrame * aContainerFrame ,
nsDisplayItem * aContainerItem ,
2011-06-22 05:11:27 -07:00
const nsDisplayList & aChildren ,
const ContainerParameters & aParameters ,
const gfx3DMatrix * aTransform )
2010-07-15 14:07:51 -07:00
{
2012-08-22 08:56:38 -07:00
uint32_t containerDisplayItemKey =
2012-11-19 02:54:50 -08:00
aContainerItem ? aContainerItem - > GetPerFrameKey ( ) : nsDisplayItem : : TYPE_ZERO ;
2010-07-15 14:07:51 -07:00
NS_ASSERTION ( aContainerFrame , " Container display items here should have a frame " ) ;
NS_ASSERTION ( ! aContainerItem | |
aContainerItem - > GetUnderlyingFrame ( ) = = aContainerFrame ,
" Container display item must match given frame " ) ;
2013-03-05 12:04:40 -08:00
if ( ! aParameters . mXScale | | ! aParameters . mYScale ) {
return nullptr ;
}
2010-07-15 14:07:51 -07:00
nsRefPtr < ContainerLayer > containerLayer ;
2012-07-03 17:24:55 -07:00
if ( aManager = = mRetainingManager ) {
2012-08-29 03:53:27 -07:00
// Using GetOldLayerFor will search merged frames, as well as the underlying
// frame. The underlying frame can change when a page scrolls, so this
// avoids layer recreation in the situation that a new underlying frame is
// picked for a layer.
2012-08-28 22:47:15 -07:00
Layer * oldLayer = nullptr ;
if ( aContainerItem ) {
oldLayer = GetOldLayerFor ( aContainerItem ) ;
} else {
DisplayItemData * data = GetOldLayerForFrame ( aContainerFrame , containerDisplayItemKey ) ;
if ( data ) {
oldLayer = data - > mLayer ;
}
}
2012-08-29 03:53:20 -07:00
2012-07-03 17:24:55 -07:00
if ( oldLayer ) {
NS_ASSERTION ( oldLayer - > Manager ( ) = = aManager , " Wrong manager " ) ;
if ( oldLayer - > HasUserData ( & gThebesDisplayItemLayerUserData ) ) {
// The old layer for this item is actually our ThebesLayer
// because we rendered its layer into that ThebesLayer. So we
// don't actually have a retained container layer.
} else {
NS_ASSERTION ( oldLayer - > GetType ( ) = = Layer : : TYPE_CONTAINER ,
" Wrong layer type " ) ;
containerLayer = static_cast < ContainerLayer * > ( oldLayer ) ;
// Clear clip rect; the caller will set it if necessary.
2012-07-30 07:20:58 -07:00
containerLayer - > SetClipRect ( nullptr ) ;
containerLayer - > SetMaskLayer ( nullptr ) ;
2012-07-03 17:24:55 -07:00
}
2010-07-15 14:07:51 -07:00
}
}
if ( ! containerLayer ) {
// No suitable existing layer was found.
containerLayer = aManager - > CreateContainerLayer ( ) ;
if ( ! containerLayer )
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-07-15 14:07:51 -07:00
}
2010-05-20 20:20:48 -07:00
2012-09-16 15:25:33 -07:00
LayerState state = aContainerItem ? aContainerItem - > GetLayerState ( aBuilder , aManager , aParameters ) : LAYER_ACTIVE ;
2012-11-22 15:29:05 -08:00
if ( state = = LAYER_INACTIVE & &
nsDisplayItem : : ForceActiveLayers ( ) ) {
state = LAYER_ACTIVE ;
}
2012-09-16 15:25:33 -07:00
if ( aContainerItem & & state = = LAYER_ACTIVE_EMPTY ) {
2011-05-18 15:54:31 -07:00
// Empty layers only have metadata and should never have display items. We
// early exit because later, invalidation will walk up the frame tree to
// determine which thebes layer gets invalidated. Since an empty layer
// should never have anything to paint, it should never be invalidated.
NS_ASSERTION ( aChildren . IsEmpty ( ) , " Should have no children " ) ;
return containerLayer . forget ( ) ;
}
2011-06-22 05:11:27 -07:00
ContainerParameters scaleParameters =
2012-09-16 15:25:33 -07:00
ChooseScaleAndSetTransform ( this , aBuilder , aContainerFrame , aTransform , aParameters ,
containerLayer , state ) ;
2010-05-20 20:20:48 -07:00
2012-08-22 08:56:38 -07:00
uint32_t oldGeneration = mContainerLayerGeneration ;
2012-07-22 20:00:36 -07:00
mContainerLayerGeneration = + + mMaxContainerLayerGeneration ;
2012-07-30 07:20:58 -07:00
nsRefPtr < RefCountedRegion > thebesLayerInvalidRegion = nullptr ;
2012-08-28 22:47:15 -07:00
if ( mRetainingManager ) {
2012-10-11 16:38:24 -07:00
if ( aContainerItem ) {
2012-10-11 19:39:46 -07:00
StoreDataForFrame ( aContainerItem , containerLayer , LAYER_ACTIVE ) ;
} else {
StoreDataForFrame ( aContainerFrame , containerDisplayItemKey , containerLayer , LAYER_ACTIVE ) ;
2012-10-11 16:38:24 -07:00
}
2012-07-22 20:00:36 -07:00
}
2012-10-11 19:39:46 -07:00
LayerManagerData * data = static_cast < LayerManagerData * >
( aManager - > GetUserData ( & gLayerManagerUserData ) ) ;
2012-07-22 20:00:36 -07:00
nsRect bounds ;
nsIntRect pixBounds ;
2012-08-22 08:56:38 -07:00
int32_t appUnitsPerDevPixel ;
2012-11-21 21:34:32 -08:00
uint32_t stateFlags = 0 ;
if ( ( aContainerFrame - > GetStateBits ( ) & NS_FRAME_NO_COMPONENT_ALPHA ) & &
mRetainingManager & & ! mRetainingManager - > AreComponentAlphaLayersEnabled ( ) ) {
stateFlags = ContainerState : : NO_COMPONENT_ALPHA ;
}
2012-08-22 08:56:38 -07:00
uint32_t flags ;
2012-07-22 20:00:36 -07:00
while ( true ) {
2012-08-20 21:06:46 -07:00
ContainerState state ( aBuilder , aManager , aManager - > GetLayerBuilder ( ) ,
2012-09-28 04:19:39 -07:00
aContainerFrame , aContainerItem ,
containerLayer , scaleParameters ) ;
2012-08-28 22:47:15 -07:00
2012-07-22 20:00:36 -07:00
Clip clip ;
state . ProcessDisplayItems ( aChildren , clip , stateFlags ) ;
2012-08-03 14:29:22 -07:00
2012-07-22 20:00:36 -07:00
// Set CONTENT_COMPONENT_ALPHA if any of our children have it.
// This is suboptimal ... a child could have text that's over transparent
// pixels in its own layer, but over opaque parts of previous siblings.
2012-08-28 22:47:15 -07:00
state . Finish ( & flags , data ) ;
2012-07-22 20:00:36 -07:00
bounds = state . GetChildrenBounds ( ) ;
pixBounds = state . ScaleToOutsidePixels ( bounds , false ) ;
appUnitsPerDevPixel = state . GetAppUnitsPerDevPixel ( ) ;
if ( ( flags & Layer : : CONTENT_COMPONENT_ALPHA ) & &
mRetainingManager & &
! mRetainingManager - > AreComponentAlphaLayersEnabled ( ) & &
! stateFlags ) {
// Since we don't want any component alpha layers on BasicLayers, we repeat
// the layer building process with this explicitely forced off.
// We restore the previous FrameLayerBuilder state since the first set
// of layer building will have changed it.
stateFlags = ContainerState : : NO_COMPONENT_ALPHA ;
2012-10-11 19:39:46 -07:00
data - > mDisplayItems . EnumerateEntries ( RestoreDisplayItemData ,
2012-07-22 20:00:36 -07:00
& mContainerLayerGeneration ) ;
mThebesLayerItems . EnumerateEntries ( RestoreThebesLayerItemEntries ,
& mContainerLayerGeneration ) ;
aContainerFrame - > AddStateBits ( NS_FRAME_NO_COMPONENT_ALPHA ) ;
continue ;
}
break ;
}
2010-12-19 17:26:14 -08:00
2011-04-18 20:07:23 -07:00
NS_ASSERTION ( bounds . IsEqualInterior ( aChildren . GetBounds ( aBuilder ) ) , " Wrong bounds " ) ;
2012-09-16 15:25:33 -07:00
pixBounds . MoveBy ( nsIntPoint ( scaleParameters . mOffset . x , scaleParameters . mOffset . y ) ) ;
2012-07-03 17:24:55 -07:00
containerLayer - > SetVisibleRegion ( pixBounds ) ;
2011-02-22 21:38:09 -08:00
// Make sure that rounding the visible region out didn't add any area
// we won't paint
2011-06-22 05:11:27 -07:00
if ( aChildren . IsOpaque ( ) & & ! aChildren . NeedsTransparentSurface ( ) ) {
bounds . ScaleRoundIn ( scaleParameters . mXScale , scaleParameters . mYScale ) ;
2012-07-22 20:00:36 -07:00
if ( bounds . Contains ( pixBounds . ToAppUnits ( appUnitsPerDevPixel ) ) ) {
2011-06-22 05:11:27 -07:00
// Clear CONTENT_COMPONENT_ALPHA
flags = Layer : : CONTENT_OPAQUE ;
}
2010-12-19 17:26:14 -08:00
}
2010-09-02 02:18:40 -07:00
containerLayer - > SetContentFlags ( flags ) ;
2010-12-19 17:26:14 -08:00
2012-07-22 20:00:36 -07:00
mContainerLayerGeneration = oldGeneration ;
2012-08-28 22:47:18 -07:00
containerLayer - > SetUserData ( & gNotifySubDocInvalidationData , nullptr ) ;
2010-08-05 15:11:23 -07:00
return containerLayer . forget ( ) ;
2010-05-20 20:20:48 -07:00
}
2010-07-15 14:07:46 -07:00
Layer *
FrameLayerBuilder : : GetLeafLayerFor ( nsDisplayListBuilder * aBuilder ,
nsDisplayItem * aItem )
{
2012-10-09 22:00:05 -07:00
NS_ASSERTION ( aItem - > GetUnderlyingFrame ( ) ,
" Can only call GetLeafLayerFor on items that have a frame " ) ;
2012-08-28 22:47:15 -07:00
Layer * layer = GetOldLayerFor ( aItem ) ;
2010-07-15 14:07:51 -07:00
if ( ! layer )
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-09-02 02:18:39 -07:00
if ( layer - > HasUserData ( & gThebesDisplayItemLayerUserData ) ) {
2010-07-15 14:07:51 -07:00
// This layer was created to render Thebes-rendered content for this
// display item. The display item should not use it for its own
// layer rendering.
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-07-15 14:07:51 -07:00
}
// Clear clip rect; the caller is responsible for setting it.
2012-07-30 07:20:58 -07:00
layer - > SetClipRect ( nullptr ) ;
layer - > SetMaskLayer ( nullptr ) ;
2010-07-15 14:07:51 -07:00
return layer ;
2010-07-15 14:07:46 -07:00
}
2012-09-27 08:34:46 -07:00
/* static */ void
FrameLayerBuilder : : InvalidateAllLayers ( LayerManager * aManager )
{
LayerManagerData * data = static_cast < LayerManagerData * >
( aManager - > GetUserData ( & gLayerManagerUserData ) ) ;
2012-08-28 22:48:45 -07:00
if ( data ) {
data - > mInvalidateAllLayers = true ;
}
}
2012-08-28 22:48:45 -07:00
/* static */ void
FrameLayerBuilder : : InvalidateAllLayersForFrame ( nsIFrame * aFrame )
{
2012-10-11 16:38:24 -07:00
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aFrame - > Properties ( ) . Get ( LayerManagerDataProperty ( ) ) ) ;
if ( array ) {
for ( uint32_t i = 0 ; i < array - > Length ( ) ; i + + ) {
array - > ElementAt ( i ) - > mParent - > mInvalidateAllLayers = true ;
}
2012-08-28 22:48:45 -07:00
}
}
2010-07-15 14:07:53 -07:00
/* static */
2011-03-27 16:59:47 -07:00
Layer *
2012-08-22 08:56:38 -07:00
FrameLayerBuilder : : GetDedicatedLayer ( nsIFrame * aFrame , uint32_t aDisplayItemKey )
2010-07-15 14:07:53 -07:00
{
2012-08-28 22:48:41 -07:00
//TODO: This isn't completely correct, since a frame could exist as a layer
// in the normal widget manager, and as a different layer (or no layer)
// in the secondary manager
2012-10-11 16:38:24 -07:00
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aFrame - > Properties ( ) . Get ( LayerManagerDataProperty ( ) ) ) ;
if ( array ) {
for ( uint32_t i = 0 ; i < array - > Length ( ) ; i + + ) {
2012-10-11 19:39:46 -07:00
DisplayItemData * element = array - > ElementAt ( i ) ;
if ( ! element - > mParent - > mLayerManager - > IsWidgetLayerManager ( ) ) {
continue ;
}
if ( element - > mDisplayItemKey = = aDisplayItemKey ) {
if ( element - > mOptLayer ) {
return element - > mOptLayer ;
2012-10-11 16:38:24 -07:00
}
2012-09-24 13:31:30 -07:00
2012-10-11 19:39:46 -07:00
Layer * layer = element - > mLayer ;
2012-10-11 16:38:24 -07:00
if ( ! layer - > HasUserData ( & gColorLayerUserData ) & &
! layer - > HasUserData ( & gImageLayerUserData ) & &
! layer - > HasUserData ( & gThebesDisplayItemLayerUserData ) ) {
return layer ;
}
}
}
2010-07-15 14:07:53 -07:00
}
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-07-15 14:07:53 -07:00
}
2012-08-04 05:26:38 -07:00
static gfxSize
PredictScaleForContent ( nsIFrame * aFrame , nsIFrame * aAncestorWithScale ,
const gfxSize & aScale )
2012-05-09 22:24:18 -07:00
{
2012-08-04 05:26:38 -07:00
gfx3DMatrix transform =
gfx3DMatrix : : ScalingMatrix ( aScale . width , aScale . height , 1.0 ) ;
2012-11-11 00:17:16 -08:00
if ( aFrame ! = aAncestorWithScale ) {
// aTransform is applied first, then the scale is applied to the result
transform = nsLayoutUtils : : GetTransformToAncestor ( aFrame , aAncestorWithScale ) * transform ;
}
2012-08-04 05:26:38 -07:00
gfxMatrix transform2d ;
if ( transform . CanDraw2D ( & transform2d ) ) {
return transform2d . ScaleFactors ( true ) ;
}
return gfxSize ( 1.0 , 1.0 ) ;
}
gfxSize
FrameLayerBuilder : : GetThebesLayerScaleForFrame ( nsIFrame * aFrame )
{
nsIFrame * last ;
for ( nsIFrame * f = aFrame ; f ; f = nsLayoutUtils : : GetCrossDocParentFrame ( f ) ) {
last = f ;
2012-11-11 00:17:16 -08:00
if ( nsLayoutUtils : : IsPopup ( f ) ) {
// Don't examine ancestors of a popup. It won't make sense to check
// the transform from some content inside the popup to some content
// which is an ancestor of the popup.
break ;
}
2012-10-11 16:38:24 -07:00
nsTArray < DisplayItemData * > * array =
reinterpret_cast < nsTArray < DisplayItemData * > * > ( aFrame - > Properties ( ) . Get ( LayerManagerDataProperty ( ) ) ) ;
if ( ! array ) {
2012-08-28 22:48:41 -07:00
continue ;
2012-10-11 16:38:24 -07:00
}
for ( uint32_t i = 0 ; i < array - > Length ( ) ; i + + ) {
2012-08-28 22:47:15 -07:00
Layer * layer = array - > ElementAt ( i ) - > mLayer ;
ContainerLayer * container = layer - > AsContainerLayer ( ) ;
2012-10-11 16:38:24 -07:00
if ( ! container | |
! layer - > Manager ( ) - > IsWidgetLayerManager ( ) ) {
2012-08-28 22:47:15 -07:00
continue ;
}
for ( Layer * l = container - > GetFirstChild ( ) ; l ; l = l - > GetNextSibling ( ) ) {
ThebesDisplayItemLayerUserData * data =
static_cast < ThebesDisplayItemLayerUserData * >
( l - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
if ( data ) {
return PredictScaleForContent ( aFrame , f , gfxSize ( data - > mXScale , data - > mYScale ) ) ;
2012-08-04 05:26:38 -07:00
}
2012-08-05 06:35:08 -07:00
}
}
}
2012-08-04 05:26:38 -07:00
return PredictScaleForContent ( aFrame , last ,
last - > PresContext ( ) - > PresShell ( ) - > GetResolution ( ) ) ;
2012-05-09 22:24:18 -07:00
}
2012-03-05 10:09:05 -08:00
# ifdef MOZ_DUMP_PAINTING
static void DebugPaintItem ( nsRenderingContext * aDest , nsDisplayItem * aItem , nsDisplayListBuilder * aBuilder )
{
2012-04-10 04:24:18 -07:00
bool snap ;
nsRect appUnitBounds = aItem - > GetBounds ( aBuilder , & snap ) ;
2012-03-05 10:09:05 -08:00
gfxRect bounds ( appUnitBounds . x , appUnitBounds . y , appUnitBounds . width , appUnitBounds . height ) ;
bounds . ScaleInverse ( aDest - > AppUnitsPerDevPixel ( ) ) ;
2012-07-31 10:28:21 -07:00
nsRefPtr < gfxASurface > surf =
gfxPlatform : : GetPlatform ( ) - > CreateOffscreenSurface ( gfxIntSize ( bounds . width , bounds . height ) ,
2012-03-05 10:09:05 -08:00
gfxASurface : : CONTENT_COLOR_ALPHA ) ;
surf - > SetDeviceOffset ( - bounds . TopLeft ( ) ) ;
nsRefPtr < gfxContext > context = new gfxContext ( surf ) ;
nsRefPtr < nsRenderingContext > ctx = new nsRenderingContext ( ) ;
ctx - > Init ( aDest - > DeviceContext ( ) , context ) ;
aItem - > Paint ( aBuilder , ctx ) ;
DumpPaintedImage ( aItem , surf ) ;
aItem - > SetPainted ( ) ;
2012-07-31 10:28:21 -07:00
2012-03-05 10:09:05 -08:00
surf - > SetDeviceOffset ( gfxPoint ( 0 , 0 ) ) ;
aDest - > ThebesContext ( ) - > SetSource ( surf , bounds . TopLeft ( ) ) ;
aDest - > ThebesContext ( ) - > Rectangle ( bounds ) ;
aDest - > ThebesContext ( ) - > Fill ( ) ;
}
# endif
2011-06-22 05:11:28 -07:00
/*
* A note on residual transforms :
*
* In a transformed subtree we sometimes apply the ThebesLayer ' s
* " residual transform " when drawing content into the ThebesLayer .
* This is a translation by components in the range [ - 0.5 , 0.5 ) provided
* by the layer system ; applying the residual transform followed by the
* transforms used by layer compositing ensures that the subpixel alignment
* of the content of the ThebesLayer exactly matches what it would be if
* we used cairo / Thebes to draw directly to the screen without going through
* retained layer buffers .
*
* The visible and valid regions of the ThebesLayer are computed without
* knowing the residual transform ( because we don ' t know what the residual
* transform is going to be until we ' ve built the layer tree ! ) . So we have to
* consider whether content painted in the range [ x , xmost ) might be painted
* outside the visible region we computed for that content . The visible region
* would be [ floor ( x ) , ceil ( xmost ) ) . The content would be rendered at
* [ x + r , xmost + r ) , where - 0.5 < = r < 0.5 . So some half - rendered pixels could
* indeed fall outside the computed visible region , which is not a big deal ;
* similar issues already arise when we snap cliprects to nearest pixels .
* Note that if the rendering of the content is snapped to nearest pixels - - -
* which it often is - - - then the content is actually rendered at
* [ snap ( x + r ) , snap ( xmost + r ) ) . It turns out that floor ( x ) < = snap ( x + r )
* and ceil ( xmost ) > = snap ( xmost + r ) , so the rendering of snapped content
* always falls within the visible region we computed .
*/
2010-05-20 20:20:48 -07:00
/* static */ void
FrameLayerBuilder : : DrawThebesLayer ( ThebesLayer * aLayer ,
gfxContext * aContext ,
const nsIntRegion & aRegionToDraw ,
2010-03-03 13:37:04 -08:00
const nsIntRegion & aRegionToInvalidate ,
2010-05-20 20:20:48 -07:00
void * aCallbackData )
{
2011-12-02 14:05:33 -08:00
SAMPLE_LABEL ( " gfx " , " DrawThebesLayer " ) ;
2010-07-15 14:07:51 -07:00
nsDisplayListBuilder * builder = static_cast < nsDisplayListBuilder * >
( aCallbackData ) ;
2010-09-17 12:09:08 -07:00
2012-08-20 21:06:46 -07:00
FrameLayerBuilder * layerBuilder = aLayer - > Manager ( ) - > GetLayerBuilder ( ) ;
2012-10-23 04:05:29 -07:00
NS_ASSERTION ( layerBuilder , " Unexpectedly null layer builder! " ) ;
2012-07-17 10:03:51 -07:00
if ( layerBuilder - > CheckDOMModified ( ) )
2010-09-17 12:09:08 -07:00
return ;
2010-07-15 14:08:10 -07:00
nsTArray < ClippedDisplayItem > items ;
2012-08-22 08:56:38 -07:00
uint32_t commonClipCount ;
2010-07-15 14:08:10 -07:00
nsIFrame * containerLayerFrame ;
{
2012-07-17 10:03:51 -07:00
ThebesLayerItemsEntry * entry = layerBuilder - > mThebesLayerItems . GetEntry ( aLayer ) ;
2010-07-15 14:08:10 -07:00
NS_ASSERTION ( entry , " We shouldn't be drawing into a layer with no items! " ) ;
items . SwapElements ( entry - > mItems ) ;
2012-02-07 14:27:44 -08:00
commonClipCount = entry - > mCommonClipCount ;
2010-07-15 14:08:10 -07:00
containerLayerFrame = entry - > mContainerLayerFrame ;
// Later after this point, due to calls to DidEndTransaction
// for temporary layer managers, mThebesLayerItems can change,
// so 'entry' could become invalid.
}
2010-03-03 13:37:04 -08:00
2012-07-24 14:39:01 -07:00
if ( ! containerLayerFrame ) {
return ;
}
2010-09-02 02:18:39 -07:00
ThebesDisplayItemLayerUserData * userData =
static_cast < ThebesDisplayItemLayerUserData * >
( aLayer - > GetUserData ( & gThebesDisplayItemLayerUserData ) ) ;
NS_ASSERTION ( userData , " where did our user data go? " ) ;
if ( NS_GET_A ( userData - > mForcedBackgroundColor ) > 0 ) {
2011-01-04 02:35:57 -08:00
nsIntRect r = aLayer - > GetVisibleRegion ( ) . GetBounds ( ) ;
aContext - > NewPath ( ) ;
aContext - > Rectangle ( gfxRect ( r . x , r . y , r . width , r . height ) ) ;
2010-09-02 02:18:39 -07:00
aContext - > SetColor ( gfxRGBA ( userData - > mForcedBackgroundColor ) ) ;
2011-01-04 02:35:57 -08:00
aContext - > Fill ( ) ;
2010-09-02 02:18:39 -07:00
}
2010-07-15 14:07:51 -07:00
// make the origin of the context coincide with the origin of the
// ThebesLayer
2011-05-17 22:48:43 -07:00
gfxContextMatrixAutoSaveRestore saveMatrix ( aContext ) ;
nsIntPoint offset = GetTranslationForThebesLayer ( aLayer ) ;
2011-06-22 05:11:28 -07:00
// Apply the residual transform if it has been enabled, to ensure that
// snapping when we draw into aContext exactly matches the ideal transform.
// See above for why this is OK.
aContext - > Translate ( aLayer - > GetResidualTranslation ( ) - gfxPoint ( offset . x , offset . y ) ) ;
2011-06-22 05:11:28 -07:00
aContext - > Scale ( userData - > mXScale , userData - > mYScale ) ;
2010-05-20 20:20:48 -07:00
2010-07-15 14:08:10 -07:00
nsPresContext * presContext = containerLayerFrame - > PresContext ( ) ;
2012-08-22 08:56:38 -07:00
int32_t appUnitsPerDevPixel = presContext - > AppUnitsPerDevPixel ( ) ;
2010-05-20 20:20:48 -07:00
2012-08-22 08:56:38 -07:00
uint32_t i ;
2012-12-13 14:50:57 -08:00
// Update visible regions. We need perform visibility analysis again
// because we may be asked to draw into part of a ThebesLayer that
// isn't actually visible in the window (e.g., because a ThebesLayer
// expanded its visible region to a rectangle internally), in which
// case the mVisibleRect stored in the display item may be wrong.
nsRegion visible = aRegionToDraw . ToAppUnits ( appUnitsPerDevPixel ) ;
2010-07-15 14:07:51 -07:00
visible . MoveBy ( NSIntPixelsToAppUnits ( offset . x , appUnitsPerDevPixel ) ,
NSIntPixelsToAppUnits ( offset . y , appUnitsPerDevPixel ) ) ;
2011-06-22 05:11:27 -07:00
visible . ScaleInverseRoundOut ( userData - > mXScale , userData - > mYScale ) ;
2010-07-15 14:07:51 -07:00
2010-07-15 14:08:10 -07:00
for ( i = items . Length ( ) ; i > 0 ; - - i ) {
ClippedDisplayItem * cdi = & items [ i - 1 ] ;
2010-07-15 14:07:51 -07:00
2010-08-08 11:49:07 -07:00
NS_ASSERTION ( AppUnitsPerDevPixel ( cdi - > mItem ) = = appUnitsPerDevPixel ,
" a thebes layer should contain items only at the same zoom " ) ;
2010-07-15 14:07:51 -07:00
2010-09-09 08:21:46 -07:00
NS_ABORT_IF_FALSE ( cdi - > mClip . mHaveClipRect | |
cdi - > mClip . mRoundedClipRects . IsEmpty ( ) ,
" If we have rounded rects, we must have a clip rect " ) ;
if ( ! cdi - > mClip . mHaveClipRect | |
( cdi - > mClip . mRoundedClipRects . IsEmpty ( ) & &
cdi - > mClip . mClipRect . Contains ( visible . GetBounds ( ) ) ) ) {
2010-07-15 14:07:51 -07:00
cdi - > mItem - > RecomputeVisibility ( builder , & visible ) ;
2012-12-13 14:50:57 -08:00
continue ;
}
// Do a little dance to account for the fact that we're clipping
// to cdi->mClipRect
nsRegion clipped ;
clipped . And ( visible , cdi - > mClip . mClipRect ) ;
nsRegion finalClipped = clipped ;
cdi - > mItem - > RecomputeVisibility ( builder , & finalClipped ) ;
// If we have rounded clip rects, don't subtract from the visible
// region since we aren't displaying everything inside the rect.
if ( cdi - > mClip . mRoundedClipRects . IsEmpty ( ) ) {
nsRegion removed ;
removed . Sub ( clipped , finalClipped ) ;
nsRegion newVisible ;
newVisible . Sub ( visible , removed ) ;
// Don't let the visible region get too complex.
if ( newVisible . GetNumRects ( ) < = 15 ) {
visible = newVisible ;
2010-09-09 08:21:46 -07:00
}
2011-01-26 10:36:11 -08:00
}
2012-12-13 14:50:57 -08:00
if ( ! cdi - > mClip . IsRectClippedByRoundedCorner ( cdi - > mItem - > GetVisibleRect ( ) ) ) {
cdi - > mClip . RemoveRoundedCorners ( ) ;
}
2010-07-15 14:07:51 -07:00
}
2011-04-16 21:08:22 -07:00
nsRefPtr < nsRenderingContext > rc = new nsRenderingContext ( ) ;
2010-08-08 11:49:07 -07:00
rc - > Init ( presContext - > DeviceContext ( ) , aContext ) ;
2010-09-09 08:21:46 -07:00
Clip currentClip ;
2011-09-28 23:19:26 -07:00
bool setClipRect = false ;
2010-08-08 11:49:07 -07:00
2010-07-15 14:08:10 -07:00
for ( i = 0 ; i < items . Length ( ) ; + + i ) {
ClippedDisplayItem * cdi = & items [ i ] ;
2010-07-15 14:07:51 -07:00
2012-12-13 14:50:57 -08:00
if ( cdi - > mItem - > GetVisibleRect ( ) . IsEmpty ( ) )
2010-07-15 14:07:51 -07:00
continue ;
2010-05-20 20:20:48 -07:00
// If the new desired clip state is different from the current state,
// update the clip.
2010-09-09 08:21:46 -07:00
if ( setClipRect ! = cdi - > mClip . mHaveClipRect | |
( cdi - > mClip . mHaveClipRect & & cdi - > mClip ! = currentClip ) ) {
2010-05-20 20:20:48 -07:00
if ( setClipRect ) {
aContext - > Restore ( ) ;
}
2010-09-09 08:21:46 -07:00
setClipRect = cdi - > mClip . mHaveClipRect ;
2010-05-20 20:20:48 -07:00
if ( setClipRect ) {
2010-09-09 08:21:46 -07:00
currentClip = cdi - > mClip ;
2010-05-20 20:20:48 -07:00
aContext - > Save ( ) ;
2012-02-07 14:27:44 -08:00
NS_ASSERTION ( commonClipCount < 100 ,
" Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong. " ) ;
currentClip . ApplyTo ( aContext , presContext , commonClipCount ) ;
2010-05-20 20:20:48 -07:00
}
}
2010-07-15 14:07:51 -07:00
2012-10-23 04:05:14 -07:00
if ( cdi - > mInactiveLayerManager ) {
PaintInactiveLayer ( builder , cdi - > mInactiveLayerManager , cdi - > mItem , aContext , rc ) ;
2010-07-15 14:08:05 -07:00
} else {
2011-10-25 20:23:26 -07:00
nsIFrame * frame = cdi - > mItem - > GetUnderlyingFrame ( ) ;
if ( frame ) {
frame - > AddStateBits ( NS_FRAME_PAINTED_THEBES ) ;
}
2012-03-05 10:09:05 -08:00
# ifdef MOZ_DUMP_PAINTING
if ( gfxUtils : : sDumpPainting ) {
DebugPaintItem ( rc , cdi - > mItem , builder ) ;
} else {
# else
{
# endif
cdi - > mItem - > Paint ( builder , rc ) ;
}
2010-05-20 20:20:48 -07:00
}
2010-09-17 12:09:08 -07:00
2012-07-17 10:03:51 -07:00
if ( layerBuilder - > CheckDOMModified ( ) )
2010-09-17 12:09:08 -07:00
break ;
2010-05-20 20:20:48 -07:00
}
2010-07-15 14:07:51 -07:00
2012-07-06 10:57:47 -07:00
{
ThebesLayerItemsEntry * entry =
2012-07-17 10:03:51 -07:00
layerBuilder - > mThebesLayerItems . GetEntry ( aLayer ) ;
2012-07-06 10:57:47 -07:00
items . SwapElements ( entry - > mItems ) ;
}
2010-05-20 20:20:48 -07:00
if ( setClipRect ) {
aContext - > Restore ( ) ;
}
2011-11-14 20:59:03 -08:00
FlashPaint ( aContext ) ;
2012-08-28 22:47:18 -07:00
if ( ! aRegionToInvalidate . IsEmpty ( ) ) {
aLayer - > AddInvalidRect ( aRegionToInvalidate . GetBounds ( ) ) ;
}
2010-05-20 20:20:48 -07:00
}
2011-09-28 23:19:26 -07:00
bool
2010-09-17 12:09:08 -07:00
FrameLayerBuilder : : CheckDOMModified ( )
{
2010-09-18 11:43:17 -07:00
if ( ! mRootPresContext | |
2010-09-17 12:09:08 -07:00
mInitialDOMGeneration = = mRootPresContext - > GetDOMGeneration ( ) )
2011-10-17 07:59:28 -07:00
return false ;
2010-09-17 12:09:08 -07:00
if ( mDetectedDOMModification ) {
// Don't spam the console with extra warnings
2011-10-17 07:59:28 -07:00
return true ;
2010-09-17 12:09:08 -07:00
}
2011-10-17 07:59:28 -07:00
mDetectedDOMModification = true ;
2010-09-17 12:09:08 -07:00
// Painting is not going to complete properly. There's not much
// we can do here though. Invalidating the window to get another repaint
// is likely to lead to an infinite repaint loop.
NS_WARNING ( " Detected DOM modification during paint, bailing out! " ) ;
2011-10-17 07:59:28 -07:00
return true ;
2010-09-17 12:09:08 -07:00
}
2011-11-16 19:44:16 -08:00
# ifdef MOZ_DUMP_PAINTING
2012-07-17 10:03:51 -07:00
/* static */ void
2012-08-07 10:57:26 -07:00
FrameLayerBuilder : : DumpRetainedLayerTree ( LayerManager * aManager , FILE * aFile , bool aDumpHtml )
2010-07-15 14:07:51 -07:00
{
2012-08-07 10:57:26 -07:00
aManager - > Dump ( aFile , " " , aDumpHtml ) ;
2010-07-15 14:07:51 -07:00
}
# endif
2010-09-09 08:21:46 -07:00
FrameLayerBuilder : : Clip : : Clip ( const Clip & aOther , nsDisplayItem * aClipItem )
: mRoundedClipRects ( aOther . mRoundedClipRects ) ,
2011-10-17 07:59:28 -07:00
mHaveClipRect ( true )
2010-09-09 08:21:46 -07:00
{
nsDisplayItem : : Type type = aClipItem - > GetType ( ) ;
NS_ABORT_IF_FALSE ( type = = nsDisplayItem : : TYPE_CLIP | |
type = = nsDisplayItem : : TYPE_CLIP_ROUNDED_RECT ,
" unexpected display item type " ) ;
nsDisplayClip * item = static_cast < nsDisplayClip * > ( aClipItem ) ;
// Always intersect with mClipRect, even if we're going to add a
// rounded rect.
if ( aOther . mHaveClipRect ) {
mClipRect . IntersectRect ( aOther . mClipRect , item - > GetClipRect ( ) ) ;
} else {
mClipRect = item - > GetClipRect ( ) ;
}
if ( type = = nsDisplayItem : : TYPE_CLIP_ROUNDED_RECT ) {
RoundedRect * rr = mRoundedClipRects . AppendElement ( ) ;
if ( rr ) {
rr - > mRect = item - > GetClipRect ( ) ;
static_cast < nsDisplayClipRoundedRect * > ( item ) - > GetRadii ( rr - > mRadii ) ;
}
}
// FIXME: Optimize away excess rounded rectangles due to the new addition.
}
void
FrameLayerBuilder : : Clip : : ApplyTo ( gfxContext * aContext ,
2012-02-07 14:27:44 -08:00
nsPresContext * aPresContext ,
2012-08-22 08:56:38 -07:00
uint32_t aBegin , uint32_t aEnd )
2010-09-09 08:21:46 -07:00
{
2012-08-22 08:56:38 -07:00
int32_t A2D = aPresContext - > AppUnitsPerDevPixel ( ) ;
2012-02-07 14:27:44 -08:00
ApplyRectTo ( aContext , A2D ) ;
ApplyRoundedRectsTo ( aContext , A2D , aBegin , aEnd ) ;
}
void
2012-08-22 08:56:38 -07:00
FrameLayerBuilder : : Clip : : ApplyRectTo ( gfxContext * aContext , int32_t A2D ) const
2012-02-07 14:27:44 -08:00
{
aContext - > NewPath ( ) ;
2010-09-09 08:21:46 -07:00
gfxRect clip = nsLayoutUtils : : RectToGfxRect ( mClipRect , A2D ) ;
2011-10-17 07:59:28 -07:00
aContext - > Rectangle ( clip , true ) ;
2010-09-09 08:21:46 -07:00
aContext - > Clip ( ) ;
2012-02-07 14:27:44 -08:00
}
2010-09-09 08:21:46 -07:00
2012-02-07 14:27:44 -08:00
void
FrameLayerBuilder : : Clip : : ApplyRoundedRectsTo ( gfxContext * aContext ,
2012-08-22 08:56:38 -07:00
int32_t A2D ,
uint32_t aBegin , uint32_t aEnd ) const
2012-02-07 14:27:44 -08:00
{
2013-01-15 04:22:03 -08:00
aEnd = std : : min < uint32_t > ( aEnd , mRoundedClipRects . Length ( ) ) ;
2012-02-07 14:27:44 -08:00
2012-08-22 08:56:38 -07:00
for ( uint32_t i = aBegin ; i < aEnd ; + + i ) {
2012-05-27 13:55:22 -07:00
AddRoundedRectPathTo ( aContext , A2D , mRoundedClipRects [ i ] ) ;
aContext - > Clip ( ) ;
}
}
2010-09-09 08:21:46 -07:00
2012-05-27 13:55:22 -07:00
void
FrameLayerBuilder : : Clip : : DrawRoundedRectsTo ( gfxContext * aContext ,
2012-08-22 08:56:38 -07:00
int32_t A2D ,
uint32_t aBegin , uint32_t aEnd ) const
2012-05-27 13:55:22 -07:00
{
2013-01-15 04:22:03 -08:00
aEnd = std : : min < uint32_t > ( aEnd , mRoundedClipRects . Length ( ) ) ;
2010-09-09 08:21:46 -07:00
2012-05-27 13:55:22 -07:00
if ( aEnd - aBegin = = 0 )
return ;
2010-09-09 08:21:46 -07:00
2012-05-27 13:55:22 -07:00
// If there is just one rounded rect we can just fill it, if there are more then we
// must clip the rest to get the intersection of clips
ApplyRoundedRectsTo ( aContext , A2D , aBegin , aEnd - 1 ) ;
AddRoundedRectPathTo ( aContext , A2D , mRoundedClipRects [ aEnd - 1 ] ) ;
aContext - > Fill ( ) ;
}
void
FrameLayerBuilder : : Clip : : AddRoundedRectPathTo ( gfxContext * aContext ,
2012-08-22 08:56:38 -07:00
int32_t A2D ,
2012-05-27 13:55:22 -07:00
const RoundedRect & aRoundRect ) const
{
gfxCornerSizes pixelRadii ;
nsCSSRendering : : ComputePixelRadii ( aRoundRect . mRadii , A2D , & pixelRadii ) ;
gfxRect clip = nsLayoutUtils : : RectToGfxRect ( aRoundRect . mRect , A2D ) ;
clip . Round ( ) ;
clip . Condition ( ) ;
aContext - > NewPath ( ) ;
aContext - > RoundedRectangle ( clip , pixelRadii ) ;
2010-09-09 08:21:46 -07:00
}
2011-01-02 17:48:09 -08:00
nsRect
2012-12-13 14:50:57 -08:00
FrameLayerBuilder : : Clip : : ApproximateIntersect ( const nsRect & aRect ) const
2011-01-02 17:48:09 -08:00
{
nsRect r = aRect ;
if ( mHaveClipRect ) {
r . IntersectRect ( r , mClipRect ) ;
}
2012-08-22 08:56:38 -07:00
for ( uint32_t i = 0 , iEnd = mRoundedClipRects . Length ( ) ;
2011-01-02 17:48:09 -08:00
i < iEnd ; + + i ) {
const Clip : : RoundedRect & rr = mRoundedClipRects [ i ] ;
nsRegion rgn = nsLayoutUtils : : RoundedRectIntersectRect ( rr . mRect , rr . mRadii , r ) ;
r = rgn . GetLargestRectangle ( ) ;
}
return r ;
}
2011-01-26 10:36:11 -08:00
// Test if (aXPoint, aYPoint) is in the ellipse with center (aXCenter, aYCenter)
// and radii aXRadius, aYRadius.
bool IsInsideEllipse ( nscoord aXRadius , nscoord aXCenter , nscoord aXPoint ,
nscoord aYRadius , nscoord aYCenter , nscoord aYPoint )
{
float scaledX = float ( aXPoint - aXCenter ) / float ( aXRadius ) ;
float scaledY = float ( aYPoint - aYCenter ) / float ( aYRadius ) ;
return scaledX * scaledX + scaledY * scaledY < 1.0f ;
}
bool
FrameLayerBuilder : : Clip : : IsRectClippedByRoundedCorner ( const nsRect & aRect ) const
{
if ( mRoundedClipRects . IsEmpty ( ) )
return false ;
nsRect rect ;
rect . IntersectRect ( aRect , NonRoundedIntersection ( ) ) ;
2012-08-22 08:56:38 -07:00
for ( uint32_t i = 0 , iEnd = mRoundedClipRects . Length ( ) ;
2011-01-26 10:36:11 -08:00
i < iEnd ; + + i ) {
const Clip : : RoundedRect & rr = mRoundedClipRects [ i ] ;
// top left
if ( rect . x < rr . mRect . x + rr . mRadii [ NS_CORNER_TOP_LEFT_X ] & &
rect . y < rr . mRect . y + rr . mRadii [ NS_CORNER_TOP_LEFT_Y ] ) {
if ( ! IsInsideEllipse ( rr . mRadii [ NS_CORNER_TOP_LEFT_X ] ,
rr . mRect . x + rr . mRadii [ NS_CORNER_TOP_LEFT_X ] ,
rect . x ,
rr . mRadii [ NS_CORNER_TOP_LEFT_Y ] ,
rr . mRect . y + rr . mRadii [ NS_CORNER_TOP_LEFT_Y ] ,
rect . y ) ) {
return true ;
}
}
// top right
if ( rect . XMost ( ) > rr . mRect . XMost ( ) - rr . mRadii [ NS_CORNER_TOP_RIGHT_X ] & &
rect . y < rr . mRect . y + rr . mRadii [ NS_CORNER_TOP_RIGHT_Y ] ) {
if ( ! IsInsideEllipse ( rr . mRadii [ NS_CORNER_TOP_RIGHT_X ] ,
rr . mRect . XMost ( ) - rr . mRadii [ NS_CORNER_TOP_RIGHT_X ] ,
rect . XMost ( ) ,
rr . mRadii [ NS_CORNER_TOP_RIGHT_Y ] ,
rr . mRect . y + rr . mRadii [ NS_CORNER_TOP_RIGHT_Y ] ,
rect . y ) ) {
return true ;
}
}
// bottom left
if ( rect . x < rr . mRect . x + rr . mRadii [ NS_CORNER_BOTTOM_LEFT_X ] & &
rect . YMost ( ) > rr . mRect . YMost ( ) - rr . mRadii [ NS_CORNER_BOTTOM_LEFT_Y ] ) {
if ( ! IsInsideEllipse ( rr . mRadii [ NS_CORNER_BOTTOM_LEFT_X ] ,
rr . mRect . x + rr . mRadii [ NS_CORNER_BOTTOM_LEFT_X ] ,
rect . x ,
rr . mRadii [ NS_CORNER_BOTTOM_LEFT_Y ] ,
rr . mRect . YMost ( ) - rr . mRadii [ NS_CORNER_BOTTOM_LEFT_Y ] ,
rect . YMost ( ) ) ) {
return true ;
}
}
// bottom right
if ( rect . XMost ( ) > rr . mRect . XMost ( ) - rr . mRadii [ NS_CORNER_BOTTOM_RIGHT_X ] & &
rect . YMost ( ) > rr . mRect . YMost ( ) - rr . mRadii [ NS_CORNER_BOTTOM_RIGHT_Y ] ) {
if ( ! IsInsideEllipse ( rr . mRadii [ NS_CORNER_BOTTOM_RIGHT_X ] ,
rr . mRect . XMost ( ) - rr . mRadii [ NS_CORNER_BOTTOM_RIGHT_X ] ,
rect . XMost ( ) ,
rr . mRadii [ NS_CORNER_BOTTOM_RIGHT_Y ] ,
rr . mRect . YMost ( ) - rr . mRadii [ NS_CORNER_BOTTOM_RIGHT_Y ] ,
rect . YMost ( ) ) ) {
return true ;
}
}
}
return false ;
}
nsRect
FrameLayerBuilder : : Clip : : NonRoundedIntersection ( ) const
{
2012-10-15 18:10:43 -07:00
NS_ASSERTION ( mHaveClipRect , " Must have a clip rect! " ) ;
2011-01-26 10:36:11 -08:00
nsRect result = mClipRect ;
2012-08-22 08:56:38 -07:00
for ( uint32_t i = 0 , iEnd = mRoundedClipRects . Length ( ) ;
2011-01-26 10:36:11 -08:00
i < iEnd ; + + i ) {
result . IntersectRect ( result , mRoundedClipRects [ i ] . mRect ) ;
}
return result ;
}
2012-10-15 18:10:43 -07:00
nsRect
FrameLayerBuilder : : Clip : : ApplyNonRoundedIntersection ( const nsRect & aRect ) const
{
if ( ! mHaveClipRect ) {
return aRect ;
}
nsRect result = aRect . Intersect ( mClipRect ) ;
for ( uint32_t i = 0 , iEnd = mRoundedClipRects . Length ( ) ;
i < iEnd ; + + i ) {
result . Intersect ( mRoundedClipRects [ i ] . mRect ) ;
}
return result ;
}
2011-01-26 10:36:11 -08:00
void
FrameLayerBuilder : : Clip : : RemoveRoundedCorners ( )
{
if ( mRoundedClipRects . IsEmpty ( ) )
return ;
mClipRect = NonRoundedIntersection ( ) ;
mRoundedClipRects . Clear ( ) ;
}
2012-08-28 22:48:44 -07:00
static void
AccumulateRectDifference ( const nsRect & aR1 , const nsRect & aR2 , nsRegion * aOut )
{
if ( aR1 . IsEqualInterior ( aR2 ) )
return ;
nsRegion r ;
r . Xor ( aR1 , aR2 ) ;
aOut - > Or ( * aOut , r ) ;
}
void
FrameLayerBuilder : : Clip : : AddOffsetAndComputeDifference ( const nsPoint & aOffset ,
const nsRect & aBounds ,
const Clip & aOther ,
const nsRect & aOtherBounds ,
nsRegion * aDifference )
{
if ( mHaveClipRect ! = aOther . mHaveClipRect | |
mRoundedClipRects . Length ( ) ! = aOther . mRoundedClipRects . Length ( ) ) {
aDifference - > Or ( * aDifference , aBounds ) ;
aDifference - > Or ( * aDifference , aOtherBounds ) ;
return ;
}
if ( mHaveClipRect ) {
AccumulateRectDifference ( ( mClipRect + aOffset ) . Intersect ( aBounds ) ,
aOther . mClipRect . Intersect ( aOtherBounds ) ,
aDifference ) ;
}
for ( uint32_t i = 0 ; i < mRoundedClipRects . Length ( ) ; + + i ) {
if ( mRoundedClipRects [ i ] + aOffset ! = aOther . mRoundedClipRects [ i ] ) {
// The corners make it tricky so we'll just add both rects here.
aDifference - > Or ( * aDifference , mRoundedClipRects [ i ] . mRect . Intersect ( aBounds ) ) ;
aDifference - > Or ( * aDifference , aOther . mRoundedClipRects [ i ] . mRect . Intersect ( aOtherBounds ) ) ;
}
}
}
2012-06-25 19:43:30 -07:00
gfxRect
2012-09-03 18:02:56 -07:00
CalculateBounds ( const nsTArray < FrameLayerBuilder : : Clip : : RoundedRect > & aRects , int32_t A2D )
2012-02-07 14:27:44 -08:00
{
2012-06-25 19:43:30 -07:00
nsRect bounds = aRects [ 0 ] . mRect ;
2012-08-22 08:56:38 -07:00
for ( uint32_t i = 1 ; i < aRects . Length ( ) ; + + i ) {
2012-06-25 19:43:30 -07:00
bounds . UnionRect ( bounds , aRects [ i ] . mRect ) ;
}
return nsLayoutUtils : : RectToGfxRect ( bounds , A2D ) ;
2012-02-07 14:27:44 -08:00
}
2012-09-03 18:02:56 -07:00
static void
SetClipCount ( ThebesDisplayItemLayerUserData * aThebesData ,
uint32_t aClipCount )
{
if ( aThebesData ) {
aThebesData - > mMaskClipCount = aClipCount ;
}
}
2012-02-07 14:27:44 -08:00
void
ContainerState : : SetupMaskLayer ( Layer * aLayer , const FrameLayerBuilder : : Clip & aClip ,
2012-08-22 08:56:38 -07:00
uint32_t aRoundedRectClipCount )
2012-02-07 14:27:44 -08:00
{
2012-09-03 18:02:56 -07:00
// if the number of clips we are going to mask has decreased, then aLayer might have
// cached graphics which assume the existence of a soon-to-be non-existent mask layer
// in that case, invalidate the whole layer.
ThebesDisplayItemLayerUserData * thebesData = GetThebesDisplayItemLayerUserData ( aLayer ) ;
if ( thebesData & &
aRoundedRectClipCount < thebesData - > mMaskClipCount ) {
ThebesLayer * thebes = aLayer - > AsThebesLayer ( ) ;
thebes - > InvalidateRegion ( thebes - > GetValidRegion ( ) . GetBounds ( ) ) ;
}
2012-02-07 14:27:44 -08:00
// don't build an unnecessary mask
2012-06-25 19:43:30 -07:00
nsIntRect layerBounds = aLayer - > GetVisibleRegion ( ) . GetBounds ( ) ;
2012-02-07 14:27:44 -08:00
if ( aClip . mRoundedClipRects . IsEmpty ( ) | |
2012-09-03 18:02:56 -07:00
aRoundedRectClipCount = = 0 | |
2012-06-25 19:43:30 -07:00
layerBounds . IsEmpty ( ) ) {
2012-09-03 18:02:56 -07:00
SetClipCount ( thebesData , 0 ) ;
2012-02-07 14:27:44 -08:00
return ;
}
// check if we can re-use the mask layer
nsRefPtr < ImageLayer > maskLayer = CreateOrRecycleMaskImageLayerFor ( aLayer ) ;
MaskLayerUserData * userData = GetMaskLayerUserData ( maskLayer ) ;
2012-06-25 19:43:30 -07:00
MaskLayerUserData newData ;
newData . mRoundedClipRects . AppendElements ( aClip . mRoundedClipRects ) ;
if ( aRoundedRectClipCount < newData . mRoundedClipRects . Length ( ) ) {
newData . mRoundedClipRects . TruncateLength ( aRoundedRectClipCount ) ;
2012-02-07 14:27:44 -08:00
}
2012-06-25 19:43:30 -07:00
newData . mScaleX = mParameters . mXScale ;
newData . mScaleY = mParameters . mYScale ;
2012-06-25 14:44:41 -07:00
2012-06-25 19:43:30 -07:00
if ( * userData = = newData ) {
aLayer - > SetMaskLayer ( maskLayer ) ;
2012-09-03 18:02:56 -07:00
SetClipCount ( thebesData , aRoundedRectClipCount ) ;
2012-06-25 15:54:05 -07:00
return ;
}
2012-07-31 10:28:21 -07:00
2012-06-25 19:43:30 -07:00
// calculate a more precise bounding rect
2012-08-22 08:56:38 -07:00
const int32_t A2D = mContainerFrame - > PresContext ( ) - > AppUnitsPerDevPixel ( ) ;
2012-06-25 19:43:30 -07:00
gfxRect boundingRect = CalculateBounds ( newData . mRoundedClipRects , A2D ) ;
boundingRect . Scale ( mParameters . mXScale , mParameters . mYScale ) ;
2012-08-22 08:56:38 -07:00
uint32_t maxSize = mManager - > GetMaxTextureSize ( ) ;
2012-05-16 15:30:10 -07:00
NS_ASSERTION ( maxSize > 0 , " Invalid max texture size " ) ;
2013-01-15 04:22:03 -08:00
nsIntSize surfaceSize ( std : : min < int32_t > ( boundingRect . Width ( ) , maxSize ) ,
std : : min < int32_t > ( boundingRect . Height ( ) , maxSize ) ) ;
2012-05-16 15:30:10 -07:00
2012-06-25 19:43:30 -07:00
// maskTransform is applied to the clip when it is painted into the mask (as a
// component of imageTransform), and its inverse used when the mask is used for
// masking.
// It is the transform from the masked layer's space to mask space
gfxMatrix maskTransform ;
maskTransform . Scale ( float ( surfaceSize . width ) / float ( boundingRect . Width ( ) ) ,
float ( surfaceSize . height ) / float ( boundingRect . Height ( ) ) ) ;
maskTransform . Translate ( - boundingRect . TopLeft ( ) ) ;
// imageTransform is only used when the clip is painted to the mask
gfxMatrix imageTransform = maskTransform ;
imageTransform . Scale ( mParameters . mXScale , mParameters . mYScale ) ;
2012-09-03 18:02:56 -07:00
nsAutoPtr < MaskLayerImageCache : : MaskLayerImageKey > newKey (
2012-12-11 13:57:52 -08:00
new MaskLayerImageCache : : MaskLayerImageKey ( ) ) ;
2012-09-03 18:02:56 -07:00
2012-06-25 19:43:30 -07:00
// copy and transform the rounded rects
2012-08-22 08:56:38 -07:00
for ( uint32_t i = 0 ; i < newData . mRoundedClipRects . Length ( ) ; + + i ) {
2012-09-03 18:02:56 -07:00
newKey - > mRoundedClipRects . AppendElement (
2012-06-25 19:43:30 -07:00
MaskLayerImageCache : : PixelRoundedRect ( newData . mRoundedClipRects [ i ] ,
mContainerFrame - > PresContext ( ) ) ) ;
2012-09-03 18:02:56 -07:00
newKey - > mRoundedClipRects [ i ] . ScaleAndTranslate ( imageTransform ) ;
2012-02-07 14:27:44 -08:00
}
2012-06-25 19:43:30 -07:00
2012-09-03 18:02:56 -07:00
const MaskLayerImageCache : : MaskLayerImageKey * lookupKey = newKey ;
2012-09-03 03:47:51 -07:00
2012-09-03 18:02:56 -07:00
// check to see if we can reuse a mask image
2012-06-25 19:43:30 -07:00
nsRefPtr < ImageContainer > container =
GetMaskLayerImageCache ( ) - > FindImageFor ( & lookupKey ) ;
2012-09-03 18:02:56 -07:00
if ( ! container ) {
2012-06-25 19:43:30 -07:00
// no existing mask image, so build a new one
nsRefPtr < gfxASurface > surface =
2012-06-25 19:43:31 -07:00
aLayer - > Manager ( ) - > CreateOptimalMaskSurface ( surfaceSize ) ;
2012-06-25 19:43:30 -07:00
// fail if we can't get the right surface
if ( ! surface | | surface - > CairoStatus ( ) ) {
NS_WARNING ( " Could not create surface for mask layer. " ) ;
2012-09-03 18:02:56 -07:00
SetClipCount ( thebesData , 0 ) ;
2012-06-25 19:43:30 -07:00
return ;
}
2012-02-07 14:27:44 -08:00
2012-06-25 19:43:30 -07:00
nsRefPtr < gfxContext > context = new gfxContext ( surface ) ;
context - > Multiply ( imageTransform ) ;
2012-02-07 14:27:44 -08:00
2012-06-25 19:43:30 -07:00
// paint the clipping rects with alpha to create the mask
2012-06-25 19:43:31 -07:00
context - > SetColor ( gfxRGBA ( 1 , 1 , 1 , 1 ) ) ;
2012-06-25 19:43:30 -07:00
aClip . DrawRoundedRectsTo ( context , A2D , 0 , aRoundedRectClipCount ) ;
2012-02-07 14:27:44 -08:00
2012-06-25 19:43:30 -07:00
// build the image and container
container = aLayer - > Manager ( ) - > CreateImageContainer ( ) ;
NS_ASSERTION ( container , " Could not create image container for mask layer. " ) ;
2012-08-19 19:39:10 -07:00
static const ImageFormat format = CAIRO_SURFACE ;
2012-06-25 19:43:30 -07:00
nsRefPtr < Image > image = container - > CreateImage ( & format , 1 ) ;
NS_ASSERTION ( image , " Could not create image container for mask layer. " ) ;
CairoImage : : Data data ;
data . mSurface = surface ;
data . mSize = surfaceSize ;
static_cast < CairoImage * > ( image . get ( ) ) - > SetData ( data ) ;
2012-07-26 11:11:22 -07:00
container - > SetCurrentImageInTransaction ( image ) ;
2012-06-25 15:54:05 -07:00
2012-09-03 18:02:56 -07:00
GetMaskLayerImageCache ( ) - > PutImage ( newKey . forget ( ) , container ) ;
2012-06-25 19:43:30 -07:00
}
2012-06-25 14:44:41 -07:00
2012-06-25 15:54:05 -07:00
maskLayer - > SetContainer ( container ) ;
2012-09-16 15:25:33 -07:00
gfx3DMatrix matrix = gfx3DMatrix : : From2D ( maskTransform . Invert ( ) ) ;
matrix . Translate ( gfxPoint3D ( mParameters . mOffset . x , mParameters . mOffset . y , 0 ) ) ;
maskLayer - > SetBaseTransform ( matrix ) ;
2012-06-25 19:43:30 -07:00
2012-02-07 14:27:44 -08:00
// save the details of the clip in user data
2012-06-25 19:43:30 -07:00
userData - > mScaleX = newData . mScaleX ;
userData - > mScaleY = newData . mScaleY ;
userData - > mRoundedClipRects . SwapElements ( newData . mRoundedClipRects ) ;
2012-09-03 18:02:56 -07:00
userData - > mImageKey = lookupKey ;
2012-02-07 14:27:44 -08:00
aLayer - > SetMaskLayer ( maskLayer ) ;
2012-09-03 18:02:56 -07:00
SetClipCount ( thebesData , aRoundedRectClipCount ) ;
2012-02-07 14:27:44 -08:00
return ;
}
2010-05-20 20:20:48 -07:00
} // namespace mozilla