/* -*- 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 gfxASurface; 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) { 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_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); 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(); } mCompositor->SetTargetContext(nullptr); mTarget = nullptr; #ifdef MOZ_LAYERS_HAVE_LOG Log(); MOZ_LAYERS_LOG(("]----- EndTransaction")); #endif } already_AddRefed LayerManagerComposite::CreateOptimalMaskSurface(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)) { 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 */