Bug 1692937 [wpt PR 27636] - new parameter --include-file for wptrunner, a=testonly
[gecko.git] / layout / svg / SVGMarkerFrame.cpp
blobb8df132fb7eae31e4432aa86eb2365d218fbfdc5
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 "SVGMarkerFrame.h"
10 // Keep others in (case-insensitive) order:
11 #include "gfxContext.h"
12 #include "mozilla/PresShell.h"
13 #include "mozilla/SVGGeometryFrame.h"
14 #include "mozilla/SVGObserverUtils.h"
15 #include "mozilla/SVGUtils.h"
16 #include "mozilla/dom/SVGGeometryElement.h"
17 #include "mozilla/dom/SVGMarkerElement.h"
19 using namespace mozilla::dom;
20 using namespace mozilla::gfx;
21 using namespace mozilla::image;
23 nsContainerFrame* NS_NewSVGMarkerFrame(mozilla::PresShell* aPresShell,
24 mozilla::ComputedStyle* aStyle) {
25 return new (aPresShell)
26 mozilla::SVGMarkerFrame(aStyle, aPresShell->GetPresContext());
29 namespace mozilla {
31 NS_IMPL_FRAMEARENA_HELPERS(SVGMarkerFrame)
33 //----------------------------------------------------------------------
34 // nsIFrame methods:
36 nsresult SVGMarkerFrame::AttributeChanged(int32_t aNameSpaceID,
37 nsAtom* aAttribute,
38 int32_t aModType) {
39 if (aNameSpaceID == kNameSpaceID_None &&
40 (aAttribute == nsGkAtoms::markerUnits || aAttribute == nsGkAtoms::refX ||
41 aAttribute == nsGkAtoms::refY || aAttribute == nsGkAtoms::markerWidth ||
42 aAttribute == nsGkAtoms::markerHeight ||
43 aAttribute == nsGkAtoms::orient ||
44 aAttribute == nsGkAtoms::preserveAspectRatio ||
45 aAttribute == nsGkAtoms::viewBox)) {
46 SVGObserverUtils::InvalidateDirectRenderingObservers(this);
49 return SVGContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
50 aModType);
53 #ifdef DEBUG
54 void SVGMarkerFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
55 nsIFrame* aPrevInFlow) {
56 NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::marker),
57 "Content is not an SVG marker");
59 SVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
61 #endif /* DEBUG */
63 //----------------------------------------------------------------------
64 // SVGContainerFrame methods:
66 gfxMatrix SVGMarkerFrame::GetCanvasTM() {
67 NS_ASSERTION(mMarkedFrame, "null SVGGeometry frame");
69 if (mInUse2) {
70 // We're going to be bailing drawing the marker, so return an identity.
71 return gfxMatrix();
74 SVGMarkerElement* content = static_cast<SVGMarkerElement*>(GetContent());
76 mInUse2 = true;
77 gfxMatrix markedTM = mMarkedFrame->GetCanvasTM();
78 mInUse2 = false;
80 Matrix viewBoxTM = content->GetViewBoxTransform();
82 return ThebesMatrix(viewBoxTM * mMarkerTM) * markedTM;
85 static nsIFrame* GetAnonymousChildFrame(nsIFrame* aFrame) {
86 nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
87 MOZ_ASSERT(kid && kid->IsSVGMarkerAnonChildFrame(),
88 "expected to find anonymous child of marker frame");
89 return kid;
92 void SVGMarkerFrame::PaintMark(gfxContext& aContext,
93 const gfxMatrix& aToMarkedFrameUserSpace,
94 SVGGeometryFrame* aMarkedFrame,
95 const SVGMark& aMark, float aStrokeWidth,
96 imgDrawingParams& aImgParams) {
97 // If the flag is set when we get here, it means this marker frame
98 // has already been used painting the current mark, and the document
99 // has a marker reference loop.
100 if (mInUse) {
101 return;
104 AutoMarkerReferencer markerRef(this, aMarkedFrame);
106 SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(GetContent());
107 if (!marker->HasValidDimensions()) {
108 return;
111 const SVGViewBox viewBox = marker->GetViewBox();
113 if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
114 // We must disable rendering if the viewBox width or height are zero.
115 return;
118 Matrix viewBoxTM = marker->GetViewBoxTransform();
120 mMarkerTM = marker->GetMarkerTransform(aStrokeWidth, aMark);
122 gfxMatrix markTM = ThebesMatrix(viewBoxTM) * ThebesMatrix(mMarkerTM) *
123 aToMarkedFrameUserSpace;
125 if (StyleDisplay()->IsScrollableOverflow()) {
126 aContext.Save();
127 gfxRect clipRect = SVGUtils::GetClipRectForFrame(
128 this, viewBox.x, viewBox.y, viewBox.width, viewBox.height);
129 SVGUtils::SetClipRect(&aContext, markTM, clipRect);
132 nsIFrame* kid = GetAnonymousChildFrame(this);
133 ISVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
134 // The CTM of each frame referencing us may be different.
135 SVGFrame->NotifySVGChanged(ISVGDisplayableFrame::TRANSFORM_CHANGED);
136 SVGUtils::PaintFrameWithEffects(kid, aContext, markTM, aImgParams);
138 if (StyleDisplay()->IsScrollableOverflow()) aContext.Restore();
141 SVGBBox SVGMarkerFrame::GetMarkBBoxContribution(const Matrix& aToBBoxUserspace,
142 uint32_t aFlags,
143 SVGGeometryFrame* aMarkedFrame,
144 const SVGMark& aMark,
145 float aStrokeWidth) {
146 SVGBBox bbox;
148 // If the flag is set when we get here, it means this marker frame
149 // has already been used in calculating the current mark bbox, and
150 // the document has a marker reference loop.
151 if (mInUse) {
152 return bbox;
155 AutoMarkerReferencer markerRef(this, aMarkedFrame);
157 SVGMarkerElement* content = static_cast<SVGMarkerElement*>(GetContent());
158 if (!content->HasValidDimensions()) {
159 return bbox;
162 const SVGViewBox viewBox = content->GetViewBox();
164 if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
165 return bbox;
168 mMarkerTM = content->GetMarkerTransform(aStrokeWidth, aMark);
169 Matrix viewBoxTM = content->GetViewBoxTransform();
171 Matrix tm = viewBoxTM * mMarkerTM * aToBBoxUserspace;
173 ISVGDisplayableFrame* child = do_QueryFrame(GetAnonymousChildFrame(this));
174 // When we're being called to obtain the invalidation area, we need to
175 // pass down all the flags so that stroke is included. However, once DOM
176 // getBBox() accepts flags, maybe we should strip some of those here?
178 // We need to include zero width/height vertical/horizontal lines, so we have
179 // to use UnionEdges.
180 bbox.UnionEdges(child->GetBBoxContribution(tm, aFlags));
182 return bbox;
185 void SVGMarkerFrame::SetParentCoordCtxProvider(SVGViewportElement* aContext) {
186 SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(GetContent());
187 marker->SetParentCoordCtxProvider(aContext);
190 void SVGMarkerFrame::AppendDirectlyOwnedAnonBoxes(
191 nsTArray<OwnedAnonBox>& aResult) {
192 aResult.AppendElement(OwnedAnonBox(GetAnonymousChildFrame(this)));
195 //----------------------------------------------------------------------
196 // helper class
198 SVGMarkerFrame::AutoMarkerReferencer::AutoMarkerReferencer(
199 SVGMarkerFrame* aFrame, SVGGeometryFrame* aMarkedFrame)
200 : mFrame(aFrame) {
201 mFrame->mInUse = true;
202 mFrame->mMarkedFrame = aMarkedFrame;
204 SVGViewportElement* ctx =
205 static_cast<SVGElement*>(aMarkedFrame->GetContent())->GetCtx();
206 mFrame->SetParentCoordCtxProvider(ctx);
209 SVGMarkerFrame::AutoMarkerReferencer::~AutoMarkerReferencer() {
210 mFrame->SetParentCoordCtxProvider(nullptr);
212 mFrame->mMarkedFrame = nullptr;
213 mFrame->mInUse = false;
216 } // namespace mozilla
218 //----------------------------------------------------------------------
219 // Implementation of SVGMarkerAnonChildFrame
221 nsContainerFrame* NS_NewSVGMarkerAnonChildFrame(
222 mozilla::PresShell* aPresShell, mozilla::ComputedStyle* aStyle) {
223 return new (aPresShell)
224 mozilla::SVGMarkerAnonChildFrame(aStyle, aPresShell->GetPresContext());
227 namespace mozilla {
229 NS_IMPL_FRAMEARENA_HELPERS(SVGMarkerAnonChildFrame)
231 #ifdef DEBUG
232 void SVGMarkerAnonChildFrame::Init(nsIContent* aContent,
233 nsContainerFrame* aParent,
234 nsIFrame* aPrevInFlow) {
235 MOZ_ASSERT(aParent->IsSVGMarkerFrame(), "Unexpected parent");
236 SVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
238 #endif
240 } // namespace mozilla