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:
@@ -1666,6 +1666,19 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShellTreeOwner()
|
|||||||
return NS_OK;
|
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 */
|
/* static */
|
||||||
nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
|
nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
|
||||||
{
|
{
|
||||||
@@ -1696,19 +1709,7 @@ nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
|
|||||||
root->SetVisibleRegion(dirtyRect);
|
root->SetVisibleRegion(dirtyRect);
|
||||||
layerManager->SetRoot(root);
|
layerManager->SetRoot(root);
|
||||||
}
|
}
|
||||||
layerManager->EndConstruction();
|
layerManager->EndTransaction(DrawThebesLayer, &browser->mBackgroundColor);
|
||||||
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();
|
|
||||||
return nsEventStatus_eConsumeDoDefault;
|
return nsEventStatus_eConsumeDoDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,14 +143,29 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void BeginTransactionWithTarget(gfxContext* aTarget) = 0;
|
virtual void BeginTransactionWithTarget(gfxContext* aTarget) = 0;
|
||||||
/**
|
/**
|
||||||
* Finish the construction phase of the transaction and enter the
|
* Function called to draw the contents of each ThebesLayer.
|
||||||
* drawing phase.
|
* 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
|
* CONSTRUCTION PHASE ONLY
|
||||||
@@ -197,6 +212,8 @@ public:
|
|||||||
virtual LayersBackend GetBackendType() = 0;
|
virtual LayersBackend GetBackendType() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ThebesLayer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Layer represents anything that can be rendered onto a destination
|
* A Layer represents anything that can be rendered onto a destination
|
||||||
* surface.
|
* surface.
|
||||||
@@ -297,6 +314,12 @@ public:
|
|||||||
void SetUserData(void* aData) { mUserData = aData; }
|
void SetUserData(void* aData) { mUserData = aData; }
|
||||||
void* GetUserData() { return mUserData; }
|
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
|
* Only the implementation should call this. This is per-implementation
|
||||||
* private data. Normally, all layers with a given layer manager
|
* private data. Normally, all layers with a given layer manager
|
||||||
@@ -358,36 +381,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void InvalidateRegion(const nsIntRegion& aRegion) = 0;
|
virtual void InvalidateRegion(const nsIntRegion& aRegion) = 0;
|
||||||
|
|
||||||
/**
|
virtual ThebesLayer* AsThebesLayer() { return this; }
|
||||||
* 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;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ThebesLayer(LayerManager* aManager, void* aImplData)
|
ThebesLayer(LayerManager* aManager, void* aImplData)
|
||||||
|
|||||||
@@ -94,7 +94,9 @@ public:
|
|||||||
* set up to account for all the properties of the layer (transform,
|
* set up to account for all the properties of the layer (transform,
|
||||||
* opacity, etc).
|
* opacity, etc).
|
||||||
*/
|
*/
|
||||||
virtual void Paint(gfxContext* aContext) {}
|
virtual void Paint(gfxContext* aContext,
|
||||||
|
LayerManager::DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsIntRegion mVisibleRegion;
|
nsIntRegion mVisibleRegion;
|
||||||
@@ -240,8 +242,9 @@ public:
|
|||||||
"Can only set properties in construction phase");
|
"Can only set properties in construction phase");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual gfxContext* BeginDrawing(nsIntRegion* aRegionToDraw);
|
virtual void Paint(gfxContext* aContext,
|
||||||
virtual void EndDrawing();
|
LayerManager::DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BasicLayerManager* BasicManager()
|
BasicLayerManager* BasicManager()
|
||||||
@@ -250,30 +253,17 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
gfxContext*
|
void
|
||||||
BasicThebesLayer::BeginDrawing(nsIntRegion* aRegionToDraw)
|
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(),
|
NS_ASSERTION(BasicManager()->InDrawing(),
|
||||||
"Can only draw in drawing phase");
|
"Can only draw in drawing phase");
|
||||||
gfxContext* target = BasicManager()->GetTarget();
|
gfxContext* target = BasicManager()->GetTarget();
|
||||||
if (!target)
|
NS_ASSERTION(target, "We shouldn't be called if there's no target");
|
||||||
return nsnull;
|
|
||||||
|
|
||||||
BasicManager()->AdvancePaintingTo(this);
|
aCallback(this, target, mVisibleRegion, aCallbackData);
|
||||||
|
|
||||||
*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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BasicImageLayer : public ImageLayer, BasicImplData {
|
class BasicImageLayer : public ImageLayer, BasicImplData {
|
||||||
@@ -295,7 +285,9 @@ public:
|
|||||||
mVisibleRegion = aRegion;
|
mVisibleRegion = aRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Paint(gfxContext* aContext);
|
virtual void Paint(gfxContext* aContext,
|
||||||
|
LayerManager::DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BasicLayerManager* BasicManager()
|
BasicLayerManager* BasicManager()
|
||||||
@@ -305,7 +297,9 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
BasicImageLayer::Paint(gfxContext* aContext)
|
BasicImageLayer::Paint(gfxContext* aContext,
|
||||||
|
LayerManager::DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
if (!mContainer)
|
if (!mContainer)
|
||||||
return;
|
return;
|
||||||
@@ -365,7 +359,9 @@ public:
|
|||||||
mVisibleRegion = aRegion;
|
mVisibleRegion = aRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Paint(gfxContext* aContext);
|
virtual void Paint(gfxContext* aContext,
|
||||||
|
LayerManager::DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BasicLayerManager* BasicManager()
|
BasicLayerManager* BasicManager()
|
||||||
@@ -375,7 +371,9 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
BasicColorLayer::Paint(gfxContext* aContext)
|
BasicColorLayer::Paint(gfxContext* aContext,
|
||||||
|
LayerManager::DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
aContext->SetColor(mColor);
|
aContext->SetColor(mColor);
|
||||||
aContext->Paint();
|
aContext->Paint();
|
||||||
@@ -397,7 +395,9 @@ public:
|
|||||||
|
|
||||||
virtual void Initialize(const Data& aData);
|
virtual void Initialize(const Data& aData);
|
||||||
virtual void Updated(const nsIntRect& aRect);
|
virtual void Updated(const nsIntRect& aRect);
|
||||||
virtual void Paint(gfxContext* aContext);
|
virtual void Paint(gfxContext* aContext,
|
||||||
|
LayerManager::DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsRefPtr<gfxASurface> mSurface;
|
nsRefPtr<gfxASurface> mSurface;
|
||||||
@@ -484,7 +484,9 @@ BasicCanvasLayer::Updated(const nsIntRect& aRect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BasicCanvasLayer::Paint(gfxContext* aContext)
|
BasicCanvasLayer::Paint(gfxContext* aContext,
|
||||||
|
LayerManager::DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
|
nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
|
||||||
|
|
||||||
@@ -511,7 +513,7 @@ BasicCanvasLayer::Paint(gfxContext* aContext)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BasicLayerManager::BasicLayerManager(gfxContext* aContext) :
|
BasicLayerManager::BasicLayerManager(gfxContext* aContext) :
|
||||||
mDefaultTarget(aContext), mLastPainted(nsnull)
|
mDefaultTarget(aContext)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
, mPhase(PHASE_NONE)
|
, mPhase(PHASE_NONE)
|
||||||
#endif
|
#endif
|
||||||
@@ -554,24 +556,23 @@ BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BasicLayerManager::EndConstruction()
|
BasicLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(mRoot, "Root not set");
|
NS_ASSERTION(mRoot, "Root not set");
|
||||||
NS_ASSERTION(mPhase == PHASE_CONSTRUCTION, "Should be in construction phase");
|
NS_ASSERTION(mPhase == PHASE_CONSTRUCTION, "Should be in construction phase");
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
mPhase = PHASE_DRAWING;
|
mPhase = PHASE_DRAWING;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
void
|
if (mTarget) {
|
||||||
BasicLayerManager::EndTransaction()
|
PaintLayer(mRoot, aCallback, aCallbackData);
|
||||||
{
|
mTarget = nsnull;
|
||||||
NS_ASSERTION(mPhase == PHASE_DRAWING, "Should be in drawing phase");
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
mPhase = PHASE_NONE;
|
mPhase = PHASE_NONE;
|
||||||
#endif
|
#endif
|
||||||
AdvancePaintingTo(nsnull);
|
|
||||||
mTarget = nsnull;
|
|
||||||
// No retained layers supported for now
|
// No retained layers supported for now
|
||||||
mRoot = nsnull;
|
mRoot = nsnull;
|
||||||
}
|
}
|
||||||
@@ -625,10 +626,14 @@ UseOpaqueSurface(Layer* aLayer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BasicLayerManager::BeginPaintingLayer(Layer* aLayer)
|
BasicLayerManager::PaintLayer(Layer* aLayer,
|
||||||
|
DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
PRBool needsGroup = NeedsGroup(aLayer);
|
PRBool needsGroup = NeedsGroup(aLayer);
|
||||||
if ((needsGroup || NeedsState(aLayer)) && mTarget) {
|
PRBool needsSaveRestore = needsGroup || NeedsState(aLayer);
|
||||||
|
|
||||||
|
if (needsSaveRestore) {
|
||||||
mTarget->Save();
|
mTarget->Save();
|
||||||
|
|
||||||
if (aLayer->GetClipRect()) {
|
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
|
if (needsSaveRestore) {
|
||||||
// them now.
|
|
||||||
ToData(aLayer)->Paint(mTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
BasicLayerManager::EndPaintingLayer()
|
|
||||||
{
|
|
||||||
PRBool needsGroup = NeedsGroup(mLastPainted);
|
|
||||||
if ((needsGroup || NeedsState(mLastPainted)) && mTarget) {
|
|
||||||
if (needsGroup) {
|
if (needsGroup) {
|
||||||
mTarget->PopGroupToSource();
|
mTarget->PopGroupToSource();
|
||||||
mTarget->Paint(mLastPainted->GetOpacity());
|
mTarget->Paint(aLayer->GetOpacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
mTarget->Restore();
|
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>
|
already_AddRefed<ThebesLayer>
|
||||||
BasicLayerManager::CreateThebesLayer()
|
BasicLayerManager::CreateThebesLayer()
|
||||||
{
|
{
|
||||||
@@ -767,54 +728,5 @@ BasicLayerManager::CreateCanvasLayer()
|
|||||||
return layer.forget();
|
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 BeginTransaction();
|
||||||
virtual void BeginTransactionWithTarget(gfxContext* aTarget);
|
virtual void BeginTransactionWithTarget(gfxContext* aTarget);
|
||||||
virtual void EndConstruction();
|
virtual void EndTransaction(DrawThebesLayerCallback aCallback,
|
||||||
virtual void EndTransaction();
|
void* aCallbackData);
|
||||||
|
|
||||||
virtual void SetRoot(Layer* aLayer);
|
virtual void SetRoot(Layer* aLayer);
|
||||||
|
|
||||||
@@ -94,36 +94,20 @@ public:
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
PRBool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
|
PRBool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
|
||||||
PRBool InDrawing() { return mPhase == PHASE_DRAWING; }
|
PRBool InDrawing() { return mPhase == PHASE_DRAWING; }
|
||||||
PRBool IsBeforeInTree(Layer* aBefore, Layer* aLayer);
|
|
||||||
#endif
|
#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; }
|
gfxContext* GetTarget() { return mTarget; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This gets called when we start painting aLayer. It can change
|
// Paints aLayer to mTarget.
|
||||||
// the state of mTarget by saving state, setting clipping and/or
|
void PaintLayer(Layer* aLayer,
|
||||||
// pushing a group.
|
DrawThebesLayerCallback aCallback,
|
||||||
void BeginPaintingLayer(Layer* aLayer);
|
void* aCallbackData);
|
||||||
// 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();
|
|
||||||
|
|
||||||
nsRefPtr<Layer> mRoot;
|
nsRefPtr<Layer> mRoot;
|
||||||
// The default context for BeginTransaction.
|
// The default context for BeginTransaction.
|
||||||
nsRefPtr<gfxContext> mDefaultTarget;
|
nsRefPtr<gfxContext> mDefaultTarget;
|
||||||
// The context to draw into. This is always the context that
|
// The context to draw into.
|
||||||
// our ThebesLayers will return.
|
|
||||||
nsRefPtr<gfxContext> mTarget;
|
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
|
#ifdef DEBUG
|
||||||
enum TransactionPhase { PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING };
|
enum TransactionPhase { PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING };
|
||||||
|
|||||||
@@ -198,7 +198,9 @@ CanvasLayerOGL::Updated(const nsIntRect& aRect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CanvasLayerOGL::RenderLayer(int aPreviousDestination)
|
CanvasLayerOGL::RenderLayer(int aPreviousDestination,
|
||||||
|
DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
|
LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
|
||||||
GLContext *gl = glManager->gl();
|
GLContext *gl = glManager->gl();
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ public:
|
|||||||
// LayerOGL implementation
|
// LayerOGL implementation
|
||||||
virtual LayerType GetType() { return TYPE_CANVAS; }
|
virtual LayerType GetType() { return TYPE_CANVAS; }
|
||||||
virtual Layer* GetLayer() { return this; }
|
virtual Layer* GetLayer() { return this; }
|
||||||
virtual void RenderLayer(int aPreviousDestination);
|
virtual void RenderLayer(int aPreviousDestination,
|
||||||
|
DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsRefPtr<gfxASurface> mSurface;
|
nsRefPtr<gfxASurface> mSurface;
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ ColorLayerOGL::GetLayer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ColorLayerOGL::RenderLayer(int)
|
ColorLayerOGL::RenderLayer(int, DrawThebesLayerCallback, void*)
|
||||||
{
|
{
|
||||||
static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
|
static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,9 @@ public:
|
|||||||
|
|
||||||
virtual Layer* GetLayer();
|
virtual Layer* GetLayer();
|
||||||
|
|
||||||
virtual void RenderLayer(int aPreviousDestination);
|
virtual void RenderLayer(int aPreviousDestination,
|
||||||
|
DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsIntRegion mVisibleRegion;
|
nsIntRegion mVisibleRegion;
|
||||||
|
|||||||
@@ -47,6 +47,15 @@ ContainerLayerOGL::ContainerLayerOGL(LayerManagerOGL *aManager)
|
|||||||
mImplData = static_cast<LayerOGL*>(this);
|
mImplData = static_cast<LayerOGL*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContainerLayerOGL::~ContainerLayerOGL()
|
||||||
|
{
|
||||||
|
LayerOGL *nextChild;
|
||||||
|
for (LayerOGL *child = GetFirstChildOGL(); child; child = nextChild) {
|
||||||
|
nextChild = child->GetNextSibling();
|
||||||
|
child->GetLayer()->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const nsIntRect&
|
const nsIntRect&
|
||||||
ContainerLayerOGL::GetVisibleRect()
|
ContainerLayerOGL::GetVisibleRect()
|
||||||
{
|
{
|
||||||
@@ -64,6 +73,7 @@ ContainerLayerOGL::InsertAfter(Layer* aChild, Layer* aAfter)
|
|||||||
{
|
{
|
||||||
LayerOGL *newChild = static_cast<LayerOGL*>(aChild->ImplData());
|
LayerOGL *newChild = static_cast<LayerOGL*>(aChild->ImplData());
|
||||||
aChild->SetParent(this);
|
aChild->SetParent(this);
|
||||||
|
NS_ADDREF(aChild);
|
||||||
if (!aAfter) {
|
if (!aAfter) {
|
||||||
LayerOGL *oldFirstChild = GetFirstChildOGL();
|
LayerOGL *oldFirstChild = GetFirstChildOGL();
|
||||||
mFirstChild = newChild->GetLayer();
|
mFirstChild = newChild->GetLayer();
|
||||||
@@ -87,6 +97,7 @@ ContainerLayerOGL::RemoveChild(Layer *aChild)
|
|||||||
{
|
{
|
||||||
if (GetFirstChild() == aChild) {
|
if (GetFirstChild() == aChild) {
|
||||||
mFirstChild = GetFirstChildOGL()->GetNextSibling()->GetLayer();
|
mFirstChild = GetFirstChildOGL()->GetNextSibling()->GetLayer();
|
||||||
|
NS_RELEASE(aChild);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LayerOGL *lastChild = NULL;
|
LayerOGL *lastChild = NULL;
|
||||||
@@ -97,6 +108,7 @@ ContainerLayerOGL::RemoveChild(Layer *aChild)
|
|||||||
lastChild->SetNextSibling(child->GetNextSibling());
|
lastChild->SetNextSibling(child->GetNextSibling());
|
||||||
child->SetNextSibling(NULL);
|
child->SetNextSibling(NULL);
|
||||||
child->GetLayer()->SetParent(NULL);
|
child->GetLayer()->SetParent(NULL);
|
||||||
|
NS_RELEASE(aChild);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastChild = child;
|
lastChild = child;
|
||||||
@@ -125,7 +137,9 @@ ContainerLayerOGL::GetFirstChildOGL()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer)
|
ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
|
||||||
|
DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Setup our temporary texture for rendering the contents of this container.
|
* Setup our temporary texture for rendering the contents of this container.
|
||||||
@@ -202,7 +216,7 @@ ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer)
|
|||||||
gl()->fScissor(0, 0, GetVisibleRect().width, GetVisibleRect().height);
|
gl()->fScissor(0, 0, GetVisibleRect().width, GetVisibleRect().height);
|
||||||
}
|
}
|
||||||
|
|
||||||
layerToRender->RenderLayer(frameBuffer);
|
layerToRender->RenderLayer(frameBuffer, aCallback, aCallbackData);
|
||||||
layerToRender = layerToRender->GetNextSibling();
|
layerToRender = layerToRender->GetNextSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class ContainerLayerOGL : public ContainerLayer,
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ContainerLayerOGL(LayerManagerOGL *aManager);
|
ContainerLayerOGL(LayerManagerOGL *aManager);
|
||||||
|
~ContainerLayerOGL();
|
||||||
|
|
||||||
const nsIntRect &GetVisibleRect();
|
const nsIntRect &GetVisibleRect();
|
||||||
|
|
||||||
@@ -68,7 +69,9 @@ public:
|
|||||||
|
|
||||||
PRBool IsEmpty();
|
PRBool IsEmpty();
|
||||||
|
|
||||||
void RenderLayer(int aPreviousFrameBuffer);
|
void RenderLayer(int aPreviousFrameBuffer,
|
||||||
|
DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
private:
|
private:
|
||||||
nsIntRect mVisibleRect;
|
nsIntRect mVisibleRect;
|
||||||
|
|
||||||
|
|||||||
@@ -269,7 +269,8 @@ ImageLayerOGL::GetLayer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ImageLayerOGL::RenderLayer(int)
|
ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
if (!GetContainer()) {
|
if (!GetContainer()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -175,7 +175,9 @@ public:
|
|||||||
|
|
||||||
virtual Layer* GetLayer();
|
virtual Layer* GetLayer();
|
||||||
|
|
||||||
virtual void RenderLayer(int aPreviousDestination);
|
virtual void RenderLayer(int aPreviousDestination,
|
||||||
|
DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
};
|
};
|
||||||
|
|
||||||
class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage
|
class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage
|
||||||
|
|||||||
@@ -282,14 +282,10 @@ LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerManagerOGL::EndConstruction()
|
LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
}
|
Render(aCallback, aCallbackData);
|
||||||
|
|
||||||
void
|
|
||||||
LayerManagerOGL::EndTransaction()
|
|
||||||
{
|
|
||||||
Render();
|
|
||||||
mTarget = NULL;
|
mTarget = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +354,8 @@ LayerManagerOGL::MakeCurrent()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerManagerOGL::Render()
|
LayerManagerOGL::Render(DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData)
|
||||||
{
|
{
|
||||||
nsIntRect rect;
|
nsIntRect rect;
|
||||||
mWidget->GetBounds(rect);
|
mWidget->GetBounds(rect);
|
||||||
@@ -384,7 +381,7 @@ LayerManagerOGL::Render()
|
|||||||
mGLContext->fScissor(0, 0, width, height);
|
mGLContext->fScissor(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
mRootLayer->RenderLayer(mFrameBuffer);
|
mRootLayer->RenderLayer(mFrameBuffer, aCallback, aCallbackData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTarget) {
|
if (mTarget) {
|
||||||
|
|||||||
@@ -216,7 +216,8 @@ public:
|
|||||||
|
|
||||||
void EndConstruction();
|
void EndConstruction();
|
||||||
|
|
||||||
void EndTransaction();
|
virtual void EndTransaction(DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
|
|
||||||
void SetRoot(Layer* aLayer);
|
void SetRoot(Layer* aLayer);
|
||||||
|
|
||||||
@@ -293,7 +294,8 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Render the current layer tree to the active target.
|
* Render the current layer tree to the active target.
|
||||||
*/
|
*/
|
||||||
void Render();
|
void Render(DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
/**
|
/**
|
||||||
* Setup the pipeline.
|
* Setup the pipeline.
|
||||||
*/
|
*/
|
||||||
@@ -316,6 +318,8 @@ private:
|
|||||||
class LayerOGL
|
class LayerOGL
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef LayerManager::DrawThebesLayerCallback DrawThebesLayerCallback;
|
||||||
|
|
||||||
LayerOGL(LayerManagerOGL *aManager);
|
LayerOGL(LayerManagerOGL *aManager);
|
||||||
|
|
||||||
enum LayerType {
|
enum LayerType {
|
||||||
@@ -336,7 +340,8 @@ public:
|
|||||||
|
|
||||||
virtual Layer* GetLayer() = 0;
|
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;
|
typedef mozilla::gl::GLContext GLContext;
|
||||||
|
|
||||||
|
|||||||
@@ -128,19 +128,28 @@ ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
|
|||||||
mInvalidatedRect = invalidatedRegion.GetBounds();
|
mInvalidatedRect = invalidatedRegion.GetBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxContext *
|
LayerOGL::LayerType
|
||||||
ThebesLayerOGL::BeginDrawing(nsIntRegion *aRegion)
|
ThebesLayerOGL::GetType()
|
||||||
{
|
{
|
||||||
if (mInvalidatedRect.IsEmpty()) {
|
return TYPE_THEBES;
|
||||||
aRegion->SetEmpty();
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
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;
|
gfxASurface::gfxImageFormat imageFormat;
|
||||||
|
|
||||||
if (UseOpaqueSurface(this)) {
|
if (UseOpaqueSurface(this)) {
|
||||||
@@ -149,40 +158,28 @@ ThebesLayerOGL::BeginDrawing(nsIntRegion *aRegion)
|
|||||||
imageFormat = gfxASurface::ImageFormatARGB32;
|
imageFormat = gfxASurface::ImageFormatARGB32;
|
||||||
}
|
}
|
||||||
|
|
||||||
mDestinationSurface =
|
nsRefPtr<gfxASurface> surface =
|
||||||
gfxPlatform::GetPlatform()->
|
gfxPlatform::GetPlatform()->
|
||||||
CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
|
CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
|
||||||
mInvalidatedRect.height),
|
mInvalidatedRect.height),
|
||||||
imageFormat);
|
imageFormat);
|
||||||
|
|
||||||
mContext = new gfxContext(mDestinationSurface);
|
nsRefPtr<gfxContext> ctx = new gfxContext(surface);
|
||||||
mContext->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
|
ctx->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
|
||||||
return mContext.get();
|
aCallback(this, ctx, mInvalidatedRect, aCallbackData);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ThebesLayerOGL::EndDrawing()
|
|
||||||
{
|
|
||||||
static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
|
static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
|
||||||
|
|
||||||
nsRefPtr<gfxImageSurface> imageSurface;
|
nsRefPtr<gfxImageSurface> imageSurface;
|
||||||
|
|
||||||
gfxASurface::gfxImageFormat imageFormat;
|
switch (surface->GetType()) {
|
||||||
|
|
||||||
if (UseOpaqueSurface(this)) {
|
|
||||||
imageFormat = gfxASurface::ImageFormatRGB24;
|
|
||||||
} else {
|
|
||||||
imageFormat = gfxASurface::ImageFormatARGB32;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (mDestinationSurface->GetType()) {
|
|
||||||
case gfxASurface::SurfaceTypeImage:
|
case gfxASurface::SurfaceTypeImage:
|
||||||
imageSurface = static_cast<gfxImageSurface*>(mDestinationSurface.get());
|
imageSurface = static_cast<gfxImageSurface*>(surface.get());
|
||||||
break;
|
break;
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
case gfxASurface::SurfaceTypeWin32:
|
case gfxASurface::SurfaceTypeWin32:
|
||||||
imageSurface =
|
imageSurface =
|
||||||
static_cast<gfxWindowsSurface*>(mDestinationSurface.get())->
|
static_cast<gfxWindowsSurface*>(surface.get())->
|
||||||
GetImageSurface();
|
GetImageSurface();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@@ -196,7 +193,7 @@ ThebesLayerOGL::EndDrawing()
|
|||||||
mInvalidatedRect.height),
|
mInvalidatedRect.height),
|
||||||
imageFormat);
|
imageFormat);
|
||||||
nsRefPtr<gfxContext> tmpContext = new gfxContext(imageSurface);
|
nsRefPtr<gfxContext> tmpContext = new gfxContext(imageSurface);
|
||||||
tmpContext->SetSource(mDestinationSurface);
|
tmpContext->SetSource(surface);
|
||||||
tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
|
tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||||
tmpContext->Paint();
|
tmpContext->Paint();
|
||||||
}
|
}
|
||||||
@@ -213,28 +210,6 @@ ThebesLayerOGL::EndDrawing()
|
|||||||
LOCAL_GL_BGRA,
|
LOCAL_GL_BGRA,
|
||||||
LOCAL_GL_UNSIGNED_BYTE,
|
LOCAL_GL_UNSIGNED_BYTE,
|
||||||
imageSurface->Data());
|
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];
|
float quadTransform[4][4];
|
||||||
|
|||||||
@@ -59,15 +59,13 @@ public:
|
|||||||
/** ThebesLayer implementation */
|
/** ThebesLayer implementation */
|
||||||
void InvalidateRegion(const nsIntRegion& aRegion);
|
void InvalidateRegion(const nsIntRegion& aRegion);
|
||||||
|
|
||||||
gfxContext *BeginDrawing(nsIntRegion* aRegionToDraw);
|
|
||||||
|
|
||||||
void EndDrawing();
|
|
||||||
|
|
||||||
/** LayerOGL implementation */
|
/** LayerOGL implementation */
|
||||||
LayerType GetType();
|
LayerType GetType();
|
||||||
Layer* GetLayer();
|
Layer* GetLayer();
|
||||||
virtual PRBool IsEmpty();
|
virtual PRBool IsEmpty();
|
||||||
virtual void RenderLayer(int aPreviousFrameBuffer);
|
virtual void RenderLayer(int aPreviousFrameBuffer,
|
||||||
|
DrawThebesLayerCallback aCallback,
|
||||||
|
void* aCallbackData);
|
||||||
|
|
||||||
/** ThebesLayerOGL */
|
/** ThebesLayerOGL */
|
||||||
const nsIntRect &GetVisibleRect();
|
const nsIntRect &GetVisibleRect();
|
||||||
@@ -83,16 +81,6 @@ private:
|
|||||||
* Currently invalidated rectangular area.
|
* Currently invalidated rectangular area.
|
||||||
*/
|
*/
|
||||||
nsIntRect mInvalidatedRect;
|
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
|
* OpenGL Texture
|
||||||
|
|||||||
539
layout/base/FrameLayerBuilder.cpp
Normal file
539
layout/base/FrameLayerBuilder.cpp
Normal file
@@ -0,0 +1,539 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||||
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is Mozilla Corporation code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Robert O'Callahan <robert@ocallahan.org>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#include "FrameLayerBuilder.h"
|
||||||
|
|
||||||
|
#include "nsDisplayList.h"
|
||||||
|
#include "nsPresContext.h"
|
||||||
|
#include "nsLayoutUtils.h"
|
||||||
|
|
||||||
|
using namespace mozilla::layers;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class iterates through a display list tree, descending only into
|
||||||
|
* nsDisplayClip items, and returns each display item encountered during
|
||||||
|
* such iteration. Along with each item we also return the clip rect
|
||||||
|
* accumulated for the item.
|
||||||
|
*/
|
||||||
|
class ClippedItemIterator {
|
||||||
|
public:
|
||||||
|
ClippedItemIterator(const nsDisplayList* aList)
|
||||||
|
{
|
||||||
|
DescendIntoList(aList, nsnull, nsnull);
|
||||||
|
AdvanceToItem();
|
||||||
|
}
|
||||||
|
PRBool IsDone()
|
||||||
|
{
|
||||||
|
return mStack.IsEmpty();
|
||||||
|
}
|
||||||
|
void Next()
|
||||||
|
{
|
||||||
|
State* top = StackTop();
|
||||||
|
top->mItem = top->mItem->GetAbove();
|
||||||
|
AdvanceToItem();
|
||||||
|
}
|
||||||
|
// Returns null if there is no clipping affecting the item. The
|
||||||
|
// clip rect is in device pixels
|
||||||
|
const gfxRect* GetEffectiveClipRect()
|
||||||
|
{
|
||||||
|
State* top = StackTop();
|
||||||
|
return top->mHasClipRect ? &top->mEffectiveClipRect : nsnull;
|
||||||
|
}
|
||||||
|
nsDisplayItem* Item()
|
||||||
|
{
|
||||||
|
return StackTop()->mItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// We maintain a stack of state objects. Each State object represents
|
||||||
|
// where we're up to in the iteration of a list.
|
||||||
|
struct State {
|
||||||
|
// The current item we're at in the list
|
||||||
|
nsDisplayItem* mItem;
|
||||||
|
// The effective clip rect applying to all the items in this list
|
||||||
|
gfxRect mEffectiveClipRect;
|
||||||
|
PRPackedBool mHasClipRect;
|
||||||
|
};
|
||||||
|
|
||||||
|
State* StackTop()
|
||||||
|
{
|
||||||
|
return &mStack[mStack.Length() - 1];
|
||||||
|
}
|
||||||
|
void DescendIntoList(const nsDisplayList* aList,
|
||||||
|
nsPresContext* aPresContext,
|
||||||
|
const nsRect* aClipRect)
|
||||||
|
{
|
||||||
|
State* state = mStack.AppendElement();
|
||||||
|
if (!state)
|
||||||
|
return;
|
||||||
|
if (mStack.Length() >= 2) {
|
||||||
|
*state = mStack[mStack.Length() - 2];
|
||||||
|
} else {
|
||||||
|
state->mHasClipRect = PR_FALSE;
|
||||||
|
}
|
||||||
|
state->mItem = aList->GetBottom();
|
||||||
|
if (aClipRect) {
|
||||||
|
gfxRect r(aClipRect->x, aClipRect->y, aClipRect->width, aClipRect->height);
|
||||||
|
r.ScaleInverse(aPresContext->AppUnitsPerDevPixel());
|
||||||
|
if (state->mHasClipRect) {
|
||||||
|
state->mEffectiveClipRect = state->mEffectiveClipRect.Intersect(r);
|
||||||
|
} else {
|
||||||
|
state->mEffectiveClipRect = r;
|
||||||
|
state->mHasClipRect = PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Advances to an item that the iterator should return.
|
||||||
|
void AdvanceToItem()
|
||||||
|
{
|
||||||
|
while (!mStack.IsEmpty()) {
|
||||||
|
State* top = StackTop();
|
||||||
|
if (!top->mItem) {
|
||||||
|
mStack.SetLength(mStack.Length() - 1);
|
||||||
|
if (!mStack.IsEmpty()) {
|
||||||
|
top = StackTop();
|
||||||
|
top->mItem = top->mItem->GetAbove();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (top->mItem->GetType() != nsDisplayItem::TYPE_CLIP)
|
||||||
|
return;
|
||||||
|
nsDisplayClip* clipItem = static_cast<nsDisplayClip*>(top->mItem);
|
||||||
|
nsRect clip = clipItem->GetClipRect();
|
||||||
|
DescendIntoList(clipItem->GetList(),
|
||||||
|
clipItem->GetClippingFrame()->PresContext(),
|
||||||
|
&clip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoTArray<State,10> mStack;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a sublist of consecutive items in an nsDisplayList.
|
||||||
|
* The first item in the sublist is mStartItem and the last item
|
||||||
|
* is the item before mEndItem.
|
||||||
|
*
|
||||||
|
* These sublists are themselves organized into a linked list of all
|
||||||
|
* the ItemGroups associated with a given layer, via mNextItemsForLayer.
|
||||||
|
* This list will have more than one element if the display items in a layer
|
||||||
|
* come from different nsDisplayLists, or if they come from the same
|
||||||
|
* nsDisplayList but they aren't consecutive in that list.
|
||||||
|
*
|
||||||
|
* These objects are allocated from the nsDisplayListBuilder arena.
|
||||||
|
*/
|
||||||
|
struct ItemGroup {
|
||||||
|
// If null, then the item group is empty.
|
||||||
|
nsDisplayItem* mStartItem;
|
||||||
|
nsDisplayItem* mEndItem;
|
||||||
|
ItemGroup* mNextItemsForLayer;
|
||||||
|
// The clipping (if any) that needs to be applied to all these items.
|
||||||
|
gfxRect mClipRect;
|
||||||
|
PRPackedBool mHasClipRect;
|
||||||
|
|
||||||
|
ItemGroup() : mStartItem(nsnull), mEndItem(nsnull),
|
||||||
|
mNextItemsForLayer(nsnull), mHasClipRect(PR_FALSE) {}
|
||||||
|
|
||||||
|
void* operator new(size_t aSize,
|
||||||
|
nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
|
||||||
|
return aBuilder->Allocate(aSize);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a layer and the display item(s) it
|
||||||
|
* will render. The items are stored in a linked list of ItemGroups.
|
||||||
|
*/
|
||||||
|
struct LayerItems {
|
||||||
|
nsRefPtr<Layer> mLayer;
|
||||||
|
// equal to mLayer, or null if mLayer is not a ThebesLayer
|
||||||
|
ThebesLayer* mThebesLayer;
|
||||||
|
ItemGroup* mItems;
|
||||||
|
// The bounds of the visible region for this layer, in device pixels
|
||||||
|
nsIntRect mVisibleRect;
|
||||||
|
|
||||||
|
LayerItems(ItemGroup* aItems) :
|
||||||
|
mThebesLayer(nsnull), mItems(aItems)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void* operator new(size_t aSize,
|
||||||
|
nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
|
||||||
|
return aBuilder->Allocate(aSize);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a (possibly clipped) display item in aItem, try to append it to
|
||||||
|
* the items in aGroup. If aItem is the next item in the sublist in
|
||||||
|
* aGroup, and the clipping matches, we can just update aGroup in-place,
|
||||||
|
* otherwise we'll allocate a new ItemGroup, add it to the linked list,
|
||||||
|
* and put aItem in the new ItemGroup. We return the ItemGroup into which
|
||||||
|
* aItem was inserted.
|
||||||
|
*/
|
||||||
|
static ItemGroup*
|
||||||
|
AddToItemGroup(nsDisplayListBuilder* aBuilder,
|
||||||
|
ItemGroup* aGroup, nsDisplayItem* aItem,
|
||||||
|
const gfxRect* aClipRect)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(!aGroup->mNextItemsForLayer,
|
||||||
|
"aGroup must be the last group in the chain");
|
||||||
|
|
||||||
|
if (!aGroup->mStartItem) {
|
||||||
|
aGroup->mStartItem = aItem;
|
||||||
|
aGroup->mEndItem = aItem->GetAbove();
|
||||||
|
aGroup->mHasClipRect = aClipRect != nsnull;
|
||||||
|
if (aClipRect) {
|
||||||
|
aGroup->mClipRect = *aClipRect;
|
||||||
|
}
|
||||||
|
return aGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aGroup->mEndItem == aItem &&
|
||||||
|
(aGroup->mHasClipRect
|
||||||
|
? (aClipRect && aGroup->mClipRect == *aClipRect)
|
||||||
|
: !aClipRect)) {
|
||||||
|
aGroup->mEndItem = aItem->GetAbove();
|
||||||
|
return aGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemGroup* itemGroup = new (aBuilder) ItemGroup();
|
||||||
|
if (!itemGroup)
|
||||||
|
return aGroup;
|
||||||
|
aGroup->mNextItemsForLayer = itemGroup;
|
||||||
|
return AddToItemGroup(aBuilder, itemGroup, aItem, aClipRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an empty Thebes layer, with an empty ItemGroup associated with
|
||||||
|
* it, and append it to aLayers.
|
||||||
|
*/
|
||||||
|
static ItemGroup*
|
||||||
|
CreateEmptyThebesLayer(nsDisplayListBuilder* aBuilder,
|
||||||
|
LayerManager* aManager,
|
||||||
|
nsTArray<LayerItems*>* aLayers)
|
||||||
|
{
|
||||||
|
ItemGroup* itemGroup = new (aBuilder) ItemGroup();
|
||||||
|
if (!itemGroup)
|
||||||
|
return nsnull;
|
||||||
|
nsRefPtr<ThebesLayer> thebesLayer = aManager->CreateThebesLayer();
|
||||||
|
if (!thebesLayer)
|
||||||
|
return nsnull;
|
||||||
|
LayerItems* layerItems = new (aBuilder) LayerItems(itemGroup);
|
||||||
|
aLayers->AppendElement(layerItems);
|
||||||
|
thebesLayer->SetUserData(layerItems);
|
||||||
|
layerItems->mThebesLayer = thebesLayer;
|
||||||
|
layerItems->mLayer = thebesLayer.forget();
|
||||||
|
return itemGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PRBool
|
||||||
|
IsAllUniform(nsDisplayListBuilder* aBuilder, ItemGroup* aGroup,
|
||||||
|
nscolor* aColor)
|
||||||
|
{
|
||||||
|
nsRect visibleRect = aGroup->mStartItem->GetVisibleRect();
|
||||||
|
nscolor finalColor = NS_RGBA(0,0,0,0);
|
||||||
|
for (ItemGroup* group = aGroup; group;
|
||||||
|
group = group->mNextItemsForLayer) {
|
||||||
|
for (nsDisplayItem* item = group->mStartItem; item != group->mEndItem;
|
||||||
|
item = item->GetAbove()) {
|
||||||
|
nscolor color;
|
||||||
|
if (visibleRect != item->GetVisibleRect())
|
||||||
|
return PR_FALSE;
|
||||||
|
if (!item->IsUniform(aBuilder, &color))
|
||||||
|
return PR_FALSE;
|
||||||
|
finalColor = NS_ComposeColors(finalColor, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*aColor = finalColor;
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the heart of layout's integration with layers. We
|
||||||
|
* use a ClippedItemIterator to iterate through descendant display
|
||||||
|
* items. Each item either has its own layer or is assigned to a
|
||||||
|
* ThebesLayer. We create ThebesLayers as necessary, although we try
|
||||||
|
* to put items in the bottom-most ThebesLayer because that is most
|
||||||
|
* likely to be able to render with an opaque background, which will often
|
||||||
|
* be required for subpixel text antialiasing to work.
|
||||||
|
*/
|
||||||
|
static void BuildLayers(nsDisplayListBuilder* aBuilder,
|
||||||
|
const nsDisplayList& aList,
|
||||||
|
LayerManager* aManager,
|
||||||
|
nsTArray<LayerItems*>* aLayers)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aLayers->IsEmpty(), "aLayers must be initially empty");
|
||||||
|
|
||||||
|
// Create "bottom" Thebes layer. We'll try to put as much content
|
||||||
|
// as possible in this layer because if the container is filled with
|
||||||
|
// opaque content, this bottommost layer can also be treated as opaque,
|
||||||
|
// which means content in this layer can have subpixel AA.
|
||||||
|
// firstThebesLayerItems always points to the last ItemGroup for the
|
||||||
|
// first Thebes layer.
|
||||||
|
ItemGroup* firstThebesLayerItems =
|
||||||
|
CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
|
||||||
|
if (!firstThebesLayerItems)
|
||||||
|
return;
|
||||||
|
// lastThebesLayerItems always points to the last ItemGroup for the
|
||||||
|
// topmost layer, if it's a ThebesLayer. If the top layer is not a
|
||||||
|
// Thebes layer, this is null.
|
||||||
|
ItemGroup* lastThebesLayerItems = firstThebesLayerItems;
|
||||||
|
// This region contains the bounds of all the content that is above
|
||||||
|
// the first Thebes layer.
|
||||||
|
nsRegion areaAboveFirstThebesLayer;
|
||||||
|
|
||||||
|
for (ClippedItemIterator iter(&aList); !iter.IsDone(); iter.Next()) {
|
||||||
|
nsDisplayItem* item = iter.Item();
|
||||||
|
const gfxRect* clipRect = iter.GetEffectiveClipRect();
|
||||||
|
// Ask the item if it manages its own layer
|
||||||
|
nsRefPtr<Layer> layer = item->BuildLayer(aBuilder, aManager);
|
||||||
|
nsRect bounds = item->GetBounds(aBuilder);
|
||||||
|
// We set layerItems to point to the LayerItems object where the
|
||||||
|
// item ends up.
|
||||||
|
LayerItems* layerItems = nsnull;
|
||||||
|
if (layer) {
|
||||||
|
// item has a dedicated layer. Add it to the list, with an ItemGroup
|
||||||
|
// covering this item only.
|
||||||
|
ItemGroup* itemGroup = new (aBuilder) ItemGroup();
|
||||||
|
if (itemGroup) {
|
||||||
|
AddToItemGroup(aBuilder, itemGroup, item, clipRect);
|
||||||
|
layerItems = new (aBuilder) LayerItems(itemGroup);
|
||||||
|
aLayers->AppendElement(layerItems);
|
||||||
|
if (layerItems) {
|
||||||
|
if (itemGroup->mHasClipRect) {
|
||||||
|
gfxRect r = itemGroup->mClipRect;
|
||||||
|
r.Round();
|
||||||
|
nsIntRect intRect(r.X(), r.Y(), r.Width(), r.Height());
|
||||||
|
layer->IntersectClipRect(intRect);
|
||||||
|
}
|
||||||
|
layerItems->mLayer = layer.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This item is above the first Thebes layer.
|
||||||
|
areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
|
||||||
|
lastThebesLayerItems = nsnull;
|
||||||
|
} else {
|
||||||
|
// No dedicated layer. Add it to a Thebes layer. First try to add
|
||||||
|
// it to the first Thebes layer, which we can do if there's no
|
||||||
|
// content between the first Thebes layer and our display item that
|
||||||
|
// overlaps our display item.
|
||||||
|
if (!areaAboveFirstThebesLayer.Intersects(bounds)) {
|
||||||
|
firstThebesLayerItems =
|
||||||
|
AddToItemGroup(aBuilder, firstThebesLayerItems, item, clipRect);
|
||||||
|
layerItems = aLayers->ElementAt(0);
|
||||||
|
} else if (lastThebesLayerItems) {
|
||||||
|
// Try to add to the last Thebes layer
|
||||||
|
lastThebesLayerItems =
|
||||||
|
AddToItemGroup(aBuilder, lastThebesLayerItems, item, clipRect);
|
||||||
|
// This item is above the first Thebes layer.
|
||||||
|
areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
|
||||||
|
layerItems = aLayers->ElementAt(aLayers->Length() - 1);
|
||||||
|
} else {
|
||||||
|
// Create a new Thebes layer
|
||||||
|
ItemGroup* itemGroup =
|
||||||
|
CreateEmptyThebesLayer(aBuilder, aManager, aLayers);
|
||||||
|
if (itemGroup) {
|
||||||
|
lastThebesLayerItems =
|
||||||
|
AddToItemGroup(aBuilder, itemGroup, item, clipRect);
|
||||||
|
NS_ASSERTION(lastThebesLayerItems == itemGroup,
|
||||||
|
"AddToItemGroup shouldn't create a new group if the "
|
||||||
|
"initial group is empty");
|
||||||
|
// This item is above the first Thebes layer.
|
||||||
|
areaAboveFirstThebesLayer.Or(areaAboveFirstThebesLayer, bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layerItems) {
|
||||||
|
// Update the visible region of the layer to account for the new
|
||||||
|
// item
|
||||||
|
nscoord appUnitsPerDevPixel =
|
||||||
|
item->GetUnderlyingFrame()->PresContext()->AppUnitsPerDevPixel();
|
||||||
|
layerItems->mVisibleRect.UnionRect(layerItems->mVisibleRect,
|
||||||
|
item->GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstThebesLayerItems->mStartItem) {
|
||||||
|
// The first Thebes layer has nothing in it. Delete the layer.
|
||||||
|
// Ensure layer is released.
|
||||||
|
aLayers->ElementAt(0)->mLayer = nsnull;
|
||||||
|
aLayers->RemoveElementAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PRUint32 i = 0; i < aLayers->Length(); ++i) {
|
||||||
|
LayerItems* layerItems = aLayers->ElementAt(i);
|
||||||
|
|
||||||
|
nscolor color;
|
||||||
|
// Only convert layers with identity transform to ColorLayers, for now.
|
||||||
|
// This simplifies the code to set the clip region.
|
||||||
|
if (layerItems->mThebesLayer &&
|
||||||
|
IsAllUniform(aBuilder, layerItems->mItems, &color) &&
|
||||||
|
layerItems->mLayer->GetTransform().IsIdentity()) {
|
||||||
|
nsRefPtr<ColorLayer> layer = aManager->CreateColorLayer();
|
||||||
|
layer->SetClipRect(layerItems->mThebesLayer->GetClipRect());
|
||||||
|
// Clip to mVisibleRect to ensure only the pixels we want are filled.
|
||||||
|
layer->IntersectClipRect(layerItems->mVisibleRect);
|
||||||
|
layer->SetColor(gfxRGBA(color));
|
||||||
|
layerItems->mLayer = layer.forget();
|
||||||
|
layerItems->mThebesLayer = nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfxMatrix transform;
|
||||||
|
nsIntRect visibleRect = layerItems->mVisibleRect;
|
||||||
|
if (layerItems->mLayer->GetTransform().Is2D(&transform)) {
|
||||||
|
// if 'transform' is not invertible, then nothing will be displayed
|
||||||
|
// for the layer, so it doesn't really matter what we do here
|
||||||
|
transform.Invert();
|
||||||
|
gfxRect layerVisible = transform.TransformBounds(
|
||||||
|
gfxRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height));
|
||||||
|
layerVisible.RoundOut();
|
||||||
|
if (NS_FAILED(nsLayoutUtils::GfxRectToIntRect(layerVisible, &visibleRect))) {
|
||||||
|
NS_ERROR("Visible rect transformed out of bounds");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NS_ERROR("Only 2D transformations currently supported");
|
||||||
|
}
|
||||||
|
layerItems->mLayer->SetVisibleRegion(nsIntRegion(visibleRect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
already_AddRefed<Layer>
|
||||||
|
FrameLayerBuilder::MakeContainerLayerFor(nsDisplayListBuilder* aBuilder,
|
||||||
|
LayerManager* aManager,
|
||||||
|
nsDisplayItem* aContainer,
|
||||||
|
const nsDisplayList& aChildren)
|
||||||
|
{
|
||||||
|
// If there's only one layer, then in principle we can try to flatten
|
||||||
|
// things by returning that layer here. But that adds complexity to
|
||||||
|
// retained layer management so we don't do it. Layer backends can
|
||||||
|
// flatten internally.
|
||||||
|
nsRefPtr<ContainerLayer> container = aManager->CreateContainerLayer();
|
||||||
|
if (!container)
|
||||||
|
return nsnull;
|
||||||
|
|
||||||
|
nsAutoTArray<LayerItems*,10> layerItems;
|
||||||
|
BuildLayers(aBuilder, aChildren, aManager, &layerItems);
|
||||||
|
|
||||||
|
Layer* lastChild = nsnull;
|
||||||
|
for (PRUint32 i = 0; i < layerItems.Length(); ++i) {
|
||||||
|
Layer* child = layerItems[i]->mLayer;
|
||||||
|
container->InsertAfter(child, lastChild);
|
||||||
|
lastChild = child;
|
||||||
|
// release the layer now because the ItemGroup destructor doesn't run;
|
||||||
|
// the container is still holding a reference to it
|
||||||
|
layerItems[i]->mLayer = nsnull;
|
||||||
|
}
|
||||||
|
container->SetIsOpaqueContent(aChildren.IsOpaque());
|
||||||
|
nsRefPtr<Layer> layer = container.forget();
|
||||||
|
return layer.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||||
|
gfxContext* aContext,
|
||||||
|
const nsIntRegion& aRegionToDraw,
|
||||||
|
void* aCallbackData)
|
||||||
|
{
|
||||||
|
LayerItems* layerItems = static_cast<LayerItems*>(aLayer->GetUserData());
|
||||||
|
nsDisplayListBuilder* builder =
|
||||||
|
static_cast<nsDisplayListBuilder*>(aCallbackData);
|
||||||
|
|
||||||
|
// For now, we'll ignore toDraw and just draw the entire visible
|
||||||
|
// area, because the "visible area" is already confined to just the
|
||||||
|
// area that needs to be repainted. Later, when we start reusing layers
|
||||||
|
// from paint to paint, we'll need to pay attention to toDraw and
|
||||||
|
// actually try to avoid drawing stuff that's not in it.
|
||||||
|
|
||||||
|
// Our list may contain content with different prescontexts at
|
||||||
|
// different zoom levels. 'rc' contains the nsIRenderingContext
|
||||||
|
// used for the previous display item, and lastPresContext is the
|
||||||
|
// prescontext for that item. We also cache the clip state for that
|
||||||
|
// item.
|
||||||
|
nsRefPtr<nsIRenderingContext> rc;
|
||||||
|
nsPresContext* lastPresContext = nsnull;
|
||||||
|
gfxRect currentClip;
|
||||||
|
PRBool setClipRect = PR_FALSE;
|
||||||
|
NS_ASSERTION(layerItems->mItems, "No empty layers allowed");
|
||||||
|
for (ItemGroup* group = layerItems->mItems; group;
|
||||||
|
group = group->mNextItemsForLayer) {
|
||||||
|
// If the new desired clip state is different from the current state,
|
||||||
|
// update the clip.
|
||||||
|
if (setClipRect != group->mHasClipRect ||
|
||||||
|
(group->mHasClipRect && group->mClipRect != currentClip)) {
|
||||||
|
if (setClipRect) {
|
||||||
|
aContext->Restore();
|
||||||
|
}
|
||||||
|
setClipRect = group->mHasClipRect;
|
||||||
|
if (setClipRect) {
|
||||||
|
aContext->Save();
|
||||||
|
aContext->NewPath();
|
||||||
|
aContext->Rectangle(group->mClipRect, PR_TRUE);
|
||||||
|
aContext->Clip();
|
||||||
|
currentClip = group->mClipRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_ASSERTION(group->mStartItem, "No empty groups allowed");
|
||||||
|
for (nsDisplayItem* item = group->mStartItem; item != group->mEndItem;
|
||||||
|
item = item->GetAbove()) {
|
||||||
|
nsPresContext* presContext = item->GetUnderlyingFrame()->PresContext();
|
||||||
|
if (presContext != lastPresContext) {
|
||||||
|
// Create a new rendering context with the right
|
||||||
|
// appunits-per-dev-pixel.
|
||||||
|
nsresult rv =
|
||||||
|
presContext->DeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc));
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
break;
|
||||||
|
rc->Init(presContext->DeviceContext(), aContext);
|
||||||
|
lastPresContext = presContext;
|
||||||
|
}
|
||||||
|
item->Paint(builder, rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (setClipRect) {
|
||||||
|
aContext->Restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
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)
|
$(NULL)
|
||||||
|
|
||||||
EXPORTS = \
|
EXPORTS = \
|
||||||
|
FrameLayerBuilder.h \
|
||||||
FramePropertyTable.h \
|
FramePropertyTable.h \
|
||||||
nsBidi.h \
|
nsBidi.h \
|
||||||
nsBidiPresUtils.h \
|
nsBidiPresUtils.h \
|
||||||
@@ -88,6 +89,7 @@ EXPORTS = \
|
|||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
CPPSRCS = \
|
CPPSRCS = \
|
||||||
|
FrameLayerBuilder.cpp \
|
||||||
FramePropertyTable.cpp \
|
FramePropertyTable.cpp \
|
||||||
nsCSSColorUtils.cpp \
|
nsCSSColorUtils.cpp \
|
||||||
nsCSSFrameConstructor.cpp \
|
nsCSSFrameConstructor.cpp \
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
#include "BasicLayers.h"
|
#include "BasicLayers.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
using namespace mozilla::layers;
|
using namespace mozilla::layers;
|
||||||
|
|
||||||
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||||
@@ -405,370 +406,6 @@ nsDisplayList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
|||||||
#endif
|
#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,
|
void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
|
||||||
nsIRenderingContext* aCtx,
|
nsIRenderingContext* aCtx,
|
||||||
PRUint32 aFlags) const {
|
PRUint32 aFlags) const {
|
||||||
@@ -813,8 +450,8 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
|
|||||||
layerManager->BeginTransaction();
|
layerManager->BeginTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoTArray<LayerItems,10> layers;
|
nsRefPtr<Layer> root = aBuilder->LayerBuilder()->
|
||||||
nsRefPtr<Layer> root = BuildLayer(aBuilder, layerManager, &layers);
|
MakeContainerLayerFor(aBuilder, layerManager, nsnull, *this);
|
||||||
if (!root)
|
if (!root)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -823,89 +460,12 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
|
|||||||
root->SetVisibleRegion(nsIntRegion(visible));
|
root->SetVisibleRegion(nsIntRegion(visible));
|
||||||
|
|
||||||
layerManager->SetRoot(root);
|
layerManager->SetRoot(root);
|
||||||
layerManager->EndConstruction();
|
layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
|
||||||
PaintThebesLayers(aBuilder, layers);
|
aBuilder);
|
||||||
layerManager->EndTransaction();
|
|
||||||
|
|
||||||
nsCSSRendering::DidPaint();
|
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 nsDisplayList::Count() const {
|
||||||
PRUint32 count = 0;
|
PRUint32 count = 0;
|
||||||
for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) {
|
for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) {
|
||||||
@@ -1584,8 +1144,8 @@ PRBool nsDisplayOpacity::IsOpaque(nsDisplayListBuilder* aBuilder) {
|
|||||||
already_AddRefed<Layer>
|
already_AddRefed<Layer>
|
||||||
nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
|
nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||||
LayerManager* aManager) {
|
LayerManager* aManager) {
|
||||||
nsRefPtr<Layer> layer =
|
nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
|
||||||
mList.BuildLayer(aBuilder, aManager, &mChildLayers);
|
MakeContainerLayerFor(aBuilder, aManager, this, mList);
|
||||||
if (!layer)
|
if (!layer)
|
||||||
return nsnull;
|
return nsnull;
|
||||||
|
|
||||||
@@ -1593,11 +1153,6 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||||||
return layer.forget();
|
return layer.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
nsDisplayOpacity::PaintThebesLayers(nsDisplayListBuilder* aBuilder) {
|
|
||||||
mList.PaintThebesLayers(aBuilder, mChildLayers);
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
PRBool nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||||
nsRegion* aVisibleRegion,
|
nsRegion* aVisibleRegion,
|
||||||
nsRegion* aVisibleRegionBeforeMove) {
|
nsRegion* aVisibleRegionBeforeMove) {
|
||||||
|
|||||||
@@ -53,12 +53,13 @@
|
|||||||
#include "nsCaret.h"
|
#include "nsCaret.h"
|
||||||
#include "plarena.h"
|
#include "plarena.h"
|
||||||
#include "Layers.h"
|
#include "Layers.h"
|
||||||
|
#include "nsRegion.h"
|
||||||
|
#include "FrameLayerBuilder.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
class nsIPresShell;
|
class nsIPresShell;
|
||||||
class nsIContent;
|
class nsIContent;
|
||||||
class nsRegion;
|
|
||||||
class nsIRenderingContext;
|
class nsIRenderingContext;
|
||||||
class nsIDeviceContext;
|
class nsIDeviceContext;
|
||||||
class nsDisplayTableItem;
|
class nsDisplayTableItem;
|
||||||
@@ -120,6 +121,7 @@ class nsDisplayItem;
|
|||||||
class NS_STACK_CLASS nsDisplayListBuilder {
|
class NS_STACK_CLASS nsDisplayListBuilder {
|
||||||
public:
|
public:
|
||||||
typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
|
typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
|
||||||
|
typedef mozilla::FrameLayerBuilder FrameLayerBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param aReferenceFrame the frame at the root of the subtree; its origin
|
* @param aReferenceFrame the frame at the root of the subtree; its origin
|
||||||
@@ -340,6 +342,11 @@ public:
|
|||||||
const nsFrameList& aFrames,
|
const nsFrameList& aFrames,
|
||||||
const nsRect& aDirtyRect);
|
const nsRect& aDirtyRect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the FrameLayerBuilder.
|
||||||
|
*/
|
||||||
|
FrameLayerBuilder* LayerBuilder() { return &mLayerBuilder; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate memory in our arena. It will only be freed when this display list
|
* Allocate memory in our arena. It will only be freed when this display list
|
||||||
* builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem
|
* builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem
|
||||||
@@ -408,6 +415,7 @@ private:
|
|||||||
return &mPresShellStates[mPresShellStates.Length() - 1];
|
return &mPresShellStates[mPresShellStates.Length() - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FrameLayerBuilder mLayerBuilder;
|
||||||
nsIFrame* mReferenceFrame;
|
nsIFrame* mReferenceFrame;
|
||||||
nsIFrame* mMovingFrame;
|
nsIFrame* mMovingFrame;
|
||||||
nsRegion* mSaveVisibleRegionOfMovingContent;
|
nsRegion* mSaveVisibleRegionOfMovingContent;
|
||||||
@@ -578,13 +586,6 @@ public:
|
|||||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||||
LayerManager* aManager)
|
LayerManager* aManager)
|
||||||
{ return nsnull; }
|
{ 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())
|
* On entry, aVisibleRegion contains the region (relative to ReferenceFrame())
|
||||||
@@ -630,6 +631,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual nsDisplayList* GetList() { return nsnull; }
|
virtual nsDisplayList* GetList() { return nsnull; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the visible rect. Should only be called after ComputeVisibility
|
||||||
|
* has happened.
|
||||||
|
*/
|
||||||
const nsRect& GetVisibleRect() { return mVisibleRect; }
|
const nsRect& GetVisibleRect() { return mVisibleRect; }
|
||||||
|
|
||||||
#ifdef NS_DEBUG
|
#ifdef NS_DEBUG
|
||||||
@@ -892,81 +897,6 @@ public:
|
|||||||
nsDisplayItem::HitTestState* aState,
|
nsDisplayItem::HitTestState* aState,
|
||||||
nsTArray<nsIFrame*> *aOutFrames) const;
|
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:
|
private:
|
||||||
// This class is only used on stack, so we don't have to worry about leaking
|
// This class is only used on stack, so we don't have to worry about leaking
|
||||||
// it. Don't let us be heap-allocated!
|
// it. Don't let us be heap-allocated!
|
||||||
@@ -1548,15 +1478,11 @@ public:
|
|||||||
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder);
|
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder);
|
||||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||||
LayerManager* aManager);
|
LayerManager* aManager);
|
||||||
virtual void PaintThebesLayers(nsDisplayListBuilder* aBuilder);
|
|
||||||
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||||
nsRegion* aVisibleRegion,
|
nsRegion* aVisibleRegion,
|
||||||
nsRegion* aVisibleRegionBeforeMove);
|
nsRegion* aVisibleRegionBeforeMove);
|
||||||
virtual PRBool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
|
virtual PRBool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
|
||||||
NS_DISPLAY_DECL_NAME("Opacity")
|
NS_DISPLAY_DECL_NAME("Opacity")
|
||||||
|
|
||||||
private:
|
|
||||||
nsTArray<nsDisplayList::LayerItems> mChildLayers;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5678,6 +5678,47 @@ nscolor PresShell::ComputeBackstopColor(nsIView* aDisplayRoot)
|
|||||||
return GetPresContext()->DefaultBackgroundColor();
|
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
|
NS_IMETHODIMP
|
||||||
PresShell::Paint(nsIView* aDisplayRoot,
|
PresShell::Paint(nsIView* aDisplayRoot,
|
||||||
nsIView* aViewToPaint,
|
nsIView* aViewToPaint,
|
||||||
@@ -5730,42 +5771,17 @@ PresShell::Paint(nsIView* aDisplayRoot,
|
|||||||
root->SetVisibleRegion(dirtyRect);
|
root->SetVisibleRegion(dirtyRect);
|
||||||
layerManager->SetRoot(root);
|
layerManager->SetRoot(root);
|
||||||
}
|
}
|
||||||
layerManager->EndConstruction();
|
if (!frame) {
|
||||||
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);
|
bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
|
||||||
ctx->NewPath();
|
|
||||||
ctx->SetColor(gfxRGBA(bgcolor));
|
|
||||||
ctx->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
|
|
||||||
ctx->Fill();
|
|
||||||
}
|
}
|
||||||
}
|
nsPoint offsetToRoot = aViewToPaint->GetOffsetTo(aDisplayRoot);
|
||||||
root->EndDrawing();
|
PaintParams params =
|
||||||
}
|
{ frame,
|
||||||
layerManager->EndTransaction();
|
offsetToRoot,
|
||||||
|
offsetToRoot - aViewToPaint->ViewToWidgetOffset(),
|
||||||
|
&aDirtyRegion,
|
||||||
|
bgcolor };
|
||||||
|
layerManager->EndTransaction(DrawThebesLayer, ¶ms);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user