Bug 1705289 Remove spurious mozMediaSource media track constraint from tests r=jib
[gecko.git] / layout / svg / SVGMaskFrame.cpp
blob90348ac4d9f8bb7a2bdcd3ada5e904f74dc496f4
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // Main header first:
8 #include "SVGMaskFrame.h"
10 // Keep others in (case-insensitive) order:
11 #include "AutoReferenceChainGuard.h"
12 #include "gfx2DGlue.h"
13 #include "gfxContext.h"
14 #include "mozilla/PresShell.h"
15 #include "mozilla/RefPtr.h"
16 #include "mozilla/SVGObserverUtils.h"
17 #include "mozilla/SVGUtils.h"
18 #include "mozilla/dom/SVGMaskElement.h"
19 #include "mozilla/dom/SVGUnitTypesBinding.h"
20 #include "mozilla/gfx/2D.h"
22 using namespace mozilla::dom;
23 using namespace mozilla::dom::SVGUnitTypes_Binding;
24 using namespace mozilla::gfx;
25 using namespace mozilla::image;
27 nsIFrame* NS_NewSVGMaskFrame(mozilla::PresShell* aPresShell,
28 mozilla::ComputedStyle* aStyle) {
29 return new (aPresShell)
30 mozilla::SVGMaskFrame(aStyle, aPresShell->GetPresContext());
33 namespace mozilla {
35 NS_IMPL_FRAMEARENA_HELPERS(SVGMaskFrame)
37 already_AddRefed<SourceSurface> SVGMaskFrame::GetMaskForMaskedFrame(
38 MaskParams& aParams) {
39 // Make sure we break reference loops and over long reference chains:
40 static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
41 AutoReferenceChainGuard refChainGuard(this, &mInUse, &sRefChainLengthCounter);
42 if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
43 // Break reference chain
44 return nullptr;
47 gfxRect maskArea = GetMaskArea(aParams.maskedFrame);
48 if (maskArea.IsEmpty()) {
49 return nullptr;
51 gfxContext* context = aParams.ctx;
52 // Get the clip extents in device space:
53 // Minimizing the mask surface extents (using both the current clip extents
54 // and maskArea) is important for performance.
56 gfxRect maskSurfaceRectDouble = aParams.toUserSpace.TransformBounds(maskArea);
57 Rect maskSurfaceRect = ToRect(maskSurfaceRectDouble);
58 maskSurfaceRect.RoundOut();
60 StyleMaskType maskType;
61 if (aParams.maskMode == StyleMaskMode::MatchSource) {
62 maskType = StyleSVGReset()->mMaskType;
63 } else {
64 maskType = aParams.maskMode == StyleMaskMode::Luminance
65 ? StyleMaskType::Luminance
66 : StyleMaskType::Alpha;
69 RefPtr<DrawTarget> maskDT;
70 if (maskType == StyleMaskType::Luminance) {
71 maskDT = context->GetDrawTarget()->CreateClippedDrawTarget(
72 maskSurfaceRect, SurfaceFormat::B8G8R8A8);
73 } else {
74 maskDT = context->GetDrawTarget()->CreateClippedDrawTarget(
75 maskSurfaceRect, SurfaceFormat::A8);
78 if (!maskDT || !maskDT->IsValid()) {
79 return nullptr;
82 RefPtr<gfxContext> tmpCtx =
83 gfxContext::CreatePreservingTransformOrNull(maskDT);
84 MOZ_ASSERT(tmpCtx); // already checked the draw target above
86 mMatrixForChildren =
87 GetMaskTransform(aParams.maskedFrame) * aParams.toUserSpace;
89 for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) {
90 gfxMatrix m = mMatrixForChildren;
92 // The CTM of each frame referencing us can be different
93 ISVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
94 if (SVGFrame) {
95 SVGFrame->NotifySVGChanged(ISVGDisplayableFrame::TRANSFORM_CHANGED);
96 m = SVGUtils::GetTransformMatrixInUserSpace(kid) * m;
99 SVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m, aParams.imgParams);
102 RefPtr<SourceSurface> surface;
103 if (maskType == StyleMaskType::Luminance) {
104 auto luminanceType = LuminanceType::LUMINANCE;
105 if (StyleSVG()->mColorInterpolation == StyleColorInterpolation::Linearrgb) {
106 luminanceType = LuminanceType::LINEARRGB;
109 RefPtr<SourceSurface> maskSnapshot =
110 maskDT->IntoLuminanceSource(luminanceType, aParams.opacity);
111 if (!maskSnapshot) {
112 return nullptr;
114 surface = std::move(maskSnapshot);
115 } else {
116 maskDT->FillRect(maskSurfaceRect,
117 ColorPattern(DeviceColor::MaskWhite(aParams.opacity)),
118 DrawOptions(1, CompositionOp::OP_IN));
119 RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();
120 if (!maskSnapshot) {
121 return nullptr;
123 surface = std::move(maskSnapshot);
126 return surface.forget();
129 gfxRect SVGMaskFrame::GetMaskArea(nsIFrame* aMaskedFrame) {
130 SVGMaskElement* maskElem = static_cast<SVGMaskElement*>(GetContent());
132 uint16_t units =
133 maskElem->mEnumAttributes[SVGMaskElement::MASKUNITS].GetAnimValue();
134 gfxRect bbox;
135 if (units == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
136 bbox =
137 SVGUtils::GetBBox(aMaskedFrame, SVGUtils::eUseFrameBoundsForOuterSVG |
138 SVGUtils::eBBoxIncludeFillGeometry);
141 // Bounds in the user space of aMaskedFrame
142 gfxRect maskArea = SVGUtils::GetRelativeRect(
143 units, &maskElem->mLengthAttributes[SVGMaskElement::ATTR_X], bbox,
144 aMaskedFrame);
146 return maskArea;
149 nsresult SVGMaskFrame::AttributeChanged(int32_t aNameSpaceID,
150 nsAtom* aAttribute, int32_t aModType) {
151 if (aNameSpaceID == kNameSpaceID_None &&
152 (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y ||
153 aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height ||
154 aAttribute == nsGkAtoms::maskUnits ||
155 aAttribute == nsGkAtoms::maskContentUnits)) {
156 SVGObserverUtils::InvalidateDirectRenderingObservers(this);
159 return SVGContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
160 aModType);
163 #ifdef DEBUG
164 void SVGMaskFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
165 nsIFrame* aPrevInFlow) {
166 NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::mask),
167 "Content is not an SVG mask");
169 SVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
171 #endif /* DEBUG */
173 gfxMatrix SVGMaskFrame::GetCanvasTM() { return mMatrixForChildren; }
175 gfxMatrix SVGMaskFrame::GetMaskTransform(nsIFrame* aMaskedFrame) {
176 SVGMaskElement* content = static_cast<SVGMaskElement*>(GetContent());
178 SVGAnimatedEnumeration* maskContentUnits =
179 &content->mEnumAttributes[SVGMaskElement::MASKCONTENTUNITS];
181 uint32_t flags = SVGUtils::eBBoxIncludeFillGeometry |
182 (aMaskedFrame->StyleBorder()->mBoxDecorationBreak ==
183 StyleBoxDecorationBreak::Clone
184 ? SVGUtils::eIncludeOnlyCurrentFrameForNonSVGElement
185 : 0);
187 return SVGUtils::AdjustMatrixForUnits(gfxMatrix(), maskContentUnits,
188 aMaskedFrame, flags);
191 } // namespace mozilla