michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "BasicLayersImpl.h" michael@0: #include // for operator new michael@0: #include "Layers.h" // for Layer, etc michael@0: #include "basic/BasicImplData.h" // for BasicImplData michael@0: #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc michael@0: #include "mozilla/DebugOnly.h" // for DebugOnly michael@0: #include "mozilla/layers/CompositorTypes.h" michael@0: #include "mozilla/layers/ISurfaceAllocator.h" michael@0: #include "AutoMaskData.h" michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: bool michael@0: GetMaskData(Layer* aMaskLayer, michael@0: const Point& aDeviceOffset, michael@0: AutoMoz2DMaskData* aMaskData) michael@0: { michael@0: if (aMaskLayer) { michael@0: RefPtr surface = michael@0: static_cast(aMaskLayer->ImplData())->GetAsSourceSurface(); michael@0: if (surface) { michael@0: Matrix transform; michael@0: Matrix4x4 effectiveTransform = aMaskLayer->GetEffectiveTransform(); michael@0: DebugOnly maskIs2D = effectiveTransform.CanDraw2D(&transform); michael@0: NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!"); michael@0: transform.Translate(-aDeviceOffset.x, -aDeviceOffset.y); michael@0: aMaskData->Construct(transform, surface); michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: PaintWithMask(gfxContext* aContext, float aOpacity, Layer* aMaskLayer) michael@0: { michael@0: AutoMoz2DMaskData mask; michael@0: if (GetMaskData(aMaskLayer, Point(), &mask)) { michael@0: if (aOpacity < 1.0) { michael@0: aContext->PushGroup(gfxContentType::COLOR_ALPHA); michael@0: aContext->Paint(aOpacity); michael@0: aContext->PopGroupToSource(); michael@0: } michael@0: aContext->SetMatrix(ThebesMatrix(mask.GetTransform())); michael@0: aContext->Mask(mask.GetSurface()); michael@0: return; michael@0: } michael@0: michael@0: // if there is no mask, just paint normally michael@0: aContext->Paint(aOpacity); michael@0: } michael@0: michael@0: void michael@0: FillRectWithMask(DrawTarget* aDT, michael@0: const Rect& aRect, michael@0: const Color& aColor, michael@0: const DrawOptions& aOptions, michael@0: SourceSurface* aMaskSource, michael@0: const Matrix* aMaskTransform) michael@0: { michael@0: if (aMaskSource && aMaskTransform) { michael@0: aDT->PushClipRect(aRect); michael@0: Matrix oldTransform = aDT->GetTransform(); michael@0: michael@0: aDT->SetTransform(*aMaskTransform); michael@0: aDT->MaskSurface(ColorPattern(aColor), aMaskSource, Point(), aOptions); michael@0: aDT->SetTransform(oldTransform); michael@0: aDT->PopClip(); michael@0: return; michael@0: } michael@0: michael@0: aDT->FillRect(aRect, ColorPattern(aColor), aOptions); michael@0: } michael@0: void michael@0: FillRectWithMask(DrawTarget* aDT, michael@0: const gfx::Point& aDeviceOffset, michael@0: const Rect& aRect, michael@0: const Color& aColor, michael@0: const DrawOptions& aOptions, michael@0: Layer* aMaskLayer) michael@0: { michael@0: AutoMoz2DMaskData mask; michael@0: if (GetMaskData(aMaskLayer, aDeviceOffset, &mask)) { michael@0: const Matrix& maskTransform = mask.GetTransform(); michael@0: FillRectWithMask(aDT, aRect, aColor, aOptions, mask.GetSurface(), &maskTransform); michael@0: return; michael@0: } michael@0: michael@0: FillRectWithMask(aDT, aRect, aColor, aOptions); michael@0: } michael@0: michael@0: void michael@0: FillRectWithMask(DrawTarget* aDT, michael@0: const Rect& aRect, michael@0: SourceSurface* aSurface, michael@0: Filter aFilter, michael@0: const DrawOptions& aOptions, michael@0: ExtendMode aExtendMode, michael@0: SourceSurface* aMaskSource, michael@0: const Matrix* aMaskTransform, michael@0: const Matrix* aSurfaceTransform) michael@0: { michael@0: if (aMaskSource && aMaskTransform) { michael@0: aDT->PushClipRect(aRect); michael@0: Matrix oldTransform = aDT->GetTransform(); michael@0: michael@0: Matrix inverseMask = *aMaskTransform; michael@0: inverseMask.Invert(); michael@0: michael@0: Matrix transform = oldTransform * inverseMask; michael@0: if (aSurfaceTransform) { michael@0: transform = (*aSurfaceTransform) * transform; michael@0: } michael@0: michael@0: SurfacePattern source(aSurface, aExtendMode, transform, aFilter); michael@0: michael@0: aDT->SetTransform(*aMaskTransform); michael@0: aDT->MaskSurface(source, aMaskSource, Point(0, 0), aOptions); michael@0: aDT->SetTransform(oldTransform); michael@0: aDT->PopClip(); michael@0: return; michael@0: } michael@0: michael@0: aDT->FillRect(aRect, michael@0: SurfacePattern(aSurface, aExtendMode, michael@0: aSurfaceTransform ? (*aSurfaceTransform) : Matrix(), michael@0: aFilter), aOptions); michael@0: } michael@0: michael@0: void michael@0: FillRectWithMask(DrawTarget* aDT, michael@0: const gfx::Point& aDeviceOffset, michael@0: const Rect& aRect, michael@0: SourceSurface* aSurface, michael@0: Filter aFilter, michael@0: const DrawOptions& aOptions, michael@0: Layer* aMaskLayer) michael@0: { michael@0: AutoMoz2DMaskData mask; michael@0: if (GetMaskData(aMaskLayer, aDeviceOffset, &mask)) { michael@0: const Matrix& maskTransform = mask.GetTransform(); michael@0: FillRectWithMask(aDT, aRect, aSurface, aFilter, aOptions, ExtendMode::CLAMP, michael@0: mask.GetSurface(), &maskTransform); michael@0: return; michael@0: } michael@0: michael@0: FillRectWithMask(aDT, aRect, aSurface, aFilter, aOptions, ExtendMode::CLAMP); michael@0: } michael@0: michael@0: BasicImplData* michael@0: ToData(Layer* aLayer) michael@0: { michael@0: return static_cast(aLayer->ImplData()); michael@0: } michael@0: michael@0: gfx::CompositionOp michael@0: GetEffectiveOperator(Layer* aLayer) michael@0: { michael@0: CompositionOp op = aLayer->GetEffectiveMixBlendMode(); michael@0: michael@0: if (op != CompositionOp::OP_OVER) { michael@0: return op; michael@0: } michael@0: michael@0: return ToData(aLayer)->GetOperator(); michael@0: } michael@0: michael@0: ShadowableLayer* michael@0: ToShadowable(Layer* aLayer) michael@0: { michael@0: return aLayer->AsShadowableLayer(); michael@0: } michael@0: michael@0: bool michael@0: ShouldShadow(Layer* aLayer) michael@0: { michael@0: if (!ToShadowable(aLayer)) { michael@0: NS_ABORT_IF_FALSE(aLayer->GetType() == Layer::TYPE_READBACK, michael@0: "Only expect not to shadow ReadbackLayers"); michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: michael@0: } michael@0: }