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 #include "mozilla/dom/SVGGraphicsElement.h"
9 #include "mozilla/dom/BindContext.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/dom/SVGGraphicsElementBinding.h"
12 #include "mozilla/dom/SVGMatrix.h"
13 #include "mozilla/dom/SVGRect.h"
14 #include "mozilla/dom/SVGSVGElement.h"
15 #include "mozilla/ISVGDisplayableFrame.h"
16 #include "mozilla/SVGContentUtils.h"
17 #include "mozilla/SVGTextFrame.h"
18 #include "mozilla/SVGUtils.h"
20 #include "nsIContentInlines.h"
21 #include "nsLayoutUtils.h"
23 namespace mozilla::dom
{
25 //----------------------------------------------------------------------
26 // nsISupports methods
28 NS_IMPL_ADDREF_INHERITED(SVGGraphicsElement
, SVGGraphicsElementBase
)
29 NS_IMPL_RELEASE_INHERITED(SVGGraphicsElement
, SVGGraphicsElementBase
)
31 NS_INTERFACE_MAP_BEGIN(SVGGraphicsElement
)
32 NS_INTERFACE_MAP_ENTRY(mozilla::dom::SVGTests
)
33 NS_INTERFACE_MAP_END_INHERITING(SVGGraphicsElementBase
)
35 //----------------------------------------------------------------------
38 SVGGraphicsElement::SVGGraphicsElement(
39 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
40 : SVGGraphicsElementBase(std::move(aNodeInfo
)) {}
42 SVGElement
* SVGGraphicsElement::GetNearestViewportElement() {
43 return SVGContentUtils::GetNearestViewportElement(this);
46 SVGElement
* SVGGraphicsElement::GetFarthestViewportElement() {
47 return SVGContentUtils::GetOuterSVGElement(this);
50 static already_AddRefed
<SVGRect
> ZeroBBox(SVGGraphicsElement
& aOwner
) {
51 return MakeAndAddRef
<SVGRect
>(&aOwner
, gfx::Rect
{0, 0, 0, 0});
54 already_AddRefed
<SVGRect
> SVGGraphicsElement::GetBBox(
55 const SVGBoundingBoxOptions
& aOptions
) {
56 nsIFrame
* frame
= GetPrimaryFrame(FlushType::Layout
);
58 if (!frame
|| (frame
->GetStateBits() & NS_FRAME_IS_NONDISPLAY
)) {
59 return ZeroBBox(*this);
61 ISVGDisplayableFrame
* svgframe
= do_QueryFrame(frame
);
64 if (!SVGUtils::IsInSVGTextSubtree(frame
)) {
65 return ZeroBBox(*this);
68 // For <tspan>, <textPath>, the frame is an nsInlineFrame or
69 // nsBlockFrame, |svgframe| will be a nullptr.
70 // We implement their getBBox directly here instead of in
71 // SVGUtils::GetBBox, because SVGUtils::GetBBox is more
72 // or less used for other purpose elsewhere. e.g. gradient
73 // code assumes GetBBox of <tspan> returns the bbox of the
75 // TODO: cleanup this sort of usecase of SVGUtils::GetBBox,
76 // then move this code SVGUtils::GetBBox.
78 static_cast<SVGTextFrame
*>(nsLayoutUtils::GetClosestFrameOfType(
79 frame
->GetParent(), LayoutFrameType::SVGText
));
81 if (text
->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY
)) {
82 return ZeroBBox(*this);
85 gfxRect rec
= text
->TransformFrameRectFromTextChild(
86 frame
->GetRectRelativeToSelf(), frame
);
88 // Should also add the |x|, |y| of the SVGTextFrame itself, since
89 // the result obtained by TransformFrameRectFromTextChild doesn't
91 rec
.x
+= float(text
->GetPosition().x
) / AppUnitsPerCSSPixel();
92 rec
.y
+= float(text
->GetPosition().y
) / AppUnitsPerCSSPixel();
94 return do_AddRef(new SVGRect(this, ToRect(rec
)));
97 if (!NS_SVGNewGetBBoxEnabled()) {
98 return do_AddRef(new SVGRect(
99 this, ToRect(SVGUtils::GetBBox(
100 frame
, SVGUtils::eBBoxIncludeFillGeometry
|
101 SVGUtils::eUseUserSpaceOfUseElement
))));
104 if (aOptions
.mFill
) {
105 flags
|= SVGUtils::eBBoxIncludeFill
;
107 if (aOptions
.mStroke
) {
108 flags
|= SVGUtils::eBBoxIncludeStroke
;
110 if (aOptions
.mMarkers
) {
111 flags
|= SVGUtils::eBBoxIncludeMarkers
;
113 if (aOptions
.mClipped
) {
114 flags
|= SVGUtils::eBBoxIncludeClipped
;
117 return do_AddRef(new SVGRect(this, gfx::Rect()));
119 if (flags
== SVGUtils::eBBoxIncludeMarkers
||
120 flags
== SVGUtils::eBBoxIncludeClipped
) {
121 flags
|= SVGUtils::eBBoxIncludeFill
;
123 flags
|= SVGUtils::eUseUserSpaceOfUseElement
;
124 return do_AddRef(new SVGRect(this, ToRect(SVGUtils::GetBBox(frame
, flags
))));
127 already_AddRefed
<SVGMatrix
> SVGGraphicsElement::GetCTM() {
128 Document
* currentDoc
= GetComposedDoc();
130 // Flush all pending notifications so that our frames are up to date
131 currentDoc
->FlushPendingNotifications(FlushType::Layout
);
133 gfx::Matrix m
= SVGContentUtils::GetCTM(this, false);
134 RefPtr
<SVGMatrix
> mat
=
135 m
.IsSingular() ? nullptr : new SVGMatrix(ThebesMatrix(m
));
139 already_AddRefed
<SVGMatrix
> SVGGraphicsElement::GetScreenCTM() {
140 Document
* currentDoc
= GetComposedDoc();
142 // Flush all pending notifications so that our frames are up to date
143 currentDoc
->FlushPendingNotifications(FlushType::Layout
);
145 gfx::Matrix m
= SVGContentUtils::GetCTM(this, true);
146 RefPtr
<SVGMatrix
> mat
=
147 m
.IsSingular() ? nullptr : new SVGMatrix(ThebesMatrix(m
));
151 bool SVGGraphicsElement::IsSVGFocusable(bool* aIsFocusable
,
152 int32_t* aTabIndex
) {
153 // XXXedgar, maybe we could factor out the common code for SVG, HTML and
154 // MathML elements, see bug 1586011.
155 if (!IsInComposedDoc() || IsInDesignMode()) {
156 // In designMode documents we only allow focusing the document.
161 *aIsFocusable
= false;
166 int32_t tabIndex
= TabIndex();
169 *aTabIndex
= tabIndex
;
172 // If a tabindex is specified at all, or the default tabindex is 0, we're
174 *aIsFocusable
= tabIndex
>= 0 || GetTabIndexAttrValue().isSome();
179 bool SVGGraphicsElement::IsFocusableInternal(int32_t* aTabIndex
,
181 bool isFocusable
= false;
182 IsSVGFocusable(&isFocusable
, aTabIndex
);
186 } // namespace mozilla::dom