Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/svg/SVGGeometryElement.cpp
Line
Count
Source (jump to first uncovered line)
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 "SVGGeometryElement.h"
8
9
#include "DOMSVGPoint.h"
10
#include "gfxPlatform.h"
11
#include "mozilla/gfx/2D.h"
12
#include "mozilla/dom/SVGLengthBinding.h"
13
#include "nsComputedDOMStyle.h"
14
#include "nsSVGUtils.h"
15
#include "nsSVGLength2.h"
16
#include "SVGContentUtils.h"
17
18
using namespace mozilla;
19
using namespace mozilla::gfx;
20
using namespace mozilla::dom;
21
22
nsSVGElement::NumberInfo SVGGeometryElement::sNumberInfo =
23
{ &nsGkAtoms::pathLength, 0, false };
24
25
//----------------------------------------------------------------------
26
// Implementation
27
28
SVGGeometryElement::SVGGeometryElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
29
  : SVGGeometryElementBase(std::move(aNodeInfo))
30
0
{
31
0
}
32
33
nsSVGElement::NumberAttributesInfo
34
SVGGeometryElement::GetNumberInfo()
35
0
{
36
0
  return NumberAttributesInfo(&mPathLength, &sNumberInfo, 1);
37
0
}
38
39
nsresult
40
SVGGeometryElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
41
                                 const nsAttrValue* aValue,
42
                                 const nsAttrValue* aOldValue,
43
                                 nsIPrincipal* aSubjectPrincipal,
44
                                 bool aNotify)
45
0
{
46
0
  if (mCachedPath &&
47
0
      aNamespaceID == kNameSpaceID_None &&
48
0
      AttributeDefinesGeometry(aName)) {
49
0
    mCachedPath = nullptr;
50
0
  }
51
0
  return SVGGeometryElementBase::AfterSetAttr(aNamespaceID, aName,
52
0
                                              aValue, aOldValue,
53
0
                                              aSubjectPrincipal,
54
0
                                              aNotify);
55
0
}
56
57
bool
58
SVGGeometryElement::IsNodeOfType(uint32_t aFlags) const
59
0
{
60
0
  return !(aFlags & ~eSHAPE);
61
0
}
62
63
bool
64
SVGGeometryElement::AttributeDefinesGeometry(const nsAtom *aName)
65
0
{
66
0
  if (aName == nsGkAtoms::pathLength) {
67
0
    return true;
68
0
  }
69
0
70
0
  // Check for nsSVGLength2 attribute
71
0
  LengthAttributesInfo info = GetLengthInfo();
72
0
  for (uint32_t i = 0; i < info.mLengthCount; i++) {
73
0
    if (aName == *info.mLengthInfo[i].mName) {
74
0
      return true;
75
0
    }
76
0
  }
77
0
78
0
  return false;
79
0
}
80
81
bool
82
SVGGeometryElement::GeometryDependsOnCoordCtx()
83
0
{
84
0
  // Check the nsSVGLength2 attribute
85
0
  LengthAttributesInfo info = const_cast<SVGGeometryElement*>(this)->GetLengthInfo();
86
0
  for (uint32_t i = 0; i < info.mLengthCount; i++) {
87
0
    if (info.mLengths[i].GetSpecifiedUnitType() ==
88
0
          SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE) {
89
0
      return true;
90
0
    }
91
0
  }
92
0
  return false;
93
0
}
94
95
bool
96
SVGGeometryElement::IsMarkable()
97
0
{
98
0
  return false;
99
0
}
100
101
void
102
SVGGeometryElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
103
0
{
104
0
}
105
106
already_AddRefed<Path>
107
SVGGeometryElement::GetOrBuildPath(const DrawTarget* aDrawTarget,
108
                                   FillRule aFillRule)
109
0
{
110
0
  // We only cache the path if it matches the backend used for screen painting:
111
0
  bool cacheable  = aDrawTarget->GetBackendType() ==
112
0
                    gfxPlatform::GetPlatform()->GetDefaultContentBackend();
113
0
114
0
  if (cacheable && mCachedPath && mCachedPath->GetFillRule() == aFillRule &&
115
0
      aDrawTarget->GetBackendType() == mCachedPath->GetBackendType()) {
116
0
    RefPtr<Path> path(mCachedPath);
117
0
    return path.forget();
118
0
  }
119
0
  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(aFillRule);
120
0
  RefPtr<Path> path = BuildPath(builder);
121
0
  if (cacheable) {
122
0
    mCachedPath = path;
123
0
  }
124
0
  return path.forget();
125
0
}
126
127
already_AddRefed<Path>
128
SVGGeometryElement::GetOrBuildPathForMeasuring()
129
0
{
130
0
  RefPtr<DrawTarget> drawTarget =
131
0
    gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
132
0
  FillRule fillRule = mCachedPath ? mCachedPath->GetFillRule() : GetFillRule();
133
0
  return GetOrBuildPath(drawTarget, fillRule);
134
0
}
135
136
FillRule
137
SVGGeometryElement::GetFillRule()
138
0
{
139
0
  FillRule fillRule = FillRule::FILL_WINDING; // Equivalent to StyleFillRule::Nonzero
140
0
141
0
  RefPtr<ComputedStyle> computedStyle =
142
0
    nsComputedDOMStyle::GetComputedStyleNoFlush(this, nullptr);
143
0
144
0
  if (computedStyle) {
145
0
    MOZ_ASSERT(computedStyle->StyleSVG()->mFillRule == StyleFillRule::Nonzero ||
146
0
               computedStyle->StyleSVG()->mFillRule == StyleFillRule::Evenodd);
147
0
148
0
    if (computedStyle->StyleSVG()->mFillRule == StyleFillRule::Evenodd) {
149
0
      fillRule = FillRule::FILL_EVEN_ODD;
150
0
    }
151
0
  } else {
152
0
    // ReportToConsole
153
0
    NS_WARNING("Couldn't get ComputedStyle for content in GetFillRule");
154
0
  }
155
0
156
0
  return fillRule;
157
0
}
158
159
float
160
SVGGeometryElement::GetTotalLength()
161
0
{
162
0
  RefPtr<Path> flat = GetOrBuildPathForMeasuring();
163
0
  return flat ? flat->ComputeLength() : 0.f;
164
0
}
165
166
already_AddRefed<nsISVGPoint>
167
SVGGeometryElement::GetPointAtLength(float distance, ErrorResult& rv)
168
0
{
169
0
  RefPtr<Path> path = GetOrBuildPathForMeasuring();
170
0
  if (!path) {
171
0
    rv.Throw(NS_ERROR_FAILURE);
172
0
    return nullptr;
173
0
  }
174
0
175
0
  nsCOMPtr<nsISVGPoint> point =
176
0
    new DOMSVGPoint(path->ComputePointAtLength(
177
0
      clamped(distance, 0.f, path->ComputeLength())));
178
0
  return point.forget();
179
0
}
180
181
float
182
SVGGeometryElement::GetPathLengthScale(PathLengthScaleForType aFor)
183
0
{
184
0
  MOZ_ASSERT(aFor == eForTextPath || aFor == eForStroking,
185
0
             "Unknown enum");
186
0
  if (mPathLength.IsExplicitlySet()) {
187
0
    float authorsPathLengthEstimate = mPathLength.GetAnimValue();
188
0
    if (authorsPathLengthEstimate > 0) {
189
0
      RefPtr<Path> path = GetOrBuildPathForMeasuring();
190
0
      if (!path) {
191
0
        // The path is empty or invalid so its length must be zero and
192
0
        // we know that 0 / authorsPathLengthEstimate = 0.
193
0
        return 0.0;
194
0
      }
195
0
      if (aFor == eForTextPath) {
196
0
        // For textPath, a transform on the referenced path affects the
197
0
        // textPath layout, so when calculating the actual path length
198
0
        // we need to take that into account.
199
0
        gfxMatrix matrix = PrependLocalTransformsTo(gfxMatrix());
200
0
        if (!matrix.IsIdentity()) {
201
0
          RefPtr<PathBuilder> builder =
202
0
            path->TransformedCopyToBuilder(ToMatrix(matrix));
203
0
          path = builder->Finish();
204
0
        }
205
0
      }
206
0
      return path->ComputeLength() / authorsPathLengthEstimate;
207
0
    }
208
0
  }
209
0
  return 1.0;
210
0
}
211
212
already_AddRefed<SVGAnimatedNumber>
213
SVGGeometryElement::PathLength()
214
0
{
215
0
  return mPathLength.ToDOMAnimatedNumber(this);
216
0
}