mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-14 04:03:47 +00:00
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:
parent
b5746a540b
commit
6391e1262a
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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;
|
||||
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()
|
||||
{
|
||||
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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 };
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -53,7 +53,7 @@ ColorLayerOGL::GetLayer()
|
||||
}
|
||||
|
||||
void
|
||||
ColorLayerOGL::RenderLayer(int)
|
||||
ColorLayerOGL::RenderLayer(int, DrawThebesLayerCallback, void*)
|
||||
{
|
||||
static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,9 @@ public:
|
||||
|
||||
PRBool IsEmpty();
|
||||
|
||||
void RenderLayer(int aPreviousFrameBuffer);
|
||||
void RenderLayer(int aPreviousFrameBuffer,
|
||||
DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData);
|
||||
private:
|
||||
nsIntRect mVisibleRect;
|
||||
|
||||
|
@ -269,7 +269,8 @@ ImageLayerOGL::GetLayer()
|
||||
}
|
||||
|
||||
void
|
||||
ImageLayerOGL::RenderLayer(int)
|
||||
ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{
|
||||
if (!GetContainer()) {
|
||||
return;
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -128,96 +128,6 @@ ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
|
||||
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()
|
||||
{
|
||||
@ -231,12 +141,77 @@ ThebesLayerOGL::GetVisibleRect()
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
497
layout/base/FrameLayerBuilder.cpp
Normal file
497
layout/base/FrameLayerBuilder.cpp
Normal 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
|
77
layout/base/FrameLayerBuilder.h
Normal file
77
layout/base/FrameLayerBuilder.h
Normal 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_ */
|
@ -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 \
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
@ -339,6 +341,11 @@ public:
|
||||
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
|
||||
@ -407,7 +414,8 @@ private:
|
||||
"Someone forgot to enter a presshell");
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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 {
|
||||
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();
|
||||
if (!frame) {
|
||||
bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
|
||||
}
|
||||
layerManager->EndTransaction();
|
||||
nsPoint offsetToRoot = aViewToPaint->GetOffsetTo(aDisplayRoot);
|
||||
PaintParams params =
|
||||
{ frame,
|
||||
offsetToRoot,
|
||||
offsetToRoot - aViewToPaint->ViewToWidgetOffset(),
|
||||
&aDirtyRegion,
|
||||
bgcolor };
|
||||
layerManager->EndTransaction(DrawThebesLayer, ¶ms);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user