--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -1661,16 +1661,29 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShe
NS_ENSURE_TRUE(mDocShellTreeOwner, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(mDocShellTreeOwner);
mDocShellTreeOwner->WebBrowser(this);
return NS_OK;
}
+static void DrawThebesLayer(ThebesLayer* aLayer,
+ gfxContext* aContext,
+ const nsIntRegion& aRegionToDraw,
+ void* aCallbackData)
+{
+ nscolor* color = static_cast<nscolor*>(aCallbackData);
+ aContext->NewPath();
+ aContext->SetColor(gfxRGBA(*color));
+ nsIntRect dirtyRect = aRegionToDraw.GetBounds();
+ aContext->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
+ aContext->Fill();
+}
+
/* static */
nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
{
nsWebBrowser *browser = nsnull;
void *data = nsnull;
nsIWidget *widget = aEvent->widget;
if (!widget)
@@ -1691,29 +1704,17 @@ nsEventStatus nsWebBrowser::HandleEvent(
layerManager->BeginTransaction();
nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
nsPaintEvent* paintEvent = static_cast<nsPaintEvent*>(aEvent);
nsIntRect dirtyRect = paintEvent->region.GetBounds();
if (root) {
root->SetVisibleRegion(dirtyRect);
layerManager->SetRoot(root);
}
- layerManager->EndConstruction();
- if (root) {
- nsIntRegion toDraw;
- gfxContext* ctx = root->BeginDrawing(&toDraw);
- if (ctx) {
- ctx->NewPath();
- ctx->SetColor(gfxRGBA(browser->mBackgroundColor));
- ctx->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
- ctx->Fill();
- }
- }
- root->EndDrawing();
- layerManager->EndTransaction();
+ layerManager->EndTransaction(DrawThebesLayer, &browser->mBackgroundColor);
return nsEventStatus_eConsumeDoDefault;
}
case NS_ACTIVATE: {
#if defined(DEBUG_smaug)
nsCOMPtr<nsIDOMDocument> domDocument = do_GetInterface(browser->mDocShell);
nsAutoString documentURI;
if (domDocument) {
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -138,24 +138,39 @@ public:
* Start a new transaction. Nested transactions are not allowed so
* there must be no transaction currently in progress.
* This transaction will render the contents of the layer tree to
* the given target context. The rendering will be complete when
* EndTransaction returns.
*/
virtual void BeginTransactionWithTarget(gfxContext* aTarget) = 0;
/**
- * Finish the construction phase of the transaction and enter the
- * drawing phase.
+ * Function called to draw the contents of each ThebesLayer.
+ * aRegionToDraw contains the region that needs to be drawn.
+ * This would normally be a subregion of the visible region. Drawing is
+ * not necessarily clipped to aRegionToDraw.
+ * The callee must draw all of aRegionToDraw.
+ *
+ * aContext must not be used after the call has returned.
+ * We guarantee that buffered contents in the visible
+ * region are valid once drawing is complete.
*/
- virtual void EndConstruction() = 0;
+ typedef void (* DrawThebesLayerCallback)(ThebesLayer* aLayer,
+ gfxContext* aContext,
+ const nsIntRegion& aRegionToDraw,
+ void* aCallbackData);
/**
- * Complete the transaction.
+ * Finish the construction phase of the transaction, perform the
+ * drawing phase, and end the transaction.
+ * During the drawing phase, all ThebesLayers in the tree are
+ * drawn in tree order, exactly once each, except for those layers
+ * where it is known that the visible region is empty.
*/
- virtual void EndTransaction() = 0;
+ virtual void EndTransaction(DrawThebesLayerCallback aCallback,
+ void* aCallbackData) = 0;
/**
* CONSTRUCTION PHASE ONLY
* Set the root layer.
*/
virtual void SetRoot(Layer* aLayer) = 0;
/**
@@ -192,16 +207,18 @@ public:
/**
* Type of layer manager his is. This is to be used sparsely in order to
* avoid a lot of Layers backend specific code. It should be used only when
* Layers backend specific functionality is necessary.
*/
virtual LayersBackend GetBackendType() = 0;
};
+class ThebesLayer;
+
/**
* A Layer represents anything that can be rendered onto a destination
* surface.
*/
class THEBES_API Layer {
NS_INLINE_DECL_REFCOUNTING(Layer)
public:
@@ -293,16 +310,22 @@ public:
virtual Layer* GetFirstChild() { return nsnull; }
const gfx3DMatrix& GetTransform() { return mTransform; }
// This setter and getter can be used anytime.
void SetUserData(void* aData) { mUserData = aData; }
void* GetUserData() { return mUserData; }
/**
+ * Dynamic downcast to a Thebes layer. Returns null if this is not
+ * a ThebesLayer.
+ */
+ virtual ThebesLayer* AsThebesLayer() { return nsnull; }
+
+ /**
* Only the implementation should call this. This is per-implementation
* private data. Normally, all layers with a given layer manager
* use the same type of ImplData.
*/
void* ImplData() { return mImplData; }
/**
* Only the implementation should use these methods.
@@ -353,46 +376,17 @@ public:
/**
* CONSTRUCTION PHASE ONLY
* Tell this layer that the content in some region has changed and
* will need to be repainted. This area is removed from the valid
* region.
*/
virtual void InvalidateRegion(const nsIntRegion& aRegion) = 0;
- /**
- * DRAWING PHASE ONLY
- * Start drawing into the layer. On return, aRegionToDraw contains the
- * region that needs to be drawn in by the caller. This would normally
- * be a subregion of the visible region. Drawing is not necessarily
- * clipped to aRegionToDraw.
- *
- * No other layer operations are allowed until we call EndDrawing on this
- * layer. During the drawing phase, all ThebesLayers in the tree must be
- * drawn in tree order, exactly once each, except for those layers
- * where it is known that the visible region is empty. (Calling
- * BeginDrawing on non-visible layers is allowed, but aRegionToDraw
- * will return empty.)
- *
- * When an empty region is returned in aRegionToDraw, BeginDrawing
- * may return a null context.
- *
- * The layer system will hold a reference to the returned gfxContext*
- * until EndDrawing is called. The returned gfxContext must not be used
- * after EndDrawing is called.
- */
- virtual gfxContext* BeginDrawing(nsIntRegion* aRegionToDraw) = 0;
- /**
- * DRAWING PHASE ONLY
- * We've finished drawing into this layer. At this point the caller
- * must have drawn all of aRegionToDraw that was returned by
- * BeginDrawing, and we guarantee that buffered contents in the visible
- * region are now valid.
- */
- virtual void EndDrawing() = 0;
+ virtual ThebesLayer* AsThebesLayer() { return this; }
protected:
ThebesLayer(LayerManager* aManager, void* aImplData)
: Layer(aManager, aImplData) {}
};
/**
* A Layer which other layers render into. It holds references to its
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -89,17 +89,19 @@ public:
const nsIntRegion& GetVisibleRegion() { return mVisibleRegion; }
/**
* Layers that paint themselves, such as ImageLayers, should paint
* in response to this method call. aContext will already have been
* set up to account for all the properties of the layer (transform,
* opacity, etc).
*/
- virtual void Paint(gfxContext* aContext) {}
+ virtual void Paint(gfxContext* aContext,
+ LayerManager::DrawThebesLayerCallback aCallback,
+ void* aCallbackData) {}
protected:
nsIntRegion mVisibleRegion;
};
static BasicImplData*
ToData(Layer* aLayer)
{
@@ -235,50 +237,38 @@ public:
mVisibleRegion = aRegion;
}
virtual void InvalidateRegion(const nsIntRegion& aRegion)
{
NS_ASSERTION(BasicManager()->InConstruction(),
"Can only set properties in construction phase");
}
- virtual gfxContext* BeginDrawing(nsIntRegion* aRegionToDraw);
- virtual void EndDrawing();
+ virtual void Paint(gfxContext* aContext,
+ LayerManager::DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
protected:
BasicLayerManager* BasicManager()
{
return static_cast<BasicLayerManager*>(mManager);
}
};
-gfxContext*
-BasicThebesLayer::BeginDrawing(nsIntRegion* aRegionToDraw)
+void
+BasicThebesLayer::Paint(gfxContext* aContext,
+ LayerManager::DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
- NS_ASSERTION(BasicManager()->IsBeforeInTree(BasicManager()->GetLastPainted(), this),
- "Painting layers out of order");
NS_ASSERTION(BasicManager()->InDrawing(),
"Can only draw in drawing phase");
gfxContext* target = BasicManager()->GetTarget();
- if (!target)
- return nsnull;
-
- BasicManager()->AdvancePaintingTo(this);
+ NS_ASSERTION(target, "We shouldn't be called if there's no target");
- *aRegionToDraw = mVisibleRegion;
- return target;
-}
-
-void
-BasicThebesLayer::EndDrawing()
-{
- NS_ASSERTION(BasicManager()->InDrawing(),
- "Can only draw in drawing phase");
- NS_ASSERTION(BasicManager()->GetLastPainted() == this,
- "Not currently drawing this layer");
+ aCallback(this, target, mVisibleRegion, aCallbackData);
}
class BasicImageLayer : public ImageLayer, BasicImplData {
public:
BasicImageLayer(BasicLayerManager* aLayerManager) :
ImageLayer(aLayerManager, static_cast<BasicImplData*>(this))
{
MOZ_COUNT_CTOR(BasicImageLayer);
@@ -290,27 +280,31 @@ public:
virtual void SetVisibleRegion(const nsIntRegion& aRegion)
{
NS_ASSERTION(BasicManager()->InConstruction(),
"Can only set properties in construction phase");
mVisibleRegion = aRegion;
}
- virtual void Paint(gfxContext* aContext);
+ virtual void Paint(gfxContext* aContext,
+ LayerManager::DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
protected:
BasicLayerManager* BasicManager()
{
return static_cast<BasicLayerManager*>(mManager);
}
};
void
-BasicImageLayer::Paint(gfxContext* aContext)
+BasicImageLayer::Paint(gfxContext* aContext,
+ LayerManager::DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
if (!mContainer)
return;
gfxIntSize size;
nsRefPtr<gfxASurface> surface = mContainer->GetCurrentAsSurface(&size);
if (!surface) {
return;
@@ -360,27 +354,31 @@ public:
virtual void SetVisibleRegion(const nsIntRegion& aRegion)
{
NS_ASSERTION(BasicManager()->InConstruction(),
"Can only set properties in construction phase");
mVisibleRegion = aRegion;
}
- virtual void Paint(gfxContext* aContext);
+ virtual void Paint(gfxContext* aContext,
+ LayerManager::DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
protected:
BasicLayerManager* BasicManager()
{
return static_cast<BasicLayerManager*>(mManager);
}
};
void
-BasicColorLayer::Paint(gfxContext* aContext)
+BasicColorLayer::Paint(gfxContext* aContext,
+ LayerManager::DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
aContext->SetColor(mColor);
aContext->Paint();
}
class BasicCanvasLayer : public CanvasLayer,
BasicImplData
{
@@ -392,17 +390,19 @@ public:
}
virtual ~BasicCanvasLayer()
{
MOZ_COUNT_DTOR(BasicCanvasLayer);
}
virtual void Initialize(const Data& aData);
virtual void Updated(const nsIntRect& aRect);
- virtual void Paint(gfxContext* aContext);
+ virtual void Paint(gfxContext* aContext,
+ LayerManager::DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
protected:
nsRefPtr<gfxASurface> mSurface;
nsRefPtr<mozilla::gl::GLContext> mGLContext;
nsIntRect mBounds;
nsIntRect mUpdatedRect;
@@ -479,17 +479,19 @@ BasicCanvasLayer::Updated(const nsIntRec
}
// sanity
NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect),
"CanvasLayer: Updated rect bigger than bounds!");
}
void
-BasicCanvasLayer::Paint(gfxContext* aContext)
+BasicCanvasLayer::Paint(gfxContext* aContext,
+ LayerManager::DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
pat->SetFilter(mFilter);
pat->SetExtend(gfxPattern::EXTEND_PAD);
gfxRect r(0, 0, mBounds.width, mBounds.height);
gfxMatrix m;
@@ -506,17 +508,17 @@ BasicCanvasLayer::Paint(gfxContext* aCon
if (mNeedsYFlip) {
aContext->SetMatrix(m);
}
mUpdatedRect.Empty();
}
BasicLayerManager::BasicLayerManager(gfxContext* aContext) :
- mDefaultTarget(aContext), mLastPainted(nsnull)
+ mDefaultTarget(aContext)
#ifdef DEBUG
, mPhase(PHASE_NONE)
#endif
{
MOZ_COUNT_CTOR(BasicLayerManager);
}
BasicLayerManager::~BasicLayerManager()
@@ -549,34 +551,33 @@ BasicLayerManager::BeginTransactionWithT
NS_ASSERTION(mPhase == PHASE_NONE, "Nested transactions not allowed");
#ifdef DEBUG
mPhase = PHASE_CONSTRUCTION;
#endif
mTarget = aTarget;
}
void
-BasicLayerManager::EndConstruction()
+BasicLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
NS_ASSERTION(mRoot, "Root not set");
NS_ASSERTION(mPhase == PHASE_CONSTRUCTION, "Should be in construction phase");
#ifdef DEBUG
mPhase = PHASE_DRAWING;
#endif
-}
-void
-BasicLayerManager::EndTransaction()
-{
- NS_ASSERTION(mPhase == PHASE_DRAWING, "Should be in drawing phase");
+ if (mTarget) {
+ PaintLayer(mRoot, aCallback, aCallbackData);
+ mTarget = nsnull;
+ }
+
#ifdef DEBUG
mPhase = PHASE_NONE;
#endif
- AdvancePaintingTo(nsnull);
- mTarget = nsnull;
// No retained layers supported for now
mRoot = nsnull;
}
void
BasicLayerManager::SetRoot(Layer* aLayer)
{
NS_ASSERTION(aLayer, "Root can't be null");
@@ -620,20 +621,24 @@ UseOpaqueSurface(Layer* aLayer)
// in the container.
BasicContainerLayer* parent =
static_cast<BasicContainerLayer*>(aLayer->GetParent());
return parent && parent->GetFirstChild() == aLayer &&
UseOpaqueSurface(parent);
}
void
-BasicLayerManager::BeginPaintingLayer(Layer* aLayer)
+BasicLayerManager::PaintLayer(Layer* aLayer,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
PRBool needsGroup = NeedsGroup(aLayer);
- if ((needsGroup || NeedsState(aLayer)) && mTarget) {
+ PRBool needsSaveRestore = needsGroup || NeedsState(aLayer);
+
+ if (needsSaveRestore) {
mTarget->Save();
if (aLayer->GetClipRect()) {
const nsIntRect& r = *aLayer->GetClipRect();
mTarget->NewPath();
mTarget->Rectangle(gfxRect(r.x, r.y, r.width, r.height), PR_TRUE);
mTarget->Clip();
}
@@ -662,76 +667,32 @@ BasicLayerManager::BeginPaintingLayer(La
mTarget->SetMatrix(currentMatrix);
gfxASurface::gfxContentType type = UseOpaqueSurface(aLayer)
? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA;
mTarget->PushGroup(type);
}
}
- mLastPainted = aLayer;
+ ToData(aLayer)->Paint(mTarget, aCallback, aCallbackData);
+ for (Layer* child = aLayer->GetFirstChild(); child;
+ child = child->GetNextSibling()) {
+ PaintLayer(child, aCallback, aCallbackData);
+ }
- // For layers that paint themselves (e.g., BasicImageLayer), paint
- // them now.
- ToData(aLayer)->Paint(mTarget);
-}
-
-void
-BasicLayerManager::EndPaintingLayer()
-{
- PRBool needsGroup = NeedsGroup(mLastPainted);
- if ((needsGroup || NeedsState(mLastPainted)) && mTarget) {
+ if (needsSaveRestore) {
if (needsGroup) {
mTarget->PopGroupToSource();
- mTarget->Paint(mLastPainted->GetOpacity());
+ mTarget->Paint(aLayer->GetOpacity());
}
mTarget->Restore();
}
}
-void
-BasicLayerManager::AdvancePaintingTo(BasicThebesLayer* aLayer)
-{
- NS_ASSERTION(!aLayer || IsBeforeInTree(mLastPainted, aLayer),
- "Painting layers out of order");
-
- // Traverse the layer tree from mLastPainted to aLayer, calling
- // BeginPaintingLayer and EndPaintingLayer as we enter or exit layers.
- do {
- Layer* firstChild;
- Layer* nextSibling;
- // Advance mLastPainted one step through the tree in preorder
- if (!mLastPainted) {
- // This is the first AdvancePaintingTo call. Start at the root.
- BeginPaintingLayer(mRoot);
- } else if ((firstChild = mLastPainted->GetFirstChild()) != nsnull) {
- // Descend into our first child, if there is one.
- BeginPaintingLayer(firstChild);
- } else if ((nextSibling = mLastPainted->GetNextSibling()) != nsnull) {
- // There are no children to descend into. Leave this layer and
- // advance to our next sibling, if there is one.
- EndPaintingLayer();
- BeginPaintingLayer(nextSibling);
- } else {
- // There are no children to descend into and we have no next sibling.
- // Exit layers until we find a layer which has a next sibling
- // (or we exit the root).
- do {
- EndPaintingLayer();
- mLastPainted = mLastPainted->GetParent();
- } while (mLastPainted && !mLastPainted->GetNextSibling());
- if (mLastPainted) {
- EndPaintingLayer();
- BeginPaintingLayer(mLastPainted->GetNextSibling());
- }
- }
- } while (mLastPainted != aLayer);
-}
-
already_AddRefed<ThebesLayer>
BasicLayerManager::CreateThebesLayer()
{
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
nsRefPtr<ThebesLayer> layer = new BasicThebesLayer(this);
return layer.forget();
}
@@ -762,59 +723,10 @@ BasicLayerManager::CreateColorLayer()
already_AddRefed<CanvasLayer>
BasicLayerManager::CreateCanvasLayer()
{
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
nsRefPtr<CanvasLayer> layer = new BasicCanvasLayer(this);
return layer.forget();
}
-#ifdef DEBUG
-static void
-AppendAncestors(Layer* aLayer, nsTArray<Layer*>* aAncestors)
-{
- while (aLayer) {
- aAncestors->AppendElement(aLayer);
- aLayer = aLayer->GetParent();
- }
-}
-
-PRBool
-BasicLayerManager::IsBeforeInTree(Layer* aBefore, Layer* aLayer)
-{
- if (!aBefore) {
- return PR_TRUE;
- }
- nsAutoTArray<Layer*,8> beforeAncestors, afterAncestors;
- AppendAncestors(aBefore, &beforeAncestors);
- AppendAncestors(aLayer, &afterAncestors);
- PRInt32 beforeIndex = beforeAncestors.Length() - 1;
- PRInt32 afterIndex = afterAncestors.Length() - 1;
- NS_ASSERTION(beforeAncestors[beforeIndex] == mRoot, "aBefore not in tree?");
- NS_ASSERTION(afterAncestors[afterIndex] == mRoot, "aLayer not in tree?");
- --beforeIndex;
- --afterIndex;
- while (beforeIndex >= 0 && afterIndex >= 0) {
- if (beforeAncestors[beforeIndex] != afterAncestors[afterIndex]) {
- BasicContainerLayer* parent =
- static_cast<BasicContainerLayer*>(beforeAncestors[beforeIndex + 1]);
- for (Layer* child = parent->GetFirstChild();
- child != afterAncestors[afterIndex];
- child = child->GetNextSibling()) {
- if (child == beforeAncestors[beforeIndex]) {
- return PR_TRUE;
- }
- }
- return PR_FALSE;
- }
- --beforeIndex;
- --afterIndex;
- }
- if (afterIndex > 0) {
- // aBefore is an ancestor of aLayer, so it's before aLayer in preorder
- return PR_TRUE;
- }
- return PR_FALSE;
-}
-#endif
-
}
}
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -73,62 +73,46 @@ public:
/**
* Set the default target context that will be used when BeginTransaction
* is called. This can only be called outside a transaction.
*/
void SetDefaultTarget(gfxContext* aContext);
virtual void BeginTransaction();
virtual void BeginTransactionWithTarget(gfxContext* aTarget);
- virtual void EndConstruction();
- virtual void EndTransaction();
+ virtual void EndTransaction(DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
virtual void SetRoot(Layer* aLayer);
virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
virtual already_AddRefed<ImageLayer> CreateImageLayer();
virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
virtual already_AddRefed<ImageContainer> CreateImageContainer();
virtual already_AddRefed<ColorLayer> CreateColorLayer();
virtual LayersBackend GetBackendType() { return LAYERS_BASIC; }
#ifdef DEBUG
PRBool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
PRBool InDrawing() { return mPhase == PHASE_DRAWING; }
- PRBool IsBeforeInTree(Layer* aBefore, Layer* aLayer);
#endif
- // Prepares mTarget for painting into aLayer. Layers are painted
- // in tree order, so this method essentially traverses the layer tree
- // in preorder from mLastPainted to aLayer, doing whatever's needed
- // as we exit container layers and enter new container layers, and
- // drawing any non-ThebesLayers we encounter.
- void AdvancePaintingTo(BasicThebesLayer* aLayer);
- Layer* GetLastPainted() { return mLastPainted; }
gfxContext* GetTarget() { return mTarget; }
private:
- // This gets called when we start painting aLayer. It can change
- // the state of mTarget by saving state, setting clipping and/or
- // pushing a group.
- void BeginPaintingLayer(Layer* aLayer);
- // This gets called when we finish painting aLayer. It can change
- // the state of mTarget by popping a group and/or restoring the state.
- void EndPaintingLayer();
+ // Paints aLayer to mTarget.
+ void PaintLayer(Layer* aLayer,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
nsRefPtr<Layer> mRoot;
// The default context for BeginTransaction.
nsRefPtr<gfxContext> mDefaultTarget;
- // The context to draw into. This is always the context that
- // our ThebesLayers will return.
+ // The context to draw into.
nsRefPtr<gfxContext> mTarget;
- // The most recently painted layer during the drawing phase of
- // a transaction, or null if no layer has been painted in this
- // transaction.
- Layer* mLastPainted;
#ifdef DEBUG
enum TransactionPhase { PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING };
TransactionPhase mPhase;
#endif
};
}
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -193,17 +193,19 @@ CanvasLayerOGL::Updated(const nsIntRect&
}
}
// sanity
NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect), "CanvasLayer: Updated rect bigger than bounds!");
}
void
-CanvasLayerOGL::RenderLayer(int aPreviousDestination)
+CanvasLayerOGL::RenderLayer(int aPreviousDestination,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
GLContext *gl = glManager->gl();
glManager->MakeCurrent();
float quadTransform[4][4];
// Transform the quad to the size of the canvas.
memset(&quadTransform, 0, sizeof(quadTransform));
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -61,17 +61,19 @@ public:
// CanvasLayer implementation
virtual void Initialize(const Data& aData);
virtual void Updated(const nsIntRect& aRect);
// LayerOGL implementation
virtual LayerType GetType() { return TYPE_CANVAS; }
virtual Layer* GetLayer() { return this; }
- virtual void RenderLayer(int aPreviousDestination);
+ virtual void RenderLayer(int aPreviousDestination,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
protected:
nsRefPtr<gfxASurface> mSurface;
nsRefPtr<GLContext> mGLContext;
unsigned int mTexture;
nsIntRect mBounds;
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -48,17 +48,17 @@ ColorLayerOGL::GetType()
Layer*
ColorLayerOGL::GetLayer()
{
return this;
}
void
-ColorLayerOGL::RenderLayer(int)
+ColorLayerOGL::RenderLayer(int, DrawThebesLayerCallback, void*)
{
static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
// XXX we might be able to improve performance by using glClear
float quadTransform[4][4];
nsIntRect visibleRect = mVisibleRegion.GetBounds();
// Transform the quad to the size of the visible area.
--- a/gfx/layers/opengl/ColorLayerOGL.h
+++ b/gfx/layers/opengl/ColorLayerOGL.h
@@ -56,17 +56,19 @@ public:
virtual void SetVisibleRegion(const nsIntRegion& aRegion) { mVisibleRegion = aRegion; }
// LayerOGL Implementation
virtual LayerType GetType();
virtual Layer* GetLayer();
- virtual void RenderLayer(int aPreviousDestination);
+ virtual void RenderLayer(int aPreviousDestination,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
protected:
nsIntRegion mVisibleRegion;
};
} /* layers */
} /* mozilla */
#endif /* GFX_COLORLAYEROGL_H */
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -42,16 +42,25 @@ namespace layers {
ContainerLayerOGL::ContainerLayerOGL(LayerManagerOGL *aManager)
: ContainerLayer(aManager, NULL)
, LayerOGL(aManager)
{
mImplData = static_cast<LayerOGL*>(this);
}
+ContainerLayerOGL::~ContainerLayerOGL()
+{
+ LayerOGL *nextChild;
+ for (LayerOGL *child = GetFirstChildOGL(); child; child = nextChild) {
+ nextChild = child->GetNextSibling();
+ child->GetLayer()->Release();
+ }
+}
+
const nsIntRect&
ContainerLayerOGL::GetVisibleRect()
{
return mVisibleRect;
}
void
ContainerLayerOGL::SetVisibleRegion(const nsIntRegion &aRegion)
@@ -59,16 +68,17 @@ ContainerLayerOGL::SetVisibleRegion(cons
mVisibleRect = aRegion.GetBounds();
}
void
ContainerLayerOGL::InsertAfter(Layer* aChild, Layer* aAfter)
{
LayerOGL *newChild = static_cast<LayerOGL*>(aChild->ImplData());
aChild->SetParent(this);
+ NS_ADDREF(aChild);
if (!aAfter) {
LayerOGL *oldFirstChild = GetFirstChildOGL();
mFirstChild = newChild->GetLayer();
newChild->SetNextSibling(oldFirstChild);
return;
}
for (LayerOGL *child = GetFirstChildOGL();
child; child = child->GetNextSibling()) {
@@ -82,26 +92,28 @@ ContainerLayerOGL::InsertAfter(Layer* aC
NS_WARNING("Failed to find aAfter layer!");
}
void
ContainerLayerOGL::RemoveChild(Layer *aChild)
{
if (GetFirstChild() == aChild) {
mFirstChild = GetFirstChildOGL()->GetNextSibling()->GetLayer();
+ NS_RELEASE(aChild);
return;
}
LayerOGL *lastChild = NULL;
for (LayerOGL *child = GetFirstChildOGL(); child;
child = child->GetNextSibling()) {
if (child->GetLayer() == aChild) {
// We're sure this is not our first child. So lastChild != NULL.
lastChild->SetNextSibling(child->GetNextSibling());
child->SetNextSibling(NULL);
child->GetLayer()->SetParent(NULL);
+ NS_RELEASE(aChild);
return;
}
lastChild = child;
}
}
LayerOGL::LayerType
ContainerLayerOGL::GetType()
@@ -120,17 +132,19 @@ ContainerLayerOGL::GetFirstChildOGL()
{
if (!mFirstChild) {
return nsnull;
}
return static_cast<LayerOGL*>(mFirstChild->ImplData());
}
void
-ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer)
+ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
/**
* Setup our temporary texture for rendering the contents of this container.
*/
GLuint containerSurface;
GLuint frameBuffer;
RGBLayerProgram *rgbProgram =
static_cast<LayerManagerOGL*>(mManager)->GetRGBLayerProgram();
@@ -197,17 +211,17 @@ ContainerLayerOGL::RenderLayer(int aPrev
gl()->fScissor(clipRect->x - GetVisibleRect().x,
clipRect->y - GetVisibleRect().y,
clipRect->width,
clipRect->height);
} else {
gl()->fScissor(0, 0, GetVisibleRect().width, GetVisibleRect().height);
}
- layerToRender->RenderLayer(frameBuffer);
+ layerToRender->RenderLayer(frameBuffer, aCallback, aCallbackData);
layerToRender = layerToRender->GetNextSibling();
}
if (GetOpacity() != 1.0) {
// Unbind the current framebuffer and rebind the previous one.
gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
gl()->fDeleteFramebuffers(1, &frameBuffer);
--- a/gfx/layers/opengl/ContainerLayerOGL.h
+++ b/gfx/layers/opengl/ContainerLayerOGL.h
@@ -44,16 +44,17 @@
namespace mozilla {
namespace layers {
class ContainerLayerOGL : public ContainerLayer,
public LayerOGL
{
public:
ContainerLayerOGL(LayerManagerOGL *aManager);
+ ~ContainerLayerOGL();
const nsIntRect &GetVisibleRect();
/** ContainerLayer implementation */
void SetVisibleRegion(const nsIntRegion& aRegion);
void InsertAfter(Layer* aChild, Layer* aAfter);
@@ -63,17 +64,19 @@ public:
LayerType GetType();
Layer* GetLayer();
LayerOGL* GetFirstChildOGL();
PRBool IsEmpty();
- void RenderLayer(int aPreviousFrameBuffer);
+ void RenderLayer(int aPreviousFrameBuffer,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
private:
nsIntRect mVisibleRect;
GLuint mTexture;
};
} /* layers */
} /* mozilla */
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -264,17 +264,18 @@ ImageLayerOGL::GetType()
Layer*
ImageLayerOGL::GetLayer()
{
return this;
}
void
-ImageLayerOGL::RenderLayer(int)
+ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
if (!GetContainer()) {
return;
}
LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(mManager);
manager->MakeCurrent();
--- a/gfx/layers/opengl/ImageLayerOGL.h
+++ b/gfx/layers/opengl/ImageLayerOGL.h
@@ -170,17 +170,19 @@ public:
mImplData = static_cast<LayerOGL*>(this);
}
// LayerOGL Implementation
virtual LayerType GetType();
virtual Layer* GetLayer();
- virtual void RenderLayer(int aPreviousDestination);
+ virtual void RenderLayer(int aPreviousDestination,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
};
class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage
{
typedef mozilla::gl::GLContext GLContext;
public:
PlanarYCbCrImageOGL(RecycleBin *aRecycleBin);
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -277,24 +277,20 @@ LayerManagerOGL::BeginTransaction()
void
LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget)
{
mTarget = aTarget;
}
void
-LayerManagerOGL::EndConstruction()
+LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
-}
-
-void
-LayerManagerOGL::EndTransaction()
-{
- Render();
+ Render(aCallback, aCallbackData);
mTarget = NULL;
}
void
LayerManagerOGL::SetRoot(Layer *aLayer)
{
mRootLayer = static_cast<LayerOGL*>(aLayer->ImplData());;
}
@@ -353,17 +349,18 @@ LayerManagerOGL::SetClippingEnabled(PRBo
void
LayerManagerOGL::MakeCurrent()
{
mGLContext->MakeCurrent();
}
void
-LayerManagerOGL::Render()
+LayerManagerOGL::Render(DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
nsIntRect rect;
mWidget->GetBounds(rect);
GLint width = rect.width;
GLint height = rect.height;
MakeCurrent();
SetupBackBuffer();
@@ -379,17 +376,17 @@ LayerManagerOGL::Render()
if (mRootLayer) {
const nsIntRect *clipRect = mRootLayer->GetLayer()->GetClipRect();
if (clipRect) {
mGLContext->fScissor(clipRect->x, clipRect->y, clipRect->width, clipRect->height);
} else {
mGLContext->fScissor(0, 0, width, height);
}
- mRootLayer->RenderLayer(mFrameBuffer);
+ mRootLayer->RenderLayer(mFrameBuffer, aCallback, aCallbackData);
}
if (mTarget) {
CopyToTarget();
} else {
/**
* Draw our backbuffer to the screen without using vertex or fragment
* shaders. We're fine with just calculating the viewport coordinates
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -211,17 +211,18 @@ public:
* LayerManager implementation.
*/
void BeginTransaction();
void BeginTransactionWithTarget(gfxContext* aTarget);
void EndConstruction();
- void EndTransaction();
+ virtual void EndTransaction(DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
void SetRoot(Layer* aLayer);
virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
virtual already_AddRefed<ImageLayer> CreateImageLayer();
@@ -288,17 +289,18 @@ private:
/**
* Region we're clipping our current drawing to.
*/
nsIntRegion mClippingRegion;
/**
* Render the current layer tree to the active target.
*/
- void Render();
+ void Render(DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
/**
* Setup the pipeline.
*/
void SetupPipeline();
/**
* Setup the backbuffer.
*
* \return PR_TRUE if setup was succesful
@@ -311,16 +313,18 @@ private:
};
/**
* General information and tree management for OGL layers.
*/
class LayerOGL
{
public:
+ typedef LayerManager::DrawThebesLayerCallback DrawThebesLayerCallback;
+
LayerOGL(LayerManagerOGL *aManager);
enum LayerType {
TYPE_THEBES,
TYPE_CONTAINER,
TYPE_IMAGE,
TYPE_COLOR,
TYPE_CANVAS
@@ -331,17 +335,18 @@ public:
LayerOGL *GetNextSibling();
virtual LayerOGL *GetFirstChildOGL() { return nsnull; }
void SetNextSibling(LayerOGL *aParent);
void SetFirstChild(LayerOGL *aParent);
virtual Layer* GetLayer() = 0;
- virtual void RenderLayer(int aPreviousFrameBuffer) = 0;
+ virtual void RenderLayer(int aPreviousFrameBuffer, DrawThebesLayerCallback aCallback,
+ void* aCallbackData) = 0;
typedef mozilla::gl::GLContext GLContext;
GLContext *gl() const { return mOGLManager->gl(); }
protected:
LayerManagerOGL *mOGLManager;
LayerOGL *mNextSibling;
};
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -123,125 +123,100 @@ void
ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
{
nsIntRegion invalidatedRegion;
invalidatedRegion.Or(aRegion, mInvalidatedRect);
invalidatedRegion.And(invalidatedRegion, mVisibleRect);
mInvalidatedRect = invalidatedRegion.GetBounds();
}
-gfxContext *
-ThebesLayerOGL::BeginDrawing(nsIntRegion *aRegion)
-{
- if (mInvalidatedRect.IsEmpty()) {
- aRegion->SetEmpty();
- return NULL;
- }
- if (!mTexture) {
- aRegion->SetEmpty();
- return NULL;
- }
- *aRegion = mInvalidatedRect;
-
- gfxASurface::gfxImageFormat imageFormat;
-
- if (UseOpaqueSurface(this)) {
- imageFormat = gfxASurface::ImageFormatRGB24;
- } else {
- imageFormat = gfxASurface::ImageFormatARGB32;
- }
-
- mDestinationSurface =
- gfxPlatform::GetPlatform()->
- CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
- mInvalidatedRect.height),
- imageFormat);
-
- mContext = new gfxContext(mDestinationSurface);
- mContext->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
- return mContext.get();
-}
-
-void
-ThebesLayerOGL::EndDrawing()
-{
- static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
-
- nsRefPtr<gfxImageSurface> imageSurface;
-
- gfxASurface::gfxImageFormat imageFormat;
-
- if (UseOpaqueSurface(this)) {
- imageFormat = gfxASurface::ImageFormatRGB24;
- } else {
- imageFormat = gfxASurface::ImageFormatARGB32;
- }
-
- switch (mDestinationSurface->GetType()) {
- case gfxASurface::SurfaceTypeImage:
- imageSurface = static_cast<gfxImageSurface*>(mDestinationSurface.get());
- break;
-#ifdef XP_WIN
- case gfxASurface::SurfaceTypeWin32:
- imageSurface =
- static_cast<gfxWindowsSurface*>(mDestinationSurface.get())->
- GetImageSurface();
- break;
-#endif
- default:
- /**
- * XXX - This is very undesirable. Implement this for other platforms in
- * a more efficient way as well!
- */
- {
- imageSurface = new gfxImageSurface(gfxIntSize(mInvalidatedRect.width,
- mInvalidatedRect.height),
- imageFormat);
- nsRefPtr<gfxContext> tmpContext = new gfxContext(imageSurface);
- tmpContext->SetSource(mDestinationSurface);
- tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
- tmpContext->Paint();
- }
- break;
- }
-
- gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
- gl()->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
- 0,
- mInvalidatedRect.x - mVisibleRect.x,
- mInvalidatedRect.y - mVisibleRect.y,
- mInvalidatedRect.width,
- mInvalidatedRect.height,
- LOCAL_GL_BGRA,
- LOCAL_GL_UNSIGNED_BYTE,
- imageSurface->Data());
-
- mDestinationSurface = NULL;
- mContext = NULL;
-}
-
LayerOGL::LayerType
ThebesLayerOGL::GetType()
{
return TYPE_THEBES;
}
const nsIntRect&
ThebesLayerOGL::GetVisibleRect()
{
return mVisibleRect;
}
void
-ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer)
+ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData)
{
if (!mTexture) {
return;
}
+ if (!mInvalidatedRect.IsEmpty()) {
+ gfxASurface::gfxImageFormat imageFormat;
+
+ if (UseOpaqueSurface(this)) {
+ imageFormat = gfxASurface::ImageFormatRGB24;
+ } else {
+ imageFormat = gfxASurface::ImageFormatARGB32;
+ }
+
+ nsRefPtr<gfxASurface> surface =
+ gfxPlatform::GetPlatform()->
+ CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
+ mInvalidatedRect.height),
+ imageFormat);
+
+ nsRefPtr<gfxContext> ctx = new gfxContext(surface);
+ ctx->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
+ aCallback(this, ctx, mInvalidatedRect, aCallbackData);
+
+ static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
+
+ nsRefPtr<gfxImageSurface> imageSurface;
+
+ switch (surface->GetType()) {
+ case gfxASurface::SurfaceTypeImage:
+ imageSurface = static_cast<gfxImageSurface*>(surface.get());
+ break;
+#ifdef XP_WIN
+ case gfxASurface::SurfaceTypeWin32:
+ imageSurface =
+ static_cast<gfxWindowsSurface*>(surface.get())->
+ GetImageSurface();
+ break;
+#endif
+ default:
+ /**
+ * XXX - This is very undesirable. Implement this for other platforms in
+ * a more efficient way as well!
+ */
+ {
+ imageSurface = new gfxImageSurface(gfxIntSize(mInvalidatedRect.width,
+ mInvalidatedRect.height),
+ imageFormat);
+ nsRefPtr<gfxContext> tmpContext = new gfxContext(imageSurface);
+ tmpContext->SetSource(surface);
+ tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
+ tmpContext->Paint();
+ }
+ break;
+ }
+
+ gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+ gl()->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
+ 0,
+ mInvalidatedRect.x - mVisibleRect.x,
+ mInvalidatedRect.y - mVisibleRect.y,
+ mInvalidatedRect.width,
+ mInvalidatedRect.height,
+ LOCAL_GL_BGRA,
+ LOCAL_GL_UNSIGNED_BYTE,
+ imageSurface->Data());
+ }
+
float quadTransform[4][4];
/*
* Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position
* and size.
*/
memset(&quadTransform, 0, sizeof(quadTransform));
quadTransform[0][0] = (float)GetVisibleRect().width;
quadTransform[1][1] = (float)GetVisibleRect().height;
--- a/gfx/layers/opengl/ThebesLayerOGL.h
+++ b/gfx/layers/opengl/ThebesLayerOGL.h
@@ -54,50 +54,38 @@ public:
virtual ~ThebesLayerOGL();
/** Layer implementation */
void SetVisibleRegion(const nsIntRegion& aRegion);
/** ThebesLayer implementation */
void InvalidateRegion(const nsIntRegion& aRegion);
- gfxContext *BeginDrawing(nsIntRegion* aRegionToDraw);
-
- void EndDrawing();
-
/** LayerOGL implementation */
LayerType GetType();
Layer* GetLayer();
virtual PRBool IsEmpty();
- virtual void RenderLayer(int aPreviousFrameBuffer);
+ virtual void RenderLayer(int aPreviousFrameBuffer,
+ DrawThebesLayerCallback aCallback,
+ void* aCallbackData);
/** ThebesLayerOGL */
const nsIntRect &GetVisibleRect();
const nsIntRect &GetInvalidatedRect();
private:
/**
* Visible rectangle, this is used to know the size and position of the quad
* when doing the rendering of this layer.
*/
nsIntRect mVisibleRect;
/**
* Currently invalidated rectangular area.
*/
nsIntRect mInvalidatedRect;
- /**
- * Destination surface used for this layer's drawing operation. This is
- * created on BeginDrawing() and should be removed on EndDrawing().
- */
- nsRefPtr<gfxASurface> mDestinationSurface;
-
- /**
- * We hold the reference to the context.
- */
- nsRefPtr<gfxContext> mContext;
/**
* OpenGL Texture
*/
GLuint mTexture;
};
new file mode 100644
--- /dev/null
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -0,0 +1,539 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Robert O'Callahan <robert@ocallahan.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "FrameLayerBuilder.h"
+
+#include "nsDisplayList.h"
+#include "nsPresContext.h"
+#include "nsLayoutUtils.h"
+
+using namespace mozilla::layers;
+
+namespace mozilla {
+
+namespace {
+
+/**
+ * This class iterates through a display list tree, descending only into
+ * nsDisplayClip items, and returns each display item encountered during
+ * such iteration. Along with each item we also return the clip rect
+ * accumulated for the item.
+ */
+class ClippedItemIterator {
+public:
+ ClippedItemIterator(const nsDisplayList* aList)
+ {
+ DescendIntoList(aList, nsnull, nsnull);
+ AdvanceToItem();
+ }
+ PRBool IsDone()
+ {
+ return mStack.IsEmpty();
+ }
+ void Next()
+ {
+ State* top = StackTop();
+ top->mItem = top->mItem->GetAbove();
+ AdvanceToItem();
+ }
+ // Returns null if there is no clipping affecting the item. The
+ // clip rect is in device pixels
+ const gfxRect* GetEffectiveClipRect()
+ {
+ State* top = StackTop();
+ return top->mHasClipRect ? &top->mEffectiveClipRect : nsnull;
+ }
+ nsDisplayItem* Item()
+ {
+ return StackTop()->mItem;
+ }
+
+private:
+ // We maintain a stack of state objects. Each State object represents
+ // where we're up to in the iteration of a list.
+ struct State {
+ // The current item we're at in the list
+ nsDisplayItem* mItem;
+ // The effective clip rect applying to all the items in this list
+ gfxRect mEffectiveClipRect;
+ PRPackedBool mHasClipRect;
+ };
+
+ State* StackTop()
+ {
+ return &mStack[mStack.Length() - 1];
+ }
+ void DescendIntoList(const nsDisplayList* aList,
+ nsPresContext* aPresContext,
+ const nsRect* aClipRect)
+ {
+ State* state = mStack.AppendElement();
+ if (!state)
+ return;
+ if (mStack.Length() >= 2) {
+ *state = mStack[mStack.Length() - 2];
+ } else {
+ state->mHasClipRect = PR_FALSE;
+ }
+ state->mItem = aList->GetBottom();
+ if (aClipRect) {
+ gfxRect r(aClipRect->x, aClipRect->y, aClipRect->width, aClipRect->height);
+ r.ScaleInverse(aPresContext->AppUnitsPerDevPixel());
+ if (state->mHasClipRect) {
+ state->mEffectiveClipRect = state->mEffectiveClipRect.Intersect(r);
+ } else {
+ state->mEffectiveClipRect = r;
+ state->mHasClipRect = PR_TRUE;
+ }
+ }
+ }
+ // Advances to an item that the iterator should return.
+ void AdvanceToItem()
+ {
+ while (!mStack.IsEmpty()) {
+ State* top = StackTop();
+ if (!top->mItem) {
+ mStack.SetLength(mStack.Length() - 1);
+ if (!mStack.IsEmpty()) {
+ top = StackTop();
+ top->mItem = top->mItem->GetAbove();
+ }
+ continue;
+ }
+ if (top->mItem->GetType() != nsDisplayItem::TYPE_CLIP)
+ return;
+ nsDisplayClip* clipItem = static_cast<nsDisplayClip*>(top->mItem);
+ nsRect clip = clipItem->GetClipRect();
+ DescendIntoList(clipItem->GetList(),
+ clipItem->GetClippingFrame()->PresContext(),
+ &clip);
+ }
+ }
+
+ nsAutoTArray<State,10> mStack;
+};
+
+/**
+ * This class represents a sublist of consecutive items in an nsDisplayList.
+ * The first item in the sublist is mStartItem and the last item
+ * is the item before mEndItem.
+ *
+ * These sublists are themselves organized into a linked list of all
+ * the ItemGroups associated with a given layer, via mNextItemsForLayer.
+ * This list will have more than one element if the display items in a layer
+ * come from different nsDisplayLists, or if they come from the same
+ * nsDisplayList but they aren't consecutive in that list.
+ *
+ * These objects are allocated from the nsDisplayListBuilder arena.
+ */
+struct ItemGroup {
+ // If null, then the item group is empty.
+ nsDisplayItem* mStartItem;
+ nsDisplayItem* mEndItem;
+ ItemGroup* mNextItemsForLayer;
+ // The clipping (if any) that needs to be applied to all these items.
+ gfxRect mClipRect;
+ PRPackedBool mHasClipRect;
+
+ ItemGroup() : mStartItem(nsnull), mEndItem(nsnull),
+ mNextItemsForLayer(nsnull), mHasClipRect(PR_FALSE) {}
+
+ void* operator new(size_t aSize,
+ nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
+ return aBuilder->Allocate(aSize);
+ }
+};
+
+/**
+ * This class represents a layer and the display item(s) it
+ * will render. The items are stored in a linked list of ItemGroups.
+ */
+struct LayerItems {
+ nsRefPtr<Layer> mLayer;
+ // equal to mLayer, or null if mLayer is not a ThebesLayer
+ ThebesLayer* mThebesLayer;
+ ItemGroup* mItems;
+ // The bounds of the visible region for this layer, in device pixels
+ nsIntRect mVisibleRect;
+
+ LayerItems(ItemGroup* aItems) :
+ mThebesLayer(nsnull), mItems(aItems)
+ {
+ }
+
+ void* operator new(size_t aSize,
+ nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
+ return aBuilder->Allocate(aSize);
+ }
+};
+
+/**
+ * Given a (possibly clipped) display item in aItem, try to append it to
+ * the items in aGroup. If aItem is the next item in the sublist in
+ * aGroup, and the clipping matches, we can just update aGroup in-place,
+ * otherwise we'll allocate a new ItemGroup, add it to the linked list,
+ * and put aItem in the new ItemGroup. We return the ItemGroup into which
+ * aItem was inserted.
+ */
+static ItemGroup*
+AddToItemGroup(nsDisplayListBuilder* aBuilder,
+ ItemGroup* aGroup, nsDisplayItem* aItem,
+ const gfxRect* aClipRect)
+{
+ NS_ASSERTION(!aGroup->mNextItemsForLayer,
+ "aGroup must be the last group in the chain");
+
+ if (!aGroup->mStartItem) {
+ aGroup->mStartItem = aItem;
+ aGroup->mEndItem = aItem->GetAbove();
+ aGroup->mHasClipRect = aClipRect != nsnull;
+ if (aClipRect) {
+ aGroup->mClipRect = *aClipRect;
+ }
+ return aGroup;
+ }
+
+ if (aGroup->mEndItem == aItem &&
+ (aGroup->mHasClipRect
+ ? (aClipRect && aGroup->mClipRect == *aClipRect)
+ : !aClipRect)) {
+ aGroup->mEndItem = aItem->GetAbove();
+ return aGroup;
+ }
+
+ ItemGroup* itemGroup = new (aBuilder) ItemGroup();
+ if (!itemGroup)
+ return aGroup;
+ aGroup->mNextItemsForLayer = itemGroup;
+ return AddToItemGroup(aBuilder, itemGroup, aItem, aClipRect);
+}
+
+/**
+ * Create an empty Thebes layer, with an empty ItemGroup associated with
+ * it, and append it to aLayers.
+ */
+static ItemGroup*
+CreateEmptyThebesLayer(nsDisplayListBuilder* aBuilder,
+ LayerManager* aManager,
+ nsTArray<LayerItems*>* aLayers)
+{
+ ItemGroup* itemGroup = new (aBuilder) ItemGroup();
+ if (!itemGroup)
+ return nsnull;
+ nsRefPtr<ThebesLayer> thebesLayer = aManager->CreateThebesLayer();
+ if (!thebesLayer)
+ return nsnull;
+ LayerItems* layerItems = new (aBuilder) LayerItems(itemGroup);
+ aLayers->AppendElement(layerItems);
+ thebesLayer->SetUserData(layerItems);
+ layerItems->mThebesLayer = thebesLayer;
+ layerItems->mLayer = thebesLayer.forget();
+ return itemGroup;
+}
+
+static PRBool
+IsAllUniform(nsDisplayListBuilder* aBuilder, ItemGroup* aGroup,
+ nscolor* aColor)
+{
+ nsRect visibleRect = aGroup->mStartItem->GetVisibleRect();
+ nscolor finalColor = NS_RGBA(0,0,0,0);
+ for (ItemGroup* group = aGroup; group;
+ group = group->mNextItemsForLayer) {
+ for (nsDisplayItem* item = group->mStartItem; item != group->mEndItem;
+ item = item->GetAbove()) {
+ nscolor color;
+ if (visibleRect != item->GetVisibleRect())
+ return PR_FALSE;
+ if (!item->IsUniform(aBuilder, &color))
+ return PR_FALSE;
+ finalColor = NS_ComposeColors(finalColor, color);
+ }
+ }
+ *aColor = finalColor;
+ return PR_TRUE;
+}
+
+/**
+ * This is the heart of layout's integration with layers. We
+ * use a ClippedItemIterator to iterate through descendant display
+ * items. Each item either has its own layer or is assigned to a
+ * ThebesLayer. We create ThebesLayers as necessary, although we try
+ * to put items in the bottom-most ThebesLayer because that is most
+ * likely to be able to render with an opaque background, which will often
+ * be required for subpixel text antialiasing to work.
+ */
+static void BuildLayers(nsDisplayListBuilder* aBuilder,
+ const nsDisplayList& aList,
+ LayerManager* aManager,
+ nsTArray<LayerItems*>* aLayers)
+{
+ NS_ASSERTION(aLayers->IsEmpty(), "aLayers must be initially empty");
+
+ // Create "bottom" Thebes layer. We'll try to put as much content
+ // as possible in this layer because if the container is filled with
+ // opaque content, this bottommost layer can also be treated as opaque,
+ // which means content in this layer can have subpixel AA.
+ // firstThebesLayerItems always points to the last ItemGroup for the
+ // first Thebes layer.
+ ItemGroup* firstThebesLayerItems =
+ CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
+ if (!firstThebesLayerItems)
+ return;
+ // lastThebesLayerItems always points to the last ItemGroup for the
+ // topmost layer, if it's a ThebesLayer. If the top layer is not a
+ // Thebes layer, this is null.
+ ItemGroup* lastThebesLayerItems = firstThebesLayerItems;
+ // This region contains the bounds of all the content that is above
+ // the first Thebes layer.
+ nsRegion areaAboveFirstThebesLayer;
+
+ for (ClippedItemIterator iter(&aList); !iter.IsDone(); iter.Next()) {
+ nsDisplayItem* item = iter.Item();
+ const gfxRect* clipRect = iter.GetEffectiveClipRect();
+ // Ask the item if it manages its own layer
+ nsRefPtr<Layer> layer = item->BuildLayer(aBuilder, aManager);
+ nsRect bounds = item->GetBounds(aBuilder);
+ // We set layerItems to point to the LayerItems object where the
+ // item ends up.
+ LayerItems* layerItems = nsnull;
+ if (layer) {
+ // item has a dedicated layer. Add it to the list, with an ItemGroup
+ // covering this item only.
+ ItemGroup* itemGroup = new (aBuilder) ItemGroup();
+ if (itemGroup) {
+ AddToItemGroup(aBuilder, itemGroup, item, clipRect);
+ layerItems = new (aBuilder) LayerItems(itemGroup);
+ aLayers->AppendElement(layerItems);
+ if (layerItems) {
+ if (itemGroup->mHasClipRect) {
+ gfxRect r = itemGroup->mClipRect;
+ r.Round();
+ nsIntRect intRect(r.X(), r.Y(), r.Width(), r.Height());
+ layer->IntersectClipRect(intRect);
+ }
+ layerItems->mLayer = layer.forget();
+ }
+ }
+ // This item is above the first Thebes layer.
+ areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
+ lastThebesLayerItems = nsnull;
+ } else {
+ // No dedicated layer. Add it to a Thebes layer. First try to add
+ // it to the first Thebes layer, which we can do if there's no
+ // content between the first Thebes layer and our display item that
+ // overlaps our display item.
+ if (!areaAboveFirstThebesLayer.Intersects(bounds)) {
+ firstThebesLayerItems =
+ AddToItemGroup(aBuilder, firstThebesLayerItems, item, clipRect);
+ layerItems = aLayers->ElementAt(0);
+ } else if (lastThebesLayerItems) {
+ // Try to add to the last Thebes layer
+ lastThebesLayerItems =
+ AddToItemGroup(aBuilder, lastThebesLayerItems, item, clipRect);
+ // This item is above the first Thebes layer.
+ areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
+ layerItems = aLayers->ElementAt(aLayers->Length() - 1);
+ } else {
+ // Create a new Thebes layer
+ ItemGroup* itemGroup =
+ CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
+ if (itemGroup) {
+ lastThebesLayerItems =
+ AddToItemGroup(aBuilder, itemGroup, item, clipRect);
+ NS_ASSERTION(lastThebesLayerItems == itemGroup,
+ "AddToItemGroup shouldn't create a new group if the "
+ "initial group is empty");
+ // This item is above the first Thebes layer.
+ areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
+ }
+ }
+ }
+
+ if (layerItems) {
+ // Update the visible region of the layer to account for the new
+ // item
+ nscoord appUnitsPerDevPixel =
+ item->GetUnderlyingFrame()->PresContext()->AppUnitsPerDevPixel();
+ layerItems->mVisibleRect.UnionRect(layerItems->mVisibleRect,
+ item->GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel));
+ }
+ }
+
+ if (!firstThebesLayerItems->mStartItem) {
+ // The first Thebes layer has nothing in it. Delete the layer.
+ // Ensure layer is released.
+ aLayers->ElementAt(0)->mLayer = nsnull;
+ aLayers->RemoveElementAt(0);
+ }
+
+ for (PRUint32 i = 0; i < aLayers->Length(); ++i) {
+ LayerItems* layerItems = aLayers->ElementAt(i);
+
+ nscolor color;
+ // Only convert layers with identity transform to ColorLayers, for now.
+ // This simplifies the code to set the clip region.
+ if (layerItems->mThebesLayer &&
+ IsAllUniform(aBuilder, layerItems->mItems, &color) &&
+ layerItems->mLayer->GetTransform().IsIdentity()) {
+ nsRefPtr<ColorLayer> layer = aManager->CreateColorLayer();
+ layer->SetClipRect(layerItems->mThebesLayer->GetClipRect());
+ // Clip to mVisibleRect to ensure only the pixels we want are filled.
+ layer->IntersectClipRect(layerItems->mVisibleRect);
+ layer->SetColor(gfxRGBA(color));
+ layerItems->mLayer = layer.forget();
+ layerItems->mThebesLayer = nsnull;
+ }
+
+ gfxMatrix transform;
+ nsIntRect visibleRect = layerItems->mVisibleRect;
+ if (layerItems->mLayer->GetTransform().Is2D(&transform)) {
+ // if 'transform' is not invertible, then nothing will be displayed
+ // for the layer, so it doesn't really matter what we do here
+ transform.Invert();
+ gfxRect layerVisible = transform.TransformBounds(
+ gfxRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height));
+ layerVisible.RoundOut();
+ if (NS_FAILED(nsLayoutUtils::GfxRectToIntRect(layerVisible, &visibleRect))) {
+ NS_ERROR("Visible rect transformed out of bounds");
+ }
+ } else {
+ NS_ERROR("Only 2D transformations currently supported");
+ }
+ layerItems->mLayer->SetVisibleRegion(nsIntRegion(visibleRect));
+ }
+}
+
+} // anonymous namespace
+
+already_AddRefed<Layer>
+FrameLayerBuilder::MakeContainerLayerFor(nsDisplayListBuilder* aBuilder,
+ LayerManager* aManager,
+ nsDisplayItem* aContainer,
+ const nsDisplayList& aChildren)
+{
+ // If there's only one layer, then in principle we can try to flatten
+ // things by returning that layer here. But that adds complexity to
+ // retained layer management so we don't do it. Layer backends can
+ // flatten internally.
+ nsRefPtr<ContainerLayer> container = aManager->CreateContainerLayer();
+ if (!container)
+ return nsnull;
+
+ nsAutoTArray<LayerItems*,10> layerItems;
+ BuildLayers(aBuilder, aChildren, aManager, &layerItems);
+
+ Layer* lastChild = nsnull;
+ for (PRUint32 i = 0; i < layerItems.Length(); ++i) {
+ Layer* child = layerItems[i]->mLayer;
+ container->InsertAfter(child, lastChild);
+ lastChild = child;
+ // release the layer now because the ItemGroup destructor doesn't run;
+ // the container is still holding a reference to it
+ layerItems[i]->mLayer = nsnull;
+ }
+ container->SetIsOpaqueContent(aChildren.IsOpaque());
+ nsRefPtr<Layer> layer = container.forget();
+ return layer.forget();
+}
+
+/* static */ void
+FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
+ gfxContext* aContext,
+ const nsIntRegion& aRegionToDraw,
+ void* aCallbackData)
+{
+ LayerItems* layerItems = static_cast<LayerItems*>(aLayer->GetUserData());
+ nsDisplayListBuilder* builder =
+ static_cast<nsDisplayListBuilder*>(aCallbackData);
+
+ // For now, we'll ignore toDraw and just draw the entire visible
+ // area, because the "visible area" is already confined to just the
+ // area that needs to be repainted. Later, when we start reusing layers
+ // from paint to paint, we'll need to pay attention to toDraw and
+ // actually try to avoid drawing stuff that's not in it.
+
+ // Our list may contain content with different prescontexts at
+ // different zoom levels. 'rc' contains the nsIRenderingContext
+ // used for the previous display item, and lastPresContext is the
+ // prescontext for that item. We also cache the clip state for that
+ // item.
+ nsRefPtr<nsIRenderingContext> rc;
+ nsPresContext* lastPresContext = nsnull;
+ gfxRect currentClip;
+ PRBool setClipRect = PR_FALSE;
+ NS_ASSERTION(layerItems->mItems, "No empty layers allowed");
+ for (ItemGroup* group = layerItems->mItems; group;
+ group = group->mNextItemsForLayer) {
+ // If the new desired clip state is different from the current state,
+ // update the clip.
+ if (setClipRect != group->mHasClipRect ||
+ (group->mHasClipRect && group->mClipRect != currentClip)) {
+ if (setClipRect) {
+ aContext->Restore();
+ }
+ setClipRect = group->mHasClipRect;
+ if (setClipRect) {
+ aContext->Save();
+ aContext->NewPath();
+ aContext->Rectangle(group->mClipRect, PR_TRUE);
+ aContext->Clip();
+ currentClip = group->mClipRect;
+ }
+ }
+ NS_ASSERTION(group->mStartItem, "No empty groups allowed");
+ for (nsDisplayItem* item = group->mStartItem; item != group->mEndItem;
+ item = item->GetAbove()) {
+ nsPresContext* presContext = item->GetUnderlyingFrame()->PresContext();
+ if (presContext != lastPresContext) {
+ // Create a new rendering context with the right
+ // appunits-per-dev-pixel.
+ nsresult rv =
+ presContext->DeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc));
+ if (NS_FAILED(rv))
+ break;
+ rc->Init(presContext->DeviceContext(), aContext);
+ lastPresContext = presContext;
+ }
+ item->Paint(builder, rc);
+ }
+ }
+ if (setClipRect) {
+ aContext->Restore();
+ }
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/base/FrameLayerBuilder.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Robert O'Callahan <robert@ocallahan.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef FRAMELAYERBUILDER_H_
+#define FRAMELAYERBUILDER_H_
+
+#include "Layers.h"
+
+class nsDisplayListBuilder;
+class nsDisplayList;
+class nsDisplayItem;
+
+namespace mozilla {
+
+class FrameLayerBuilder {
+public:
+ typedef mozilla::layers::Layer Layer;
+ typedef mozilla::layers::ThebesLayer ThebesLayer;
+ typedef mozilla::layers::LayerManager LayerManager;
+
+ /**
+ * Create a container layer for a display item that contains a child
+ * list, either reusing an existing one or creating a new one.
+ * aContainer may be null, in which case we construct a root layer.
+ */
+ already_AddRefed<Layer> MakeContainerLayerFor(nsDisplayListBuilder* aBuilder,
+ LayerManager* aManager,
+ nsDisplayItem* aContainer,
+ const nsDisplayList& aChildren);
+
+ /**
+ * This callback must be provided to EndTransaction. The callback data
+ * must be the nsDisplayListBuilder containing this FrameLayerBuilder.
+ */
+ static void DrawThebesLayer(ThebesLayer* aLayer,
+ gfxContext* aContext,
+ const nsIntRegion& aRegionToDraw,
+ void* aCallbackData);
+};
+
+}
+
+#endif /* FRAMELAYERBUILDER_H_ */
--- a/layout/base/Makefile.in
+++ b/layout/base/Makefile.in
@@ -54,16 +54,17 @@ LIBXUL_LIBRARY = 1
XPIDLSRCS = \
nsIStyleSheetService.idl \
$(NULL)
EXPORTS = \
+ FrameLayerBuilder.h \
FramePropertyTable.h \
nsBidi.h \
nsBidiPresUtils.h \
nsCaret.h \
nsCSSFrameConstructor.h \
nsChangeHint.h \
nsCompatibility.h \
nsDisplayList.h \
@@ -83,16 +84,17 @@ EXPORTS = \
nsPresContext.h \
nsPresState.h \
nsRefreshDriver.h \
nsStyleChangeList.h \
nsStyleConsts.h \
$(NULL)
CPPSRCS = \
+ FrameLayerBuilder.cpp \
FramePropertyTable.cpp \
nsCSSColorUtils.cpp \
nsCSSFrameConstructor.cpp \
nsCSSRendering.cpp \
nsCSSRenderingBorders.cpp \
nsCaret.cpp \
nsChildIterator.cpp \
nsCounterManager.cpp \
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -57,16 +57,17 @@
#include "nsSVGIntegrationUtils.h"
#endif
#include "nsLayoutUtils.h"
#include "imgIContainer.h"
#include "nsIInterfaceRequestorUtils.h"
#include "BasicLayers.h"
+using namespace mozilla;
using namespace mozilla::layers;
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
PRBool aIsForEvents, PRBool aBuildCaret)
: mReferenceFrame(aReferenceFrame),
mMovingFrame(nsnull),
mSaveVisibleRegionOfMovingContent(nsnull),
mIgnoreScrollFrame(nsnull),
@@ -400,380 +401,16 @@ nsDisplayList::ComputeVisibility(nsDispl
movingContentVisibleRegionAfterMove);
mIsOpaque = aVisibleRegion->IsEmpty();
#ifdef DEBUG
mDidComputeVisibility = PR_TRUE;
#endif
}
-namespace {
-/**
- * This class iterates through a display list tree, descending only into
- * nsDisplayClip items, and returns each display item encountered during
- * such iteration. Along with each item we also return the clip rect
- * accumulated for the item.
- */
-class ClippedItemIterator {
-public:
- ClippedItemIterator(const nsDisplayList* aList)
- {
- DescendIntoList(aList, nsnull, nsnull);
- AdvanceToItem();
- }
- PRBool IsDone()
- {
- return mStack.IsEmpty();
- }
- void Next()
- {
- State* top = StackTop();
- top->mItem = top->mItem->GetAbove();
- AdvanceToItem();
- }
- // Returns null if there is no clipping affecting the item. The
- // clip rect is in device pixels
- const gfxRect* GetEffectiveClipRect()
- {
- State* top = StackTop();
- return top->mHasClipRect ? &top->mEffectiveClipRect : nsnull;
- }
- nsDisplayItem* Item()
- {
- return StackTop()->mItem;
- }
-
-private:
- // We maintain a stack of state objects. Each State object represents
- // where we're up to in the iteration of a list.
- struct State {
- // The current item we're at in the list
- nsDisplayItem* mItem;
- // The effective clip rect applying to all the items in this list
- gfxRect mEffectiveClipRect;
- PRPackedBool mHasClipRect;
- };
-
- State* StackTop()
- {
- return &mStack[mStack.Length() - 1];
- }
- void DescendIntoList(const nsDisplayList* aList,
- nsPresContext* aPresContext,
- const nsRect* aClipRect)
- {
- State* state = mStack.AppendElement();
- if (!state)
- return;
- if (mStack.Length() >= 2) {
- *state = mStack[mStack.Length() - 2];
- } else {
- state->mHasClipRect = PR_FALSE;
- }
- state->mItem = aList->GetBottom();
- if (aClipRect) {
- gfxRect r(aClipRect->x, aClipRect->y, aClipRect->width, aClipRect->height);
- r.ScaleInverse(aPresContext->AppUnitsPerDevPixel());
- if (state->mHasClipRect) {
- state->mEffectiveClipRect = state->mEffectiveClipRect.Intersect(r);
- } else {
- state->mEffectiveClipRect = r;
- state->mHasClipRect = PR_TRUE;
- }
- }
- }
- // Advances to an item that the iterator should return.
- void AdvanceToItem()
- {
- while (!mStack.IsEmpty()) {
- State* top = StackTop();
- if (!top->mItem) {
- mStack.SetLength(mStack.Length() - 1);
- if (!mStack.IsEmpty()) {
- top = StackTop();
- top->mItem = top->mItem->GetAbove();
- }
- continue;
- }
- if (top->mItem->GetType() != nsDisplayItem::TYPE_CLIP)
- return;
- nsDisplayClip* clipItem = static_cast<nsDisplayClip*>(top->mItem);
- nsRect clip = clipItem->GetClipRect();
- DescendIntoList(clipItem->GetList(),
- clipItem->GetClippingFrame()->PresContext(),
- &clip);
- }
- }
-
- nsAutoTArray<State,10> mStack;
-};
-}
-
-/**
- * Given a (possibly clipped) display item in aItem, try to append it to
- * the items in aGroup. If aItem is the next item in the sublist in
- * aGroup, and the clipping matches, we can just update aGroup in-place,
- * otherwise we'll allocate a new ItemGroup, add it to the linked list,
- * and put aItem in the new ItemGroup. We return the ItemGroup into which
- * aItem was inserted.
- */
-static nsDisplayList::ItemGroup*
-AddToItemGroup(nsDisplayListBuilder* aBuilder,
- nsDisplayList::ItemGroup* aGroup, nsDisplayItem* aItem,
- const gfxRect* aClipRect) {
- NS_ASSERTION(!aGroup->mNextItemsForLayer,
- "aGroup must be the last group in the chain");
-
- if (!aGroup->mStartItem) {
- aGroup->mStartItem = aItem;
- aGroup->mEndItem = aItem->GetAbove();
- aGroup->mHasClipRect = aClipRect != nsnull;
- if (aClipRect) {
- aGroup->mClipRect = *aClipRect;
- }
- return aGroup;
- }
-
- if (aGroup->mEndItem == aItem &&
- (aGroup->mHasClipRect
- ? (aClipRect && aGroup->mClipRect == *aClipRect)
- : !aClipRect)) {
- aGroup->mEndItem = aItem->GetAbove();
- return aGroup;
- }
-
- nsDisplayList::ItemGroup* itemGroup =
- new (aBuilder) nsDisplayList::ItemGroup();
- if (!itemGroup)
- return aGroup;
- aGroup->mNextItemsForLayer = itemGroup;
- return AddToItemGroup(aBuilder, itemGroup, aItem, aClipRect);
-}
-
-/**
- * Create an empty Thebes layer, with an empty ItemGroup associated with
- * it, and append it to aLayers.
- */
-static nsDisplayList::ItemGroup*
-CreateEmptyThebesLayer(nsDisplayListBuilder* aBuilder,
- LayerManager* aManager,
- nsTArray<nsDisplayList::LayerItems>* aLayers) {
- nsDisplayList::ItemGroup* itemGroup =
- new (aBuilder) nsDisplayList::ItemGroup();
- if (!itemGroup)
- return nsnull;
- nsRefPtr<ThebesLayer> thebesLayer =
- aManager->CreateThebesLayer();
- if (!thebesLayer)
- return nsnull;
- nsDisplayList::LayerItems* layerItems =
- aLayers->AppendElement(nsDisplayList::LayerItems(itemGroup));
- layerItems->mThebesLayer = thebesLayer;
- layerItems->mLayer = thebesLayer.forget();
- return itemGroup;
-}
-
-static PRBool
-IsAllUniform(nsDisplayListBuilder* aBuilder, nsDisplayList::ItemGroup* aGroup,
- nscolor* aColor)
-{
- nsRect visibleRect = aGroup->mStartItem->GetVisibleRect();
- nscolor finalColor = NS_RGBA(0,0,0,0);
- for (nsDisplayList::ItemGroup* group = aGroup; group;
- group = group->mNextItemsForLayer) {
- for (nsDisplayItem* item = group->mStartItem; item != group->mEndItem;
- item = item->GetAbove()) {
- nscolor color;
- if (visibleRect != item->GetVisibleRect())
- return PR_FALSE;
- if (!item->IsUniform(aBuilder, &color))
- return PR_FALSE;
- finalColor = NS_ComposeColors(finalColor, color);
- }
- }
- *aColor = finalColor;
- return PR_TRUE;
-}
-
-/**
- * This is the heart of layout's integration with layers. We
- * use a ClippedItemIterator to iterate through descendant display
- * items. Each item either has its own layer or is assigned to a
- * ThebesLayer. We create ThebesLayers as necessary, although we try
- * to put items in the bottom-most ThebesLayer because that is most
- * likely to be able to render with an opaque background, which will often
- * be required for subpixel text antialiasing to work.
- */
-void nsDisplayList::BuildLayers(nsDisplayListBuilder* aBuilder,
- LayerManager* aManager,
- nsTArray<LayerItems>* aLayers) const {
- NS_ASSERTION(aLayers->IsEmpty(), "aLayers must be initially empty");
-
- // Create "bottom" Thebes layer. We'll try to put as much content
- // as possible in this layer because if the container is filled with
- // opaque content, this bottommost layer can also be treated as opaque,
- // which means content in this layer can have subpixel AA.
- // firstThebesLayerItems always points to the last ItemGroup for the
- // first Thebes layer.
- ItemGroup* firstThebesLayerItems =
- CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
- if (!firstThebesLayerItems)
- return;
- // lastThebesLayerItems always points to the last ItemGroup for the
- // topmost layer, if it's a ThebesLayer. If the top layer is not a
- // Thebes layer, this is null.
- ItemGroup* lastThebesLayerItems = firstThebesLayerItems;
- // This region contains the bounds of all the content that is above
- // the first Thebes layer.
- nsRegion areaAboveFirstThebesLayer;
-
- for (ClippedItemIterator iter(this); !iter.IsDone(); iter.Next()) {
- nsDisplayItem* item = iter.Item();
- const gfxRect* clipRect = iter.GetEffectiveClipRect();
- // Ask the item if it manages its own layer
- nsRefPtr<Layer> layer = item->BuildLayer(aBuilder, aManager);
- nsRect bounds = item->GetBounds(aBuilder);
- // We set layerItems to point to the LayerItems object where the
- // item ends up.
- LayerItems* layerItems = nsnull;
- if (layer) {
- // item has a dedicated layer. Add it to the list, with an ItemGroup
- // covering this item only.
- ItemGroup* itemGroup = new (aBuilder) ItemGroup();
- if (itemGroup) {
- AddToItemGroup(aBuilder, itemGroup, item, clipRect);
- layerItems = aLayers->AppendElement(LayerItems(itemGroup));
- if (layerItems) {
- if (itemGroup->mHasClipRect) {
- gfxRect r = itemGroup->mClipRect;
- r.Round();
- nsIntRect intRect(r.X(), r.Y(), r.Width(), r.Height());
- layer->IntersectClipRect(intRect);
- }
- layerItems->mLayer = layer.forget();
- }
- }
- // This item is above the first Thebes layer.
- areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
- lastThebesLayerItems = nsnull;
- } else {
- // No dedicated layer. Add it to a Thebes layer. First try to add
- // it to the first Thebes layer, which we can do if there's no
- // content between the first Thebes layer and our display item that
- // overlaps our display item.
- if (!areaAboveFirstThebesLayer.Intersects(bounds)) {
- firstThebesLayerItems =
- AddToItemGroup(aBuilder, firstThebesLayerItems, item, clipRect);
- layerItems = &aLayers->ElementAt(0);
- } else if (lastThebesLayerItems) {
- // Try to add to the last Thebes layer
- lastThebesLayerItems =
- AddToItemGroup(aBuilder, lastThebesLayerItems, item, clipRect);
- // This item is above the first Thebes layer.
- areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
- layerItems = &aLayers->ElementAt(aLayers->Length() - 1);
- } else {
- // Create a new Thebes layer
- ItemGroup* itemGroup =
- CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
- if (itemGroup) {
- lastThebesLayerItems =
- AddToItemGroup(aBuilder, itemGroup, item, clipRect);
- NS_ASSERTION(lastThebesLayerItems == itemGroup,
- "AddToItemGroup shouldn't create a new group if the "
- "initial group is empty");
- // This item is above the first Thebes layer.
- areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
- layerItems = &aLayers->ElementAt(aLayers->Length() - 1);
- }
- }
- }
-
- if (layerItems) {
- // Update the visible region of the layer to account for the new
- // item
- nscoord appUnitsPerDevPixel =
- item->GetUnderlyingFrame()->PresContext()->AppUnitsPerDevPixel();
- layerItems->mVisibleRect.UnionRect(layerItems->mVisibleRect,
- item->mVisibleRect.ToNearestPixels(appUnitsPerDevPixel));
- }
- }
-
- if (!firstThebesLayerItems->mStartItem) {
- // The first Thebes layer has nothing in it. Delete the layer.
- aLayers->RemoveElementAt(0);
- }
-
- for (PRUint32 i = 0; i < aLayers->Length(); ++i) {
- LayerItems* layerItems = &aLayers->ElementAt(i);
-
- nscolor color;
- // Only convert layers with identity transform to ColorLayers, for now.
- // This simplifies the code to set the clip region.
- if (layerItems->mThebesLayer &&
- IsAllUniform(aBuilder, layerItems->mItems, &color) &&
- layerItems->mLayer->GetTransform().IsIdentity()) {
- nsRefPtr<ColorLayer> layer = aManager->CreateColorLayer();
- layer->SetClipRect(layerItems->mThebesLayer->GetClipRect());
- // Clip to mVisibleRect to ensure only the pixels we want are filled.
- layer->IntersectClipRect(layerItems->mVisibleRect);
- layer->SetColor(gfxRGBA(color));
- layerItems->mLayer = layer.forget();
- layerItems->mThebesLayer = nsnull;
- }
-
- gfxMatrix transform;
- nsIntRect visibleRect = layerItems->mVisibleRect;
- if (layerItems->mLayer->GetTransform().Is2D(&transform)) {
- // if 'transform' is not invertible, then nothing will be displayed
- // for the layer, so it doesn't really matter what we do here
- transform.Invert();
- gfxRect layerVisible = transform.TransformBounds(
- gfxRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height));
- layerVisible.RoundOut();
- if (NS_FAILED(nsLayoutUtils::GfxRectToIntRect(layerVisible, &visibleRect))) {
- NS_ERROR("Visible rect transformed out of bounds");
- }
- } else {
- NS_ERROR("Only 2D transformations currently supported");
- }
- layerItems->mLayer->SetVisibleRegion(nsIntRegion(visibleRect));
- }
-}
-
-/**
- * We build a single layer by building a list of layers needed for
- * all the display items and building a container layer to hold them.
- */
-already_AddRefed<Layer>
-nsDisplayList::BuildLayer(nsDisplayListBuilder* aBuilder,
- LayerManager* aManager,
- nsTArray<LayerItems>* aLayers) const {
- // If there's only one layer, then in principle we can try to flatten
- // things by returning that layer here. But that adds complexity to
- // retained layer management so we don't do it. Layer backends can
- // flatten internally.
- nsRefPtr<ContainerLayer> container =
- aManager->CreateContainerLayer();
- if (!container)
- return nsnull;
-
- BuildLayers(aBuilder, aManager, aLayers);
-
- Layer* lastChild = nsnull;
- for (PRUint32 i = 0; i < aLayers->Length(); ++i) {
- Layer* child = aLayers->ElementAt(i).mLayer;
- container->InsertAfter(child, lastChild);
- lastChild = child;
- }
- container->SetIsOpaqueContent(mIsOpaque);
- nsRefPtr<Layer> layer = container.forget();
- return layer.forget();
-}
-
void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx,
PRUint32 aFlags) const {
PaintForFrame(aBuilder, aCtx, aBuilder->ReferenceFrame(), aFlags);
}
/**
* We paint by executing a layer manager transaction, constructing a
@@ -808,109 +445,32 @@ void nsDisplayList::PaintForFrame(nsDisp
}
if (aCtx) {
layerManager->BeginTransactionWithTarget(aCtx->ThebesContext());
} else {
layerManager->BeginTransaction();
}
- nsAutoTArray<LayerItems,10> layers;
- nsRefPtr<Layer> root = BuildLayer(aBuilder, layerManager, &layers);
+ nsRefPtr<Layer> root = aBuilder->LayerBuilder()->
+ MakeContainerLayerFor(aBuilder, layerManager, nsnull, *this);
if (!root)
return;
nsIntRect visible =
mVisibleRect.ToNearestPixels(aForFrame->PresContext()->AppUnitsPerDevPixel());
root->SetVisibleRegion(nsIntRegion(visible));
layerManager->SetRoot(root);
- layerManager->EndConstruction();
- PaintThebesLayers(aBuilder, layers);
- layerManager->EndTransaction();
+ layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
+ aBuilder);
nsCSSRendering::DidPaint();
}
-void
-nsDisplayList::PaintThebesLayers(nsDisplayListBuilder* aBuilder,
- const nsTArray<LayerItems>& aLayers) const
-{
- for (PRUint32 i = 0; i < aLayers.Length(); ++i) {
- ThebesLayer* thebesLayer = aLayers[i].mThebesLayer;
- if (!thebesLayer) {
- // Just ask the display item to paint any Thebes layers that it
- // used to construct its layer
- aLayers[i].mItems->mStartItem->PaintThebesLayers(aBuilder);
- continue;
- }
-
- // OK, we have a real Thebes layer. Start drawing into it.
- nsIntRegion toDraw;
- gfxContext* ctx = thebesLayer->BeginDrawing(&toDraw);
- if (!ctx)
- continue;
- // For now, we'll ignore toDraw and just draw the entire visible
- // area, because the "visible area" is already confined to just the
- // area that needs to be repainted. Later, when we start reusing layers
- // from paint to paint, we'll need to pay attention to toDraw and
- // actually try to avoid drawing stuff that's not in it.
-
- // Our list may contain content with different prescontexts at
- // different zoom levels. 'rc' contains the nsIRenderingContext
- // used for the previous display item, and lastPresContext is the
- // prescontext for that item. We also cache the clip state for that
- // item.
- nsRefPtr<nsIRenderingContext> rc;
- nsPresContext* lastPresContext = nsnull;
- gfxRect currentClip;
- PRBool setClipRect = PR_FALSE;
- NS_ASSERTION(aLayers[i].mItems, "No empty layers allowed");
- for (ItemGroup* group = aLayers[i].mItems; group;
- group = group->mNextItemsForLayer) {
- // If the new desired clip state is different from the current state,
- // update the clip.
- if (setClipRect != group->mHasClipRect ||
- (group->mHasClipRect && group->mClipRect != currentClip)) {
- if (setClipRect) {
- ctx->Restore();
- }
- setClipRect = group->mHasClipRect;
- if (setClipRect) {
- ctx->Save();
- ctx->NewPath();
- ctx->Rectangle(group->mClipRect, PR_TRUE);
- ctx->Clip();
- currentClip = group->mClipRect;
- }
- }
- NS_ASSERTION(group->mStartItem, "No empty groups allowed");
- for (nsDisplayItem* item = group->mStartItem; item != group->mEndItem;
- item = item->GetAbove()) {
- nsPresContext* presContext = item->GetUnderlyingFrame()->PresContext();
- if (presContext != lastPresContext) {
- // Create a new rendering context with the right
- // appunits-per-dev-pixel.
- nsresult rv =
- presContext->DeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc));
- if (NS_FAILED(rv))
- break;
- rc->Init(presContext->DeviceContext(), ctx);
- lastPresContext = presContext;
- }
- item->Paint(aBuilder, rc);
- }
- }
- if (setClipRect) {
- ctx->Restore();
- }
- thebesLayer->EndDrawing();
- }
-}
-
PRUint32 nsDisplayList::Count() const {
PRUint32 count = 0;
for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) {
++count;
}
return count;
}
@@ -1579,30 +1139,25 @@ PRBool nsDisplayOpacity::IsOpaque(nsDisp
// been created.
return PR_FALSE;
}
// nsDisplayOpacity uses layers for rendering
already_AddRefed<Layer>
nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager) {
- nsRefPtr<Layer> layer =
- mList.BuildLayer(aBuilder, aManager, &mChildLayers);
+ nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
+ MakeContainerLayerFor(aBuilder, aManager, this, mList);
if (!layer)
return nsnull;
layer->SetOpacity(mFrame->GetStyleDisplay()->mOpacity);
return layer.forget();
}
-void
-nsDisplayOpacity::PaintThebesLayers(nsDisplayListBuilder* aBuilder) {
- mList.PaintThebesLayers(aBuilder, mChildLayers);
-}
-
PRBool nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
nsRegion* aVisibleRegionBeforeMove) {
NS_ASSERTION((aVisibleRegionBeforeMove != nsnull) == aBuilder->HasMovingFrames(),
"Should have aVisibleRegionBeforeMove when there are moving frames");
// Our children are translucent so we should not allow them to subtract
// area from aVisibleRegion. We do need to find out what is visible under
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -48,22 +48,23 @@
#include "nsCOMPtr.h"
#include "nsIFrame.h"
#include "nsPoint.h"
#include "nsRect.h"
#include "nsISelection.h"
#include "nsCaret.h"
#include "plarena.h"
#include "Layers.h"
+#include "nsRegion.h"
+#include "FrameLayerBuilder.h"
#include <stdlib.h>
class nsIPresShell;
class nsIContent;
-class nsRegion;
class nsIRenderingContext;
class nsIDeviceContext;
class nsDisplayTableItem;
class nsDisplayItem;
/*
* An nsIFrame can have many different visual parts. For example an image frame
* can have a background, border, and outline, the image itself, and a
@@ -115,16 +116,17 @@ class nsDisplayItem;
* the display list memory using a PLArena. It also establishes the reference
* coordinate system for all display list items. Some of the parameters are
* available from the prescontext/presshell, but we copy them into the builder
* for faster/more convenient access.
*/
class NS_STACK_CLASS nsDisplayListBuilder {
public:
typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
+ typedef mozilla::FrameLayerBuilder FrameLayerBuilder;
/**
* @param aReferenceFrame the frame at the root of the subtree; its origin
* is the origin of the reference coordinate system for this display list
* @param aIsForEvents PR_TRUE if we're creating this list in order to
* determine which frame is under the mouse position
* @param aBuildCaret whether or not we should include the caret in any
* display lists that we make.
@@ -334,16 +336,21 @@ public:
* that might not be displayed, we mark the placeholders and their ancestors
* to ensure that display list construction descends into them
* anyway. nsDisplayListBuilder will take care of unmarking them when it is
* destroyed.
*/
void MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
const nsFrameList& aFrames,
const nsRect& aDirtyRect);
+
+ /**
+ * Return the FrameLayerBuilder.
+ */
+ FrameLayerBuilder* LayerBuilder() { return &mLayerBuilder; }
/**
* Allocate memory in our arena. It will only be freed when this display list
* builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem
* destructors are called as soon as the item is no longer used.
*/
void* Allocate(size_t aSize);
@@ -402,17 +409,18 @@ private:
nsIFrame* mCaretFrame;
PRUint32 mFirstFrameMarkedForDisplay;
};
PresShellState* CurrentPresShellState() {
NS_ASSERTION(mPresShellStates.Length() > 0,
"Someone forgot to enter a presshell");
return &mPresShellStates[mPresShellStates.Length() - 1];
}
-
+
+ FrameLayerBuilder mLayerBuilder;
nsIFrame* mReferenceFrame;
nsIFrame* mMovingFrame;
nsRegion* mSaveVisibleRegionOfMovingContent;
nsIFrame* mIgnoreScrollFrame;
nsPoint mMoveDelta; // only valid when mMovingFrame is non-null
PLArenaPool mPool;
nsCOMPtr<nsISelection> mBoundingSelection;
nsAutoTArray<PresShellState,8> mPresShellStates;
@@ -573,23 +581,16 @@ public:
* rendering) instead of cairo.
*
* The caller (nsDisplayList) is responsible for setting the visible
* region of the layer.
*/
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
{ return nsnull; }
- /**
- * If BuildLayer returned non-null, then this method is called to
- * paint any ThebesLayers which are descendants of the returned layer.
- */
- virtual void PaintThebesLayers(nsDisplayListBuilder* aBuilder)
- {
- }
/**
* On entry, aVisibleRegion contains the region (relative to ReferenceFrame())
* which may be visible. If the display item opaquely covers an area, it
* can remove that area from aVisibleRegion before returning.
* If we're doing scroll analysis with moving frames, then
* aVisibleRegionBeforeMove will be non-null and contains the region that
* would have been visible before the move. aVisibleRegion contains the
@@ -625,16 +626,20 @@ public:
}
/**
* If this is a leaf item we return null, otherwise we return the wrapped
* list.
*/
virtual nsDisplayList* GetList() { return nsnull; }
+ /**
+ * Returns the visible rect. Should only be called after ComputeVisibility
+ * has happened.
+ */
const nsRect& GetVisibleRect() { return mVisibleRect; }
#ifdef NS_DEBUG
/**
* For debugging and stuff
*/
virtual const char* Name() = 0;
#endif
@@ -887,91 +892,16 @@ public:
/**
* Find the topmost display item that returns a non-null frame, and return
* the frame.
*/
void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
nsDisplayItem::HitTestState* aState,
nsTArray<nsIFrame*> *aOutFrames) const;
- /**
- * This class represents a sublist of consecutive items in an nsDisplayList.
- * The first item in the sublist is mStartItem and the last item
- * is the item before mEndItem.
- *
- * These sublists are themselves organized into a linked list of all
- * the ItemGroups associated with a given layer, via mNextItemsForLayer.
- * This list will have more than one element if the display items in a layer
- * come from different nsDisplayLists, or if they come from the same
- * nsDisplayList but they aren't consecutive in that list.
- *
- * These objects are allocated from the nsDisplayListBuilder arena.
- */
- struct ItemGroup {
- // If null, then the item group is empty.
- nsDisplayItem* mStartItem;
- nsDisplayItem* mEndItem;
- ItemGroup* mNextItemsForLayer;
- // The clipping (if any) that needs to be applied to all these items.
- gfxRect mClipRect;
- PRPackedBool mHasClipRect;
-
- ItemGroup() : mStartItem(nsnull), mEndItem(nsnull),
- mNextItemsForLayer(nsnull), mHasClipRect(PR_FALSE) {}
-
- void* operator new(size_t aSize,
- nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
- return aBuilder->Allocate(aSize);
- }
- };
- /**
- * This class represents a layer and the display item(s) it
- * will render. The items are stored in a linked list of ItemGroups.
- */
- struct LayerItems {
- nsRefPtr<Layer> mLayer;
- // equal to mLayer, or null if mLayer is not a ThebesLayer
- ThebesLayer* mThebesLayer;
- ItemGroup* mItems;
- // The bounds of the visible region for this layer, in device pixels
- nsIntRect mVisibleRect;
-
- LayerItems(ItemGroup* aItems) :
- mThebesLayer(nsnull), mItems(aItems)
- {
- }
- };
- /**
- * Compute a list of layers needed to render this display list. The layers
- * are added to aLayers, which must be empty on entry. This
- * must be called while aManager is in the construction phase, because
- * we construct layers belonging to aManager. The layers used to
- * construct the layer tree (along with the display items associated
- * with each layer) are returned in aLayers.
- */
- void BuildLayers(nsDisplayListBuilder* aBuilder,
- LayerManager* aManager,
- nsTArray<LayerItems>* aLayers) const;
- /**
- * Return a single layer which renders this display list. This
- * must be called while aManager is in the construction phase, because
- * we construct layers belonging to aManager. The layers used to
- * construct the layer tree (along with the display items associated
- * with each layer) are returned in aLayers.
- * The caller is responsible for setting the visible region on the layer.
- */
- already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
- LayerManager* aManager,
- nsTArray<LayerItems>* aLayers) const;
- /**
- * Paint the ThebesLayers in the list of layers.
- */
- void PaintThebesLayers(nsDisplayListBuilder* aBuilder,
- const nsTArray<LayerItems>& aLayers) const;
-
private:
// This class is only used on stack, so we don't have to worry about leaking
// it. Don't let us be heap-allocated!
void* operator new(size_t sz) CPP_THROW_NEW;
// Utility function used to massage the list during ComputeVisibility.
void FlattenTo(nsTArray<nsDisplayItem*>* aElements);
// Utility function used to massage the list during sorting, to rewrite
@@ -1543,25 +1473,21 @@ public:
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayOpacity();
#endif
virtual Type GetType() { return TYPE_OPACITY; }
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder);
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);
- virtual void PaintThebesLayers(nsDisplayListBuilder* aBuilder);
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
nsRegion* aVisibleRegionBeforeMove);
virtual PRBool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
NS_DISPLAY_DECL_NAME("Opacity")
-
-private:
- nsTArray<nsDisplayList::LayerItems> mChildLayers;
};
/**
* nsDisplayClip can clip a list of items, but we take a single item
* initially and then later merge other items into it when we merge
* adjacent matching nsDisplayClips
*/
class nsDisplayClip : public nsDisplayWrapList {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5673,16 +5673,57 @@ nscolor PresShell::ComputeBackstopColor(
return NS_RGBA(0,0,0,0);
}
// Within an opaque widget (or no widget at all), so the backstop
// color must be totally opaque. The user's default background
// as reported by the prescontext is guaranteed to be opaque.
return GetPresContext()->DefaultBackgroundColor();
}
+struct PaintParams {
+ nsIFrame* mFrame;
+ nsPoint mOffsetToRoot;
+ nsPoint mOffsetToWidget;
+ const nsRegion* mDirtyRegion;
+ nscolor mBackgroundColor;
+};
+
+static void DrawThebesLayer(ThebesLayer* aLayer,
+ gfxContext* aContext,
+ const nsIntRegion& aRegionToDraw,
+ void* aCallbackData)
+{
+ PaintParams* params = static_cast<PaintParams*>(aCallbackData);
+ nsIFrame* frame = params->mFrame;
+ if (frame) {
+ // We're drawing into a child window. Don't pass
+ // nsLayoutUtils::PAINT_WIDGET_LAYERS, since that will draw into
+ // the widget for the display root.
+ nsIDeviceContext* devCtx = frame->PresContext()->DeviceContext();
+ nsCOMPtr<nsIRenderingContext> rc;
+ nsresult rv = devCtx->CreateRenderingContextInstance(*getter_AddRefs(rc));
+ if (NS_SUCCEEDED(rv)) {
+ rc->Init(devCtx, aContext);
+ nsRegion dirtyRegion = *params->mDirtyRegion;
+ dirtyRegion.MoveBy(params->mOffsetToRoot);
+ nsIRenderingContext::AutoPushTranslation
+ push(rc, -params->mOffsetToWidget.x, -params->mOffsetToWidget.y);
+ nsLayoutUtils::PaintFrame(rc, frame, dirtyRegion,
+ params->mBackgroundColor);
+ }
+ } else {
+ aContext->NewPath();
+ aContext->SetColor(gfxRGBA(params->mBackgroundColor));
+ nsIntRect dirtyRect = aRegionToDraw.GetBounds();
+ aContext->Rectangle(
+ gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
+ aContext->Fill();
+ }
+}
+
NS_IMETHODIMP
PresShell::Paint(nsIView* aDisplayRoot,
nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
PRBool aPaintDefaultBackground)
{
#ifdef NS_FUNCTION_TIMER
@@ -5725,52 +5766,27 @@ PresShell::Paint(nsIView* aDispla
layerManager->BeginTransaction();
nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
nsIntRect dirtyRect = aDirtyRegion.GetBounds().
ToOutsidePixels(presContext->AppUnitsPerDevPixel());
if (root) {
root->SetVisibleRegion(dirtyRect);
layerManager->SetRoot(root);
}
- layerManager->EndConstruction();
- if (root) {
- nsIntRegion toDraw;
- gfxContext* ctx = root->BeginDrawing(&toDraw);
- if (ctx) {
- if (frame) {
- // We're drawing into a child window. Don't pass
- // nsLayoutUtils::PAINT_WIDGET_LAYERS, since that will draw into
- // the widget for the display root.
- nsIDeviceContext* devCtx = GetPresContext()->DeviceContext();
- nsCOMPtr<nsIRenderingContext> rc;
- nsresult rv = devCtx->CreateRenderingContextInstance(*getter_AddRefs(rc));
- if (NS_SUCCEEDED(rv)) {
- rc->Init(devCtx, ctx);
- // Offset to add to aView coordinates to get aWidget coordinates
- nsPoint offsetToRoot = aViewToPaint->GetOffsetTo(aDisplayRoot);
- nsRegion dirtyRegion = aDirtyRegion;
- dirtyRegion.MoveBy(offsetToRoot);
-
- nsPoint translate = -offsetToRoot + aViewToPaint->ViewToWidgetOffset();
- nsIRenderingContext::AutoPushTranslation
- push(rc, translate.x, translate.y);
-
- nsLayoutUtils::PaintFrame(rc, frame, dirtyRegion, bgcolor);
- }
- } else {
- bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
- ctx->NewPath();
- ctx->SetColor(gfxRGBA(bgcolor));
- ctx->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
- ctx->Fill();
- }
- }
- root->EndDrawing();
- }
- layerManager->EndTransaction();
+ if (!frame) {
+ bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
+ }
+ nsPoint offsetToRoot = aViewToPaint->GetOffsetTo(aDisplayRoot);
+ PaintParams params =
+ { frame,
+ offsetToRoot,
+ offsetToRoot - aViewToPaint->ViewToWidgetOffset(),
+ &aDirtyRegion,
+ bgcolor };
+ layerManager->EndTransaction(DrawThebesLayer, ¶ms);
return NS_OK;
}
// static
void
nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
{