Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/svg/SVGMarkerElement.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 "mozilla/ArrayUtils.h"
8
9
#include "nsGkAtoms.h"
10
#include "nsCOMPtr.h"
11
#include "SVGAnimatedPreserveAspectRatio.h"
12
#include "nsError.h"
13
#include "mozilla/dom/SVGAngle.h"
14
#include "mozilla/dom/SVGLengthBinding.h"
15
#include "mozilla/dom/SVGMarkerElement.h"
16
#include "mozilla/dom/SVGMarkerElementBinding.h"
17
#include "mozilla/gfx/Matrix.h"
18
#include "mozilla/FloatingPoint.h"
19
#include "SVGContentUtils.h"
20
21
using namespace mozilla::gfx;
22
using namespace mozilla::dom::SVGMarkerElement_Binding;
23
24
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Marker)
25
26
namespace mozilla {
27
namespace dom {
28
29
using namespace SVGAngle_Binding;
30
31
JSObject*
32
SVGMarkerElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
33
0
{
34
0
  return SVGMarkerElement_Binding::Wrap(aCx, this, aGivenProto);
35
0
}
36
37
nsSVGElement::LengthInfo SVGMarkerElement::sLengthInfo[4] =
38
{
39
  { &nsGkAtoms::refX, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
40
  { &nsGkAtoms::refY, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
41
  { &nsGkAtoms::markerWidth, 3, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
42
  { &nsGkAtoms::markerHeight, 3, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
43
};
44
45
nsSVGEnumMapping SVGMarkerElement::sUnitsMap[] = {
46
  {&nsGkAtoms::strokeWidth, SVG_MARKERUNITS_STROKEWIDTH},
47
  {&nsGkAtoms::userSpaceOnUse, SVG_MARKERUNITS_USERSPACEONUSE},
48
  {nullptr, 0}
49
};
50
51
nsSVGElement::EnumInfo SVGMarkerElement::sEnumInfo[1] =
52
{
53
  { &nsGkAtoms::markerUnits,
54
    sUnitsMap,
55
    SVG_MARKERUNITS_STROKEWIDTH
56
  }
57
};
58
59
nsSVGElement::AngleInfo SVGMarkerElement::sAngleInfo[1] =
60
{
61
  { &nsGkAtoms::orient, 0, SVG_ANGLETYPE_UNSPECIFIED }
62
};
63
64
//----------------------------------------------------------------------
65
// Implementation
66
67
nsresult
68
nsSVGOrientType::SetBaseValue(uint16_t aValue,
69
                              nsSVGElement *aSVGElement)
70
0
{
71
0
  if (aValue == SVG_MARKER_ORIENT_AUTO ||
72
0
      aValue == SVG_MARKER_ORIENT_ANGLE ||
73
0
      aValue == SVG_MARKER_ORIENT_AUTO_START_REVERSE) {
74
0
    SetBaseValue(aValue);
75
0
    aSVGElement->SetAttr(
76
0
      kNameSpaceID_None, nsGkAtoms::orient, nullptr,
77
0
      (aValue == SVG_MARKER_ORIENT_AUTO ?
78
0
        NS_LITERAL_STRING("auto") :
79
0
        aValue == SVG_MARKER_ORIENT_ANGLE ?
80
0
          NS_LITERAL_STRING("0") :
81
0
          NS_LITERAL_STRING("auto-start-reverse")),
82
0
      true);
83
0
    return NS_OK;
84
0
  }
85
0
  return NS_ERROR_DOM_TYPE_ERR;
86
0
}
87
88
already_AddRefed<SVGAnimatedEnumeration>
89
nsSVGOrientType::ToDOMAnimatedEnum(nsSVGElement *aSVGElement)
90
0
{
91
0
  RefPtr<SVGAnimatedEnumeration> toReturn =
92
0
    new DOMAnimatedEnum(this, aSVGElement);
93
0
  return toReturn.forget();
94
0
}
95
96
SVGMarkerElement::SVGMarkerElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
97
  : SVGMarkerElementBase(std::move(aNodeInfo)), mCoordCtx(nullptr)
98
0
{
99
0
}
100
101
//----------------------------------------------------------------------
102
// nsINode methods
103
104
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGMarkerElement)
105
106
//----------------------------------------------------------------------
107
108
already_AddRefed<SVGAnimatedRect>
109
SVGMarkerElement::ViewBox()
110
0
{
111
0
  return mViewBox.ToSVGAnimatedRect(this);
112
0
}
113
114
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
115
SVGMarkerElement::PreserveAspectRatio()
116
0
{
117
0
  return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
118
0
}
119
120
//----------------------------------------------------------------------
121
122
already_AddRefed<SVGAnimatedLength>
123
SVGMarkerElement::RefX()
124
0
{
125
0
  return mLengthAttributes[REFX].ToDOMAnimatedLength(this);
126
0
}
127
128
already_AddRefed<SVGAnimatedLength>
129
SVGMarkerElement::RefY()
130
0
{
131
0
  return mLengthAttributes[REFY].ToDOMAnimatedLength(this);
132
0
}
133
134
already_AddRefed<SVGAnimatedEnumeration>
135
SVGMarkerElement::MarkerUnits()
136
0
{
137
0
  return mEnumAttributes[MARKERUNITS].ToDOMAnimatedEnum(this);
138
0
}
139
140
already_AddRefed<SVGAnimatedLength>
141
SVGMarkerElement::MarkerWidth()
142
0
{
143
0
  return mLengthAttributes[MARKERWIDTH].ToDOMAnimatedLength(this);
144
0
}
145
146
already_AddRefed<SVGAnimatedLength>
147
SVGMarkerElement::MarkerHeight()
148
0
{
149
0
  return mLengthAttributes[MARKERHEIGHT].ToDOMAnimatedLength(this);
150
0
}
151
152
already_AddRefed<SVGAnimatedEnumeration>
153
SVGMarkerElement::OrientType()
154
0
{
155
0
  return mOrientType.ToDOMAnimatedEnum(this);
156
0
}
157
158
already_AddRefed<SVGAnimatedAngle>
159
SVGMarkerElement::OrientAngle()
160
0
{
161
0
  return mAngleAttributes[ORIENT].ToDOMAnimatedAngle(this);
162
0
}
163
164
void SVGMarkerElement::SetOrientToAuto()
165
0
{
166
0
  SetAttr(kNameSpaceID_None, nsGkAtoms::orient, nullptr,
167
0
          NS_LITERAL_STRING("auto"), true);
168
0
}
169
170
void
171
SVGMarkerElement::SetOrientToAngle(SVGAngle& angle, ErrorResult& rv)
172
0
{
173
0
  float f = angle.Value();
174
0
  if (!IsFinite(f)) {
175
0
    rv.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
176
0
    return;
177
0
  }
178
0
  mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
179
0
  mAngleAttributes[ORIENT].SetBaseValue(f, angle.UnitType(), this, true);
180
0
}
181
182
//----------------------------------------------------------------------
183
// nsIContent methods
184
185
NS_IMETHODIMP_(bool)
186
SVGMarkerElement::IsAttributeMapped(const nsAtom* name) const
187
0
{
188
0
  static const MappedAttributeEntry* const map[] = {
189
0
    sFEFloodMap,
190
0
    sFiltersMap,
191
0
    sFontSpecificationMap,
192
0
    sGradientStopMap,
193
0
    sLightingEffectsMap,
194
0
    sMarkersMap,
195
0
    sTextContentElementsMap,
196
0
    sViewportsMap,
197
0
    sColorMap,
198
0
    sFillStrokeMap,
199
0
    sGraphicsMap
200
0
  };
201
0
202
0
  return FindAttributeDependence(name, map) ||
203
0
    SVGMarkerElementBase::IsAttributeMapped(name);
204
0
}
205
206
//----------------------------------------------------------------------
207
// nsSVGElement methods
208
209
bool
210
SVGMarkerElement::ParseAttribute(int32_t aNameSpaceID, nsAtom* aName,
211
                                 const nsAString& aValue,
212
                                 nsIPrincipal* aMaybeScriptedPrincipal,
213
                                 nsAttrValue& aResult)
214
0
{
215
0
  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::orient) {
216
0
    if (aValue.EqualsLiteral("auto")) {
217
0
      mOrientType.SetBaseValue(SVG_MARKER_ORIENT_AUTO);
218
0
      aResult.SetTo(aValue);
219
0
      mAngleAttributes[ORIENT].SetBaseValue(0.f, SVG_ANGLETYPE_UNSPECIFIED,
220
0
                                            this, false);
221
0
      return true;
222
0
    }
223
0
    if (aValue.EqualsLiteral("auto-start-reverse")) {
224
0
      mOrientType.SetBaseValue(SVG_MARKER_ORIENT_AUTO_START_REVERSE);
225
0
      aResult.SetTo(aValue);
226
0
      mAngleAttributes[ORIENT].SetBaseValue(0.f, SVG_ANGLETYPE_UNSPECIFIED,
227
0
                                            this, false);
228
0
      return true;
229
0
    }
230
0
    mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
231
0
  }
232
0
  return SVGMarkerElementBase::ParseAttribute(aNameSpaceID, aName,
233
0
                                              aValue,
234
0
                                              aMaybeScriptedPrincipal,
235
0
                                              aResult);
236
0
}
237
238
nsresult
239
SVGMarkerElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
240
                                const nsAttrValue* aValue,
241
                                const nsAttrValue* aOldValue,
242
                                nsIPrincipal* aMaybeScriptedPrincipal,
243
                                bool aNotify)
244
0
{
245
0
  if (!aValue && aNamespaceID == kNameSpaceID_None &&
246
0
      aName == nsGkAtoms::orient) {
247
0
    mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
248
0
  }
249
0
250
0
  return SVGMarkerElementBase::AfterSetAttr(aNamespaceID, aName,
251
0
                                            aValue, aOldValue,
252
0
                                            aMaybeScriptedPrincipal,
253
0
                                            aNotify);
254
0
}
255
256
//----------------------------------------------------------------------
257
// nsSVGElement methods
258
259
void
260
SVGMarkerElement::SetParentCoordCtxProvider(SVGViewportElement *aContext)
261
0
{
262
0
  mCoordCtx = aContext;
263
0
  mViewBoxToViewportTransform = nullptr;
264
0
}
265
266
/* virtual */ bool
267
SVGMarkerElement::HasValidDimensions() const
268
0
{
269
0
  return (!mLengthAttributes[MARKERWIDTH].IsExplicitlySet() ||
270
0
           mLengthAttributes[MARKERWIDTH].GetAnimValInSpecifiedUnits() > 0) &&
271
0
         (!mLengthAttributes[MARKERHEIGHT].IsExplicitlySet() ||
272
0
           mLengthAttributes[MARKERHEIGHT].GetAnimValInSpecifiedUnits() > 0);
273
0
}
274
275
nsSVGElement::LengthAttributesInfo
276
SVGMarkerElement::GetLengthInfo()
277
0
{
278
0
  return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
279
0
                              ArrayLength(sLengthInfo));
280
0
}
281
282
nsSVGElement::AngleAttributesInfo
283
SVGMarkerElement::GetAngleInfo()
284
0
{
285
0
  return AngleAttributesInfo(mAngleAttributes, sAngleInfo,
286
0
                             ArrayLength(sAngleInfo));
287
0
}
288
289
nsSVGElement::EnumAttributesInfo
290
SVGMarkerElement::GetEnumInfo()
291
0
{
292
0
  return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
293
0
                            ArrayLength(sEnumInfo));
294
0
}
295
296
nsSVGViewBox *
297
SVGMarkerElement::GetViewBox()
298
0
{
299
0
  return &mViewBox;
300
0
}
301
302
SVGAnimatedPreserveAspectRatio *
303
SVGMarkerElement::GetPreserveAspectRatio()
304
0
{
305
0
  return &mPreserveAspectRatio;
306
0
}
307
308
//----------------------------------------------------------------------
309
// public helpers
310
311
gfx::Matrix
312
SVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
313
                                     const nsSVGMark& aMark)
314
0
{
315
0
  float scale = mEnumAttributes[MARKERUNITS].GetAnimValue() ==
316
0
                     SVG_MARKERUNITS_STROKEWIDTH ? aStrokeWidth : 1.0f;
317
0
318
0
  float angle;
319
0
  switch (mOrientType.GetAnimValueInternal()) {
320
0
    case SVG_MARKER_ORIENT_AUTO:
321
0
      angle = aMark.angle;
322
0
      break;
323
0
    case SVG_MARKER_ORIENT_AUTO_START_REVERSE:
324
0
      angle = aMark.angle + (aMark.type == nsSVGMark::eStart ? M_PI : 0.0f);
325
0
      break;
326
0
    default: // SVG_MARKER_ORIENT_ANGLE
327
0
      angle = mAngleAttributes[ORIENT].GetAnimValue() * M_PI / 180.0f;
328
0
      break;
329
0
  }
330
0
331
0
  return gfx::Matrix(cos(angle) * scale,   sin(angle) * scale,
332
0
                     -sin(angle) * scale,  cos(angle) * scale,
333
0
                     aMark.x,              aMark.y);
334
0
}
335
336
nsSVGViewBoxRect
337
SVGMarkerElement::GetViewBoxRect()
338
0
{
339
0
  if (mViewBox.HasRect()) {
340
0
    return mViewBox.GetAnimValue();
341
0
  }
342
0
  return nsSVGViewBoxRect(
343
0
           0, 0,
344
0
           mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx),
345
0
           mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx));
346
0
}
347
348
gfx::Matrix
349
SVGMarkerElement::GetViewBoxTransform()
350
0
{
351
0
  if (!mViewBoxToViewportTransform) {
352
0
    float viewportWidth =
353
0
      mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx);
354
0
    float viewportHeight =
355
0
      mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx);
356
0
357
0
    nsSVGViewBoxRect viewbox = GetViewBoxRect();
358
0
359
0
    MOZ_ASSERT(viewbox.width > 0.0f && viewbox.height > 0.0f,
360
0
               "Rendering should be disabled");
361
0
362
0
    gfx::Matrix viewBoxTM =
363
0
      SVGContentUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
364
0
                                           viewbox.x, viewbox.y,
365
0
                                           viewbox.width, viewbox.height,
366
0
                                           mPreserveAspectRatio);
367
0
368
0
    float refX = mLengthAttributes[REFX].GetAnimValue(mCoordCtx);
369
0
    float refY = mLengthAttributes[REFY].GetAnimValue(mCoordCtx);
370
0
371
0
    gfx::Point ref = viewBoxTM.TransformPoint(gfx::Point(refX, refY));
372
0
373
0
    Matrix TM = viewBoxTM;
374
0
    TM.PostTranslate(-ref.x, -ref.y);
375
0
376
0
    mViewBoxToViewportTransform = new gfx::Matrix(TM);
377
0
  }
378
0
379
0
  return *mViewBoxToViewportTransform;
380
0
}
381
382
} // namespace dom
383
} // namespace mozilla