diff -r 000000000000 -r 6474c204b198 gfx/layers/composite/LayerManagerComposite.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/layers/composite/LayerManagerComposite.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,927 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "LayerManagerComposite.h" +#include // for size_t +#include // for uint16_t, uint32_t +#include "CanvasLayerComposite.h" // for CanvasLayerComposite +#include "ColorLayerComposite.h" // for ColorLayerComposite +#include "Composer2D.h" // for Composer2D +#include "CompositableHost.h" // for CompositableHost +#include "ContainerLayerComposite.h" // for ContainerLayerComposite, etc +#include "FPSCounter.h" // for FPSState, FPSCounter +#include "FrameMetrics.h" // for FrameMetrics +#include "GeckoProfiler.h" // for profiler_set_frame_number, etc +#include "ImageLayerComposite.h" // for ImageLayerComposite +#include "Layers.h" // for Layer, ContainerLayer, etc +#include "ThebesLayerComposite.h" // for ThebesLayerComposite +#include "TiledLayerBuffer.h" // for TiledLayerComposer +#include "Units.h" // for ScreenIntRect +#include "gfx2DGlue.h" // for ToMatrix4x4 +#include "gfx3DMatrix.h" // for gfx3DMatrix +#include "gfxPrefs.h" // for gfxPrefs +#ifdef XP_MACOSX +#include "gfxPlatformMac.h" +#endif +#include "gfxRect.h" // for gfxRect +#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc +#include "mozilla/RefPtr.h" // for RefPtr, TemporaryRef +#include "mozilla/gfx/2D.h" // for DrawTarget +#include "mozilla/gfx/Matrix.h" // for Matrix4x4 +#include "mozilla/gfx/Point.h" // for IntSize, Point +#include "mozilla/gfx/Rect.h" // for Rect +#include "mozilla/gfx/Types.h" // for Color, SurfaceFormat +#include "mozilla/layers/Compositor.h" // for Compositor +#include "mozilla/layers/CompositorTypes.h" +#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc +#include "mozilla/layers/LayersTypes.h" // for etc +#include "ipc/ShadowLayerUtils.h" +#include "mozilla/mozalloc.h" // for operator new, etc +#include "nsAutoPtr.h" // for nsRefPtr +#include "nsCOMPtr.h" // for already_AddRefed +#include "nsDebug.h" // for NS_WARNING, NS_RUNTIMEABORT, etc +#include "nsISupportsImpl.h" // for Layer::AddRef, etc +#include "nsIWidget.h" // for nsIWidget +#include "nsPoint.h" // for nsIntPoint +#include "nsRect.h" // for nsIntRect +#include "nsRegion.h" // for nsIntRegion, etc +#ifdef MOZ_WIDGET_ANDROID +#include +#endif +#include "GeckoProfiler.h" +#include "TextRenderer.h" // for TextRenderer + +class gfxContext; +struct nsIntSize; + + +namespace mozilla { +namespace layers { + +class ImageLayer; + +using namespace mozilla::gfx; +using namespace mozilla::gl; + +static LayerComposite* +ToLayerComposite(Layer* aLayer) +{ + return static_cast(aLayer->ImplData()); +} + +static void ClearSubtree(Layer* aLayer) +{ + ToLayerComposite(aLayer)->CleanupResources(); + for (Layer* child = aLayer->GetFirstChild(); child; + child = child->GetNextSibling()) { + ClearSubtree(child); + } +} + +void +LayerManagerComposite::ClearCachedResources(Layer* aSubtree) +{ + MOZ_ASSERT(!aSubtree || aSubtree->Manager() == this); + Layer* subtree = aSubtree ? aSubtree : mRoot.get(); + if (!subtree) { + return; + } + + ClearSubtree(subtree); + // FIXME [bjacob] + // XXX the old LayerManagerOGL code had a mMaybeInvalidTree that it set to true here. + // Do we need that? +} + +/** + * LayerManagerComposite + */ +LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor) +: mCompositor(aCompositor) +, mInTransaction(false) +, mIsCompositorReady(false) +, mDebugOverlayWantsNextFrame(false) +, mGeometryChanged(true) +{ + mTextRenderer = new TextRenderer(aCompositor); + MOZ_ASSERT(aCompositor); +} + +LayerManagerComposite::~LayerManagerComposite() +{ + Destroy(); +} + + +bool +LayerManagerComposite::Initialize() +{ + bool result = mCompositor->Initialize(); + return result; +} + +void +LayerManagerComposite::Destroy() +{ + if (!mDestroyed) { + mCompositor->GetWidget()->CleanupWindowEffects(); + if (mRoot) { + RootLayer()->Destroy(); + } + mRoot = nullptr; + + mCompositor->Destroy(); + + mDestroyed = true; + } +} + +void +LayerManagerComposite::UpdateRenderBounds(const nsIntRect& aRect) +{ + mRenderBounds = aRect; +} + +void +LayerManagerComposite::BeginTransaction() +{ + mInTransaction = true; + + if (!mCompositor->Ready()) { + return; + } + + mIsCompositorReady = true; + + if (Compositor::GetBackend() == LayersBackend::LAYERS_OPENGL || + Compositor::GetBackend() == LayersBackend::LAYERS_BASIC) { + mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot()); + } +} + +void +LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget) +{ + mInTransaction = true; + + if (!mCompositor->Ready()) { + return; + } + +#ifdef MOZ_LAYERS_HAVE_LOG + MOZ_LAYERS_LOG(("[----- BeginTransaction")); + Log(); +#endif + + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return; + } + + mIsCompositorReady = true; + mCompositor->SetTargetContext(aTarget); + mTarget = aTarget; +} + +bool +LayerManagerComposite::EndEmptyTransaction(EndTransactionFlags aFlags) +{ + NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); + if (!mRoot) { + mInTransaction = false; + mIsCompositorReady = false; + return false; + } + + EndTransaction(nullptr, nullptr); + return true; +} + +void +LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback, + void* aCallbackData, + EndTransactionFlags aFlags) +{ + NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); + NS_ASSERTION(!aCallback && !aCallbackData, "Not expecting callbacks here"); + mInTransaction = false; + + if (!mIsCompositorReady) { + return; + } + mIsCompositorReady = false; + +#ifdef MOZ_LAYERS_HAVE_LOG + MOZ_LAYERS_LOG((" ----- (beginning paint)")); + Log(); +#endif + + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return; + } + + if (mRoot && mClonedLayerTreeProperties) { + nsIntRegion invalid = + mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged); + mClonedLayerTreeProperties = nullptr; + + mInvalidRegion.Or(mInvalidRegion, invalid); + } else { + mInvalidRegion.Or(mInvalidRegion, mRenderBounds); + } + + if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) { + if (aFlags & END_NO_COMPOSITE) { + // Apply pending tree updates before recomputing effective + // properties. + mRoot->ApplyPendingUpdatesToSubtree(); + } + + // The results of our drawing always go directly into a pixel buffer, + // so we don't need to pass any global transform here. + mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4()); + + Render(); + mGeometryChanged = false; + } + + mCompositor->SetTargetContext(nullptr); + mTarget = nullptr; + +#ifdef MOZ_LAYERS_HAVE_LOG + Log(); + MOZ_LAYERS_LOG(("]----- EndTransaction")); +#endif +} + +TemporaryRef +LayerManagerComposite::CreateOptimalMaskDrawTarget(const IntSize &aSize) +{ + NS_RUNTIMEABORT("Should only be called on the drawing side"); + return nullptr; +} + +already_AddRefed +LayerManagerComposite::CreateThebesLayer() +{ + NS_RUNTIMEABORT("Should only be called on the drawing side"); + return nullptr; +} + +already_AddRefed +LayerManagerComposite::CreateContainerLayer() +{ + NS_RUNTIMEABORT("Should only be called on the drawing side"); + return nullptr; +} + +already_AddRefed +LayerManagerComposite::CreateImageLayer() +{ + NS_RUNTIMEABORT("Should only be called on the drawing side"); + return nullptr; +} + +already_AddRefed +LayerManagerComposite::CreateColorLayer() +{ + NS_RUNTIMEABORT("Should only be called on the drawing side"); + return nullptr; +} + +already_AddRefed +LayerManagerComposite::CreateCanvasLayer() +{ + NS_RUNTIMEABORT("Should only be called on the drawing side"); + return nullptr; +} + +LayerComposite* +LayerManagerComposite::RootLayer() const +{ + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nullptr; + } + + return ToLayerComposite(mRoot); +} + +// Size of the builtin font. +static const float FontHeight = 7.f; +static const float FontWidth = 4.f; +static const float FontStride = 4.f; + +// Scale the font when drawing it to the viewport for better readability. +static const float FontScaleX = 2.f; +static const float FontScaleY = 3.f; + +static void DrawDigits(unsigned int aValue, + int aOffsetX, int aOffsetY, + Compositor* aCompositor, + EffectChain& aEffectChain) +{ + if (aValue > 999) { + aValue = 999; + } + + unsigned int divisor = 100; + float textureWidth = FontWidth * 10; + gfx::Float opacity = 1; + gfx::Matrix4x4 transform; + transform.Scale(FontScaleX, FontScaleY, 1); + + for (size_t n = 0; n < 3; ++n) { + unsigned int digit = aValue % (divisor * 10) / divisor; + divisor /= 10; + + RefPtr texturedEffect = static_cast(aEffectChain.mPrimaryEffect.get()); + texturedEffect->mTextureCoords = Rect(float(digit * FontWidth) / textureWidth, 0, FontWidth / textureWidth, 1.0f); + + Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight); + Rect clipRect = Rect(0, 0, 300, 100); + aCompositor->DrawQuad(drawRect, clipRect, + aEffectChain, opacity, transform); + } +} + +void FPSState::DrawFPS(TimeStamp aNow, + unsigned int aFillRatio, + Compositor* aCompositor) +{ + if (!mFPSTextureSource) { + const char *text = + " " + " XXX XX XXX XXX X X XXX XXX XXX XXX XXX" + " X X X X X X X X X X X X X X" + " X X X XXX XXX XXX XXX XXX X XXX XXX" + " X X X X X X X X X X X X X" + " XXX XXX XXX XXX X XXX XXX X XXX X" + " "; + + // Convert the text encoding above to RGBA. + int w = FontWidth * 10; + int h = FontHeight; + uint32_t* buf = (uint32_t *) malloc(w * h * sizeof(uint32_t)); + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + uint32_t purple = 0xfff000ff; + uint32_t white = 0xffffffff; + buf[i * w + j] = (text[i * w + j] == ' ') ? purple : white; + } + } + + int bytesPerPixel = 4; + RefPtr fpsSurface = Factory::CreateWrappingDataSourceSurface( + reinterpret_cast(buf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8); + mFPSTextureSource = aCompositor->CreateDataTextureSource(); + mFPSTextureSource->Update(fpsSurface); + } + + EffectChain effectChain; + effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mFPSTextureSource, Filter::POINT); + + unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow)); + unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow)); + + DrawDigits(fps, 0, 0, aCompositor, effectChain); + DrawDigits(txnFps, FontWidth * 4, 0, aCompositor, effectChain); + DrawDigits(aFillRatio, FontWidth * 8, 0, aCompositor, effectChain); +} + +static uint16_t sFrameCount = 0; +void +LayerManagerComposite::RenderDebugOverlay(const Rect& aBounds) +{ + if (gfxPrefs::LayersDrawFPS()) { + if (!mFPS) { + mFPS = new FPSState(); + } + + float fillRatio = mCompositor->GetFillRatio(); + mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mCompositor); + } else { + mFPS = nullptr; + } + + if (gfxPrefs::DrawFrameCounter()) { + profiler_set_frame_number(sFrameCount); + + uint16_t frameNumber = sFrameCount; + const uint16_t bitWidth = 3; + float opacity = 1.0; + gfx::Rect clip(0,0, bitWidth*16, bitWidth); + for (size_t i = 0; i < 16; i++) { + + gfx::Color bitColor; + if ((frameNumber >> i) & 0x1) { + bitColor = gfx::Color(0, 0, 0, 1.0); + } else { + bitColor = gfx::Color(1.0, 1.0, 1.0, 1.0); + } + EffectChain effects; + effects.mPrimaryEffect = new EffectSolidColor(bitColor); + mCompositor->DrawQuad(gfx::Rect(bitWidth*i, 0, bitWidth, bitWidth), + clip, + effects, + opacity, + gfx::Matrix4x4()); + } + // We intentionally overflow at 2^16. + sFrameCount++; + } +} + +void +LayerManagerComposite::Render() +{ + PROFILER_LABEL("LayerManagerComposite", "Render"); + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return; + } + + if (gfxPrefs::LayersDump()) { + this->Dump(); + } + + /** Our more efficient but less powerful alter ego, if one is available. */ + nsRefPtr composer2D = mCompositor->GetWidget()->GetComposer2D(); + + if (!mTarget && composer2D && composer2D->TryRender(mRoot, mWorldMatrix, mGeometryChanged)) { + if (mFPS) { + double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now()); + if (gfxPrefs::LayersDrawFPS()) { + printf_stderr("HWComposer: FPS is %g\n", fps); + } + } + mCompositor->EndFrameForExternalComposition(mWorldMatrix); + return; + } + + { + PROFILER_LABEL("LayerManagerComposite", "PreRender"); + if (!mCompositor->GetWidget()->PreRender(this)) { + return; + } + } + + nsIntRect clipRect; + Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height); + Rect actualBounds; + if (mRoot->GetClipRect()) { + clipRect = *mRoot->GetClipRect(); + WorldTransformRect(clipRect); + Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height); + mCompositor->BeginFrame(mInvalidRegion, &rect, mWorldMatrix, bounds, nullptr, &actualBounds); + } else { + gfx::Rect rect; + mCompositor->BeginFrame(mInvalidRegion, nullptr, mWorldMatrix, bounds, &rect, &actualBounds); + clipRect = nsIntRect(rect.x, rect.y, rect.width, rect.height); + } + + // Reset the invalid region now that we've begun compositing. + mInvalidRegion.SetEmpty(); + + if (actualBounds.IsEmpty()) { + mCompositor->GetWidget()->PostRender(this); + return; + } + + // Allow widget to render a custom background. + mCompositor->GetWidget()->DrawWindowUnderlay(this, nsIntRect(actualBounds.x, + actualBounds.y, + actualBounds.width, + actualBounds.height)); + + // Render our layers. + RootLayer()->RenderLayer(clipRect); + + if (!mRegionToClear.IsEmpty()) { + nsIntRegionRectIterator iter(mRegionToClear); + const nsIntRect *r; + while ((r = iter.Next())) { + mCompositor->ClearRect(Rect(r->x, r->y, r->width, r->height)); + } + } + + // Allow widget to render a custom foreground. + mCompositor->GetWidget()->DrawWindowOverlay(this, nsIntRect(actualBounds.x, + actualBounds.y, + actualBounds.width, + actualBounds.height)); + + // Debugging + RenderDebugOverlay(actualBounds); + + { + PROFILER_LABEL("LayerManagerComposite", "EndFrame"); + mCompositor->EndFrame(); + mCompositor->SetFBAcquireFence(mRoot); + } + + mCompositor->GetWidget()->PostRender(this); + + RecordFrame(); +} + +void +LayerManagerComposite::SetWorldTransform(const gfx::Matrix& aMatrix) +{ + NS_ASSERTION(aMatrix.PreservesAxisAlignedRectangles(), + "SetWorldTransform only accepts matrices that satisfy PreservesAxisAlignedRectangles"); + NS_ASSERTION(!aMatrix.HasNonIntegerScale(), + "SetWorldTransform only accepts matrices with integer scale"); + + mWorldMatrix = aMatrix; +} + +gfx::Matrix& +LayerManagerComposite::GetWorldTransform(void) +{ + return mWorldMatrix; +} + +void +LayerManagerComposite::WorldTransformRect(nsIntRect& aRect) +{ + gfx::Rect grect(aRect.x, aRect.y, aRect.width, aRect.height); + grect = mWorldMatrix.TransformBounds(grect); + aRect.SetRect(grect.X(), grect.Y(), grect.Width(), grect.Height()); +} + +static void +SubtractTransformedRegion(nsIntRegion& aRegion, + const nsIntRegion& aRegionToSubtract, + const gfx3DMatrix& aTransform) +{ + if (aRegionToSubtract.IsEmpty()) { + return; + } + + // For each rect in the region, find out its bounds in screen space and + // subtract it from the screen region. + nsIntRegionRectIterator it(aRegionToSubtract); + while (const nsIntRect* rect = it.Next()) { + gfxRect incompleteRect = aTransform.TransformBounds(gfxRect(*rect)); + aRegion.Sub(aRegion, nsIntRect(incompleteRect.x, + incompleteRect.y, + incompleteRect.width, + incompleteRect.height)); + } +} + +/* static */ void +LayerManagerComposite::ComputeRenderIntegrityInternal(Layer* aLayer, + nsIntRegion& aScreenRegion, + nsIntRegion& aLowPrecisionScreenRegion, + const gfx3DMatrix& aTransform) +{ + if (aLayer->GetOpacity() <= 0.f || + (aScreenRegion.IsEmpty() && aLowPrecisionScreenRegion.IsEmpty())) { + return; + } + + // If the layer's a container, recurse into all of its children + ContainerLayer* container = aLayer->AsContainerLayer(); + if (container) { + // Accumulate the transform of intermediate surfaces + gfx3DMatrix transform = aTransform; + if (container->UseIntermediateSurface()) { + gfx::To3DMatrix(aLayer->GetEffectiveTransform(), transform); + transform.PreMultiply(aTransform); + } + for (Layer* child = aLayer->GetFirstChild(); child; + child = child->GetNextSibling()) { + ComputeRenderIntegrityInternal(child, aScreenRegion, aLowPrecisionScreenRegion, transform); + } + return; + } + + // Only thebes layers can be incomplete + ThebesLayer* thebesLayer = aLayer->AsThebesLayer(); + if (!thebesLayer) { + return; + } + + // See if there's any incomplete rendering + nsIntRegion incompleteRegion = aLayer->GetEffectiveVisibleRegion(); + incompleteRegion.Sub(incompleteRegion, thebesLayer->GetValidRegion()); + + if (!incompleteRegion.IsEmpty()) { + // Calculate the transform to get between screen and layer space + gfx3DMatrix transformToScreen; + To3DMatrix(aLayer->GetEffectiveTransform(), transformToScreen); + transformToScreen.PreMultiply(aTransform); + + SubtractTransformedRegion(aScreenRegion, incompleteRegion, transformToScreen); + + // See if there's any incomplete low-precision rendering + TiledLayerComposer* composer = nullptr; + LayerComposite* shadow = aLayer->AsLayerComposite(); + if (shadow) { + composer = shadow->GetTiledLayerComposer(); + if (composer) { + incompleteRegion.Sub(incompleteRegion, composer->GetValidLowPrecisionRegion()); + if (!incompleteRegion.IsEmpty()) { + SubtractTransformedRegion(aLowPrecisionScreenRegion, incompleteRegion, transformToScreen); + } + } + } + + // If we can't get a valid low precision region, assume it's the same as + // the high precision region. + if (!composer) { + SubtractTransformedRegion(aLowPrecisionScreenRegion, incompleteRegion, transformToScreen); + } + } +} + +#ifdef MOZ_ANDROID_OMTC +static float +GetDisplayportCoverage(const CSSRect& aDisplayPort, + const gfx3DMatrix& aTransformToScreen, + const nsIntRect& aScreenRect) +{ + gfxRect transformedDisplayport = + aTransformToScreen.TransformBounds(gfxRect(aDisplayPort.x, + aDisplayPort.y, + aDisplayPort.width, + aDisplayPort.height)); + transformedDisplayport.RoundOut(); + nsIntRect displayport = nsIntRect(transformedDisplayport.x, + transformedDisplayport.y, + transformedDisplayport.width, + transformedDisplayport.height); + if (!displayport.Contains(aScreenRect)) { + nsIntRegion coveredRegion; + coveredRegion.And(aScreenRect, displayport); + return coveredRegion.Area() / (float)(aScreenRect.width * aScreenRect.height); + } + + return 1.0f; +} +#endif // MOZ_ANDROID_OMTC + +float +LayerManagerComposite::ComputeRenderIntegrity() +{ + // We only ever have incomplete rendering when progressive tiles are enabled. + Layer* root = GetRoot(); + if (!gfxPrefs::UseProgressiveTilePainting() || !root) { + return 1.f; + } + + const FrameMetrics& rootMetrics = root->AsContainerLayer()->GetFrameMetrics(); + nsIntRect screenRect(rootMetrics.mCompositionBounds.x, + rootMetrics.mCompositionBounds.y, + rootMetrics.mCompositionBounds.width, + rootMetrics.mCompositionBounds.height); + + float lowPrecisionMultiplier = 1.0f; + float highPrecisionMultiplier = 1.0f; + +#ifdef MOZ_ANDROID_OMTC + // Use the transform on the primary scrollable layer and its FrameMetrics + // to find out how much of the viewport the current displayport covers + Layer* primaryScrollable = GetPrimaryScrollableLayer(); + if (primaryScrollable) { + // This is derived from the code in + // AsyncCompositionManager::TransformScrollableLayer + const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics(); + gfx3DMatrix transform; + gfx::To3DMatrix(primaryScrollable->GetEffectiveTransform(), transform); + transform.ScalePost(metrics.mResolution.scale, metrics.mResolution.scale, 1); + + // Clip the screen rect to the document bounds + gfxRect documentBounds = + transform.TransformBounds(gfxRect(metrics.mScrollableRect.x - metrics.GetScrollOffset().x, + metrics.mScrollableRect.y - metrics.GetScrollOffset().y, + metrics.mScrollableRect.width, + metrics.mScrollableRect.height)); + documentBounds.RoundOut(); + screenRect = screenRect.Intersect(nsIntRect(documentBounds.x, documentBounds.y, + documentBounds.width, documentBounds.height)); + + // If the screen rect is empty, the user has scrolled entirely into + // over-scroll and so we can be considered to have full integrity. + if (screenRect.IsEmpty()) { + return 1.0f; + } + + // Work out how much of the critical display-port covers the screen + bool hasLowPrecision = false; + if (!metrics.mCriticalDisplayPort.IsEmpty()) { + hasLowPrecision = true; + highPrecisionMultiplier = + GetDisplayportCoverage(metrics.mCriticalDisplayPort, transform, screenRect); + } + + // Work out how much of the display-port covers the screen + if (!metrics.mDisplayPort.IsEmpty()) { + if (hasLowPrecision) { + lowPrecisionMultiplier = + GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect); + } else { + lowPrecisionMultiplier = highPrecisionMultiplier = + GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect); + } + } + } + + // If none of the screen is covered, we have zero integrity. + if (highPrecisionMultiplier <= 0.0f && lowPrecisionMultiplier <= 0.0f) { + return 0.0f; + } +#endif // MOZ_ANDROID_OMTC + + nsIntRegion screenRegion(screenRect); + nsIntRegion lowPrecisionScreenRegion(screenRect); + gfx3DMatrix transform; + ComputeRenderIntegrityInternal(root, screenRegion, + lowPrecisionScreenRegion, transform); + + if (!screenRegion.IsEqual(screenRect)) { + // Calculate the area of the region. All rects in an nsRegion are + // non-overlapping. + float screenArea = screenRect.width * screenRect.height; + float highPrecisionIntegrity = screenRegion.Area() / screenArea; + float lowPrecisionIntegrity = 1.f; + if (!lowPrecisionScreenRegion.IsEqual(screenRect)) { + lowPrecisionIntegrity = lowPrecisionScreenRegion.Area() / screenArea; + } + + return ((highPrecisionIntegrity * highPrecisionMultiplier) + + (lowPrecisionIntegrity * lowPrecisionMultiplier)) / 2; + } + + return 1.f; +} + +already_AddRefed +LayerManagerComposite::CreateThebesLayerComposite() +{ + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nullptr; + } + return nsRefPtr(new ThebesLayerComposite(this)).forget(); +} + +already_AddRefed +LayerManagerComposite::CreateContainerLayerComposite() +{ + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nullptr; + } + return nsRefPtr(new ContainerLayerComposite(this)).forget(); +} + +already_AddRefed +LayerManagerComposite::CreateImageLayerComposite() +{ + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nullptr; + } + return nsRefPtr(new ImageLayerComposite(this)).forget(); +} + +already_AddRefed +LayerManagerComposite::CreateColorLayerComposite() +{ + if (LayerManagerComposite::mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nullptr; + } + return nsRefPtr(new ColorLayerComposite(this)).forget(); +} + +already_AddRefed +LayerManagerComposite::CreateCanvasLayerComposite() +{ + if (LayerManagerComposite::mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nullptr; + } + return nsRefPtr(new CanvasLayerComposite(this)).forget(); +} + +already_AddRefed +LayerManagerComposite::CreateRefLayerComposite() +{ + if (LayerManagerComposite::mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nullptr; + } + return nsRefPtr(new RefLayerComposite(this)).forget(); +} + +LayerManagerComposite::AutoAddMaskEffect::AutoAddMaskEffect(Layer* aMaskLayer, + EffectChain& aEffects, + bool aIs3D) + : mCompositable(nullptr) +{ + if (!aMaskLayer) { + return; + } + + mCompositable = ToLayerComposite(aMaskLayer)->GetCompositableHost(); + if (!mCompositable) { + NS_WARNING("Mask layer with no compositable host"); + return; + } + + if (!mCompositable->AddMaskEffect(aEffects, aMaskLayer->GetEffectiveTransform(), aIs3D)) { + mCompositable = nullptr; + } +} + +LayerManagerComposite::AutoAddMaskEffect::~AutoAddMaskEffect() +{ + if (!mCompositable) { + return; + } + + mCompositable->RemoveMaskEffect(); +} + +TemporaryRef +LayerManagerComposite::CreateDrawTarget(const IntSize &aSize, + SurfaceFormat aFormat) +{ +#ifdef XP_MACOSX + // We don't want to accelerate if the surface is too small which indicates + // that it's likely used for an icon/static image. We also don't want to + // accelerate anything that is above the maximum texture size of weakest gpu. + // Safari uses 5000 area as the minimum for acceleration, we decided 64^2 is more logical. + bool useAcceleration = aSize.width <= 4096 && aSize.height <= 4096 && + aSize.width > 64 && aSize.height > 64 && + gfxPlatformMac::GetPlatform()->UseAcceleratedCanvas(); + if (useAcceleration) { + return Factory::CreateDrawTarget(BackendType::COREGRAPHICS_ACCELERATED, + aSize, aFormat); + } +#endif + return LayerManager::CreateDrawTarget(aSize, aFormat); +} + +LayerComposite::LayerComposite(LayerManagerComposite *aManager) + : mCompositeManager(aManager) + , mCompositor(aManager->GetCompositor()) + , mShadowOpacity(1.0) + , mUseShadowClipRect(false) + , mShadowTransformSetByAnimation(false) + , mDestroyed(false) + , mLayerComposited(false) +{ } + +LayerComposite::~LayerComposite() +{ +} + +void +LayerComposite::Destroy() +{ + if (!mDestroyed) { + mDestroyed = true; + CleanupResources(); + } +} + +bool +LayerManagerComposite::CanUseCanvasLayerForSize(const IntSize &aSize) +{ + return mCompositor->CanUseCanvasLayerForSize(gfx::IntSize(aSize.width, + aSize.height)); +} + +void +LayerManagerComposite::NotifyShadowTreeTransaction() +{ + if (mFPS) { + mFPS->NotifyShadowTreeTransaction(); + } +} + +#ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS + +/*static*/ bool +LayerManagerComposite::SupportsDirectTexturing() +{ + return false; +} + +/*static*/ void +LayerManagerComposite::PlatformSyncBeforeReplyUpdate() +{ +} + +#endif // !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS) + +} /* layers */ +} /* mozilla */