From b058c7e33367d415173c5a3c07607f5d3b3ebf02 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Thu, 3 May 2012 23:31:02 +0200 Subject: [PATCH] Bug 738413 - Part 2: Use OpaqueRect API in BasicLayers with non-cairo contexts. r=roc --- gfx/layers/basic/BasicLayers.cpp | 55 +++++++++++++++++++++++++------- gfx/thebes/gfxUtils.cpp | 8 +++++ gfx/thebes/gfxUtils.h | 7 ++++ 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index b2202741ac51..eed08a5c38fb 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -74,6 +74,8 @@ #define PIXMAN_DONT_DEFINE_STDINT #include "pixman.h" +using namespace mozilla::gfx; + namespace mozilla { namespace layers { @@ -1946,19 +1948,40 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, bool pushedTargetOpaqueRect = false; nsRefPtr currentSurface = aTarget->CurrentSurface(); + DrawTarget *dt = aTarget->GetDrawTarget(); const nsIntRect& bounds = visibleRegion.GetBounds(); - if (aTarget->IsCairo()) { - const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect(); + if (is2D) { + if (aTarget->IsCairo()) { + const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect(); - // Try to annotate currentSurface with a region of pixels that have been - // (or will be) painted opaque, if no such region is currently set. - if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 && - (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) && - !transform.HasNonAxisAlignedTransform()) { - currentSurface->SetOpaqueRect( - aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height))); - pushedTargetOpaqueRect = true; + // Try to annotate currentSurface with a region of pixels that have been + // (or will be) painted opaque, if no such region is currently set. + if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 && + (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) && + !transform.HasNonAxisAlignedTransform()) { + currentSurface->SetOpaqueRect( + aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height))); + pushedTargetOpaqueRect = true; + } + } else { + const IntRect& targetOpaqueRect = dt->GetOpaqueRect(); + + // Try to annotate currentSurface with a region of pixels that have been + // (or will be) painted opaque, if no such region is currently set. + if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 && + (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) && + !transform.HasNonAxisAlignedTransform()) { + + Rect opaqueRect = dt->GetTransform().TransformBounds( + Rect(bounds.x, bounds.y, bounds.width, bounds.height)); + opaqueRect.RoundIn(); + IntRect intOpaqueRect; + if (gfxUtils::RectToIntRect(opaqueRect, &intOpaqueRect)) { + aTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect); + pushedTargetOpaqueRect = true; + } + } } } @@ -1970,7 +1993,11 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, gfxASurface::CONTENT_COLOR_ALPHA); if (!untransformedSurface) { if (pushedTargetOpaqueRect) { - currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0)); + if (aTarget->IsCairo()) { + currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0)); + } else { + dt->SetOpaqueRect(IntRect()); + } } NS_ASSERTION(needsSaveRestore, "Should always need to restore with 3d transforms!"); aTarget->Restore(); @@ -2085,7 +2112,11 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, } if (pushedTargetOpaqueRect) { - currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0)); + if (aTarget->IsCairo()) { + currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0)); + } else { + dt->SetOpaqueRect(IntRect()); + } } if (needsSaveRestore) { diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 5247b399d76c..11bf4337a164 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -574,6 +574,14 @@ gfxUtils::GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut) return gfxRect(aOut->x, aOut->y, aOut->width, aOut->height).IsEqualEdges(aIn); } +bool +gfxUtils::RectToIntRect(const Rect& aIn, IntRect* aOut) +{ + *aOut = IntRect(int32_t(aIn.X()), int32_t(aIn.Y()), + int32_t(aIn.Width()), int32_t(aIn.Height())); + return Rect(aOut->x, aOut->y, aOut->width, aOut->height).IsEqualEdges(aIn); +} + void gfxUtils::GetYCbCrToRGBDestFormatAndSize(const PlanarYCbCrImage::Data& aData, gfxASurface::gfxImageFormat& aSuggestedFormat, diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 56ccfe6d4c24..46a5031749e1 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -125,6 +125,13 @@ public: */ static bool GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut); + /** + * If aIn can be represented exactly using an nsIntRect (i.e. + * integer-aligned edges and coordinates in the PRInt32 range) then we + * set aOut to that rectangle, otherwise return failure. + */ + static bool RectToIntRect(const mozilla::gfx::Rect& aIn, mozilla::gfx::IntRect* aOut); + /** * Return the smallest power of kScaleResolution (2) greater than or equal to * aVal.