Bug 564993. Part 5: Change ThebesLayer painting to be callback-based; move layer tree construction to FrameLayerBuilder. r=Bas,mats,sr=vlad

This commit is contained in:
Robert O'Callahan 2010-05-21 15:20:48 +12:00
parent b5746a540b
commit 6391e1262a
22 changed files with 854 additions and 912 deletions

View File

@ -1666,6 +1666,19 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShellTreeOwner()
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)
{
@ -1696,19 +1709,7 @@ nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
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;
}

View File

@ -143,14 +143,29 @@ public:
*/
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
@ -197,6 +212,8 @@ public:
virtual LayersBackend GetBackendType() = 0;
};
class ThebesLayer;
/**
* A Layer represents anything that can be rendered onto a destination
* surface.
@ -297,6 +314,12 @@ public:
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
@ -358,36 +381,7 @@ public:
*/
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)

View File

@ -94,7 +94,9 @@ public:
* 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;
@ -240,8 +242,9 @@ public:
"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()
@ -250,30 +253,17 @@ protected:
}
};
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;
NS_ASSERTION(target, "We shouldn't be called if there's no target");
BasicManager()->AdvancePaintingTo(this);
*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 {
@ -295,7 +285,9 @@ public:
mVisibleRegion = aRegion;
}
virtual void Paint(gfxContext* aContext);
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData);
protected:
BasicLayerManager* BasicManager()
@ -305,7 +297,9 @@ protected:
};
void
BasicImageLayer::Paint(gfxContext* aContext)
BasicImageLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
if (!mContainer)
return;
@ -365,7 +359,9 @@ public:
mVisibleRegion = aRegion;
}
virtual void Paint(gfxContext* aContext);
virtual void Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData);
protected:
BasicLayerManager* BasicManager()
@ -375,7 +371,9 @@ protected:
};
void
BasicColorLayer::Paint(gfxContext* aContext)
BasicColorLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
aContext->SetColor(mColor);
aContext->Paint();
@ -397,7 +395,9 @@ public:
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;
@ -484,7 +484,9 @@ BasicCanvasLayer::Updated(const nsIntRect& aRect)
}
void
BasicCanvasLayer::Paint(gfxContext* aContext)
BasicCanvasLayer::Paint(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
@ -511,7 +513,7 @@ BasicCanvasLayer::Paint(gfxContext* aContext)
}
BasicLayerManager::BasicLayerManager(gfxContext* aContext) :
mDefaultTarget(aContext), mLastPainted(nsnull)
mDefaultTarget(aContext)
#ifdef DEBUG
, mPhase(PHASE_NONE)
#endif
@ -554,24 +556,23 @@ BasicLayerManager::BeginTransactionWithTarget(gfxContext* 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
if (mTarget) {
PaintLayer(mRoot, aCallback, aCallbackData);
mTarget = nsnull;
}
void
BasicLayerManager::EndTransaction()
{
NS_ASSERTION(mPhase == PHASE_DRAWING, "Should be in drawing phase");
#ifdef DEBUG
mPhase = PHASE_NONE;
#endif
AdvancePaintingTo(nsnull);
mTarget = nsnull;
// No retained layers supported for now
mRoot = nsnull;
}
@ -625,10 +626,14 @@ UseOpaqueSurface(Layer* aLayer)
}
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()) {
@ -667,66 +672,22 @@ BasicLayerManager::BeginPaintingLayer(Layer* aLayer)
}
}
mLastPainted = aLayer;
// For layers that paint themselves (e.g., BasicImageLayer), paint
// them now.
ToData(aLayer)->Paint(mTarget);
ToData(aLayer)->Paint(mTarget, aCallback, aCallbackData);
for (Layer* child = aLayer->GetFirstChild(); child;
child = child->GetNextSibling()) {
PaintLayer(child, aCallback, aCallbackData);
}
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()
{
@ -767,54 +728,5 @@ BasicLayerManager::CreateCanvasLayer()
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
}
}

View File

@ -78,8 +78,8 @@ public:
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);
@ -94,36 +94,20 @@ public:
#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 };

View File

@ -198,7 +198,9 @@ CanvasLayerOGL::Updated(const nsIntRect& aRect)
}
void
CanvasLayerOGL::RenderLayer(int aPreviousDestination)
CanvasLayerOGL::RenderLayer(int aPreviousDestination,
DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
GLContext *gl = glManager->gl();

View File

@ -66,7 +66,9 @@ public:
// 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;

View File

@ -53,7 +53,7 @@ ColorLayerOGL::GetLayer()
}
void
ColorLayerOGL::RenderLayer(int)
ColorLayerOGL::RenderLayer(int, DrawThebesLayerCallback, void*)
{
static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();

View File

@ -61,7 +61,9 @@ public:
virtual Layer* GetLayer();
virtual void RenderLayer(int aPreviousDestination);
virtual void RenderLayer(int aPreviousDestination,
DrawThebesLayerCallback aCallback,
void* aCallbackData);
protected:
nsIntRegion mVisibleRegion;

View File

@ -125,7 +125,9 @@ ContainerLayerOGL::GetFirstChildOGL()
}
void
ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer)
ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
/**
* Setup our temporary texture for rendering the contents of this container.
@ -202,7 +204,7 @@ ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer)
gl()->fScissor(0, 0, GetVisibleRect().width, GetVisibleRect().height);
}
layerToRender->RenderLayer(frameBuffer);
layerToRender->RenderLayer(frameBuffer, aCallback, aCallbackData);
layerToRender = layerToRender->GetNextSibling();
}

View File

@ -68,7 +68,9 @@ public:
PRBool IsEmpty();
void RenderLayer(int aPreviousFrameBuffer);
void RenderLayer(int aPreviousFrameBuffer,
DrawThebesLayerCallback aCallback,
void* aCallbackData);
private:
nsIntRect mVisibleRect;

View File

@ -269,7 +269,8 @@ ImageLayerOGL::GetLayer()
}
void
ImageLayerOGL::RenderLayer(int)
ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
if (!GetContainer()) {
return;

View File

@ -175,7 +175,9 @@ public:
virtual Layer* GetLayer();
virtual void RenderLayer(int aPreviousDestination);
virtual void RenderLayer(int aPreviousDestination,
DrawThebesLayerCallback aCallback,
void* aCallbackData);
};
class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage

View File

@ -282,14 +282,10 @@ LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget)
}
void
LayerManagerOGL::EndConstruction()
LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
}
void
LayerManagerOGL::EndTransaction()
{
Render();
Render(aCallback, aCallbackData);
mTarget = NULL;
}
@ -358,7 +354,8 @@ LayerManagerOGL::MakeCurrent()
}
void
LayerManagerOGL::Render()
LayerManagerOGL::Render(DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
nsIntRect rect;
mWidget->GetBounds(rect);
@ -384,7 +381,7 @@ LayerManagerOGL::Render()
mGLContext->fScissor(0, 0, width, height);
}
mRootLayer->RenderLayer(mFrameBuffer);
mRootLayer->RenderLayer(mFrameBuffer, aCallback, aCallbackData);
}
if (mTarget) {

View File

@ -216,7 +216,8 @@ public:
void EndConstruction();
void EndTransaction();
virtual void EndTransaction(DrawThebesLayerCallback aCallback,
void* aCallbackData);
void SetRoot(Layer* aLayer);
@ -293,7 +294,8 @@ private:
/**
* Render the current layer tree to the active target.
*/
void Render();
void Render(DrawThebesLayerCallback aCallback,
void* aCallbackData);
/**
* Setup the pipeline.
*/
@ -316,6 +318,8 @@ private:
class LayerOGL
{
public:
typedef LayerManager::DrawThebesLayerCallback DrawThebesLayerCallback;
LayerOGL(LayerManagerOGL *aManager);
enum LayerType {
@ -336,7 +340,8 @@ public:
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;

View File

@ -128,19 +128,28 @@ ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
mInvalidatedRect = invalidatedRegion.GetBounds();
}
gfxContext *
ThebesLayerOGL::BeginDrawing(nsIntRegion *aRegion)
LayerOGL::LayerType
ThebesLayerOGL::GetType()
{
if (mInvalidatedRect.IsEmpty()) {
aRegion->SetEmpty();
return NULL;
return TYPE_THEBES;
}
if (!mTexture) {
aRegion->SetEmpty();
return NULL;
}
*aRegion = mInvalidatedRect;
const nsIntRect&
ThebesLayerOGL::GetVisibleRect()
{
return mVisibleRect;
}
void
ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
if (!mTexture) {
return;
}
if (!mInvalidatedRect.IsEmpty()) {
gfxASurface::gfxImageFormat imageFormat;
if (UseOpaqueSurface(this)) {
@ -149,40 +158,28 @@ ThebesLayerOGL::BeginDrawing(nsIntRegion *aRegion)
imageFormat = gfxASurface::ImageFormatARGB32;
}
mDestinationSurface =
nsRefPtr<gfxASurface> surface =
gfxPlatform::GetPlatform()->
CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
mInvalidatedRect.height),
imageFormat);
mContext = new gfxContext(mDestinationSurface);
mContext->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
return mContext.get();
}
nsRefPtr<gfxContext> ctx = new gfxContext(surface);
ctx->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
aCallback(this, ctx, mInvalidatedRect, aCallbackData);
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()) {
switch (surface->GetType()) {
case gfxASurface::SurfaceTypeImage:
imageSurface = static_cast<gfxImageSurface*>(mDestinationSurface.get());
imageSurface = static_cast<gfxImageSurface*>(surface.get());
break;
#ifdef XP_WIN
case gfxASurface::SurfaceTypeWin32:
imageSurface =
static_cast<gfxWindowsSurface*>(mDestinationSurface.get())->
static_cast<gfxWindowsSurface*>(surface.get())->
GetImageSurface();
break;
#endif
@ -196,7 +193,7 @@ ThebesLayerOGL::EndDrawing()
mInvalidatedRect.height),
imageFormat);
nsRefPtr<gfxContext> tmpContext = new gfxContext(imageSurface);
tmpContext->SetSource(mDestinationSurface);
tmpContext->SetSource(surface);
tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpContext->Paint();
}
@ -213,28 +210,6 @@ ThebesLayerOGL::EndDrawing()
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)
{
if (!mTexture) {
return;
}
float quadTransform[4][4];

View File

@ -59,15 +59,13 @@ public:
/** 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();
@ -83,16 +81,6 @@ private:
* 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

View File

@ -0,0 +1,497 @@
/* -*- 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;
}
/**
* 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.
aLayers->RemoveElementAt(0);
}
for (PRUint32 i = 0; i < aLayers->Length(); ++i) {
LayerItems* layerItems = aLayers->ElementAt(i);
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;
}
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

View File

@ -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_ */

View File

@ -59,6 +59,7 @@ XPIDLSRCS = \
$(NULL)
EXPORTS = \
FrameLayerBuilder.h \
FramePropertyTable.h \
nsBidi.h \
nsBidiPresUtils.h \
@ -88,6 +89,7 @@ EXPORTS = \
$(NULL)
CPPSRCS = \
FrameLayerBuilder.cpp \
FramePropertyTable.cpp \
nsCSSColorUtils.cpp \
nsCSSFrameConstructor.cpp \

View File

@ -62,6 +62,7 @@
#include "nsIInterfaceRequestorUtils.h"
#include "BasicLayers.h"
using namespace mozilla;
using namespace mozilla::layers;
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
@ -405,370 +406,6 @@ nsDisplayList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
#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 {
@ -813,8 +450,8 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
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;
@ -823,89 +460,12 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
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()) {
@ -1584,8 +1144,8 @@ PRBool nsDisplayOpacity::IsOpaque(nsDisplayListBuilder* aBuilder) {
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;
@ -1593,11 +1153,6 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
return layer.forget();
}
void
nsDisplayOpacity::PaintThebesLayers(nsDisplayListBuilder* aBuilder) {
mList.PaintThebesLayers(aBuilder, mChildLayers);
}
PRBool nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
nsRegion* aVisibleRegionBeforeMove) {

View File

@ -53,12 +53,13 @@
#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;
@ -120,6 +121,7 @@ class nsDisplayItem;
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
@ -340,6 +342,11 @@ public:
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
@ -408,6 +415,7 @@ private:
return &mPresShellStates[mPresShellStates.Length() - 1];
}
FrameLayerBuilder mLayerBuilder;
nsIFrame* mReferenceFrame;
nsIFrame* mMovingFrame;
nsRegion* mSaveVisibleRegionOfMovingContent;
@ -578,13 +586,6 @@ public:
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())
@ -630,6 +631,10 @@ public:
*/
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
@ -892,81 +897,6 @@ public:
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!
@ -1548,15 +1478,11 @@ public:
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;
};
/**

View File

@ -5678,6 +5678,47 @@ nscolor PresShell::ComputeBackstopColor(nsIView* aDisplayRoot)
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,
@ -5730,42 +5771,17 @@ PresShell::Paint(nsIView* aDisplayRoot,
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 {
if (!frame) {
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();
nsPoint offsetToRoot = aViewToPaint->GetOffsetTo(aDisplayRoot);
PaintParams params =
{ frame,
offsetToRoot,
offsetToRoot - aViewToPaint->ViewToWidgetOffset(),
&aDirtyRegion,
bgcolor };
layerManager->EndTransaction(DrawThebesLayer, &params);
return NS_OK;
}