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/. */
6
7 #include "nsSVGPathGeometryElement.h"
8
9 #include "gfxPlatform.h"
10 #include "mozilla/gfx/2D.h"
11 #include "nsComputedDOMStyle.h"
12 #include "nsSVGUtils.h"
13 #include "nsSVGLength2.h"
14 #include "SVGContentUtils.h"
15
16 using namespace mozilla;
17 using namespace mozilla::gfx;
18
19 //----------------------------------------------------------------------
20 // Implementation
21
nsSVGPathGeometryElement(already_AddRefed<mozilla::dom::NodeInfo> & aNodeInfo)22 nsSVGPathGeometryElement::nsSVGPathGeometryElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
23 : nsSVGPathGeometryElementBase(aNodeInfo)
24 {
25 }
26
27 nsresult
AfterSetAttr(int32_t aNamespaceID,nsIAtom * aName,const nsAttrValue * aValue,bool aNotify)28 nsSVGPathGeometryElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
29 const nsAttrValue* aValue, bool aNotify)
30 {
31 if (mCachedPath &&
32 aNamespaceID == kNameSpaceID_None &&
33 AttributeDefinesGeometry(aName)) {
34 mCachedPath = nullptr;
35 }
36 return nsSVGPathGeometryElementBase::AfterSetAttr(aNamespaceID, aName,
37 aValue, aNotify);
38 }
39
40 bool
AttributeDefinesGeometry(const nsIAtom * aName)41 nsSVGPathGeometryElement::AttributeDefinesGeometry(const nsIAtom *aName)
42 {
43 // Check for nsSVGLength2 attribute
44 LengthAttributesInfo info = GetLengthInfo();
45 for (uint32_t i = 0; i < info.mLengthCount; i++) {
46 if (aName == *info.mLengthInfo[i].mName) {
47 return true;
48 }
49 }
50
51 return false;
52 }
53
54 bool
GeometryDependsOnCoordCtx()55 nsSVGPathGeometryElement::GeometryDependsOnCoordCtx()
56 {
57 // Check the nsSVGLength2 attribute
58 LengthAttributesInfo info = const_cast<nsSVGPathGeometryElement*>(this)->GetLengthInfo();
59 for (uint32_t i = 0; i < info.mLengthCount; i++) {
60 if (info.mLengths[i].GetSpecifiedUnitType() == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
61 return true;
62 }
63 }
64 return false;
65 }
66
67 bool
IsMarkable()68 nsSVGPathGeometryElement::IsMarkable()
69 {
70 return false;
71 }
72
73 void
GetMarkPoints(nsTArray<nsSVGMark> * aMarks)74 nsSVGPathGeometryElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
75 {
76 }
77
78 already_AddRefed<Path>
GetOrBuildPath(const DrawTarget & aDrawTarget,FillRule aFillRule)79 nsSVGPathGeometryElement::GetOrBuildPath(const DrawTarget& aDrawTarget,
80 FillRule aFillRule)
81 {
82 // We only cache the path if it matches the backend used for screen painting:
83 bool cacheable = aDrawTarget.GetBackendType() ==
84 gfxPlatform::GetPlatform()->GetDefaultContentBackend();
85
86 // Checking for and returning mCachedPath before checking the pref means
87 // that the pref is only live on page reload (or app restart for SVG in
88 // chrome). The benefit is that we avoid causing a CPU memory cache miss by
89 // looking at the global variable that the pref's stored in.
90 if (cacheable && mCachedPath) {
91 if (aDrawTarget.GetBackendType() == mCachedPath->GetBackendType()) {
92 RefPtr<Path> path(mCachedPath);
93 return path.forget();
94 }
95 }
96 RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder(aFillRule);
97 RefPtr<Path> path = BuildPath(builder);
98 if (cacheable && NS_SVGPathCachingEnabled()) {
99 mCachedPath = path;
100 }
101 return path.forget();
102 }
103
104 already_AddRefed<Path>
GetOrBuildPathForMeasuring()105 nsSVGPathGeometryElement::GetOrBuildPathForMeasuring()
106 {
107 return nullptr;
108 }
109
110 FillRule
GetFillRule()111 nsSVGPathGeometryElement::GetFillRule()
112 {
113 FillRule fillRule = FillRule::FILL_WINDING; // Equivalent to StyleFillRule::Nonzero
114
115 RefPtr<nsStyleContext> styleContext =
116 nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
117 nullptr);
118
119 if (styleContext) {
120 MOZ_ASSERT(styleContext->StyleSVG()->mFillRule == StyleFillRule::Nonzero ||
121 styleContext->StyleSVG()->mFillRule == StyleFillRule::Evenodd);
122
123 if (styleContext->StyleSVG()->mFillRule == StyleFillRule::Evenodd) {
124 fillRule = FillRule::FILL_EVEN_ODD;
125 }
126 } else {
127 // ReportToConsole
128 NS_WARNING("Couldn't get style context for content in GetFillRule");
129 }
130
131 return fillRule;
132 }
133