Backed out changeset 496886cb30a5 (bug 1867152) for bc failures on browser_user_input...
[gecko.git] / layout / svg / SVGMaskFrame.cpp
blobae80f730cb5e4c96a87fd096df6a34ec004faf47
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 // Get the clip extents in device space:
52 // Minimizing the mask surface extents (using both the current clip extents
53 // and maskArea) is important for performance.
55 gfxRect maskSurfaceRectDouble = aParams.toUserSpace.TransformBounds(maskArea);
56 Rect maskSurfaceRect = ToRect(maskSurfaceRectDouble);
57 maskSurfaceRect.RoundOut();
59 StyleMaskType maskType;
60 if (aParams.maskMode == StyleMaskMode::MatchSource) {
61 maskType = StyleSVGReset()->mMaskType;
62 } else {
63 maskType = aParams.maskMode == StyleMaskMode::Luminance
64 ? StyleMaskType::Luminance
65 : StyleMaskType::Alpha;
68 RefPtr<DrawTarget> maskDT;
69 if (maskType == StyleMaskType::Luminance) {
70 maskDT = aParams.dt->CreateClippedDrawTarget(maskSurfaceRect,
71 SurfaceFormat::B8G8R8A8);
72 } else {
73 maskDT =
74 aParams.dt->CreateClippedDrawTarget(maskSurfaceRect, SurfaceFormat::A8);
77 if (!maskDT || !maskDT->IsValid()) {
78 return nullptr;
81 gfxContext tmpCtx(maskDT, /* aPreserveTransform */ true);
83 mMatrixForChildren =
84 GetMaskTransform(aParams.maskedFrame) * aParams.toUserSpace;
86 for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) {
87 gfxMatrix m = mMatrixForChildren;
89 // The CTM of each frame referencing us can be different
90 ISVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
91 if (SVGFrame) {
92 SVGFrame->NotifySVGChanged(ISVGDisplayableFrame::TRANSFORM_CHANGED);
93 m = SVGUtils::GetTransformMatrixInUserSpace(kid) * m;
96 SVGUtils::PaintFrameWithEffects(kid, tmpCtx, m, aParams.imgParams);
99 RefPtr<SourceSurface> surface;
100 if (maskType == StyleMaskType::Luminance) {
101 auto luminanceType = LuminanceType::LUMINANCE;
102 if (StyleSVG()->mColorInterpolation == StyleColorInterpolation::Linearrgb) {
103 luminanceType = LuminanceType::LINEARRGB;
106 RefPtr<SourceSurface> maskSnapshot =
107 maskDT->IntoLuminanceSource(luminanceType, aParams.opacity);
108 if (!maskSnapshot) {
109 return nullptr;
111 surface = std::move(maskSnapshot);
112 } else {
113 maskDT->FillRect(maskSurfaceRect,
114 ColorPattern(DeviceColor::MaskWhite(aParams.opacity)),
115 DrawOptions(1, CompositionOp::OP_IN));
116 RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();
117 if (!maskSnapshot) {
118 return nullptr;
120 surface = std::move(maskSnapshot);
123 return surface.forget();
126 gfxRect SVGMaskFrame::GetMaskArea(nsIFrame* aMaskedFrame) {
127 SVGMaskElement* maskElem = static_cast<SVGMaskElement*>(GetContent());
129 uint16_t units =
130 maskElem->mEnumAttributes[SVGMaskElement::MASKUNITS].GetAnimValue();
131 gfxRect bbox;
132 if (units == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
133 bbox =
134 SVGUtils::GetBBox(aMaskedFrame, SVGUtils::eUseFrameBoundsForOuterSVG |
135 SVGUtils::eBBoxIncludeFillGeometry);
138 // Bounds in the user space of aMaskedFrame
139 gfxRect maskArea = SVGUtils::GetRelativeRect(
140 units, &maskElem->mLengthAttributes[SVGMaskElement::ATTR_X], bbox,
141 aMaskedFrame);
143 return maskArea;
146 nsresult SVGMaskFrame::AttributeChanged(int32_t aNameSpaceID,
147 nsAtom* aAttribute, int32_t aModType) {
148 if (aNameSpaceID == kNameSpaceID_None &&
149 (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y ||
150 aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height ||
151 aAttribute == nsGkAtoms::maskUnits ||
152 aAttribute == nsGkAtoms::maskContentUnits)) {
153 SVGObserverUtils::InvalidateRenderingObservers(this);
156 return SVGContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
157 aModType);
160 #ifdef DEBUG
161 void SVGMaskFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
162 nsIFrame* aPrevInFlow) {
163 NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::mask),
164 "Content is not an SVG mask");
166 SVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
168 #endif /* DEBUG */
170 gfxMatrix SVGMaskFrame::GetCanvasTM() { return mMatrixForChildren; }
172 gfxMatrix SVGMaskFrame::GetMaskTransform(nsIFrame* aMaskedFrame) {
173 SVGMaskElement* content = static_cast<SVGMaskElement*>(GetContent());
175 SVGAnimatedEnumeration* maskContentUnits =
176 &content->mEnumAttributes[SVGMaskElement::MASKCONTENTUNITS];
178 uint32_t flags = SVGUtils::eBBoxIncludeFillGeometry |
179 (aMaskedFrame->StyleBorder()->mBoxDecorationBreak ==
180 StyleBoxDecorationBreak::Clone
181 ? SVGUtils::eIncludeOnlyCurrentFrameForNonSVGElement
182 : 0);
184 return SVGUtils::AdjustMatrixForUnits(gfxMatrix(), maskContentUnits,
185 aMaskedFrame, flags);
188 } // namespace mozilla