mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
d56ce7399f
- Bug 1232506: Make dom/devicestorage really work with e10s. r=alchen (7f95105c5e)
- Bug 1208944 - Part 1. Dispatch CompositionEvent to Plugin. r=masayuki (85c062b417)
- Bug 1208944 - Part 2-a. Handle CompositionEvent on plugin. r=masayuki (ea2cebfca9)
- Bug 1208944 - Part 2-b. Workaround for OSX. r=masayuki (ca401cbc04)
- Bug 1208944 - Part 3. Allow IME window messages on plugin process. r=jmathies (571fd75010)
- Bug 1192844: Accept 0xCC padding in WindowsDllDetourPatcher::CreateTrampoline. r=m_kato (b34b6173d3)
- Bug 1201205 part 1: Add an AutoVirtualProtect helper class to make the next patch easier. r=m_kato (b384bd2412)
- Bug 1201205 part 2: Restore protection on the nop space separately from the function. r=m_kato (a822b2414b)
- Bug 1208944 - Part 4. nsWindowsDllInterceptor supports IMM32 API hook. r=ehsan (9b409ff15a)
- Bug 1208944 - Part 5. Send PluginEvent to content process. r=jmathies (4ee0341190)
- Bug 1208944 - Part 6. Get vaild TextRangeArray on compositionupdate. r=masayuki (18f184931c)
- Bug 1208944 - Part 7. Don't post WM_IME_REQUEST on windowless plugin since we don't convert pointer over process. r=masayuki (6b1a9ce71f)
- Bug 1208944 - Part 8. Don't get selection on start compostion when plugin has foucs. r=masayuki (daf400620e)
- Add Telemetry for the drawing models that plugins use. (bug 1229961 part 1, r=aklotz,vladan) (c9645a68ec)
- Enable direct plugin drawing by default. (bug 1229961 part 2, r=aklotz) (080c9337cb)
- Bug 1213845 - enable osk support on windows 8, but hide it behind a preference, r=jaws (fcb8dfb10b)
- Bug 1192248 - Fix wchar_t/char16_t mismatch WinIMEHandler.cpp. r=masayuki (13e61f3f0c)
- Bug 1226145 - actually check whether the on-screen keyboard is up rather than relying on internal state, r=masayuki (da090b605d)
- Bug 1208944 - Part 9. Hook IMM32 APIs on plugin process. r=masayuki (f15d73721f)
- Bug 1208944 - Part 10-a. Call CallWindowProc when WidgetPluginEvent isn't handled by plugin. r=masayuki (c54eaa50ed)
- Bug 1208944 - Part 10-b. Call DefaultProc When CompositionEvent isn't handled correctly by plugin. r=masayuki (0e77eaa40f)
- Bug 1157046 - Remove ARRAY_LENGTH in favor of MOZ_ARRAY_LENGTH; r=Waldo (a7f8ce3684)
- Bug 1196834 - Add a test that confirms plugin windows are hidden after switching from a remote to local tab. r=roc (a09d4a32af)
- Bug 1208944 - Part 11. Add test. r=jmathies (ed8e4c87d2)
- Bug 1231378 - part 1 - Fix uninitialized members of classes in docshell/*, r=smaug (fcd7615d97)
- Bug 1231378 - part 2 - Fix uninitialized members of classes in dom/*,r=smaug (40b354438f)
- Bug 1231378 - part 3 - Fix uninitialized members of classes in module/libjar and mfbt, r=smaug (ee15d8739a)
- Bug 1231378 - part 4 - Fix uninitialized members of classes in netwerk/widget/storage/uriloader/memory/tools, r=smaug (6aec559dd8)
- Bug 1238082 - Fix mode lines in dom/ipc. r=baku (a49aa3555b)
- Bug 1024149 - Use element size for upload texture when using SVG image. r=jgilbert r=roc (531bdd2406)
- Bug 1233922 - Skip Camera preinit for browser elements. r=fabrice (cd8ffbb112)
- Bug 1159327 - Enable accessibility more broadly with e10s and add an e10s a11y blacklist for clients with known issues. r=tbsaunde (374f49a942)
- Bug 1198459 - Prevent accessibility from initializing in content processes when e10s is running. r=tbsaunde (33bdfccd56)
- Bug 1115956 - Improve notice string for when e10s was disabled for accessibility. r=mconley (e5ff276d9e)
- Bug 1172491 - Let e10s be enabled in safe mode. r=felipe (bd0a3fbbd5)
- Bug 1226487 - Allow e10s to run on Beta. r=mconley (05103c816d)
- Bug 634063 - Use gfxPrefs for some layers acceleration prefs. r=nical (9a20bcd8d2)
- Bug 1198459 - Add support for disabling e10s if a11y was run in the previous session, or run in a session over the previous week. r=felipe (7154a021bd)
- Bug 1171171 - Make sure the graphics preferences are initialized early enough. r=billm (34801701aa)
- Bug 1171171: Move nsAppRunner's gfxPrefs #include out of windows-specific section. r=milan a=KWierso (492fa00f99)
- Bug 1182048 - Part 1: Allow e10s to be enabled,r=vlad (628949ad83)
- Bug 1182048 - Part 2: Implement e10s support for WebVR,r=vlad (a77d280b48)
- Bug 1207221 - Do not prevent the system app from vibrating when it is hidden. r=bz r=dhylands (f3d2306f41)
- Bug 1233902 - Check the TP list in sendBeacon(). r=gcp (bc279755ab)
- Bug 1216207 - Modify navigator.hasFeature method to implement new (9b4571468e)
- Bug 1217187 - Modify navigator.hasFeature method to detect new (d9ea58e65c)
- Bug 1125477 - Part 1: Modify dom/tv mochitest in order to enable e10s test. r=seanlin (7b535fddaa)
- Bug 1125477 - Part 2: Modify permission check of TV Manager API in order to remove dom.testing.tv_enabled_for_hosted_apps. r=seanlin;r=smaug (5719fdf3a7)
- Bug 1125477 - Part3: Remove permission removing code. r=seanlin (614de5dfd1)
- Bug 1223672 - NSec package cannot use device storage API. r=kchen (f1fc6711ea)
- Bug 1224609 - Ensure the primary screen is always returned in RecvScreenForBrowser if all else fails. r=wmccloskey (d562935754)
- Bug 1180288 - Use native filepickers for Graphene. r=khuey (0b9c78ce13)
- Bug 1201394 - Use cached preferences value in ProcessPriorityManager. r=gsvelto (d211492014)
- Bug 1212833 - Delay the MemoryPressure when an application goes to background. r=gsvelto (ce33de4324)
- Bug 1186812 (part 1) - Replace nsBaseHashtable::EnumerateRead() calls in dom/{ipc,plugins}/. r=jimm. (c061bb9d1b)
- Bug 1212984 - HangMonitorChild should delete its Transport. r=billm (3331593b2d)
- Bug 1186812 (part 2) - Replace nsBaseHashtable::EnumerateRead() calls in dom/{ipc,plugins}/. r=jimm. (fdac3f52cb)
- Bug 1215239 - Do not set ownApp for a browser element. r=bholley (e3cc250c3f)
- Bug 1241278 - Change Notification.requestPermission() to return a promise. r=baku (b0a86eeeb5)
- Bug 1249102. Make overrides of WorkerRunnable::PostRun a bit more consistent. r=khuey (a23bf9468f)
- Bug 1209812 (part 6) - Convert all gfxImageFormat values to SurfaceFormat equivalents. r=jrmuizel. (9a5da3597f)
- Bug 1239225 - Remove unused args from TextureImage's constructor and related functions. r=mattwoodrow. (26ff005ecb)
- Bug 1240708 - Various trivial coverity warning fixes. r=kats (74a485c2b8)
- Bug 1240708 - Various trivial coverity warning fixes (part 2). r=kats (34bcd568dc)
- Bug 1219494 - Part 3 gfx/gl with gfxCrash. r=mchang (268968a3d9)
- Bug 1232456 - Create EGL surface through widget; r=snorp (13634bebc6)
- Bug 1232456 - Renew EGL surface using existing compositor widget; r=snorp (2649b088d3)
- Bug 1187322 - Don't require accelerated OpenGL contexts for BasicCompositor on OS X. r=jrmuizel (87f92af2c8)
- Bug 1238753 - Use StartRemoteDrawingInRegion on Mac. r=mattwoodrow (22870ed043)
- Bug 1238755 - Avoid a copy when uploading the BasicCompositor result to a texture. r=mattwoodrow (0b6663ab61)
- Bug 890156 - patch 0.2 - Remove the (unused) aRect parameter from nsBaseWidget::BaseCreate. r=kats (1120763eef)
- Bug 1241983 - Make DOM Identity observe inner-window-destroyed not dom-window-destroyed; r=ferjm (7cf4cf3211)
- Bug 1236282 - Clip color layer drawing in BasicCompositor so that unbounded operators don't erase stuff outside the layer. r=Bas (a7e73d1d8d)
- Bug 1238753 - Make BasicCompositor respect changes to mInvalidRegion through StartRemoteDrawingWithRegion properly. r=mattwoodrow (36e20bccce)
- Bug 1238753 - Don't skip the call to StartRemoteDrawing in from BasicCompositor::BeginFrame if the invalid region is empty. r=mattwoodrow (783b25775f)
- Bug 1239137 - Return early from BasicCompositor::DrawQuad if transformBounds is empty. r=mattwoodrow (0815cfc28a)
- Bug 1239530 (part 1) - Remove PuppetWidget::Scroll(), which is dead. r=kats. (63ab8c32b6)
- Bug 1239530 (part 2) - Use LayoutDevice coordinates in {Start,End}RemoteDrawingInRegion() and related functions. r=kats. (609001767d)
- Bug 1239537 - Remove Compositor::GetWidgetSize(), which is unused. r=mattwoodrow. (25732d37b1)
- Bug 1242293 - Don't call EndRemoteDrawingInRegion if StartRemoteDrawingInRegion returns a null DrawTarget. r=mstange (8e297c3b84)
- import changes from mozilla: Bug 1211642: Whitelist test plugin for async plugin init; r=jimm (f02deaaeb8) (6689ce99c8)
1144 lines
39 KiB
C++
1144 lines
39 KiB
C++
/* -*- Mode: C++; tab-width: 2; 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 <stdint.h> // for uint32_t
|
|
#include <stdlib.h> // for rand, RAND_MAX
|
|
#include <sys/types.h> // for int32_t
|
|
#include "BasicContainerLayer.h" // for BasicContainerLayer
|
|
#include "BasicLayersImpl.h" // for ToData, BasicReadbackLayer, etc
|
|
#include "GeckoProfiler.h" // for PROFILER_LABEL
|
|
#include "ImageContainer.h" // for ImageFactory
|
|
#include "Layers.h" // for Layer, ContainerLayer, etc
|
|
#include "ReadbackLayer.h" // for ReadbackLayer
|
|
#include "ReadbackProcessor.h" // for ReadbackProcessor
|
|
#include "RenderTrace.h" // for RenderTraceLayers, etc
|
|
#include "basic/BasicImplData.h" // for BasicImplData
|
|
#include "basic/BasicLayers.h" // for BasicLayerManager, etc
|
|
#include "gfxASurface.h" // for gfxASurface, etc
|
|
#include "gfxContext.h" // for gfxContext, etc
|
|
#include "gfxImageSurface.h" // for gfxImageSurface
|
|
#include "gfxMatrix.h" // for gfxMatrix
|
|
#include "gfxPlatform.h" // for gfxPlatform
|
|
#include "gfxPrefs.h" // for gfxPrefs
|
|
#include "gfxPoint.h" // for IntSize, gfxPoint
|
|
#include "gfxRect.h" // for gfxRect
|
|
#include "gfxUtils.h" // for gfxUtils
|
|
#include "gfx2DGlue.h" // for thebes --> moz2d transition
|
|
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
|
#include "mozilla/WidgetUtils.h" // for ScreenRotation
|
|
#include "mozilla/gfx/2D.h" // for DrawTarget
|
|
#include "mozilla/gfx/BasePoint.h" // for BasePoint
|
|
#include "mozilla/gfx/BaseRect.h" // for BaseRect
|
|
#include "mozilla/gfx/Matrix.h" // for Matrix
|
|
#include "mozilla/gfx/PathHelpers.h"
|
|
#include "mozilla/gfx/Rect.h" // for IntRect, Rect
|
|
#include "mozilla/layers/LayersTypes.h" // for BufferMode::BUFFER_NONE, etc
|
|
#include "mozilla/mozalloc.h" // for operator new
|
|
#include "nsAutoPtr.h" // for nsRefPtr
|
|
#include "nsCOMPtr.h" // for already_AddRefed
|
|
#include "nsDebug.h" // for NS_ASSERTION, etc
|
|
#include "nsISupportsImpl.h" // for gfxContext::Release, etc
|
|
#include "nsPoint.h" // for nsIntPoint
|
|
#include "nsRect.h" // for mozilla::gfx::IntRect
|
|
#include "nsRegion.h" // for nsIntRegion, etc
|
|
#include "nsTArray.h" // for nsAutoTArray
|
|
#ifdef MOZ_ENABLE_SKIA
|
|
#include "skia/include/core/SkCanvas.h" // for SkCanvas
|
|
#include "skia/include/core/SkBitmapDevice.h" // for SkBitmapDevice
|
|
#else
|
|
#define PIXMAN_DONT_DEFINE_STDINT
|
|
#include "pixman.h" // for pixman_f_transform, etc
|
|
#endif
|
|
class nsIWidget;
|
|
|
|
namespace mozilla {
|
|
namespace layers {
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
/**
|
|
* Clips to the smallest device-pixel-aligned rectangle containing aRect
|
|
* in user space.
|
|
* Returns true if the clip is "perfect", i.e. we actually clipped exactly to
|
|
* aRect.
|
|
*/
|
|
static bool
|
|
ClipToContain(gfxContext* aContext, const IntRect& aRect)
|
|
{
|
|
gfxRect userRect(aRect.x, aRect.y, aRect.width, aRect.height);
|
|
gfxRect deviceRect = aContext->UserToDevice(userRect);
|
|
deviceRect.RoundOut();
|
|
|
|
gfxMatrix currentMatrix = aContext->CurrentMatrix();
|
|
aContext->SetMatrix(gfxMatrix());
|
|
aContext->NewPath();
|
|
aContext->Rectangle(deviceRect);
|
|
aContext->Clip();
|
|
aContext->SetMatrix(currentMatrix);
|
|
|
|
return aContext->DeviceToUser(deviceRect).IsEqualInterior(userRect);
|
|
}
|
|
|
|
BasicLayerManager::PushedGroup
|
|
BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer, const nsIntRegion& aRegion)
|
|
{
|
|
PushedGroup group;
|
|
|
|
group.mVisibleRegion = aRegion;
|
|
group.mFinalTarget = aContext;
|
|
group.mOperator = GetEffectiveOperator(aLayer);
|
|
group.mOpacity = aLayer->GetEffectiveOpacity();
|
|
|
|
// If we need to call PushGroup, we should clip to the smallest possible
|
|
// area first to minimize the size of the temporary surface.
|
|
bool didCompleteClip = ClipToContain(aContext, aRegion.GetBounds());
|
|
|
|
bool canPushGroup = group.mOperator == CompositionOp::OP_OVER ||
|
|
(group.mOperator == CompositionOp::OP_SOURCE && (aLayer->CanUseOpaqueSurface() || aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA));
|
|
|
|
if (!canPushGroup) {
|
|
aContext->Save();
|
|
gfxUtils::ClipToRegion(group.mFinalTarget, group.mVisibleRegion);
|
|
|
|
// PushGroup/PopGroup do not support non operator over.
|
|
gfxMatrix oldMat = aContext->CurrentMatrix();
|
|
aContext->SetMatrix(gfxMatrix());
|
|
gfxRect rect = aContext->GetClipExtents();
|
|
aContext->SetMatrix(oldMat);
|
|
rect.RoundOut();
|
|
IntRect surfRect;
|
|
ToRect(rect).ToIntRect(&surfRect);
|
|
|
|
if (!surfRect.IsEmpty()) {
|
|
RefPtr<DrawTarget> dt = aContext->GetDrawTarget()->CreateSimilarDrawTarget(surfRect.Size(), SurfaceFormat::B8G8R8A8);
|
|
|
|
RefPtr<gfxContext> ctx = new gfxContext(dt, ToRect(rect).TopLeft());
|
|
ctx->SetMatrix(oldMat);
|
|
|
|
group.mGroupOffset = surfRect.TopLeft();
|
|
group.mGroupTarget = ctx;
|
|
|
|
group.mMaskSurface = GetMaskForLayer(aLayer, &group.mMaskTransform);
|
|
return group;
|
|
}
|
|
}
|
|
|
|
Matrix maskTransform;
|
|
RefPtr<SourceSurface> maskSurf = GetMaskForLayer(aLayer, &maskTransform);
|
|
|
|
if (aLayer->CanUseOpaqueSurface() &&
|
|
((didCompleteClip && aRegion.GetNumRects() == 1) ||
|
|
!aContext->CurrentMatrix().HasNonIntegerTranslation())) {
|
|
// If the layer is opaque in its visible region we can push a gfxContentType::COLOR
|
|
// group. We need to make sure that only pixels inside the layer's visible
|
|
// region are copied back to the destination. Remember if we've already
|
|
// clipped precisely to the visible region.
|
|
group.mNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1;
|
|
if (group.mNeedsClipToVisibleRegion) {
|
|
group.mFinalTarget->Save();
|
|
gfxUtils::ClipToRegion(group.mFinalTarget, group.mVisibleRegion);
|
|
}
|
|
|
|
aContext->PushGroupForBlendBack(gfxContentType::COLOR, group.mOpacity, maskSurf, maskTransform);
|
|
} else {
|
|
if (aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) {
|
|
aContext->PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA, group.mOpacity, maskSurf, maskTransform);
|
|
} else {
|
|
aContext->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, group.mOpacity, maskSurf, maskTransform);
|
|
}
|
|
}
|
|
|
|
group.mGroupTarget = group.mFinalTarget;
|
|
return group;
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::PopGroupForLayer(PushedGroup &group)
|
|
{
|
|
if (group.mFinalTarget == group.mGroupTarget) {
|
|
group.mFinalTarget->PopGroupAndBlend();
|
|
if (group.mNeedsClipToVisibleRegion) {
|
|
group.mFinalTarget->Restore();
|
|
}
|
|
return;
|
|
}
|
|
|
|
DrawTarget* dt = group.mFinalTarget->GetDrawTarget();
|
|
RefPtr<DrawTarget> sourceDT = group.mGroupTarget->GetDrawTarget();
|
|
group.mGroupTarget = nullptr;
|
|
|
|
RefPtr<SourceSurface> src = sourceDT->Snapshot();
|
|
|
|
if (group.mMaskSurface) {
|
|
dt->SetTransform(group.mMaskTransform * Matrix::Translation(-group.mFinalTarget->GetDeviceOffset()));
|
|
dt->MaskSurface(SurfacePattern(src, ExtendMode::CLAMP, Matrix::Translation(group.mGroupOffset.x, group.mGroupOffset.y)),
|
|
group.mMaskSurface, Point(0, 0), DrawOptions(group.mOpacity, group.mOperator));
|
|
} else {
|
|
// For now this is required since our group offset is in device space of the final target,
|
|
// context but that may still have its own device offset. Once PushGroup/PopGroup logic is
|
|
// migrated to DrawTargets this can go as gfxContext::GetDeviceOffset will essentially
|
|
// always become null.
|
|
dt->SetTransform(Matrix::Translation(-group.mFinalTarget->GetDeviceOffset()));
|
|
dt->DrawSurface(src, Rect(group.mGroupOffset.x, group.mGroupOffset.y, src->GetSize().width, src->GetSize().height),
|
|
Rect(0, 0, src->GetSize().width, src->GetSize().height), DrawSurfaceOptions(Filter::POINT), DrawOptions(group.mOpacity, group.mOperator));
|
|
}
|
|
|
|
if (group.mNeedsClipToVisibleRegion) {
|
|
dt->PopClip();
|
|
}
|
|
|
|
group.mFinalTarget->Restore();
|
|
}
|
|
|
|
static IntRect
|
|
ToInsideIntRect(const gfxRect& aRect)
|
|
{
|
|
gfxRect r = aRect;
|
|
r.RoundIn();
|
|
return IntRect(r.X(), r.Y(), r.Width(), r.Height());
|
|
}
|
|
|
|
// A context helper for BasicLayerManager::PaintLayer() that holds all the
|
|
// painting context together in a data structure so it can be easily passed
|
|
// around. It also uses ensures that the Transform and Opaque rect are restored
|
|
// to their former state on destruction.
|
|
|
|
class PaintLayerContext {
|
|
public:
|
|
PaintLayerContext(gfxContext* aTarget, Layer* aLayer,
|
|
LayerManager::DrawPaintedLayerCallback aCallback,
|
|
void* aCallbackData)
|
|
: mTarget(aTarget)
|
|
, mTargetMatrixSR(aTarget)
|
|
, mLayer(aLayer)
|
|
, mCallback(aCallback)
|
|
, mCallbackData(aCallbackData)
|
|
, mPushedOpaqueRect(false)
|
|
{}
|
|
|
|
~PaintLayerContext()
|
|
{
|
|
// Matrix is restored by mTargetMatrixSR
|
|
if (mPushedOpaqueRect)
|
|
{
|
|
ClearOpaqueRect();
|
|
}
|
|
}
|
|
|
|
// Gets the effective transform and returns true if it is a 2D
|
|
// transform.
|
|
bool Setup2DTransform()
|
|
{
|
|
// Will return an identity matrix for 3d transforms.
|
|
return mLayer->GetEffectiveTransformForBuffer().CanDraw2D(&mTransform);
|
|
}
|
|
|
|
// Applies the effective transform if it's 2D. If it's a 3D transform then
|
|
// it applies an identity.
|
|
void Apply2DTransform()
|
|
{
|
|
mTarget->SetMatrix(ThebesMatrix(mTransform));
|
|
}
|
|
|
|
// Set the opaque rect to match the bounds of the visible region.
|
|
void AnnotateOpaqueRect()
|
|
{
|
|
const nsIntRegion visibleRegion = mLayer->GetEffectiveVisibleRegion().ToUnknownRegion();
|
|
const IntRect& bounds = visibleRegion.GetBounds();
|
|
|
|
DrawTarget *dt = mTarget->GetDrawTarget();
|
|
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 &&
|
|
(mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
|
|
!mTransform.HasNonAxisAlignedTransform()) {
|
|
|
|
gfx::Rect opaqueRect = dt->GetTransform().TransformBounds(
|
|
gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
|
|
opaqueRect.RoundIn();
|
|
IntRect intOpaqueRect;
|
|
if (opaqueRect.ToIntRect(&intOpaqueRect)) {
|
|
mTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect);
|
|
mPushedOpaqueRect = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clear the Opaque rect. Although this doesn't really restore it to it's
|
|
// previous state it will happen on the exit path of the PaintLayer() so when
|
|
// painting is complete the opaque rect qill be clear.
|
|
void ClearOpaqueRect() {
|
|
mTarget->GetDrawTarget()->SetOpaqueRect(IntRect());
|
|
}
|
|
|
|
gfxContext* mTarget;
|
|
gfxContextMatrixAutoSaveRestore mTargetMatrixSR;
|
|
Layer* mLayer;
|
|
LayerManager::DrawPaintedLayerCallback mCallback;
|
|
void* mCallbackData;
|
|
Matrix mTransform;
|
|
bool mPushedOpaqueRect;
|
|
};
|
|
|
|
BasicLayerManager::BasicLayerManager(nsIWidget* aWidget)
|
|
: mPhase(PHASE_NONE)
|
|
, mWidget(aWidget)
|
|
, mDoubleBuffering(BufferMode::BUFFER_NONE)
|
|
, mType(BLM_WIDGET)
|
|
, mUsingDefaultTarget(false)
|
|
, mTransactionIncomplete(false)
|
|
, mCompositorMightResample(false)
|
|
{
|
|
MOZ_COUNT_CTOR(BasicLayerManager);
|
|
NS_ASSERTION(aWidget, "Must provide a widget");
|
|
}
|
|
|
|
BasicLayerManager::BasicLayerManager(BasicLayerManagerType aType)
|
|
: mPhase(PHASE_NONE)
|
|
, mWidget(nullptr)
|
|
, mDoubleBuffering(BufferMode::BUFFER_NONE)
|
|
, mType(aType)
|
|
, mUsingDefaultTarget(false)
|
|
, mTransactionIncomplete(false)
|
|
{
|
|
MOZ_COUNT_CTOR(BasicLayerManager);
|
|
MOZ_ASSERT(mType != BLM_WIDGET);
|
|
}
|
|
|
|
BasicLayerManager::~BasicLayerManager()
|
|
{
|
|
NS_ASSERTION(!InTransaction(), "Died during transaction?");
|
|
|
|
ClearCachedResources();
|
|
|
|
mRoot = nullptr;
|
|
|
|
MOZ_COUNT_DTOR(BasicLayerManager);
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::SetDefaultTarget(gfxContext* aContext)
|
|
{
|
|
NS_ASSERTION(!InTransaction(),
|
|
"Must set default target outside transaction");
|
|
mDefaultTarget = aContext;
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::SetDefaultTargetConfiguration(BufferMode aDoubleBuffering, ScreenRotation aRotation)
|
|
{
|
|
mDoubleBuffering = aDoubleBuffering;
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::BeginTransaction()
|
|
{
|
|
mInTransaction = true;
|
|
mUsingDefaultTarget = true;
|
|
BeginTransactionWithTarget(mDefaultTarget);
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
|
|
{
|
|
mInTransaction = true;
|
|
|
|
#ifdef MOZ_LAYERS_HAVE_LOG
|
|
MOZ_LAYERS_LOG(("[----- BeginTransaction"));
|
|
Log();
|
|
#endif
|
|
|
|
NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
|
|
mPhase = PHASE_CONSTRUCTION;
|
|
mTarget = aTarget;
|
|
}
|
|
|
|
static void
|
|
TransformIntRect(IntRect& aRect, const Matrix& aMatrix,
|
|
IntRect (*aRoundMethod)(const gfxRect&))
|
|
{
|
|
Rect gr = Rect(aRect.x, aRect.y, aRect.width, aRect.height);
|
|
gr = aMatrix.TransformBounds(gr);
|
|
aRect = (*aRoundMethod)(ThebesRect(gr));
|
|
}
|
|
|
|
/**
|
|
* This function assumes that GetEffectiveTransform transforms
|
|
* all layers to the same coordinate system (the "root coordinate system").
|
|
* It can't be used as is by accelerated layers because of intermediate surfaces.
|
|
* This must set the hidden flag to true or false on *all* layers in the subtree.
|
|
* It also sets the operator for all layers to "OVER", and call
|
|
* SetDrawAtomically(false).
|
|
* It clears mClipToVisibleRegion on all layers.
|
|
* @param aClipRect the cliprect, in the root coordinate system. We assume
|
|
* that any layer drawing is clipped to this rect. It is therefore not
|
|
* allowed to add to the opaque region outside that rect.
|
|
* @param aDirtyRect the dirty rect that will be painted, in the root
|
|
* coordinate system. Layers outside this rect should be hidden.
|
|
* @param aOpaqueRegion the opaque region covering aLayer, in the
|
|
* root coordinate system.
|
|
*/
|
|
enum {
|
|
ALLOW_OPAQUE = 0x01,
|
|
};
|
|
static void
|
|
MarkLayersHidden(Layer* aLayer, const IntRect& aClipRect,
|
|
const IntRect& aDirtyRect,
|
|
nsIntRegion& aOpaqueRegion,
|
|
uint32_t aFlags)
|
|
{
|
|
IntRect newClipRect(aClipRect);
|
|
uint32_t newFlags = aFlags;
|
|
|
|
// Allow aLayer or aLayer's descendants to cover underlying layers
|
|
// only if it's opaque.
|
|
if (aLayer->GetOpacity() != 1.0f) {
|
|
newFlags &= ~ALLOW_OPAQUE;
|
|
}
|
|
|
|
{
|
|
const Maybe<ParentLayerIntRect>& clipRect = aLayer->GetEffectiveClipRect();
|
|
if (clipRect) {
|
|
IntRect cr = clipRect->ToUnknownRect();
|
|
// clipRect is in the container's coordinate system. Get it into the
|
|
// global coordinate system.
|
|
if (aLayer->GetParent()) {
|
|
Matrix tr;
|
|
if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
|
|
// Clip rect is applied after aLayer's transform, i.e., in the coordinate
|
|
// system of aLayer's parent.
|
|
TransformIntRect(cr, tr, ToInsideIntRect);
|
|
} else {
|
|
cr.SetRect(0, 0, 0, 0);
|
|
}
|
|
}
|
|
newClipRect.IntersectRect(newClipRect, cr);
|
|
}
|
|
}
|
|
|
|
BasicImplData* data = ToData(aLayer);
|
|
data->SetOperator(CompositionOp::OP_OVER);
|
|
data->SetClipToVisibleRegion(false);
|
|
data->SetDrawAtomically(false);
|
|
|
|
if (!aLayer->AsContainerLayer()) {
|
|
Matrix transform;
|
|
if (!aLayer->GetEffectiveTransform().CanDraw2D(&transform)) {
|
|
data->SetHidden(false);
|
|
return;
|
|
}
|
|
|
|
nsIntRegion region = aLayer->GetEffectiveVisibleRegion().ToUnknownRegion();
|
|
IntRect r = region.GetBounds();
|
|
TransformIntRect(r, transform, ToOutsideIntRect);
|
|
r.IntersectRect(r, aDirtyRect);
|
|
data->SetHidden(aOpaqueRegion.Contains(r));
|
|
|
|
// Allow aLayer to cover underlying layers only if aLayer's
|
|
// content is opaque
|
|
if ((aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
|
|
(newFlags & ALLOW_OPAQUE)) {
|
|
nsIntRegionRectIterator it(region);
|
|
while (const IntRect* sr = it.Next()) {
|
|
r = *sr;
|
|
TransformIntRect(r, transform, ToInsideIntRect);
|
|
|
|
r.IntersectRect(r, newClipRect);
|
|
aOpaqueRegion.Or(aOpaqueRegion, r);
|
|
}
|
|
}
|
|
} else {
|
|
Layer* child = aLayer->GetLastChild();
|
|
bool allHidden = true;
|
|
for (; child; child = child->GetPrevSibling()) {
|
|
MarkLayersHidden(child, newClipRect, aDirtyRect, aOpaqueRegion, newFlags);
|
|
if (!ToData(child)->IsHidden()) {
|
|
allHidden = false;
|
|
}
|
|
}
|
|
data->SetHidden(allHidden);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function assumes that GetEffectiveTransform transforms
|
|
* all layers to the same coordinate system (the "root coordinate system").
|
|
* MarkLayersHidden must be called before calling this.
|
|
* @param aVisibleRect the rectangle of aLayer that is visible (i.e. not
|
|
* clipped and in the dirty rect), in the root coordinate system.
|
|
*/
|
|
static void
|
|
ApplyDoubleBuffering(Layer* aLayer, const IntRect& aVisibleRect)
|
|
{
|
|
BasicImplData* data = ToData(aLayer);
|
|
if (data->IsHidden())
|
|
return;
|
|
|
|
IntRect newVisibleRect(aVisibleRect);
|
|
|
|
{
|
|
const Maybe<ParentLayerIntRect>& clipRect = aLayer->GetEffectiveClipRect();
|
|
if (clipRect) {
|
|
IntRect cr = clipRect->ToUnknownRect();
|
|
// clipRect is in the container's coordinate system. Get it into the
|
|
// global coordinate system.
|
|
if (aLayer->GetParent()) {
|
|
Matrix tr;
|
|
if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
|
|
NS_ASSERTION(!ThebesMatrix(tr).HasNonIntegerTranslation(),
|
|
"Parent can only have an integer translation");
|
|
cr += nsIntPoint(int32_t(tr._31), int32_t(tr._32));
|
|
} else {
|
|
NS_ERROR("Parent can only have an integer translation");
|
|
}
|
|
}
|
|
newVisibleRect.IntersectRect(newVisibleRect, cr);
|
|
}
|
|
}
|
|
|
|
BasicContainerLayer* container =
|
|
static_cast<BasicContainerLayer*>(aLayer->AsContainerLayer());
|
|
// Layers that act as their own backbuffers should be drawn to the destination
|
|
// using OP_SOURCE to ensure that alpha values in a transparent window are
|
|
// cleared. This can also be faster than OP_OVER.
|
|
if (!container) {
|
|
data->SetOperator(CompositionOp::OP_SOURCE);
|
|
data->SetDrawAtomically(true);
|
|
} else {
|
|
if (container->UseIntermediateSurface() ||
|
|
!container->ChildrenPartitionVisibleRegion(newVisibleRect)) {
|
|
// We need to double-buffer this container.
|
|
data->SetOperator(CompositionOp::OP_SOURCE);
|
|
container->ForceIntermediateSurface();
|
|
} else {
|
|
// Tell the children to clip to their visible regions so our assumption
|
|
// that they don't paint outside their visible regions is valid!
|
|
for (Layer* child = aLayer->GetFirstChild(); child;
|
|
child = child->GetNextSibling()) {
|
|
ToData(child)->SetClipToVisibleRegion(true);
|
|
ApplyDoubleBuffering(child, newVisibleRect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
|
|
void* aCallbackData,
|
|
EndTransactionFlags aFlags)
|
|
{
|
|
mInTransaction = false;
|
|
|
|
EndTransactionInternal(aCallback, aCallbackData, aFlags);
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::AbortTransaction()
|
|
{
|
|
NS_ASSERTION(InConstruction(), "Should be in construction phase");
|
|
mPhase = PHASE_NONE;
|
|
mUsingDefaultTarget = false;
|
|
mInTransaction = false;
|
|
}
|
|
|
|
bool
|
|
BasicLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
|
|
void* aCallbackData,
|
|
EndTransactionFlags aFlags)
|
|
{
|
|
PROFILER_LABEL("BasicLayerManager", "EndTransactionInternal",
|
|
js::ProfileEntry::Category::GRAPHICS);
|
|
|
|
#ifdef MOZ_LAYERS_HAVE_LOG
|
|
MOZ_LAYERS_LOG((" ----- (beginning paint)"));
|
|
Log();
|
|
#endif
|
|
|
|
NS_ASSERTION(InConstruction(), "Should be in construction phase");
|
|
mPhase = PHASE_DRAWING;
|
|
|
|
RenderTraceLayers(mRoot, "FF00");
|
|
|
|
mTransactionIncomplete = false;
|
|
|
|
if (mRoot) {
|
|
if (aFlags & END_NO_COMPOSITE) {
|
|
// Apply pending tree updates before recomputing effective
|
|
// properties.
|
|
mRoot->ApplyPendingUpdatesToSubtree();
|
|
}
|
|
|
|
// Need to do this before we call ApplyDoubleBuffering,
|
|
// which depends on correct effective transforms
|
|
if (mTarget) {
|
|
mSnapEffectiveTransforms =
|
|
!mTarget->GetDrawTarget()->GetUserData(&sDisablePixelSnapping);
|
|
} else {
|
|
mSnapEffectiveTransforms = true;
|
|
}
|
|
mRoot->ComputeEffectiveTransforms(mTarget ? Matrix4x4::From2D(ToMatrix(mTarget->CurrentMatrix())) : Matrix4x4());
|
|
|
|
ToData(mRoot)->Validate(aCallback, aCallbackData, nullptr);
|
|
if (mRoot->GetMaskLayer()) {
|
|
ToData(mRoot->GetMaskLayer())->Validate(aCallback, aCallbackData, nullptr);
|
|
}
|
|
}
|
|
|
|
if (mTarget && mRoot &&
|
|
!(aFlags & END_NO_IMMEDIATE_REDRAW) &&
|
|
!(aFlags & END_NO_COMPOSITE)) {
|
|
IntRect clipRect;
|
|
|
|
{
|
|
gfxContextMatrixAutoSaveRestore save(mTarget);
|
|
mTarget->SetMatrix(gfxMatrix());
|
|
clipRect = ToOutsideIntRect(mTarget->GetClipExtents());
|
|
}
|
|
|
|
if (IsRetained()) {
|
|
nsIntRegion region;
|
|
MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
|
|
if (mUsingDefaultTarget && mDoubleBuffering != BufferMode::BUFFER_NONE) {
|
|
ApplyDoubleBuffering(mRoot, clipRect);
|
|
}
|
|
}
|
|
|
|
PaintLayer(mTarget, mRoot, aCallback, aCallbackData);
|
|
if (!mRegionToClear.IsEmpty()) {
|
|
nsIntRegionRectIterator iter(mRegionToClear);
|
|
const IntRect *r;
|
|
while ((r = iter.Next())) {
|
|
mTarget->GetDrawTarget()->ClearRect(Rect(r->x, r->y, r->width, r->height));
|
|
}
|
|
}
|
|
if (mWidget) {
|
|
FlashWidgetUpdateArea(mTarget);
|
|
}
|
|
RecordFrame();
|
|
PostPresent();
|
|
|
|
if (!mTransactionIncomplete) {
|
|
// Clear out target if we have a complete transaction.
|
|
mTarget = nullptr;
|
|
}
|
|
}
|
|
|
|
if (mRoot) {
|
|
mAnimationReadyTime = TimeStamp::Now();
|
|
mRoot->StartPendingAnimations(mAnimationReadyTime);
|
|
}
|
|
|
|
#ifdef MOZ_LAYERS_HAVE_LOG
|
|
Log();
|
|
MOZ_LAYERS_LOG(("]----- EndTransaction"));
|
|
#endif
|
|
|
|
// Go back to the construction phase if the transaction isn't complete.
|
|
// Layout will update the layer tree and call EndTransaction().
|
|
mPhase = mTransactionIncomplete ? PHASE_CONSTRUCTION : PHASE_NONE;
|
|
|
|
if (!mTransactionIncomplete) {
|
|
// This is still valid if the transaction was incomplete.
|
|
mUsingDefaultTarget = false;
|
|
}
|
|
|
|
NS_ASSERTION(!aCallback || !mTransactionIncomplete,
|
|
"If callback is not null, transaction must be complete");
|
|
|
|
// XXX - We should probably assert here that for an incomplete transaction
|
|
// out target is the default target.
|
|
|
|
return !mTransactionIncomplete;
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::FlashWidgetUpdateArea(gfxContext *aContext)
|
|
{
|
|
if (gfxPrefs::WidgetUpdateFlashing()) {
|
|
float r = float(rand()) / RAND_MAX;
|
|
float g = float(rand()) / RAND_MAX;
|
|
float b = float(rand()) / RAND_MAX;
|
|
aContext->SetColor(Color(r, g, b, 0.2f));
|
|
aContext->Paint();
|
|
}
|
|
}
|
|
|
|
bool
|
|
BasicLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
|
|
{
|
|
mInTransaction = false;
|
|
|
|
if (!mRoot) {
|
|
return false;
|
|
}
|
|
|
|
return EndTransactionInternal(nullptr, nullptr, aFlags);
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::SetRoot(Layer* aLayer)
|
|
{
|
|
NS_ASSERTION(aLayer, "Root can't be null");
|
|
NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
|
|
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
|
mRoot = aLayer;
|
|
}
|
|
|
|
#ifdef MOZ_ENABLE_SKIA
|
|
static SkMatrix
|
|
BasicLayerManager_Matrix3DToSkia(const Matrix4x4& aMatrix)
|
|
{
|
|
SkMatrix transform;
|
|
transform.setAll(aMatrix._11,
|
|
aMatrix._21,
|
|
aMatrix._41,
|
|
aMatrix._12,
|
|
aMatrix._22,
|
|
aMatrix._42,
|
|
aMatrix._14,
|
|
aMatrix._24,
|
|
aMatrix._44);
|
|
|
|
return transform;
|
|
}
|
|
|
|
static void
|
|
Transform(const gfxImageSurface* aDest,
|
|
RefPtr<DataSourceSurface> aSrc,
|
|
const Matrix4x4& aTransform,
|
|
gfxPoint aDestOffset)
|
|
{
|
|
if (aTransform.IsSingular()) {
|
|
return;
|
|
}
|
|
|
|
IntSize destSize = aDest->GetSize();
|
|
SkImageInfo destInfo = SkImageInfo::Make(destSize.width,
|
|
destSize.height,
|
|
kBGRA_8888_SkColorType,
|
|
kPremul_SkAlphaType);
|
|
SkBitmap destBitmap;
|
|
destBitmap.setInfo(destInfo, aDest->Stride());
|
|
destBitmap.setPixels((uint32_t*)aDest->Data());
|
|
SkCanvas destCanvas(destBitmap);
|
|
|
|
IntSize srcSize = aSrc->GetSize();
|
|
SkImageInfo srcInfo = SkImageInfo::Make(srcSize.width,
|
|
srcSize.height,
|
|
kBGRA_8888_SkColorType,
|
|
kPremul_SkAlphaType);
|
|
SkBitmap src;
|
|
src.setInfo(srcInfo, aSrc->Stride());
|
|
src.setPixels((uint32_t*)aSrc->GetData());
|
|
|
|
Matrix4x4 transform = aTransform;
|
|
transform.PostTranslate(Point3D(-aDestOffset.x, -aDestOffset.y, 0));
|
|
destCanvas.setMatrix(BasicLayerManager_Matrix3DToSkia(transform));
|
|
|
|
SkPaint paint;
|
|
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
|
paint.setAntiAlias(true);
|
|
paint.setFilterQuality(kLow_SkFilterQuality);
|
|
SkRect destRect = SkRect::MakeXYWH(0, 0, srcSize.width, srcSize.height);
|
|
destCanvas.drawBitmapRect(src, destRect, &paint);
|
|
}
|
|
#else
|
|
static pixman_transform
|
|
BasicLayerManager_Matrix3DToPixman(const Matrix4x4& aMatrix)
|
|
{
|
|
pixman_f_transform transform;
|
|
|
|
transform.m[0][0] = aMatrix._11;
|
|
transform.m[0][1] = aMatrix._21;
|
|
transform.m[0][2] = aMatrix._41;
|
|
transform.m[1][0] = aMatrix._12;
|
|
transform.m[1][1] = aMatrix._22;
|
|
transform.m[1][2] = aMatrix._42;
|
|
transform.m[2][0] = aMatrix._14;
|
|
transform.m[2][1] = aMatrix._24;
|
|
transform.m[2][2] = aMatrix._44;
|
|
|
|
pixman_transform result;
|
|
pixman_transform_from_pixman_f_transform(&result, &transform);
|
|
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
Transform(const gfxImageSurface* aDest,
|
|
RefPtr<DataSourceSurface> aSrc,
|
|
const Matrix4x4& aTransform,
|
|
gfxPoint aDestOffset)
|
|
{
|
|
IntSize destSize = aDest->GetSize();
|
|
pixman_image_t* dest = pixman_image_create_bits(aDest->Format() == SurfaceFormat::A8R8G8B8_UINT32 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
|
|
destSize.width,
|
|
destSize.height,
|
|
(uint32_t*)aDest->Data(),
|
|
aDest->Stride());
|
|
|
|
IntSize srcSize = aSrc->GetSize();
|
|
pixman_image_t* src = pixman_image_create_bits(aSrc->GetFormat() == SurfaceFormat::B8G8R8A8 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
|
|
srcSize.width,
|
|
srcSize.height,
|
|
(uint32_t*)aSrc->GetData(),
|
|
aSrc->Stride());
|
|
|
|
MOZ_ASSERT(src != 0 && dest !=0, "Failed to create pixman images?");
|
|
|
|
pixman_transform pixTransform = BasicLayerManager_Matrix3DToPixman(aTransform);
|
|
pixman_transform pixTransformInverted;
|
|
|
|
// If the transform is singular then nothing would be drawn anyway, return here
|
|
if (!pixman_transform_invert(&pixTransformInverted, &pixTransform)) {
|
|
pixman_image_unref(dest);
|
|
pixman_image_unref(src);
|
|
return;
|
|
}
|
|
pixman_image_set_transform(src, &pixTransformInverted);
|
|
|
|
pixman_image_composite32(PIXMAN_OP_SRC,
|
|
src,
|
|
nullptr,
|
|
dest,
|
|
aDestOffset.x,
|
|
aDestOffset.y,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
destSize.width,
|
|
destSize.height);
|
|
|
|
pixman_image_unref(dest);
|
|
pixman_image_unref(src);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Transform a surface using a Matrix4x4 and blit to the destination if
|
|
* it is efficient to do so.
|
|
*
|
|
* @param aSource Source surface.
|
|
* @param aDest Desintation context.
|
|
* @param aBounds Area represented by aSource.
|
|
* @param aTransform Transformation matrix.
|
|
* @param aDestRect Output: rectangle in which to draw returned surface on aDest
|
|
* (same size as aDest). Only filled in if this returns
|
|
* a surface.
|
|
* @return Transformed surface
|
|
*/
|
|
static already_AddRefed<gfxASurface>
|
|
Transform3D(RefPtr<SourceSurface> aSource,
|
|
gfxContext* aDest,
|
|
const gfxRect& aBounds,
|
|
const Matrix4x4& aTransform,
|
|
gfxRect& aDestRect)
|
|
{
|
|
// Find the transformed rectangle of our layer, intersected with the
|
|
// destination rectangle.
|
|
// This is in device space since we have an identity transform set on aTarget.
|
|
aDestRect = ThebesRect(aTransform.TransformAndClipBounds(
|
|
ToRectDouble(aBounds),
|
|
ToRectDouble(aDest->GetClipExtents())));
|
|
aDestRect.RoundOut();
|
|
|
|
// Create a surface the size of the transformed object.
|
|
RefPtr<gfxASurface> dest = aDest->CurrentSurface();
|
|
RefPtr<gfxImageSurface> destImage = new gfxImageSurface(IntSize(aDestRect.width,
|
|
aDestRect.height),
|
|
SurfaceFormat::A8R8G8B8_UINT32);
|
|
gfxPoint offset = aDestRect.TopLeft();
|
|
|
|
// Include a translation to the correct origin.
|
|
Matrix4x4 translation = Matrix4x4::Translation(aBounds.x, aBounds.y, 0);
|
|
|
|
// Transform the content and offset it such that the content begins at the origin.
|
|
Transform(destImage, aSource->GetDataSurface(), translation * aTransform, offset);
|
|
|
|
// If we haven't actually drawn to aDest then return our temporary image so
|
|
// that the caller can do this.
|
|
return destImage.forget();
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::PaintSelfOrChildren(PaintLayerContext& aPaintContext,
|
|
gfxContext* aGroupTarget)
|
|
{
|
|
MOZ_ASSERT(aGroupTarget);
|
|
BasicImplData* data = ToData(aPaintContext.mLayer);
|
|
|
|
/* Only paint ourself, or our children - This optimization relies on this! */
|
|
Layer* child = aPaintContext.mLayer->GetFirstChild();
|
|
if (!child) {
|
|
if (aPaintContext.mLayer->AsPaintedLayer()) {
|
|
data->PaintThebes(aGroupTarget, aPaintContext.mLayer->GetMaskLayer(),
|
|
aPaintContext.mCallback, aPaintContext.mCallbackData);
|
|
} else {
|
|
data->Paint(aGroupTarget->GetDrawTarget(),
|
|
aGroupTarget->GetDeviceOffset(),
|
|
aPaintContext.mLayer->GetMaskLayer());
|
|
}
|
|
} else {
|
|
ContainerLayer* container =
|
|
static_cast<ContainerLayer*>(aPaintContext.mLayer);
|
|
nsAutoTArray<Layer*, 12> children;
|
|
container->SortChildrenBy3DZOrder(children);
|
|
for (uint32_t i = 0; i < children.Length(); i++) {
|
|
Layer* layer = children.ElementAt(i);
|
|
if (layer->IsBackfaceHidden()) {
|
|
continue;
|
|
}
|
|
if (!layer->AsContainerLayer() && !layer->IsVisible()) {
|
|
continue;
|
|
}
|
|
|
|
PaintLayer(aGroupTarget, layer, aPaintContext.mCallback,
|
|
aPaintContext.mCallbackData);
|
|
if (mTransactionIncomplete)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::FlushGroup(PaintLayerContext& aPaintContext, bool aNeedsClipToVisibleRegion)
|
|
{
|
|
// If we're doing our own double-buffering, we need to avoid drawing
|
|
// the results of an incomplete transaction to the destination surface ---
|
|
// that could cause flicker. Double-buffering is implemented using a
|
|
// temporary surface for one or more container layers, so we need to stop
|
|
// those temporary surfaces from being composited to aTarget.
|
|
// ApplyDoubleBuffering guarantees that this container layer can't
|
|
// intersect any other leaf layers, so if the transaction is not yet marked
|
|
// incomplete, the contents of this container layer are the final contents
|
|
// for the window.
|
|
if (!mTransactionIncomplete) {
|
|
if (aNeedsClipToVisibleRegion) {
|
|
gfxUtils::ClipToRegion(aPaintContext.mTarget,
|
|
aPaintContext.mLayer->GetEffectiveVisibleRegion().ToUnknownRegion());
|
|
}
|
|
|
|
CompositionOp op = GetEffectiveOperator(aPaintContext.mLayer);
|
|
AutoSetOperator setOperator(aPaintContext.mTarget, op);
|
|
|
|
PaintWithMask(aPaintContext.mTarget, aPaintContext.mLayer->GetEffectiveOpacity(),
|
|
aPaintContext.mLayer->GetMaskLayer());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Install the clip applied to the layer on the given gfxContext. The
|
|
* given gfxContext is the buffer that the layer will be painted to.
|
|
*/
|
|
static void
|
|
InstallLayerClipPreserves3D(gfxContext* aTarget, Layer* aLayer)
|
|
{
|
|
const Maybe<ParentLayerIntRect> &clipRect = aLayer->GetEffectiveClipRect();
|
|
|
|
if (!clipRect) {
|
|
return;
|
|
}
|
|
MOZ_ASSERT(!aLayer->Extend3DContext() ||
|
|
!aLayer->Combines3DTransformWithAncestors(),
|
|
"Layers in a preserve 3D context have no clip"
|
|
" except leaves and the estabisher!");
|
|
|
|
Layer* parent = aLayer->GetParent();
|
|
Matrix4x4 transform3d =
|
|
parent && parent->Extend3DContext() ?
|
|
parent->GetEffectiveTransform() :
|
|
Matrix4x4();
|
|
Matrix transform;
|
|
if (!transform3d.CanDraw2D(&transform)) {
|
|
gfxDevCrash(LogReason::CannotDraw3D) << "GFX: We should not have a 3D transform that CanDraw2D() is false!";
|
|
}
|
|
gfxMatrix oldTransform = aTarget->CurrentMatrix();
|
|
transform *= ToMatrix(oldTransform);
|
|
aTarget->SetMatrix(ThebesMatrix(transform));
|
|
|
|
aTarget->NewPath();
|
|
aTarget->SnappedRectangle(gfxRect(clipRect->x, clipRect->y,
|
|
clipRect->width, clipRect->height));
|
|
aTarget->Clip();
|
|
|
|
aTarget->SetMatrix(oldTransform);
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::PaintLayer(gfxContext* aTarget,
|
|
Layer* aLayer,
|
|
DrawPaintedLayerCallback aCallback,
|
|
void* aCallbackData)
|
|
{
|
|
MOZ_ASSERT(aTarget);
|
|
|
|
PROFILER_LABEL("BasicLayerManager", "PaintLayer",
|
|
js::ProfileEntry::Category::GRAPHICS);
|
|
|
|
PaintLayerContext paintLayerContext(aTarget, aLayer, aCallback, aCallbackData);
|
|
|
|
// Don't attempt to paint layers with a singular transform, cairo will
|
|
// just throw an error.
|
|
if (aLayer->GetEffectiveTransform().IsSingular()) {
|
|
return;
|
|
}
|
|
|
|
RenderTraceScope trace("BasicLayerManager::PaintLayer", "707070");
|
|
|
|
const Maybe<ParentLayerIntRect>& clipRect = aLayer->GetEffectiveClipRect();
|
|
BasicContainerLayer* container =
|
|
static_cast<BasicContainerLayer*>(aLayer->AsContainerLayer());
|
|
bool needsGroup = container && container->UseIntermediateSurface();
|
|
BasicImplData* data = ToData(aLayer);
|
|
bool needsClipToVisibleRegion =
|
|
data->GetClipToVisibleRegion() && !aLayer->AsPaintedLayer();
|
|
NS_ASSERTION(needsGroup || !container ||
|
|
container->GetOperator() == CompositionOp::OP_OVER,
|
|
"non-OVER operator should have forced UseIntermediateSurface");
|
|
NS_ASSERTION(!container || !aLayer->GetMaskLayer() ||
|
|
container->UseIntermediateSurface(),
|
|
"ContainerLayer with mask layer should force UseIntermediateSurface");
|
|
|
|
gfxContextAutoSaveRestore contextSR;
|
|
gfxMatrix transform;
|
|
// Will return an identity matrix for 3d transforms, and is handled separately below.
|
|
bool is2D = paintLayerContext.Setup2DTransform();
|
|
MOZ_ASSERT(is2D || needsGroup || !container ||
|
|
container->Extend3DContext() ||
|
|
container->Is3DContextLeaf(),
|
|
"Must PushGroup for 3d transforms!");
|
|
|
|
Layer* parent = aLayer->GetParent();
|
|
bool inPreserves3DChain = parent && parent->Extend3DContext();
|
|
bool needsSaveRestore =
|
|
needsGroup || clipRect || needsClipToVisibleRegion || !is2D ||
|
|
inPreserves3DChain;
|
|
if (needsSaveRestore) {
|
|
contextSR.SetContext(aTarget);
|
|
|
|
// The clips on ancestors on the preserved3d chain should be
|
|
// installed on the aTarget before painting the layer.
|
|
InstallLayerClipPreserves3D(aTarget, aLayer);
|
|
for (Layer* l = parent; l && l->Extend3DContext(); l = l->GetParent()) {
|
|
InstallLayerClipPreserves3D(aTarget, l);
|
|
}
|
|
}
|
|
|
|
paintLayerContext.Apply2DTransform();
|
|
|
|
const nsIntRegion visibleRegion = aLayer->GetEffectiveVisibleRegion().ToUnknownRegion();
|
|
// If needsGroup is true, we'll clip to the visible region after we've popped the group
|
|
if (needsClipToVisibleRegion && !needsGroup) {
|
|
gfxUtils::ClipToRegion(aTarget, visibleRegion);
|
|
// Don't need to clip to visible region again
|
|
needsClipToVisibleRegion = false;
|
|
}
|
|
|
|
if (is2D) {
|
|
paintLayerContext.AnnotateOpaqueRect();
|
|
}
|
|
|
|
bool clipIsEmpty = aTarget->GetClipExtents().IsEmpty();
|
|
if (clipIsEmpty) {
|
|
PaintSelfOrChildren(paintLayerContext, aTarget);
|
|
return;
|
|
}
|
|
|
|
if (is2D) {
|
|
if (needsGroup) {
|
|
PushedGroup pushedGroup =
|
|
PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion().ToUnknownRegion());
|
|
PaintSelfOrChildren(paintLayerContext, pushedGroup.mGroupTarget);
|
|
PopGroupForLayer(pushedGroup);
|
|
} else {
|
|
PaintSelfOrChildren(paintLayerContext, aTarget);
|
|
}
|
|
} else {
|
|
if (!needsGroup && container) {
|
|
PaintSelfOrChildren(paintLayerContext, aTarget);
|
|
return;
|
|
}
|
|
|
|
const IntRect& bounds = visibleRegion.GetBounds();
|
|
RefPtr<DrawTarget> untransformedDT =
|
|
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(bounds.width, bounds.height),
|
|
SurfaceFormat::B8G8R8A8);
|
|
if (!untransformedDT) {
|
|
return;
|
|
}
|
|
|
|
RefPtr<gfxContext> groupTarget = new gfxContext(untransformedDT,
|
|
Point(bounds.x, bounds.y));
|
|
|
|
PaintSelfOrChildren(paintLayerContext, groupTarget);
|
|
|
|
// Temporary fast fix for bug 725886
|
|
// Revert these changes when 725886 is ready
|
|
MOZ_ASSERT(untransformedDT,
|
|
"We should always allocate an untransformed surface with 3d transforms!");
|
|
gfxRect destRect;
|
|
#ifdef DEBUG
|
|
if (aLayer->GetDebugColorIndex() != 0) {
|
|
Color color((aLayer->GetDebugColorIndex() & 1) ? 1.f : 0.f,
|
|
(aLayer->GetDebugColorIndex() & 2) ? 1.f : 0.f,
|
|
(aLayer->GetDebugColorIndex() & 4) ? 1.f : 0.f);
|
|
|
|
RefPtr<gfxContext> temp = new gfxContext(untransformedDT, Point(bounds.x, bounds.y));
|
|
temp->SetColor(color);
|
|
temp->Paint();
|
|
}
|
|
#endif
|
|
Matrix4x4 effectiveTransform = aLayer->GetEffectiveTransform();
|
|
RefPtr<gfxASurface> result =
|
|
Transform3D(untransformedDT->Snapshot(), aTarget, ThebesRect(bounds),
|
|
effectiveTransform, destRect);
|
|
|
|
if (result) {
|
|
aTarget->SetSource(result, destRect.TopLeft());
|
|
// Azure doesn't support EXTEND_NONE, so to avoid extending the edges
|
|
// of the source surface out to the current clip region, clip to
|
|
// the rectangle of the result surface now.
|
|
aTarget->NewPath();
|
|
aTarget->SnappedRectangle(destRect);
|
|
aTarget->Clip();
|
|
FlushGroup(paintLayerContext, needsClipToVisibleRegion);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
BasicLayerManager::ClearCachedResources(Layer* aSubtree)
|
|
{
|
|
MOZ_ASSERT(!aSubtree || aSubtree->Manager() == this);
|
|
if (aSubtree) {
|
|
ClearLayer(aSubtree);
|
|
} else if (mRoot) {
|
|
ClearLayer(mRoot);
|
|
}
|
|
}
|
|
void
|
|
BasicLayerManager::ClearLayer(Layer* aLayer)
|
|
{
|
|
ToData(aLayer)->ClearCachedResources();
|
|
for (Layer* child = aLayer->GetFirstChild(); child;
|
|
child = child->GetNextSibling()) {
|
|
ClearLayer(child);
|
|
}
|
|
}
|
|
|
|
already_AddRefed<ReadbackLayer>
|
|
BasicLayerManager::CreateReadbackLayer()
|
|
{
|
|
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
|
RefPtr<ReadbackLayer> layer = new BasicReadbackLayer(this);
|
|
return layer.forget();
|
|
}
|
|
|
|
} // namespace layers
|
|
} // namespace mozilla
|