/src/mozilla-central/dom/svg/nsSVGElement.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 | | #include "mozilla/DebugOnly.h" |
9 | | #include "mozilla/Unused.h" |
10 | | |
11 | | #include "nsSVGElement.h" |
12 | | |
13 | | #include "mozilla/dom/SVGLengthBinding.h" |
14 | | #include "mozilla/dom/SVGSVGElement.h" |
15 | | #include "mozilla/dom/SVGTests.h" |
16 | | #include "mozilla/dom/SVGUnitTypesBinding.h" |
17 | | #include "nsContentUtils.h" |
18 | | #include "nsICSSDeclaration.h" |
19 | | #include "nsIContentInlines.h" |
20 | | #include "nsIDocument.h" |
21 | | #include "mozilla/InternalMutationEvent.h" |
22 | | #include "mozAutoDocUpdate.h" |
23 | | #include "nsError.h" |
24 | | #include "nsIPresShell.h" |
25 | | #include "nsGkAtoms.h" |
26 | | #include "nsCSSProps.h" |
27 | | #include "mozilla/EventListenerManager.h" |
28 | | #include "nsLayoutUtils.h" |
29 | | #include "nsSVGAnimatedTransformList.h" |
30 | | #include "nsSVGLength2.h" |
31 | | #include "nsSVGNumber2.h" |
32 | | #include "nsSVGNumberPair.h" |
33 | | #include "nsSVGInteger.h" |
34 | | #include "nsSVGIntegerPair.h" |
35 | | #include "nsSVGAngle.h" |
36 | | #include "nsSVGBoolean.h" |
37 | | #include "nsSVGEnum.h" |
38 | | #include "nsSVGViewBox.h" |
39 | | #include "nsSVGString.h" |
40 | | #include "mozilla/dom/SVGAnimatedEnumeration.h" |
41 | | #include "SVGAnimatedNumberList.h" |
42 | | #include "SVGAnimatedLengthList.h" |
43 | | #include "SVGAnimatedPointList.h" |
44 | | #include "SVGAnimatedPathSegList.h" |
45 | | #include "SVGContentUtils.h" |
46 | | #include "SVGGeometryElement.h" |
47 | | #include "nsIFrame.h" |
48 | | #include "nsQueryObject.h" |
49 | | #include <stdarg.h> |
50 | | #include "SVGMotionSMILAttr.h" |
51 | | #include "nsAttrValueOrString.h" |
52 | | #include "nsSMILAnimationController.h" |
53 | | #include "mozilla/dom/MutationEventBinding.h" |
54 | | #include "mozilla/dom/SVGElementBinding.h" |
55 | | #include "mozilla/DeclarationBlock.h" |
56 | | #include "mozilla/Unused.h" |
57 | | #include "mozilla/RestyleManager.h" |
58 | | |
59 | | using namespace mozilla; |
60 | | using namespace mozilla::dom; |
61 | | using namespace mozilla::dom::SVGUnitTypes_Binding; |
62 | | |
63 | | // This is needed to ensure correct handling of calls to the |
64 | | // vararg-list methods in this file: |
65 | | // nsSVGElement::GetAnimated{Length,Number,Integer}Values |
66 | | // See bug 547964 for details: |
67 | | static_assert(sizeof(void*) == sizeof(nullptr), |
68 | | "nullptr should be the correct size"); |
69 | | |
70 | | nsresult |
71 | | NS_NewSVGElement(Element **aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) |
72 | 0 | { |
73 | 0 | RefPtr<nsSVGElement> it = new nsSVGElement(std::move(aNodeInfo)); |
74 | 0 | nsresult rv = it->Init(); |
75 | 0 |
|
76 | 0 | if (NS_FAILED(rv)) { |
77 | 0 | return rv; |
78 | 0 | } |
79 | 0 | |
80 | 0 | it.forget(aResult); |
81 | 0 | return rv; |
82 | 0 | } |
83 | | |
84 | | NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGElement) |
85 | | |
86 | | nsSVGEnumMapping nsSVGElement::sSVGUnitTypesMap[] = { |
87 | | {&nsGkAtoms::userSpaceOnUse, SVG_UNIT_TYPE_USERSPACEONUSE}, |
88 | | {&nsGkAtoms::objectBoundingBox, SVG_UNIT_TYPE_OBJECTBOUNDINGBOX}, |
89 | | {nullptr, 0} |
90 | | }; |
91 | | |
92 | | nsSVGElement::nsSVGElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) |
93 | | : nsSVGElementBase(std::move(aNodeInfo)) |
94 | 0 | { |
95 | 0 | } |
96 | | |
97 | | nsSVGElement::~nsSVGElement() |
98 | 0 | { |
99 | 0 | OwnerDoc()->UnscheduleSVGForPresAttrEvaluation(this); |
100 | 0 | } |
101 | | |
102 | | JSObject* |
103 | | nsSVGElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) |
104 | 0 | { |
105 | 0 | return SVGElement_Binding::Wrap(aCx, this, aGivenProto); |
106 | 0 | } |
107 | | |
108 | | //---------------------------------------------------------------------- |
109 | | // nsSVGElement methods |
110 | | |
111 | | void |
112 | | nsSVGElement::DidAnimateClass() |
113 | 0 | { |
114 | 0 | // For Servo, snapshot the element before we change it. |
115 | 0 | nsIPresShell* shell = OwnerDoc()->GetShell(); |
116 | 0 | if (shell) { |
117 | 0 | nsPresContext* presContext = shell->GetPresContext(); |
118 | 0 | if (presContext) { |
119 | 0 | presContext->RestyleManager()->ClassAttributeWillBeChangedBySMIL(this); |
120 | 0 | } |
121 | 0 | } |
122 | 0 |
|
123 | 0 | nsAutoString src; |
124 | 0 | mClassAttribute.GetAnimValue(src, this); |
125 | 0 | if (!mClassAnimAttr) { |
126 | 0 | mClassAnimAttr = new nsAttrValue(); |
127 | 0 | } |
128 | 0 | mClassAnimAttr->ParseAtomArray(src); |
129 | 0 |
|
130 | 0 | if (shell) { |
131 | 0 | shell->RestyleForAnimation(this, eRestyle_Self); |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | nsresult |
136 | | nsSVGElement::Init() |
137 | 0 | { |
138 | 0 | // Set up length attributes - can't do this in the constructor |
139 | 0 | // because we can't do a virtual call at that point |
140 | 0 |
|
141 | 0 | LengthAttributesInfo lengthInfo = GetLengthInfo(); |
142 | 0 |
|
143 | 0 | uint32_t i; |
144 | 0 | for (i = 0; i < lengthInfo.mLengthCount; i++) { |
145 | 0 | lengthInfo.Reset(i); |
146 | 0 | } |
147 | 0 |
|
148 | 0 | NumberAttributesInfo numberInfo = GetNumberInfo(); |
149 | 0 |
|
150 | 0 | for (i = 0; i < numberInfo.mNumberCount; i++) { |
151 | 0 | numberInfo.Reset(i); |
152 | 0 | } |
153 | 0 |
|
154 | 0 | NumberPairAttributesInfo numberPairInfo = GetNumberPairInfo(); |
155 | 0 |
|
156 | 0 | for (i = 0; i < numberPairInfo.mNumberPairCount; i++) { |
157 | 0 | numberPairInfo.Reset(i); |
158 | 0 | } |
159 | 0 |
|
160 | 0 | IntegerAttributesInfo integerInfo = GetIntegerInfo(); |
161 | 0 |
|
162 | 0 | for (i = 0; i < integerInfo.mIntegerCount; i++) { |
163 | 0 | integerInfo.Reset(i); |
164 | 0 | } |
165 | 0 |
|
166 | 0 | IntegerPairAttributesInfo integerPairInfo = GetIntegerPairInfo(); |
167 | 0 |
|
168 | 0 | for (i = 0; i < integerPairInfo.mIntegerPairCount; i++) { |
169 | 0 | integerPairInfo.Reset(i); |
170 | 0 | } |
171 | 0 |
|
172 | 0 | AngleAttributesInfo angleInfo = GetAngleInfo(); |
173 | 0 |
|
174 | 0 | for (i = 0; i < angleInfo.mAngleCount; i++) { |
175 | 0 | angleInfo.Reset(i); |
176 | 0 | } |
177 | 0 |
|
178 | 0 | BooleanAttributesInfo booleanInfo = GetBooleanInfo(); |
179 | 0 |
|
180 | 0 | for (i = 0; i < booleanInfo.mBooleanCount; i++) { |
181 | 0 | booleanInfo.Reset(i); |
182 | 0 | } |
183 | 0 |
|
184 | 0 | EnumAttributesInfo enumInfo = GetEnumInfo(); |
185 | 0 |
|
186 | 0 | for (i = 0; i < enumInfo.mEnumCount; i++) { |
187 | 0 | enumInfo.Reset(i); |
188 | 0 | } |
189 | 0 |
|
190 | 0 | nsSVGViewBox *viewBox = GetViewBox(); |
191 | 0 |
|
192 | 0 | if (viewBox) { |
193 | 0 | viewBox->Init(); |
194 | 0 | } |
195 | 0 |
|
196 | 0 | SVGAnimatedPreserveAspectRatio *preserveAspectRatio = |
197 | 0 | GetPreserveAspectRatio(); |
198 | 0 |
|
199 | 0 | if (preserveAspectRatio) { |
200 | 0 | preserveAspectRatio->Init(); |
201 | 0 | } |
202 | 0 |
|
203 | 0 | LengthListAttributesInfo lengthListInfo = GetLengthListInfo(); |
204 | 0 |
|
205 | 0 | for (i = 0; i < lengthListInfo.mLengthListCount; i++) { |
206 | 0 | lengthListInfo.Reset(i); |
207 | 0 | } |
208 | 0 |
|
209 | 0 | NumberListAttributesInfo numberListInfo = GetNumberListInfo(); |
210 | 0 |
|
211 | 0 | for (i = 0; i < numberListInfo.mNumberListCount; i++) { |
212 | 0 | numberListInfo.Reset(i); |
213 | 0 | } |
214 | 0 |
|
215 | 0 | // No need to reset SVGPointList since the default value is always the same |
216 | 0 | // (an empty list). |
217 | 0 |
|
218 | 0 | // No need to reset SVGPathData since the default value is always the same |
219 | 0 | // (an empty list). |
220 | 0 |
|
221 | 0 | StringAttributesInfo stringInfo = GetStringInfo(); |
222 | 0 |
|
223 | 0 | for (i = 0; i < stringInfo.mStringCount; i++) { |
224 | 0 | stringInfo.Reset(i); |
225 | 0 | } |
226 | 0 |
|
227 | 0 | return NS_OK; |
228 | 0 | } |
229 | | |
230 | | //---------------------------------------------------------------------- |
231 | | // Implementation |
232 | | |
233 | | //---------------------------------------------------------------------- |
234 | | // nsIContent methods |
235 | | |
236 | | nsresult |
237 | | nsSVGElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, |
238 | | nsIContent* aBindingParent) |
239 | 0 | { |
240 | 0 | nsresult rv = nsSVGElementBase::BindToTree(aDocument, aParent, |
241 | 0 | aBindingParent); |
242 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
243 | 0 |
|
244 | 0 | if (!MayHaveStyle()) { |
245 | 0 | return NS_OK; |
246 | 0 | } |
247 | 0 | const nsAttrValue* oldVal = mAttrs.GetAttr(nsGkAtoms::style); |
248 | 0 |
|
249 | 0 | if (oldVal && oldVal->Type() == nsAttrValue::eCSSDeclaration) { |
250 | 0 | // we need to force a reparse because the baseURI of the document |
251 | 0 | // may have changed, and in particular because we may be clones of |
252 | 0 | // XBL anonymous content now being bound to the document we should |
253 | 0 | // render in and due to the hacky way in which we implement the |
254 | 0 | // interaction of XBL and SVG resources. Once we have a sane |
255 | 0 | // ownerDocument on XBL anonymous content, this can all go away. |
256 | 0 | nsAttrValue attrValue; |
257 | 0 | nsAutoString stringValue; |
258 | 0 | oldVal->ToString(stringValue); |
259 | 0 | // Force in data doc, since we already have a style rule |
260 | 0 | ParseStyleAttribute(stringValue, nullptr, attrValue, true); |
261 | 0 | // Don't bother going through SetInlineStyleDeclaration; we don't |
262 | 0 | // want to fire off mutation events or document notifications anyway |
263 | 0 | bool oldValueSet; |
264 | 0 | rv = mAttrs.SetAndSwapAttr(nsGkAtoms::style, attrValue, &oldValueSet); |
265 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
266 | 0 | } |
267 | 0 |
|
268 | 0 | return NS_OK; |
269 | 0 | } |
270 | | |
271 | | nsresult |
272 | | nsSVGElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, |
273 | | const nsAttrValue* aValue, |
274 | | const nsAttrValue* aOldValue, |
275 | | nsIPrincipal* aSubjectPrincipal, |
276 | | bool aNotify) |
277 | 0 | { |
278 | 0 | // We don't currently use nsMappedAttributes within SVG. If this changes, we |
279 | 0 | // need to be very careful because some nsAttrValues used by SVG point to |
280 | 0 | // member data of SVG elements and if an nsAttrValue outlives the SVG element |
281 | 0 | // whose data it points to (by virtue of being stored in |
282 | 0 | // mAttrs->mMappedAttributes, meaning it's shared between |
283 | 0 | // elements), the pointer will dangle. See bug 724680. |
284 | 0 | MOZ_ASSERT(!mAttrs.HasMappedAttrs(), |
285 | 0 | "Unexpected use of nsMappedAttributes within SVG"); |
286 | 0 |
|
287 | 0 | // If this is an svg presentation attribute we need to map it into |
288 | 0 | // the content declaration block. |
289 | 0 | // XXX For some reason incremental mapping doesn't work, so for now |
290 | 0 | // just delete the style rule and lazily reconstruct it as needed). |
291 | 0 | if (aNamespaceID == kNameSpaceID_None && IsAttributeMapped(aName)) { |
292 | 0 | mContentDeclarationBlock = nullptr; |
293 | 0 | OwnerDoc()->ScheduleSVGForPresAttrEvaluation(this); |
294 | 0 | } |
295 | 0 |
|
296 | 0 | if (IsEventAttributeName(aName) && aValue) { |
297 | 0 | MOZ_ASSERT(aValue->Type() == nsAttrValue::eString, |
298 | 0 | "Expected string value for script body"); |
299 | 0 | nsresult rv = SetEventHandler(GetEventNameForAttr(aName), |
300 | 0 | aValue->GetStringValue()); |
301 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
302 | 0 | } |
303 | 0 |
|
304 | 0 | return nsSVGElementBase::AfterSetAttr(aNamespaceID, aName, aValue, aOldValue, |
305 | 0 | aSubjectPrincipal, aNotify); |
306 | 0 | } |
307 | | |
308 | | bool |
309 | | nsSVGElement::ParseAttribute(int32_t aNamespaceID, |
310 | | nsAtom* aAttribute, |
311 | | const nsAString& aValue, |
312 | | nsIPrincipal* aMaybeScriptedPrincipal, |
313 | | nsAttrValue& aResult) |
314 | 0 | { |
315 | 0 | nsresult rv = NS_OK; |
316 | 0 | bool foundMatch = false; |
317 | 0 | bool didSetResult = false; |
318 | 0 |
|
319 | 0 | if (aNamespaceID == kNameSpaceID_None) { |
320 | 0 | // Check for nsSVGLength2 attribute |
321 | 0 | LengthAttributesInfo lengthInfo = GetLengthInfo(); |
322 | 0 |
|
323 | 0 | uint32_t i; |
324 | 0 | for (i = 0; i < lengthInfo.mLengthCount; i++) { |
325 | 0 | if (aAttribute == *lengthInfo.mLengthInfo[i].mName) { |
326 | 0 | rv = lengthInfo.mLengths[i].SetBaseValueString(aValue, this, false); |
327 | 0 | if (NS_FAILED(rv)) { |
328 | 0 | lengthInfo.Reset(i); |
329 | 0 | } else { |
330 | 0 | aResult.SetTo(lengthInfo.mLengths[i], &aValue); |
331 | 0 | didSetResult = true; |
332 | 0 | } |
333 | 0 | foundMatch = true; |
334 | 0 | break; |
335 | 0 | } |
336 | 0 | } |
337 | 0 |
|
338 | 0 | if (!foundMatch) { |
339 | 0 | // Check for SVGAnimatedLengthList attribute |
340 | 0 | LengthListAttributesInfo lengthListInfo = GetLengthListInfo(); |
341 | 0 | for (i = 0; i < lengthListInfo.mLengthListCount; i++) { |
342 | 0 | if (aAttribute == *lengthListInfo.mLengthListInfo[i].mName) { |
343 | 0 | rv = lengthListInfo.mLengthLists[i].SetBaseValueString(aValue); |
344 | 0 | if (NS_FAILED(rv)) { |
345 | 0 | lengthListInfo.Reset(i); |
346 | 0 | } else { |
347 | 0 | aResult.SetTo(lengthListInfo.mLengthLists[i].GetBaseValue(), |
348 | 0 | &aValue); |
349 | 0 | didSetResult = true; |
350 | 0 | } |
351 | 0 | foundMatch = true; |
352 | 0 | break; |
353 | 0 | } |
354 | 0 | } |
355 | 0 | } |
356 | 0 |
|
357 | 0 | if (!foundMatch) { |
358 | 0 | // Check for SVGAnimatedNumberList attribute |
359 | 0 | NumberListAttributesInfo numberListInfo = GetNumberListInfo(); |
360 | 0 | for (i = 0; i < numberListInfo.mNumberListCount; i++) { |
361 | 0 | if (aAttribute == *numberListInfo.mNumberListInfo[i].mName) { |
362 | 0 | rv = numberListInfo.mNumberLists[i].SetBaseValueString(aValue); |
363 | 0 | if (NS_FAILED(rv)) { |
364 | 0 | numberListInfo.Reset(i); |
365 | 0 | } else { |
366 | 0 | aResult.SetTo(numberListInfo.mNumberLists[i].GetBaseValue(), |
367 | 0 | &aValue); |
368 | 0 | didSetResult = true; |
369 | 0 | } |
370 | 0 | foundMatch = true; |
371 | 0 | break; |
372 | 0 | } |
373 | 0 | } |
374 | 0 | } |
375 | 0 |
|
376 | 0 | if (!foundMatch) { |
377 | 0 | // Check for SVGAnimatedPointList attribute |
378 | 0 | if (GetPointListAttrName() == aAttribute) { |
379 | 0 | SVGAnimatedPointList* pointList = GetAnimatedPointList(); |
380 | 0 | if (pointList) { |
381 | 0 | pointList->SetBaseValueString(aValue); |
382 | 0 | // The spec says we parse everything up to the failure, so we DON'T |
383 | 0 | // need to check the result of SetBaseValueString or call |
384 | 0 | // pointList->ClearBaseValue() if it fails |
385 | 0 | aResult.SetTo(pointList->GetBaseValue(), &aValue); |
386 | 0 | didSetResult = true; |
387 | 0 | foundMatch = true; |
388 | 0 | } |
389 | 0 | } |
390 | 0 | } |
391 | 0 |
|
392 | 0 | if (!foundMatch) { |
393 | 0 | // Check for SVGAnimatedPathSegList attribute |
394 | 0 | if (GetPathDataAttrName() == aAttribute) { |
395 | 0 | SVGAnimatedPathSegList* segList = GetAnimPathSegList(); |
396 | 0 | if (segList) { |
397 | 0 | segList->SetBaseValueString(aValue); |
398 | 0 | // The spec says we parse everything up to the failure, so we DON'T |
399 | 0 | // need to check the result of SetBaseValueString or call |
400 | 0 | // segList->ClearBaseValue() if it fails |
401 | 0 | aResult.SetTo(segList->GetBaseValue(), &aValue); |
402 | 0 | didSetResult = true; |
403 | 0 | foundMatch = true; |
404 | 0 | } |
405 | 0 | } |
406 | 0 | } |
407 | 0 |
|
408 | 0 | if (!foundMatch) { |
409 | 0 | // Check for nsSVGNumber2 attribute |
410 | 0 | NumberAttributesInfo numberInfo = GetNumberInfo(); |
411 | 0 | for (i = 0; i < numberInfo.mNumberCount; i++) { |
412 | 0 | if (aAttribute == *numberInfo.mNumberInfo[i].mName) { |
413 | 0 | rv = numberInfo.mNumbers[i].SetBaseValueString(aValue, this); |
414 | 0 | if (NS_FAILED(rv)) { |
415 | 0 | numberInfo.Reset(i); |
416 | 0 | } else { |
417 | 0 | aResult.SetTo(numberInfo.mNumbers[i].GetBaseValue(), &aValue); |
418 | 0 | didSetResult = true; |
419 | 0 | } |
420 | 0 | foundMatch = true; |
421 | 0 | break; |
422 | 0 | } |
423 | 0 | } |
424 | 0 | } |
425 | 0 |
|
426 | 0 | if (!foundMatch) { |
427 | 0 | // Check for nsSVGNumberPair attribute |
428 | 0 | NumberPairAttributesInfo numberPairInfo = GetNumberPairInfo(); |
429 | 0 | for (i = 0; i < numberPairInfo.mNumberPairCount; i++) { |
430 | 0 | if (aAttribute == *numberPairInfo.mNumberPairInfo[i].mName) { |
431 | 0 | rv = numberPairInfo.mNumberPairs[i].SetBaseValueString(aValue, this); |
432 | 0 | if (NS_FAILED(rv)) { |
433 | 0 | numberPairInfo.Reset(i); |
434 | 0 | } else { |
435 | 0 | aResult.SetTo(numberPairInfo.mNumberPairs[i], &aValue); |
436 | 0 | didSetResult = true; |
437 | 0 | } |
438 | 0 | foundMatch = true; |
439 | 0 | break; |
440 | 0 | } |
441 | 0 | } |
442 | 0 | } |
443 | 0 |
|
444 | 0 | if (!foundMatch) { |
445 | 0 | // Check for nsSVGInteger attribute |
446 | 0 | IntegerAttributesInfo integerInfo = GetIntegerInfo(); |
447 | 0 | for (i = 0; i < integerInfo.mIntegerCount; i++) { |
448 | 0 | if (aAttribute == *integerInfo.mIntegerInfo[i].mName) { |
449 | 0 | rv = integerInfo.mIntegers[i].SetBaseValueString(aValue, this); |
450 | 0 | if (NS_FAILED(rv)) { |
451 | 0 | integerInfo.Reset(i); |
452 | 0 | } else { |
453 | 0 | aResult.SetTo(integerInfo.mIntegers[i].GetBaseValue(), &aValue); |
454 | 0 | didSetResult = true; |
455 | 0 | } |
456 | 0 | foundMatch = true; |
457 | 0 | break; |
458 | 0 | } |
459 | 0 | } |
460 | 0 | } |
461 | 0 |
|
462 | 0 | if (!foundMatch) { |
463 | 0 | // Check for nsSVGIntegerPair attribute |
464 | 0 | IntegerPairAttributesInfo integerPairInfo = GetIntegerPairInfo(); |
465 | 0 | for (i = 0; i < integerPairInfo.mIntegerPairCount; i++) { |
466 | 0 | if (aAttribute == *integerPairInfo.mIntegerPairInfo[i].mName) { |
467 | 0 | rv = |
468 | 0 | integerPairInfo.mIntegerPairs[i].SetBaseValueString(aValue, this); |
469 | 0 | if (NS_FAILED(rv)) { |
470 | 0 | integerPairInfo.Reset(i); |
471 | 0 | } else { |
472 | 0 | aResult.SetTo(integerPairInfo.mIntegerPairs[i], &aValue); |
473 | 0 | didSetResult = true; |
474 | 0 | } |
475 | 0 | foundMatch = true; |
476 | 0 | break; |
477 | 0 | } |
478 | 0 | } |
479 | 0 | } |
480 | 0 |
|
481 | 0 | if (!foundMatch) { |
482 | 0 | // Check for nsSVGAngle attribute |
483 | 0 | AngleAttributesInfo angleInfo = GetAngleInfo(); |
484 | 0 | for (i = 0; i < angleInfo.mAngleCount; i++) { |
485 | 0 | if (aAttribute == *angleInfo.mAngleInfo[i].mName) { |
486 | 0 | rv = angleInfo.mAngles[i].SetBaseValueString(aValue, this, false); |
487 | 0 | if (NS_FAILED(rv)) { |
488 | 0 | angleInfo.Reset(i); |
489 | 0 | } else { |
490 | 0 | aResult.SetTo(angleInfo.mAngles[i], &aValue); |
491 | 0 | didSetResult = true; |
492 | 0 | } |
493 | 0 | foundMatch = true; |
494 | 0 | break; |
495 | 0 | } |
496 | 0 | } |
497 | 0 | } |
498 | 0 |
|
499 | 0 | if (!foundMatch) { |
500 | 0 | // Check for nsSVGBoolean attribute |
501 | 0 | BooleanAttributesInfo booleanInfo = GetBooleanInfo(); |
502 | 0 | for (i = 0; i < booleanInfo.mBooleanCount; i++) { |
503 | 0 | if (aAttribute == *booleanInfo.mBooleanInfo[i].mName) { |
504 | 0 | nsAtom *valAtom = NS_GetStaticAtom(aValue); |
505 | 0 | rv = valAtom ? booleanInfo.mBooleans[i].SetBaseValueAtom(valAtom, this) : |
506 | 0 | NS_ERROR_DOM_SYNTAX_ERR; |
507 | 0 | if (NS_FAILED(rv)) { |
508 | 0 | booleanInfo.Reset(i); |
509 | 0 | } else { |
510 | 0 | aResult.SetTo(valAtom); |
511 | 0 | didSetResult = true; |
512 | 0 | } |
513 | 0 | foundMatch = true; |
514 | 0 | break; |
515 | 0 | } |
516 | 0 | } |
517 | 0 | } |
518 | 0 |
|
519 | 0 | if (!foundMatch) { |
520 | 0 | // Check for nsSVGEnum attribute |
521 | 0 | EnumAttributesInfo enumInfo = GetEnumInfo(); |
522 | 0 | for (i = 0; i < enumInfo.mEnumCount; i++) { |
523 | 0 | if (aAttribute == *enumInfo.mEnumInfo[i].mName) { |
524 | 0 | RefPtr<nsAtom> valAtom = NS_Atomize(aValue); |
525 | 0 | rv = enumInfo.mEnums[i].SetBaseValueAtom(valAtom, this); |
526 | 0 | if (NS_FAILED(rv)) { |
527 | 0 | enumInfo.SetUnknownValue(i); |
528 | 0 | } else { |
529 | 0 | aResult.SetTo(valAtom); |
530 | 0 | didSetResult = true; |
531 | 0 | } |
532 | 0 | foundMatch = true; |
533 | 0 | break; |
534 | 0 | } |
535 | 0 | } |
536 | 0 | } |
537 | 0 |
|
538 | 0 | if (!foundMatch) { |
539 | 0 | // Check for conditional processing attributes |
540 | 0 | nsCOMPtr<SVGTests> tests = do_QueryObject(this); |
541 | 0 | if (tests && tests->ParseConditionalProcessingAttribute( |
542 | 0 | aAttribute, aValue, aResult)) { |
543 | 0 | foundMatch = true; |
544 | 0 | } |
545 | 0 | } |
546 | 0 |
|
547 | 0 | if (!foundMatch) { |
548 | 0 | // Check for StringList attribute |
549 | 0 | StringListAttributesInfo stringListInfo = GetStringListInfo(); |
550 | 0 | for (i = 0; i < stringListInfo.mStringListCount; i++) { |
551 | 0 | if (aAttribute == *stringListInfo.mStringListInfo[i].mName) { |
552 | 0 | rv = stringListInfo.mStringLists[i].SetValue(aValue); |
553 | 0 | if (NS_FAILED(rv)) { |
554 | 0 | stringListInfo.Reset(i); |
555 | 0 | } else { |
556 | 0 | aResult.SetTo(stringListInfo.mStringLists[i], &aValue); |
557 | 0 | didSetResult = true; |
558 | 0 | } |
559 | 0 | foundMatch = true; |
560 | 0 | break; |
561 | 0 | } |
562 | 0 | } |
563 | 0 | } |
564 | 0 |
|
565 | 0 | if (!foundMatch) { |
566 | 0 | // Check for nsSVGViewBox attribute |
567 | 0 | if (aAttribute == nsGkAtoms::viewBox) { |
568 | 0 | nsSVGViewBox* viewBox = GetViewBox(); |
569 | 0 | if (viewBox) { |
570 | 0 | rv = viewBox->SetBaseValueString(aValue, this, false); |
571 | 0 | if (NS_FAILED(rv)) { |
572 | 0 | viewBox->Init(); |
573 | 0 | } else { |
574 | 0 | aResult.SetTo(*viewBox, &aValue); |
575 | 0 | didSetResult = true; |
576 | 0 | } |
577 | 0 | foundMatch = true; |
578 | 0 | } |
579 | 0 | // Check for SVGAnimatedPreserveAspectRatio attribute |
580 | 0 | } else if (aAttribute == nsGkAtoms::preserveAspectRatio) { |
581 | 0 | SVGAnimatedPreserveAspectRatio *preserveAspectRatio = |
582 | 0 | GetPreserveAspectRatio(); |
583 | 0 | if (preserveAspectRatio) { |
584 | 0 | rv = preserveAspectRatio->SetBaseValueString(aValue, this, false); |
585 | 0 | if (NS_FAILED(rv)) { |
586 | 0 | preserveAspectRatio->Init(); |
587 | 0 | } else { |
588 | 0 | aResult.SetTo(*preserveAspectRatio, &aValue); |
589 | 0 | didSetResult = true; |
590 | 0 | } |
591 | 0 | foundMatch = true; |
592 | 0 | } |
593 | 0 | // Check for SVGAnimatedTransformList attribute |
594 | 0 | } else if (GetTransformListAttrName() == aAttribute) { |
595 | 0 | // The transform attribute is being set, so we must ensure that the |
596 | 0 | // nsSVGAnimatedTransformList is/has been allocated: |
597 | 0 | nsSVGAnimatedTransformList *transformList = |
598 | 0 | GetAnimatedTransformList(DO_ALLOCATE); |
599 | 0 | rv = transformList->SetBaseValueString(aValue, this); |
600 | 0 | if (NS_FAILED(rv)) { |
601 | 0 | transformList->ClearBaseValue(); |
602 | 0 | } else { |
603 | 0 | aResult.SetTo(transformList->GetBaseValue(), &aValue); |
604 | 0 | didSetResult = true; |
605 | 0 | } |
606 | 0 | foundMatch = true; |
607 | 0 | } else if (aAttribute == nsGkAtoms::tabindex) { |
608 | 0 | didSetResult = aResult.ParseIntValue(aValue); |
609 | 0 | foundMatch = true; |
610 | 0 | } |
611 | 0 | } |
612 | 0 |
|
613 | 0 | if (aAttribute == nsGkAtoms::_class) { |
614 | 0 | mClassAttribute.SetBaseValue(aValue, this, false); |
615 | 0 | aResult.ParseAtomArray(aValue); |
616 | 0 | return true; |
617 | 0 | } |
618 | 0 | |
619 | 0 | if (aAttribute == nsGkAtoms::rel) { |
620 | 0 | aResult.ParseAtomArray(aValue); |
621 | 0 | return true; |
622 | 0 | } |
623 | 0 | } |
624 | 0 | |
625 | 0 | if (!foundMatch) { |
626 | 0 | // Check for nsSVGString attribute |
627 | 0 | StringAttributesInfo stringInfo = GetStringInfo(); |
628 | 0 | for (uint32_t i = 0; i < stringInfo.mStringCount; i++) { |
629 | 0 | if (aNamespaceID == stringInfo.mStringInfo[i].mNamespaceID && |
630 | 0 | aAttribute == *stringInfo.mStringInfo[i].mName) { |
631 | 0 | stringInfo.mStrings[i].SetBaseValue(aValue, this, false); |
632 | 0 | foundMatch = true; |
633 | 0 | break; |
634 | 0 | } |
635 | 0 | } |
636 | 0 | } |
637 | 0 |
|
638 | 0 | if (foundMatch) { |
639 | 0 | if (NS_FAILED(rv)) { |
640 | 0 | ReportAttributeParseFailure(OwnerDoc(), aAttribute, aValue); |
641 | 0 | return false; |
642 | 0 | } |
643 | 0 | if (!didSetResult) { |
644 | 0 | aResult.SetTo(aValue); |
645 | 0 | } |
646 | 0 | return true; |
647 | 0 | } |
648 | 0 |
|
649 | 0 | return nsSVGElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue, |
650 | 0 | aMaybeScriptedPrincipal, aResult); |
651 | 0 | } |
652 | | |
653 | | void |
654 | | nsSVGElement::UnsetAttrInternal(int32_t aNamespaceID, nsAtom* aName, |
655 | | bool aNotify) |
656 | 0 | { |
657 | 0 | // XXXbz there's a bunch of redundancy here with AfterSetAttr. |
658 | 0 | // Maybe consolidate? |
659 | 0 |
|
660 | 0 | if (aNamespaceID == kNameSpaceID_None) { |
661 | 0 | // If this is an svg presentation attribute, remove declaration block to |
662 | 0 | // force an update |
663 | 0 | if (IsAttributeMapped(aName)) { |
664 | 0 | mContentDeclarationBlock = nullptr; |
665 | 0 | } |
666 | 0 |
|
667 | 0 | if (IsEventAttributeName(aName)) { |
668 | 0 | EventListenerManager* manager = GetExistingListenerManager(); |
669 | 0 | if (manager) { |
670 | 0 | nsAtom* eventName = GetEventNameForAttr(aName); |
671 | 0 | manager->RemoveEventHandler(eventName); |
672 | 0 | } |
673 | 0 | return; |
674 | 0 | } |
675 | 0 |
|
676 | 0 | // Check if this is a length attribute going away |
677 | 0 | LengthAttributesInfo lenInfo = GetLengthInfo(); |
678 | 0 |
|
679 | 0 | for (uint32_t i = 0; i < lenInfo.mLengthCount; i++) { |
680 | 0 | if (aName == *lenInfo.mLengthInfo[i].mName) { |
681 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
682 | 0 | lenInfo.Reset(i); |
683 | 0 | return; |
684 | 0 | } |
685 | 0 | } |
686 | 0 |
|
687 | 0 | // Check if this is a length list attribute going away |
688 | 0 | LengthListAttributesInfo lengthListInfo = GetLengthListInfo(); |
689 | 0 |
|
690 | 0 | for (uint32_t i = 0; i < lengthListInfo.mLengthListCount; i++) { |
691 | 0 | if (aName == *lengthListInfo.mLengthListInfo[i].mName) { |
692 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
693 | 0 | lengthListInfo.Reset(i); |
694 | 0 | return; |
695 | 0 | } |
696 | 0 | } |
697 | 0 |
|
698 | 0 | // Check if this is a number list attribute going away |
699 | 0 | NumberListAttributesInfo numberListInfo = GetNumberListInfo(); |
700 | 0 |
|
701 | 0 | for (uint32_t i = 0; i < numberListInfo.mNumberListCount; i++) { |
702 | 0 | if (aName == *numberListInfo.mNumberListInfo[i].mName) { |
703 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
704 | 0 | numberListInfo.Reset(i); |
705 | 0 | return; |
706 | 0 | } |
707 | 0 | } |
708 | 0 |
|
709 | 0 | // Check if this is a point list attribute going away |
710 | 0 | if (GetPointListAttrName() == aName) { |
711 | 0 | SVGAnimatedPointList *pointList = GetAnimatedPointList(); |
712 | 0 | if (pointList) { |
713 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
714 | 0 | pointList->ClearBaseValue(); |
715 | 0 | return; |
716 | 0 | } |
717 | 0 | } |
718 | 0 | |
719 | 0 | // Check if this is a path segment list attribute going away |
720 | 0 | if (GetPathDataAttrName() == aName) { |
721 | 0 | SVGAnimatedPathSegList *segList = GetAnimPathSegList(); |
722 | 0 | if (segList) { |
723 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
724 | 0 | segList->ClearBaseValue(); |
725 | 0 | return; |
726 | 0 | } |
727 | 0 | } |
728 | 0 | |
729 | 0 | // Check if this is a number attribute going away |
730 | 0 | NumberAttributesInfo numInfo = GetNumberInfo(); |
731 | 0 |
|
732 | 0 | for (uint32_t i = 0; i < numInfo.mNumberCount; i++) { |
733 | 0 | if (aName == *numInfo.mNumberInfo[i].mName) { |
734 | 0 | numInfo.Reset(i); |
735 | 0 | return; |
736 | 0 | } |
737 | 0 | } |
738 | 0 |
|
739 | 0 | // Check if this is a number pair attribute going away |
740 | 0 | NumberPairAttributesInfo numPairInfo = GetNumberPairInfo(); |
741 | 0 |
|
742 | 0 | for (uint32_t i = 0; i < numPairInfo.mNumberPairCount; i++) { |
743 | 0 | if (aName == *numPairInfo.mNumberPairInfo[i].mName) { |
744 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
745 | 0 | numPairInfo.Reset(i); |
746 | 0 | return; |
747 | 0 | } |
748 | 0 | } |
749 | 0 |
|
750 | 0 | // Check if this is an integer attribute going away |
751 | 0 | IntegerAttributesInfo intInfo = GetIntegerInfo(); |
752 | 0 |
|
753 | 0 | for (uint32_t i = 0; i < intInfo.mIntegerCount; i++) { |
754 | 0 | if (aName == *intInfo.mIntegerInfo[i].mName) { |
755 | 0 | intInfo.Reset(i); |
756 | 0 | return; |
757 | 0 | } |
758 | 0 | } |
759 | 0 |
|
760 | 0 | // Check if this is an integer pair attribute going away |
761 | 0 | IntegerPairAttributesInfo intPairInfo = GetIntegerPairInfo(); |
762 | 0 |
|
763 | 0 | for (uint32_t i = 0; i < intPairInfo.mIntegerPairCount; i++) { |
764 | 0 | if (aName == *intPairInfo.mIntegerPairInfo[i].mName) { |
765 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
766 | 0 | intPairInfo.Reset(i); |
767 | 0 | return; |
768 | 0 | } |
769 | 0 | } |
770 | 0 |
|
771 | 0 | // Check if this is an angle attribute going away |
772 | 0 | AngleAttributesInfo angleInfo = GetAngleInfo(); |
773 | 0 |
|
774 | 0 | for (uint32_t i = 0; i < angleInfo.mAngleCount; i++) { |
775 | 0 | if (aName == *angleInfo.mAngleInfo[i].mName) { |
776 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
777 | 0 | angleInfo.Reset(i); |
778 | 0 | return; |
779 | 0 | } |
780 | 0 | } |
781 | 0 |
|
782 | 0 | // Check if this is a boolean attribute going away |
783 | 0 | BooleanAttributesInfo boolInfo = GetBooleanInfo(); |
784 | 0 |
|
785 | 0 | for (uint32_t i = 0; i < boolInfo.mBooleanCount; i++) { |
786 | 0 | if (aName == *boolInfo.mBooleanInfo[i].mName) { |
787 | 0 | boolInfo.Reset(i); |
788 | 0 | return; |
789 | 0 | } |
790 | 0 | } |
791 | 0 |
|
792 | 0 | // Check if this is an enum attribute going away |
793 | 0 | EnumAttributesInfo enumInfo = GetEnumInfo(); |
794 | 0 |
|
795 | 0 | for (uint32_t i = 0; i < enumInfo.mEnumCount; i++) { |
796 | 0 | if (aName == *enumInfo.mEnumInfo[i].mName) { |
797 | 0 | enumInfo.Reset(i); |
798 | 0 | return; |
799 | 0 | } |
800 | 0 | } |
801 | 0 |
|
802 | 0 | // Check if this is a nsViewBox attribute going away |
803 | 0 | if (aName == nsGkAtoms::viewBox) { |
804 | 0 | nsSVGViewBox* viewBox = GetViewBox(); |
805 | 0 | if (viewBox) { |
806 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
807 | 0 | viewBox->Init(); |
808 | 0 | return; |
809 | 0 | } |
810 | 0 | } |
811 | 0 | |
812 | 0 | // Check if this is a preserveAspectRatio attribute going away |
813 | 0 | if (aName == nsGkAtoms::preserveAspectRatio) { |
814 | 0 | SVGAnimatedPreserveAspectRatio *preserveAspectRatio = |
815 | 0 | GetPreserveAspectRatio(); |
816 | 0 | if (preserveAspectRatio) { |
817 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
818 | 0 | preserveAspectRatio->Init(); |
819 | 0 | return; |
820 | 0 | } |
821 | 0 | } |
822 | 0 | |
823 | 0 | // Check if this is a transform list attribute going away |
824 | 0 | if (GetTransformListAttrName() == aName) { |
825 | 0 | nsSVGAnimatedTransformList *transformList = GetAnimatedTransformList(); |
826 | 0 | if (transformList) { |
827 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
828 | 0 | transformList->ClearBaseValue(); |
829 | 0 | return; |
830 | 0 | } |
831 | 0 | } |
832 | 0 | |
833 | 0 | // Check for conditional processing attributes |
834 | 0 | nsCOMPtr<SVGTests> tests = do_QueryObject(this); |
835 | 0 | if (tests && tests->IsConditionalProcessingAttribute(aName)) { |
836 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
837 | 0 | tests->UnsetAttr(aName); |
838 | 0 | return; |
839 | 0 | } |
840 | 0 | |
841 | 0 | // Check if this is a string list attribute going away |
842 | 0 | StringListAttributesInfo stringListInfo = GetStringListInfo(); |
843 | 0 |
|
844 | 0 | for (uint32_t i = 0; i < stringListInfo.mStringListCount; i++) { |
845 | 0 | if (aName == *stringListInfo.mStringListInfo[i].mName) { |
846 | 0 | MaybeSerializeAttrBeforeRemoval(aName, aNotify); |
847 | 0 | stringListInfo.Reset(i); |
848 | 0 | return; |
849 | 0 | } |
850 | 0 | } |
851 | 0 |
|
852 | 0 | if (aName == nsGkAtoms::_class) { |
853 | 0 | mClassAttribute.Init(); |
854 | 0 | return; |
855 | 0 | } |
856 | 0 | } |
857 | 0 | |
858 | 0 | // Check if this is a string attribute going away |
859 | 0 | StringAttributesInfo stringInfo = GetStringInfo(); |
860 | 0 |
|
861 | 0 | for (uint32_t i = 0; i < stringInfo.mStringCount; i++) { |
862 | 0 | if (aNamespaceID == stringInfo.mStringInfo[i].mNamespaceID && |
863 | 0 | aName == *stringInfo.mStringInfo[i].mName) { |
864 | 0 | stringInfo.Reset(i); |
865 | 0 | return; |
866 | 0 | } |
867 | 0 | } |
868 | 0 | } |
869 | | |
870 | | nsresult |
871 | | nsSVGElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName, |
872 | | const nsAttrValueOrString* aValue, |
873 | | bool aNotify) |
874 | 0 | { |
875 | 0 | if (!aValue) { |
876 | 0 | UnsetAttrInternal(aNamespaceID, aName, aNotify); |
877 | 0 | } |
878 | 0 | return nsSVGElementBase::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify); |
879 | 0 | } |
880 | | |
881 | | nsChangeHint |
882 | | nsSVGElement::GetAttributeChangeHint(const nsAtom* aAttribute, |
883 | | int32_t aModType) const |
884 | 0 | { |
885 | 0 | nsChangeHint retval = |
886 | 0 | nsSVGElementBase::GetAttributeChangeHint(aAttribute, aModType); |
887 | 0 |
|
888 | 0 | nsCOMPtr<SVGTests> tests = do_QueryObject(const_cast<nsSVGElement*>(this)); |
889 | 0 | if (tests && tests->IsConditionalProcessingAttribute(aAttribute)) { |
890 | 0 | // It would be nice to only reconstruct the frame if the value returned by |
891 | 0 | // SVGTests::PassesConditionalProcessingTests has changed, but we don't |
892 | 0 | // know that |
893 | 0 | retval |= nsChangeHint_ReconstructFrame; |
894 | 0 | } |
895 | 0 | return retval; |
896 | 0 | } |
897 | | |
898 | | bool |
899 | | nsSVGElement::IsNodeOfType(uint32_t aFlags) const |
900 | 0 | { |
901 | 0 | return false; |
902 | 0 | } |
903 | | |
904 | | void |
905 | | nsSVGElement::NodeInfoChanged(nsIDocument* aOldDoc) |
906 | 0 | { |
907 | 0 | nsSVGElementBase::NodeInfoChanged(aOldDoc); |
908 | 0 | aOldDoc->UnscheduleSVGForPresAttrEvaluation(this); |
909 | 0 | mContentDeclarationBlock = nullptr; |
910 | 0 | OwnerDoc()->ScheduleSVGForPresAttrEvaluation(this); |
911 | 0 | } |
912 | | |
913 | | |
914 | | NS_IMETHODIMP_(bool) |
915 | | nsSVGElement::IsAttributeMapped(const nsAtom* name) const |
916 | 0 | { |
917 | 0 | if (name == nsGkAtoms::lang) { |
918 | 0 | return true; |
919 | 0 | } |
920 | 0 | return nsSVGElementBase::IsAttributeMapped(name); |
921 | 0 | } |
922 | | |
923 | | // PresentationAttributes-FillStroke |
924 | | /* static */ const Element::MappedAttributeEntry |
925 | | nsSVGElement::sFillStrokeMap[] = { |
926 | | { &nsGkAtoms::fill }, |
927 | | { &nsGkAtoms::fill_opacity }, |
928 | | { &nsGkAtoms::fill_rule }, |
929 | | { &nsGkAtoms::paint_order }, |
930 | | { &nsGkAtoms::stroke }, |
931 | | { &nsGkAtoms::stroke_dasharray }, |
932 | | { &nsGkAtoms::stroke_dashoffset }, |
933 | | { &nsGkAtoms::stroke_linecap }, |
934 | | { &nsGkAtoms::stroke_linejoin }, |
935 | | { &nsGkAtoms::stroke_miterlimit }, |
936 | | { &nsGkAtoms::stroke_opacity }, |
937 | | { &nsGkAtoms::stroke_width }, |
938 | | { &nsGkAtoms::vector_effect }, |
939 | | { nullptr } |
940 | | }; |
941 | | |
942 | | // PresentationAttributes-Graphics |
943 | | /* static */ const Element::MappedAttributeEntry |
944 | | nsSVGElement::sGraphicsMap[] = { |
945 | | { &nsGkAtoms::clip_path }, |
946 | | { &nsGkAtoms::clip_rule }, |
947 | | { &nsGkAtoms::colorInterpolation }, |
948 | | { &nsGkAtoms::cursor }, |
949 | | { &nsGkAtoms::display }, |
950 | | { &nsGkAtoms::filter }, |
951 | | { &nsGkAtoms::image_rendering }, |
952 | | { &nsGkAtoms::mask }, |
953 | | { &nsGkAtoms::opacity }, |
954 | | { &nsGkAtoms::pointer_events }, |
955 | | { &nsGkAtoms::shape_rendering }, |
956 | | { &nsGkAtoms::text_rendering }, |
957 | | { &nsGkAtoms::visibility }, |
958 | | { nullptr } |
959 | | }; |
960 | | |
961 | | // PresentationAttributes-TextContentElements |
962 | | /* static */ const Element::MappedAttributeEntry |
963 | | nsSVGElement::sTextContentElementsMap[] = { |
964 | | // Properties that we don't support are commented out. |
965 | | // { &nsGkAtoms::alignment_baseline }, |
966 | | // { &nsGkAtoms::baseline_shift }, |
967 | | { &nsGkAtoms::direction }, |
968 | | { &nsGkAtoms::dominant_baseline }, |
969 | | { &nsGkAtoms::letter_spacing }, |
970 | | { &nsGkAtoms::text_anchor }, |
971 | | { &nsGkAtoms::text_decoration }, |
972 | | { &nsGkAtoms::unicode_bidi }, |
973 | | { &nsGkAtoms::word_spacing }, |
974 | | { &nsGkAtoms::writing_mode }, |
975 | | { nullptr } |
976 | | }; |
977 | | |
978 | | // PresentationAttributes-FontSpecification |
979 | | /* static */ const Element::MappedAttributeEntry |
980 | | nsSVGElement::sFontSpecificationMap[] = { |
981 | | { &nsGkAtoms::font_family }, |
982 | | { &nsGkAtoms::font_size }, |
983 | | { &nsGkAtoms::font_size_adjust }, |
984 | | { &nsGkAtoms::font_stretch }, |
985 | | { &nsGkAtoms::font_style }, |
986 | | { &nsGkAtoms::font_variant }, |
987 | | { &nsGkAtoms::fontWeight }, |
988 | | { nullptr } |
989 | | }; |
990 | | |
991 | | // PresentationAttributes-GradientStop |
992 | | /* static */ const Element::MappedAttributeEntry |
993 | | nsSVGElement::sGradientStopMap[] = { |
994 | | { &nsGkAtoms::stop_color }, |
995 | | { &nsGkAtoms::stop_opacity }, |
996 | | { nullptr } |
997 | | }; |
998 | | |
999 | | // PresentationAttributes-Viewports |
1000 | | /* static */ const Element::MappedAttributeEntry |
1001 | | nsSVGElement::sViewportsMap[] = { |
1002 | | { &nsGkAtoms::overflow }, |
1003 | | { &nsGkAtoms::clip }, |
1004 | | { nullptr } |
1005 | | }; |
1006 | | |
1007 | | // PresentationAttributes-Makers |
1008 | | /* static */ const Element::MappedAttributeEntry |
1009 | | nsSVGElement::sMarkersMap[] = { |
1010 | | { &nsGkAtoms::marker_end }, |
1011 | | { &nsGkAtoms::marker_mid }, |
1012 | | { &nsGkAtoms::marker_start }, |
1013 | | { nullptr } |
1014 | | }; |
1015 | | |
1016 | | // PresentationAttributes-Color |
1017 | | /* static */ const Element::MappedAttributeEntry |
1018 | | nsSVGElement::sColorMap[] = { |
1019 | | { &nsGkAtoms::color }, |
1020 | | { nullptr } |
1021 | | }; |
1022 | | |
1023 | | // PresentationAttributes-Filters |
1024 | | /* static */ const Element::MappedAttributeEntry |
1025 | | nsSVGElement::sFiltersMap[] = { |
1026 | | { &nsGkAtoms::colorInterpolationFilters }, |
1027 | | { nullptr } |
1028 | | }; |
1029 | | |
1030 | | // PresentationAttributes-feFlood |
1031 | | /* static */ const Element::MappedAttributeEntry |
1032 | | nsSVGElement::sFEFloodMap[] = { |
1033 | | { &nsGkAtoms::flood_color }, |
1034 | | { &nsGkAtoms::flood_opacity }, |
1035 | | { nullptr } |
1036 | | }; |
1037 | | |
1038 | | // PresentationAttributes-LightingEffects |
1039 | | /* static */ const Element::MappedAttributeEntry |
1040 | | nsSVGElement::sLightingEffectsMap[] = { |
1041 | | { &nsGkAtoms::lighting_color }, |
1042 | | { nullptr } |
1043 | | }; |
1044 | | |
1045 | | // PresentationAttributes-mask |
1046 | | /* static */ const Element::MappedAttributeEntry |
1047 | | nsSVGElement::sMaskMap[] = { |
1048 | | { &nsGkAtoms::mask_type }, |
1049 | | { nullptr } |
1050 | | }; |
1051 | | |
1052 | | //---------------------------------------------------------------------- |
1053 | | // Element methods |
1054 | | |
1055 | | // forwarded to Element implementations |
1056 | | |
1057 | | |
1058 | | //---------------------------------------------------------------------- |
1059 | | |
1060 | | SVGSVGElement* |
1061 | | nsSVGElement::GetOwnerSVGElement() |
1062 | 0 | { |
1063 | 0 | nsIContent* ancestor = GetFlattenedTreeParent(); |
1064 | 0 |
|
1065 | 0 | while (ancestor && ancestor->IsSVGElement()) { |
1066 | 0 | if (ancestor->IsSVGElement(nsGkAtoms::foreignObject)) { |
1067 | 0 | return nullptr; |
1068 | 0 | } |
1069 | 0 | if (ancestor->IsSVGElement(nsGkAtoms::svg)) { |
1070 | 0 | return static_cast<SVGSVGElement*>(ancestor); |
1071 | 0 | } |
1072 | 0 | ancestor = ancestor->GetFlattenedTreeParent(); |
1073 | 0 | } |
1074 | 0 |
|
1075 | 0 | // we don't have an ancestor <svg> element... |
1076 | 0 | return nullptr; |
1077 | 0 | } |
1078 | | |
1079 | | nsSVGElement* |
1080 | | nsSVGElement::GetViewportElement() |
1081 | 0 | { |
1082 | 0 | return SVGContentUtils::GetNearestViewportElement(this); |
1083 | 0 | } |
1084 | | |
1085 | | already_AddRefed<SVGAnimatedString> |
1086 | | nsSVGElement::ClassName() |
1087 | 0 | { |
1088 | 0 | return mClassAttribute.ToDOMAnimatedString(this); |
1089 | 0 | } |
1090 | | |
1091 | | bool |
1092 | | nsSVGElement::IsSVGFocusable(bool* aIsFocusable, int32_t* aTabIndex) |
1093 | 0 | { |
1094 | 0 | nsIDocument* doc = GetComposedDoc(); |
1095 | 0 | if (!doc || doc->HasFlag(NODE_IS_EDITABLE)) { |
1096 | 0 | // In designMode documents we only allow focusing the document. |
1097 | 0 | if (aTabIndex) { |
1098 | 0 | *aTabIndex = -1; |
1099 | 0 | } |
1100 | 0 |
|
1101 | 0 | *aIsFocusable = false; |
1102 | 0 |
|
1103 | 0 | return true; |
1104 | 0 | } |
1105 | 0 |
|
1106 | 0 | int32_t tabIndex = TabIndex(); |
1107 | 0 |
|
1108 | 0 | if (aTabIndex) { |
1109 | 0 | *aTabIndex = tabIndex; |
1110 | 0 | } |
1111 | 0 |
|
1112 | 0 | // If a tabindex is specified at all, or the default tabindex is 0, we're focusable |
1113 | 0 | *aIsFocusable = tabIndex >= 0 || HasAttr(nsGkAtoms::tabindex); |
1114 | 0 |
|
1115 | 0 | return false; |
1116 | 0 | } |
1117 | | |
1118 | | bool |
1119 | | nsSVGElement::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) |
1120 | 0 | { |
1121 | 0 | bool isFocusable = false; |
1122 | 0 | IsSVGFocusable(&isFocusable, aTabIndex); |
1123 | 0 | return isFocusable; |
1124 | 0 | } |
1125 | | |
1126 | | //------------------------------------------------------------------------ |
1127 | | // Helper class: MappedAttrParser, for parsing values of mapped attributes |
1128 | | |
1129 | | namespace { |
1130 | | |
1131 | | class MOZ_STACK_CLASS MappedAttrParser { |
1132 | | public: |
1133 | | MappedAttrParser(css::Loader* aLoader, |
1134 | | nsIURI* aDocURI, |
1135 | | already_AddRefed<nsIURI> aBaseURI, |
1136 | | nsSVGElement* aElement); |
1137 | | ~MappedAttrParser(); |
1138 | | |
1139 | | // Parses a mapped attribute value. |
1140 | | void ParseMappedAttrValue(nsAtom* aMappedAttrName, |
1141 | | const nsAString& aMappedAttrValue); |
1142 | | |
1143 | | // If we've parsed any values for mapped attributes, this method returns the |
1144 | | // already_AddRefed css::Declaration that incorporates the parsed |
1145 | | // values. Otherwise, this method returns null. |
1146 | | already_AddRefed<DeclarationBlock> GetDeclarationBlock(); |
1147 | | |
1148 | | private: |
1149 | | // MEMBER DATA |
1150 | | // ----------- |
1151 | | css::Loader* mLoader; |
1152 | | |
1153 | | // Arguments for nsCSSParser::ParseProperty |
1154 | | nsIURI* mDocURI; |
1155 | | nsCOMPtr<nsIURI> mBaseURI; |
1156 | | |
1157 | | // Declaration for storing parsed values (lazily initialized) |
1158 | | RefPtr<DeclarationBlock> mDecl; |
1159 | | |
1160 | | // For reporting use counters |
1161 | | nsSVGElement* mElement; |
1162 | | }; |
1163 | | |
1164 | | MappedAttrParser::MappedAttrParser(css::Loader* aLoader, |
1165 | | nsIURI* aDocURI, |
1166 | | already_AddRefed<nsIURI> aBaseURI, |
1167 | | nsSVGElement* aElement) |
1168 | | : mLoader(aLoader) |
1169 | | , mDocURI(aDocURI) |
1170 | | , mBaseURI(aBaseURI) |
1171 | | , mElement(aElement) |
1172 | 0 | { |
1173 | 0 | } |
1174 | | |
1175 | | MappedAttrParser::~MappedAttrParser() |
1176 | 0 | { |
1177 | 0 | MOZ_ASSERT(!mDecl, |
1178 | 0 | "If mDecl was initialized, it should have been returned via " |
1179 | 0 | "GetDeclarationBlock (and had its pointer cleared)"); |
1180 | 0 | } |
1181 | | |
1182 | | void |
1183 | | MappedAttrParser::ParseMappedAttrValue(nsAtom* aMappedAttrName, |
1184 | | const nsAString& aMappedAttrValue) |
1185 | 0 | { |
1186 | 0 | if (!mDecl) { |
1187 | 0 | mDecl = new DeclarationBlock(); |
1188 | 0 | } |
1189 | 0 |
|
1190 | 0 | // Get the nsCSSPropertyID ID for our mapped attribute. |
1191 | 0 | nsCSSPropertyID propertyID = |
1192 | 0 | nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName)); |
1193 | 0 | if (propertyID != eCSSProperty_UNKNOWN) { |
1194 | 0 | bool changed = false; // outparam for ParseProperty. |
1195 | 0 | NS_ConvertUTF16toUTF8 value(aMappedAttrValue); |
1196 | 0 | // FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo |
1197 | 0 | RefPtr<URLExtraData> data = |
1198 | 0 | new URLExtraData(mBaseURI, mDocURI, mElement->NodePrincipal(), |
1199 | 0 | mElement->OwnerDoc()->GetReferrerPolicy()); |
1200 | 0 | changed = Servo_DeclarationBlock_SetPropertyById( |
1201 | 0 | mDecl->Raw(), propertyID, &value, false, data, |
1202 | 0 | ParsingMode::AllowUnitlessLength, |
1203 | 0 | mElement->OwnerDoc()->GetCompatibilityMode(), mLoader, { }); |
1204 | 0 |
|
1205 | 0 | if (changed) { |
1206 | 0 | // The normal reporting of use counters by the nsCSSParser won't happen |
1207 | 0 | // since it doesn't have a sheet. |
1208 | 0 | if (nsCSSProps::IsShorthand(propertyID)) { |
1209 | 0 | CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subprop, propertyID, |
1210 | 0 | CSSEnabledState::eForAllContent) { |
1211 | 0 | UseCounter useCounter = nsCSSProps::UseCounterFor(*subprop); |
1212 | 0 | if (useCounter != eUseCounter_UNKNOWN) { |
1213 | 0 | mElement->OwnerDoc()->SetDocumentAndPageUseCounter(useCounter); |
1214 | 0 | } |
1215 | 0 | } |
1216 | 0 | } else { |
1217 | 0 | UseCounter useCounter = nsCSSProps::UseCounterFor(propertyID); |
1218 | 0 | if (useCounter != eUseCounter_UNKNOWN) { |
1219 | 0 | mElement->OwnerDoc()->SetDocumentAndPageUseCounter(useCounter); |
1220 | 0 | } |
1221 | 0 | } |
1222 | 0 | } |
1223 | 0 | return; |
1224 | 0 | } |
1225 | 0 | MOZ_ASSERT(aMappedAttrName == nsGkAtoms::lang, |
1226 | 0 | "Only 'lang' should be unrecognized!"); |
1227 | 0 | // nsCSSParser doesn't know about 'lang', so we need to handle it specially. |
1228 | 0 | if (aMappedAttrName == nsGkAtoms::lang) { |
1229 | 0 | propertyID = eCSSProperty__x_lang; |
1230 | 0 | RefPtr<nsAtom> atom = NS_Atomize(aMappedAttrValue); |
1231 | 0 | Servo_DeclarationBlock_SetIdentStringValue(mDecl->Raw(), propertyID, atom); |
1232 | 0 | } |
1233 | 0 | } |
1234 | | |
1235 | | already_AddRefed<DeclarationBlock> |
1236 | | MappedAttrParser::GetDeclarationBlock() |
1237 | 0 | { |
1238 | 0 | return mDecl.forget(); |
1239 | 0 | } |
1240 | | |
1241 | | } // namespace |
1242 | | |
1243 | | //---------------------------------------------------------------------- |
1244 | | // Implementation Helpers: |
1245 | | |
1246 | | void |
1247 | | nsSVGElement::UpdateContentDeclarationBlock() |
1248 | 0 | { |
1249 | 0 | NS_ASSERTION(!mContentDeclarationBlock, |
1250 | 0 | "we already have a content declaration block"); |
1251 | 0 |
|
1252 | 0 | uint32_t attrCount = mAttrs.AttrCount(); |
1253 | 0 | if (!attrCount) { |
1254 | 0 | // nothing to do |
1255 | 0 | return; |
1256 | 0 | } |
1257 | 0 | |
1258 | 0 | nsIDocument* doc = OwnerDoc(); |
1259 | 0 | MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(), |
1260 | 0 | GetBaseURI(), this); |
1261 | 0 |
|
1262 | 0 | for (uint32_t i = 0; i < attrCount; ++i) { |
1263 | 0 | const nsAttrName* attrName = mAttrs.AttrNameAt(i); |
1264 | 0 | if (!attrName->IsAtom() || !IsAttributeMapped(attrName->Atom())) |
1265 | 0 | continue; |
1266 | 0 | |
1267 | 0 | if (attrName->NamespaceID() != kNameSpaceID_None && |
1268 | 0 | !attrName->Equals(nsGkAtoms::lang, kNameSpaceID_XML)) { |
1269 | 0 | continue; |
1270 | 0 | } |
1271 | 0 | |
1272 | 0 | if (attrName->Equals(nsGkAtoms::lang, kNameSpaceID_None) && |
1273 | 0 | HasAttr(kNameSpaceID_XML, nsGkAtoms::lang)) { |
1274 | 0 | continue; // xml:lang has precedence |
1275 | 0 | } |
1276 | 0 | |
1277 | 0 | if (IsSVGElement(nsGkAtoms::svg)) { |
1278 | 0 | // Special case: we don't want <svg> 'width'/'height' mapped into style |
1279 | 0 | // if the attribute value isn't a valid <length> according to SVG (which |
1280 | 0 | // only supports a subset of the CSS <length> values). We don't enforce |
1281 | 0 | // this by checking the attribute value in SVGSVGElement:: |
1282 | 0 | // IsAttributeMapped since we don't want that method to depend on the |
1283 | 0 | // value of the attribute that is being checked. Rather we just prevent |
1284 | 0 | // the actual mapping here, as necessary. |
1285 | 0 | if (attrName->Atom() == nsGkAtoms::width && |
1286 | 0 | !GetAnimatedLength(nsGkAtoms::width)->HasBaseVal()) { |
1287 | 0 | continue; |
1288 | 0 | } |
1289 | 0 | if (attrName->Atom() == nsGkAtoms::height && |
1290 | 0 | !GetAnimatedLength(nsGkAtoms::height)->HasBaseVal()) { |
1291 | 0 | continue; |
1292 | 0 | } |
1293 | 0 | } |
1294 | 0 | |
1295 | 0 | nsAutoString value; |
1296 | 0 | mAttrs.AttrAt(i)->ToString(value); |
1297 | 0 | mappedAttrParser.ParseMappedAttrValue(attrName->Atom(), value); |
1298 | 0 | } |
1299 | 0 | mContentDeclarationBlock = mappedAttrParser.GetDeclarationBlock(); |
1300 | 0 | } |
1301 | | |
1302 | | const DeclarationBlock* |
1303 | | nsSVGElement::GetContentDeclarationBlock() const |
1304 | 0 | { |
1305 | 0 | return mContentDeclarationBlock; |
1306 | 0 | } |
1307 | | |
1308 | | /** |
1309 | | * Helper methods for the type-specific WillChangeXXX methods. |
1310 | | * |
1311 | | * This method sends out appropriate pre-change notifications so that selector |
1312 | | * restyles (e.g. due to changes that cause |elem[attr="val"]| to start/stop |
1313 | | * matching) work, and it returns an nsAttrValue that _may_ contain the |
1314 | | * attribute's pre-change value. |
1315 | | * |
1316 | | * The nsAttrValue returned by this method depends on whether there are |
1317 | | * mutation event listeners listening for changes to this element's attributes. |
1318 | | * If not, then the object returned is empty. If there are, then the |
1319 | | * nsAttrValue returned contains a serialized copy of the attribute's value |
1320 | | * prior to the change, and this object should be passed to the corresponding |
1321 | | * DidChangeXXX method call (assuming a WillChangeXXX call is required for the |
1322 | | * SVG type - see comment below). This is necessary so that the 'prevValue' |
1323 | | * property of the mutation event that is dispatched will correctly contain the |
1324 | | * old value. |
1325 | | * |
1326 | | * The reason we need to serialize the old value if there are mutation |
1327 | | * event listeners is because the underlying nsAttrValue for the attribute |
1328 | | * points directly to a parsed representation of the attribute (e.g. an |
1329 | | * SVGAnimatedLengthList*) that is a member of the SVG element. That object |
1330 | | * will have changed by the time DidChangeXXX has been called, so without the |
1331 | | * serialization of the old attribute value that we provide, DidChangeXXX |
1332 | | * would have no way to get the old value to pass to SetAttrAndNotify. |
1333 | | * |
1334 | | * We only return the old value when there are mutation event listeners because |
1335 | | * it's not needed otherwise, and because it's expensive to serialize the old |
1336 | | * value. This is especially true for list type attributes, which may be built |
1337 | | * up via the SVG DOM resulting in a large number of Will/DidModifyXXX calls |
1338 | | * before the script finally finishes setting the attribute. |
1339 | | * |
1340 | | * Note that unlike using SetParsedAttr, using Will/DidChangeXXX does NOT check |
1341 | | * and filter out redundant changes. Before calling WillChangeXXX, the caller |
1342 | | * should check whether the new and old values are actually the same, and skip |
1343 | | * calling Will/DidChangeXXX if they are. |
1344 | | * |
1345 | | * Also note that not all SVG types use this scheme. For types that can be |
1346 | | * represented by an nsAttrValue without pointing back to an SVG object (e.g. |
1347 | | * enums, booleans, integers) we can simply use SetParsedAttr which will do all |
1348 | | * of the above for us. For such types there is no matching WillChangeXXX |
1349 | | * method, only DidChangeXXX which calls SetParsedAttr. |
1350 | | */ |
1351 | | nsAttrValue |
1352 | | nsSVGElement::WillChangeValue(nsAtom* aName) |
1353 | 0 | { |
1354 | 0 | // We need an empty attr value: |
1355 | 0 | // a) to pass to BeforeSetAttr when GetParsedAttr returns nullptr |
1356 | 0 | // b) to store the old value in the case we have mutation listeners |
1357 | 0 | // |
1358 | 0 | // We can use the same value for both purposes, because if GetParsedAttr |
1359 | 0 | // returns non-null its return value is what will get passed to BeforeSetAttr, |
1360 | 0 | // not matter what our mutation listener situation is. |
1361 | 0 | // |
1362 | 0 | // Also, we should be careful to always return this value to benefit from |
1363 | 0 | // return value optimization. |
1364 | 0 | nsAttrValue emptyOrOldAttrValue; |
1365 | 0 | const nsAttrValue* attrValue = GetParsedAttr(aName); |
1366 | 0 |
|
1367 | 0 | // We only need to set the old value if we have listeners since otherwise it |
1368 | 0 | // isn't used. |
1369 | 0 | if (attrValue && |
1370 | 0 | nsContentUtils::HasMutationListeners(this, |
1371 | 0 | NS_EVENT_BITS_MUTATION_ATTRMODIFIED, |
1372 | 0 | this)) { |
1373 | 0 | emptyOrOldAttrValue.SetToSerialized(*attrValue); |
1374 | 0 | } |
1375 | 0 |
|
1376 | 0 | uint8_t modType = attrValue |
1377 | 0 | ? static_cast<uint8_t>(MutationEvent_Binding::MODIFICATION) |
1378 | 0 | : static_cast<uint8_t>(MutationEvent_Binding::ADDITION); |
1379 | 0 | nsNodeUtils::AttributeWillChange(this, kNameSpaceID_None, aName, modType, |
1380 | 0 | nullptr); |
1381 | 0 |
|
1382 | 0 | // This is not strictly correct--the attribute value parameter for |
1383 | 0 | // BeforeSetAttr should reflect the value that *will* be set but that implies |
1384 | 0 | // allocating, e.g. an extra nsSVGLength2, and isn't necessary at the moment |
1385 | 0 | // since no SVG elements overload BeforeSetAttr. For now we just pass the |
1386 | 0 | // current value. |
1387 | 0 | nsAttrValueOrString attrStringOrValue(attrValue ? *attrValue |
1388 | 0 | : emptyOrOldAttrValue); |
1389 | 0 | DebugOnly<nsresult> rv = |
1390 | 0 | BeforeSetAttr(kNameSpaceID_None, aName, &attrStringOrValue, |
1391 | 0 | kNotifyDocumentObservers); |
1392 | 0 | // SVG elements aren't expected to overload BeforeSetAttr in such a way that |
1393 | 0 | // it may fail. So long as this is the case we don't need to check and pass on |
1394 | 0 | // the return value which simplifies the calling code significantly. |
1395 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Unexpected failure from BeforeSetAttr"); |
1396 | 0 |
|
1397 | 0 | return emptyOrOldAttrValue; |
1398 | 0 | } |
1399 | | |
1400 | | /** |
1401 | | * Helper methods for the type-specific DidChangeXXX methods. |
1402 | | * |
1403 | | * aEmptyOrOldValue will normally be the object returned from the corresponding |
1404 | | * WillChangeXXX call. This is because: |
1405 | | * a) WillChangeXXX will ensure the object is set when we have mutation |
1406 | | * listeners, and |
1407 | | * b) WillChangeXXX will ensure the object represents a serialized version of |
1408 | | * the old attribute value so that the value doesn't change when the |
1409 | | * underlying SVG type is updated. |
1410 | | * |
1411 | | * aNewValue is replaced with the old value. |
1412 | | */ |
1413 | | void |
1414 | | nsSVGElement::DidChangeValue(nsAtom* aName, |
1415 | | const nsAttrValue& aEmptyOrOldValue, |
1416 | | nsAttrValue& aNewValue) |
1417 | 0 | { |
1418 | 0 | bool hasListeners = |
1419 | 0 | nsContentUtils::HasMutationListeners(this, |
1420 | 0 | NS_EVENT_BITS_MUTATION_ATTRMODIFIED, |
1421 | 0 | this); |
1422 | 0 | uint8_t modType = HasAttr(kNameSpaceID_None, aName) |
1423 | 0 | ? static_cast<uint8_t>(MutationEvent_Binding::MODIFICATION) |
1424 | 0 | : static_cast<uint8_t>(MutationEvent_Binding::ADDITION); |
1425 | 0 |
|
1426 | 0 | nsIDocument* document = GetComposedDoc(); |
1427 | 0 | mozAutoDocUpdate updateBatch(document, kNotifyDocumentObservers); |
1428 | 0 | // XXX Really, the fourth argument to SetAttrAndNotify should be null if |
1429 | 0 | // aEmptyOrOldValue does not represent the actual previous value of the |
1430 | 0 | // attribute, but currently SVG elements do not even use the old attribute |
1431 | 0 | // value in |AfterSetAttr|, so this should be ok. |
1432 | 0 | SetAttrAndNotify(kNameSpaceID_None, aName, nullptr, &aEmptyOrOldValue, |
1433 | 0 | aNewValue, nullptr, modType, hasListeners, kNotifyDocumentObservers, |
1434 | 0 | kCallAfterSetAttr, document, updateBatch); |
1435 | 0 | } |
1436 | | |
1437 | | void |
1438 | | nsSVGElement::MaybeSerializeAttrBeforeRemoval(nsAtom* aName, bool aNotify) |
1439 | 0 | { |
1440 | 0 | if (!aNotify || |
1441 | 0 | !nsContentUtils::HasMutationListeners(this, |
1442 | 0 | NS_EVENT_BITS_MUTATION_ATTRMODIFIED, |
1443 | 0 | this)) { |
1444 | 0 | return; |
1445 | 0 | } |
1446 | 0 | |
1447 | 0 | const nsAttrValue* attrValue = mAttrs.GetAttr(aName); |
1448 | 0 | if (!attrValue) |
1449 | 0 | return; |
1450 | 0 | |
1451 | 0 | nsAutoString serializedValue; |
1452 | 0 | attrValue->ToString(serializedValue); |
1453 | 0 | nsAttrValue oldAttrValue(serializedValue); |
1454 | 0 | bool oldValueSet; |
1455 | 0 | mAttrs.SetAndSwapAttr(aName, oldAttrValue, &oldValueSet); |
1456 | 0 | } |
1457 | | |
1458 | | /* static */ |
1459 | | nsAtom* nsSVGElement::GetEventNameForAttr(nsAtom* aAttr) |
1460 | 0 | { |
1461 | 0 | if (aAttr == nsGkAtoms::onload) |
1462 | 0 | return nsGkAtoms::onSVGLoad; |
1463 | 0 | if (aAttr == nsGkAtoms::onunload) |
1464 | 0 | return nsGkAtoms::onSVGUnload; |
1465 | 0 | if (aAttr == nsGkAtoms::onresize) |
1466 | 0 | return nsGkAtoms::onSVGResize; |
1467 | 0 | if (aAttr == nsGkAtoms::onscroll) |
1468 | 0 | return nsGkAtoms::onSVGScroll; |
1469 | 0 | if (aAttr == nsGkAtoms::onzoom) |
1470 | 0 | return nsGkAtoms::onSVGZoom; |
1471 | 0 | if (aAttr == nsGkAtoms::onbegin) |
1472 | 0 | return nsGkAtoms::onbeginEvent; |
1473 | 0 | if (aAttr == nsGkAtoms::onrepeat) |
1474 | 0 | return nsGkAtoms::onrepeatEvent; |
1475 | 0 | if (aAttr == nsGkAtoms::onend) |
1476 | 0 | return nsGkAtoms::onendEvent; |
1477 | 0 | |
1478 | 0 | return aAttr; |
1479 | 0 | } |
1480 | | |
1481 | | SVGViewportElement * |
1482 | | nsSVGElement::GetCtx() const |
1483 | 0 | { |
1484 | 0 | return SVGContentUtils::GetNearestViewportElement(this); |
1485 | 0 | } |
1486 | | |
1487 | | /* virtual */ gfxMatrix |
1488 | | nsSVGElement::PrependLocalTransformsTo( |
1489 | | const gfxMatrix &aMatrix, SVGTransformTypes aWhich) const |
1490 | 0 | { |
1491 | 0 | return aMatrix; |
1492 | 0 | } |
1493 | | |
1494 | | nsSVGElement::LengthAttributesInfo |
1495 | | nsSVGElement::GetLengthInfo() |
1496 | 0 | { |
1497 | 0 | return LengthAttributesInfo(nullptr, nullptr, 0); |
1498 | 0 | } |
1499 | | |
1500 | | void |
1501 | | nsSVGElement::LengthAttributesInfo::Reset(uint8_t aAttrEnum) |
1502 | 0 | { |
1503 | 0 | mLengths[aAttrEnum].Init(mLengthInfo[aAttrEnum].mCtxType, |
1504 | 0 | aAttrEnum, |
1505 | 0 | mLengthInfo[aAttrEnum].mDefaultValue, |
1506 | 0 | mLengthInfo[aAttrEnum].mDefaultUnitType); |
1507 | 0 | } |
1508 | | |
1509 | | void |
1510 | | nsSVGElement::SetLength(nsAtom* aName, const nsSVGLength2 &aLength) |
1511 | 0 | { |
1512 | 0 | LengthAttributesInfo lengthInfo = GetLengthInfo(); |
1513 | 0 |
|
1514 | 0 | for (uint32_t i = 0; i < lengthInfo.mLengthCount; i++) { |
1515 | 0 | if (aName == *lengthInfo.mLengthInfo[i].mName) { |
1516 | 0 | lengthInfo.mLengths[i] = aLength; |
1517 | 0 | DidAnimateLength(i); |
1518 | 0 | return; |
1519 | 0 | } |
1520 | 0 | } |
1521 | 0 | MOZ_ASSERT(false, "no length found to set"); |
1522 | 0 | } |
1523 | | |
1524 | | nsAttrValue |
1525 | | nsSVGElement::WillChangeLength(uint8_t aAttrEnum) |
1526 | 0 | { |
1527 | 0 | return WillChangeValue(*GetLengthInfo().mLengthInfo[aAttrEnum].mName); |
1528 | 0 | } |
1529 | | |
1530 | | void |
1531 | | nsSVGElement::DidChangeLength(uint8_t aAttrEnum, |
1532 | | const nsAttrValue& aEmptyOrOldValue) |
1533 | 0 | { |
1534 | 0 | LengthAttributesInfo info = GetLengthInfo(); |
1535 | 0 |
|
1536 | 0 | NS_ASSERTION(info.mLengthCount > 0, |
1537 | 0 | "DidChangeLength on element with no length attribs"); |
1538 | 0 | NS_ASSERTION(aAttrEnum < info.mLengthCount, "aAttrEnum out of range"); |
1539 | 0 |
|
1540 | 0 | nsAttrValue newValue; |
1541 | 0 | newValue.SetTo(info.mLengths[aAttrEnum], nullptr); |
1542 | 0 |
|
1543 | 0 | DidChangeValue(*info.mLengthInfo[aAttrEnum].mName, aEmptyOrOldValue, |
1544 | 0 | newValue); |
1545 | 0 | } |
1546 | | |
1547 | | void |
1548 | | nsSVGElement::DidAnimateLength(uint8_t aAttrEnum) |
1549 | 0 | { |
1550 | 0 | ClearAnyCachedPath(); |
1551 | 0 |
|
1552 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
1553 | 0 |
|
1554 | 0 | if (frame) { |
1555 | 0 | LengthAttributesInfo info = GetLengthInfo(); |
1556 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
1557 | 0 | *info.mLengthInfo[aAttrEnum].mName, |
1558 | 0 | MutationEvent_Binding::SMIL); |
1559 | 0 | } |
1560 | 0 | } |
1561 | | |
1562 | | nsSVGLength2* |
1563 | | nsSVGElement::GetAnimatedLength(const nsAtom *aAttrName) |
1564 | 0 | { |
1565 | 0 | LengthAttributesInfo lengthInfo = GetLengthInfo(); |
1566 | 0 |
|
1567 | 0 | for (uint32_t i = 0; i < lengthInfo.mLengthCount; i++) { |
1568 | 0 | if (aAttrName == *lengthInfo.mLengthInfo[i].mName) { |
1569 | 0 | return &lengthInfo.mLengths[i]; |
1570 | 0 | } |
1571 | 0 | } |
1572 | 0 | MOZ_ASSERT(false, "no matching length found"); |
1573 | 0 | return nullptr; |
1574 | 0 | } |
1575 | | |
1576 | | void |
1577 | | nsSVGElement::GetAnimatedLengthValues(float *aFirst, ...) |
1578 | 0 | { |
1579 | 0 | LengthAttributesInfo info = GetLengthInfo(); |
1580 | 0 |
|
1581 | 0 | NS_ASSERTION(info.mLengthCount > 0, |
1582 | 0 | "GetAnimatedLengthValues on element with no length attribs"); |
1583 | 0 |
|
1584 | 0 | SVGViewportElement *ctx = nullptr; |
1585 | 0 |
|
1586 | 0 | float *f = aFirst; |
1587 | 0 | uint32_t i = 0; |
1588 | 0 |
|
1589 | 0 | va_list args; |
1590 | 0 | va_start(args, aFirst); |
1591 | 0 |
|
1592 | 0 | while (f && i < info.mLengthCount) { |
1593 | 0 | uint8_t type = info.mLengths[i].GetSpecifiedUnitType(); |
1594 | 0 | if (!ctx) { |
1595 | 0 | if (type != SVGLength_Binding::SVG_LENGTHTYPE_NUMBER && |
1596 | 0 | type != SVGLength_Binding::SVG_LENGTHTYPE_PX) |
1597 | 0 | ctx = GetCtx(); |
1598 | 0 | } |
1599 | 0 | if (type == SVGLength_Binding::SVG_LENGTHTYPE_EMS || |
1600 | 0 | type == SVGLength_Binding::SVG_LENGTHTYPE_EXS) |
1601 | 0 | *f = info.mLengths[i++].GetAnimValue(this); |
1602 | 0 | else |
1603 | 0 | *f = info.mLengths[i++].GetAnimValue(ctx); |
1604 | 0 | f = va_arg(args, float*); |
1605 | 0 | } |
1606 | 0 |
|
1607 | 0 | va_end(args); |
1608 | 0 | } |
1609 | | |
1610 | | nsSVGElement::LengthListAttributesInfo |
1611 | | nsSVGElement::GetLengthListInfo() |
1612 | 0 | { |
1613 | 0 | return LengthListAttributesInfo(nullptr, nullptr, 0); |
1614 | 0 | } |
1615 | | |
1616 | | void |
1617 | | nsSVGElement::LengthListAttributesInfo::Reset(uint8_t aAttrEnum) |
1618 | 0 | { |
1619 | 0 | mLengthLists[aAttrEnum].ClearBaseValue(aAttrEnum); |
1620 | 0 | // caller notifies |
1621 | 0 | } |
1622 | | |
1623 | | nsAttrValue |
1624 | | nsSVGElement::WillChangeLengthList(uint8_t aAttrEnum) |
1625 | 0 | { |
1626 | 0 | return WillChangeValue(*GetLengthListInfo().mLengthListInfo[aAttrEnum].mName); |
1627 | 0 | } |
1628 | | |
1629 | | void |
1630 | | nsSVGElement::DidChangeLengthList(uint8_t aAttrEnum, |
1631 | | const nsAttrValue& aEmptyOrOldValue) |
1632 | 0 | { |
1633 | 0 | LengthListAttributesInfo info = GetLengthListInfo(); |
1634 | 0 |
|
1635 | 0 | NS_ASSERTION(info.mLengthListCount > 0, |
1636 | 0 | "DidChangeLengthList on element with no length list attribs"); |
1637 | 0 | NS_ASSERTION(aAttrEnum < info.mLengthListCount, "aAttrEnum out of range"); |
1638 | 0 |
|
1639 | 0 | nsAttrValue newValue; |
1640 | 0 | newValue.SetTo(info.mLengthLists[aAttrEnum].GetBaseValue(), nullptr); |
1641 | 0 |
|
1642 | 0 | DidChangeValue(*info.mLengthListInfo[aAttrEnum].mName, aEmptyOrOldValue, |
1643 | 0 | newValue); |
1644 | 0 | } |
1645 | | |
1646 | | void |
1647 | | nsSVGElement::DidAnimateLengthList(uint8_t aAttrEnum) |
1648 | 0 | { |
1649 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
1650 | 0 |
|
1651 | 0 | if (frame) { |
1652 | 0 | LengthListAttributesInfo info = GetLengthListInfo(); |
1653 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
1654 | 0 | *info.mLengthListInfo[aAttrEnum].mName, |
1655 | 0 | MutationEvent_Binding::SMIL); |
1656 | 0 | } |
1657 | 0 | } |
1658 | | |
1659 | | void |
1660 | | nsSVGElement::GetAnimatedLengthListValues(SVGUserUnitList *aFirst, ...) |
1661 | 0 | { |
1662 | 0 | LengthListAttributesInfo info = GetLengthListInfo(); |
1663 | 0 |
|
1664 | 0 | NS_ASSERTION(info.mLengthListCount > 0, |
1665 | 0 | "GetAnimatedLengthListValues on element with no length list attribs"); |
1666 | 0 |
|
1667 | 0 | SVGUserUnitList *list = aFirst; |
1668 | 0 | uint32_t i = 0; |
1669 | 0 |
|
1670 | 0 | va_list args; |
1671 | 0 | va_start(args, aFirst); |
1672 | 0 |
|
1673 | 0 | while (list && i < info.mLengthListCount) { |
1674 | 0 | list->Init(&(info.mLengthLists[i].GetAnimValue()), this, info.mLengthListInfo[i].mAxis); |
1675 | 0 | ++i; |
1676 | 0 | list = va_arg(args, SVGUserUnitList*); |
1677 | 0 | } |
1678 | 0 |
|
1679 | 0 | va_end(args); |
1680 | 0 | } |
1681 | | |
1682 | | SVGAnimatedLengthList* |
1683 | | nsSVGElement::GetAnimatedLengthList(uint8_t aAttrEnum) |
1684 | 0 | { |
1685 | 0 | LengthListAttributesInfo info = GetLengthListInfo(); |
1686 | 0 | if (aAttrEnum < info.mLengthListCount) { |
1687 | 0 | return &(info.mLengthLists[aAttrEnum]); |
1688 | 0 | } |
1689 | 0 | MOZ_ASSERT_UNREACHABLE("Bad attrEnum"); |
1690 | 0 | return nullptr; |
1691 | 0 | } |
1692 | | |
1693 | | |
1694 | | nsSVGElement::NumberListAttributesInfo |
1695 | | nsSVGElement::GetNumberListInfo() |
1696 | 0 | { |
1697 | 0 | return NumberListAttributesInfo(nullptr, nullptr, 0); |
1698 | 0 | } |
1699 | | |
1700 | | void |
1701 | | nsSVGElement::NumberListAttributesInfo::Reset(uint8_t aAttrEnum) |
1702 | 0 | { |
1703 | 0 | MOZ_ASSERT(aAttrEnum < mNumberListCount, "Bad attr enum"); |
1704 | 0 | mNumberLists[aAttrEnum].ClearBaseValue(aAttrEnum); |
1705 | 0 | // caller notifies |
1706 | 0 | } |
1707 | | |
1708 | | nsAttrValue |
1709 | | nsSVGElement::WillChangeNumberList(uint8_t aAttrEnum) |
1710 | 0 | { |
1711 | 0 | return WillChangeValue(*GetNumberListInfo().mNumberListInfo[aAttrEnum].mName); |
1712 | 0 | } |
1713 | | |
1714 | | void |
1715 | | nsSVGElement::DidChangeNumberList(uint8_t aAttrEnum, |
1716 | | const nsAttrValue& aEmptyOrOldValue) |
1717 | 0 | { |
1718 | 0 | NumberListAttributesInfo info = GetNumberListInfo(); |
1719 | 0 |
|
1720 | 0 | MOZ_ASSERT(info.mNumberListCount > 0, |
1721 | 0 | "DidChangeNumberList on element with no number list attribs"); |
1722 | 0 | MOZ_ASSERT(aAttrEnum < info.mNumberListCount, |
1723 | 0 | "aAttrEnum out of range"); |
1724 | 0 |
|
1725 | 0 | nsAttrValue newValue; |
1726 | 0 | newValue.SetTo(info.mNumberLists[aAttrEnum].GetBaseValue(), nullptr); |
1727 | 0 |
|
1728 | 0 | DidChangeValue(*info.mNumberListInfo[aAttrEnum].mName, aEmptyOrOldValue, |
1729 | 0 | newValue); |
1730 | 0 | } |
1731 | | |
1732 | | void |
1733 | | nsSVGElement::DidAnimateNumberList(uint8_t aAttrEnum) |
1734 | 0 | { |
1735 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
1736 | 0 |
|
1737 | 0 | if (frame) { |
1738 | 0 | NumberListAttributesInfo info = GetNumberListInfo(); |
1739 | 0 | MOZ_ASSERT(aAttrEnum < info.mNumberListCount, "aAttrEnum out of range"); |
1740 | 0 |
|
1741 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
1742 | 0 | *info.mNumberListInfo[aAttrEnum].mName, |
1743 | 0 | MutationEvent_Binding::SMIL); |
1744 | 0 | } |
1745 | 0 | } |
1746 | | |
1747 | | SVGAnimatedNumberList* |
1748 | | nsSVGElement::GetAnimatedNumberList(uint8_t aAttrEnum) |
1749 | 0 | { |
1750 | 0 | NumberListAttributesInfo info = GetNumberListInfo(); |
1751 | 0 | if (aAttrEnum < info.mNumberListCount) { |
1752 | 0 | return &(info.mNumberLists[aAttrEnum]); |
1753 | 0 | } |
1754 | 0 | MOZ_ASSERT(false, "Bad attrEnum"); |
1755 | 0 | return nullptr; |
1756 | 0 | } |
1757 | | |
1758 | | SVGAnimatedNumberList* |
1759 | | nsSVGElement::GetAnimatedNumberList(nsAtom *aAttrName) |
1760 | 0 | { |
1761 | 0 | NumberListAttributesInfo info = GetNumberListInfo(); |
1762 | 0 | for (uint32_t i = 0; i < info.mNumberListCount; i++) { |
1763 | 0 | if (aAttrName == *info.mNumberListInfo[i].mName) { |
1764 | 0 | return &info.mNumberLists[i]; |
1765 | 0 | } |
1766 | 0 | } |
1767 | 0 | MOZ_ASSERT(false, "Bad caller"); |
1768 | 0 | return nullptr; |
1769 | 0 | } |
1770 | | |
1771 | | nsAttrValue |
1772 | | nsSVGElement::WillChangePointList() |
1773 | 0 | { |
1774 | 0 | MOZ_ASSERT(GetPointListAttrName(), |
1775 | 0 | "Changing non-existent point list?"); |
1776 | 0 | return WillChangeValue(GetPointListAttrName()); |
1777 | 0 | } |
1778 | | |
1779 | | void |
1780 | | nsSVGElement::DidChangePointList(const nsAttrValue& aEmptyOrOldValue) |
1781 | 0 | { |
1782 | 0 | MOZ_ASSERT(GetPointListAttrName(), |
1783 | 0 | "Changing non-existent point list?"); |
1784 | 0 |
|
1785 | 0 | nsAttrValue newValue; |
1786 | 0 | newValue.SetTo(GetAnimatedPointList()->GetBaseValue(), nullptr); |
1787 | 0 |
|
1788 | 0 | DidChangeValue(GetPointListAttrName(), aEmptyOrOldValue, newValue); |
1789 | 0 | } |
1790 | | |
1791 | | void |
1792 | | nsSVGElement::DidAnimatePointList() |
1793 | 0 | { |
1794 | 0 | MOZ_ASSERT(GetPointListAttrName(), |
1795 | 0 | "Animating non-existent path data?"); |
1796 | 0 |
|
1797 | 0 | ClearAnyCachedPath(); |
1798 | 0 |
|
1799 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
1800 | 0 |
|
1801 | 0 | if (frame) { |
1802 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
1803 | 0 | GetPointListAttrName(), |
1804 | 0 | MutationEvent_Binding::SMIL); |
1805 | 0 | } |
1806 | 0 | } |
1807 | | |
1808 | | nsAttrValue |
1809 | | nsSVGElement::WillChangePathSegList() |
1810 | 0 | { |
1811 | 0 | MOZ_ASSERT(GetPathDataAttrName(), |
1812 | 0 | "Changing non-existent path seg list?"); |
1813 | 0 | return WillChangeValue(GetPathDataAttrName()); |
1814 | 0 | } |
1815 | | |
1816 | | void |
1817 | | nsSVGElement::DidChangePathSegList(const nsAttrValue& aEmptyOrOldValue) |
1818 | 0 | { |
1819 | 0 | MOZ_ASSERT(GetPathDataAttrName(), |
1820 | 0 | "Changing non-existent path seg list?"); |
1821 | 0 |
|
1822 | 0 | nsAttrValue newValue; |
1823 | 0 | newValue.SetTo(GetAnimPathSegList()->GetBaseValue(), nullptr); |
1824 | 0 |
|
1825 | 0 | DidChangeValue(GetPathDataAttrName(), aEmptyOrOldValue, newValue); |
1826 | 0 | } |
1827 | | |
1828 | | void |
1829 | | nsSVGElement::DidAnimatePathSegList() |
1830 | 0 | { |
1831 | 0 | MOZ_ASSERT(GetPathDataAttrName(), |
1832 | 0 | "Animating non-existent path data?"); |
1833 | 0 |
|
1834 | 0 | ClearAnyCachedPath(); |
1835 | 0 |
|
1836 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
1837 | 0 |
|
1838 | 0 | if (frame) { |
1839 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
1840 | 0 | GetPathDataAttrName(), |
1841 | 0 | MutationEvent_Binding::SMIL); |
1842 | 0 | } |
1843 | 0 | } |
1844 | | |
1845 | | nsSVGElement::NumberAttributesInfo |
1846 | | nsSVGElement::GetNumberInfo() |
1847 | 0 | { |
1848 | 0 | return NumberAttributesInfo(nullptr, nullptr, 0); |
1849 | 0 | } |
1850 | | |
1851 | | void |
1852 | | nsSVGElement::NumberAttributesInfo::Reset(uint8_t aAttrEnum) |
1853 | 0 | { |
1854 | 0 | mNumbers[aAttrEnum].Init(aAttrEnum, |
1855 | 0 | mNumberInfo[aAttrEnum].mDefaultValue); |
1856 | 0 | } |
1857 | | |
1858 | | void |
1859 | | nsSVGElement::DidChangeNumber(uint8_t aAttrEnum) |
1860 | 0 | { |
1861 | 0 | NumberAttributesInfo info = GetNumberInfo(); |
1862 | 0 |
|
1863 | 0 | NS_ASSERTION(info.mNumberCount > 0, |
1864 | 0 | "DidChangeNumber on element with no number attribs"); |
1865 | 0 | NS_ASSERTION(aAttrEnum < info.mNumberCount, "aAttrEnum out of range"); |
1866 | 0 |
|
1867 | 0 | nsAttrValue attrValue; |
1868 | 0 | attrValue.SetTo(info.mNumbers[aAttrEnum].GetBaseValue(), nullptr); |
1869 | 0 |
|
1870 | 0 | SetParsedAttr(kNameSpaceID_None, *info.mNumberInfo[aAttrEnum].mName, nullptr, |
1871 | 0 | attrValue, true); |
1872 | 0 | } |
1873 | | |
1874 | | void |
1875 | | nsSVGElement::DidAnimateNumber(uint8_t aAttrEnum) |
1876 | 0 | { |
1877 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
1878 | 0 |
|
1879 | 0 | if (frame) { |
1880 | 0 | NumberAttributesInfo info = GetNumberInfo(); |
1881 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
1882 | 0 | *info.mNumberInfo[aAttrEnum].mName, |
1883 | 0 | MutationEvent_Binding::SMIL); |
1884 | 0 | } |
1885 | 0 | } |
1886 | | |
1887 | | void |
1888 | | nsSVGElement::GetAnimatedNumberValues(float *aFirst, ...) |
1889 | 0 | { |
1890 | 0 | NumberAttributesInfo info = GetNumberInfo(); |
1891 | 0 |
|
1892 | 0 | NS_ASSERTION(info.mNumberCount > 0, |
1893 | 0 | "GetAnimatedNumberValues on element with no number attribs"); |
1894 | 0 |
|
1895 | 0 | float *f = aFirst; |
1896 | 0 | uint32_t i = 0; |
1897 | 0 |
|
1898 | 0 | va_list args; |
1899 | 0 | va_start(args, aFirst); |
1900 | 0 |
|
1901 | 0 | while (f && i < info.mNumberCount) { |
1902 | 0 | *f = info.mNumbers[i++].GetAnimValue(); |
1903 | 0 | f = va_arg(args, float*); |
1904 | 0 | } |
1905 | 0 | va_end(args); |
1906 | 0 | } |
1907 | | |
1908 | | nsSVGElement::NumberPairAttributesInfo |
1909 | | nsSVGElement::GetNumberPairInfo() |
1910 | 0 | { |
1911 | 0 | return NumberPairAttributesInfo(nullptr, nullptr, 0); |
1912 | 0 | } |
1913 | | |
1914 | | void |
1915 | | nsSVGElement::NumberPairAttributesInfo::Reset(uint8_t aAttrEnum) |
1916 | 0 | { |
1917 | 0 | mNumberPairs[aAttrEnum].Init(aAttrEnum, |
1918 | 0 | mNumberPairInfo[aAttrEnum].mDefaultValue1, |
1919 | 0 | mNumberPairInfo[aAttrEnum].mDefaultValue2); |
1920 | 0 | } |
1921 | | |
1922 | | nsAttrValue |
1923 | | nsSVGElement::WillChangeNumberPair(uint8_t aAttrEnum) |
1924 | 0 | { |
1925 | 0 | return WillChangeValue(*GetNumberPairInfo().mNumberPairInfo[aAttrEnum].mName); |
1926 | 0 | } |
1927 | | |
1928 | | void |
1929 | | nsSVGElement::DidChangeNumberPair(uint8_t aAttrEnum, |
1930 | | const nsAttrValue& aEmptyOrOldValue) |
1931 | 0 | { |
1932 | 0 | NumberPairAttributesInfo info = GetNumberPairInfo(); |
1933 | 0 |
|
1934 | 0 | NS_ASSERTION(info.mNumberPairCount > 0, |
1935 | 0 | "DidChangePairNumber on element with no number pair attribs"); |
1936 | 0 | NS_ASSERTION(aAttrEnum < info.mNumberPairCount, "aAttrEnum out of range"); |
1937 | 0 |
|
1938 | 0 | nsAttrValue newValue; |
1939 | 0 | newValue.SetTo(info.mNumberPairs[aAttrEnum], nullptr); |
1940 | 0 |
|
1941 | 0 | DidChangeValue(*info.mNumberPairInfo[aAttrEnum].mName, aEmptyOrOldValue, |
1942 | 0 | newValue); |
1943 | 0 | } |
1944 | | |
1945 | | void |
1946 | | nsSVGElement::DidAnimateNumberPair(uint8_t aAttrEnum) |
1947 | 0 | { |
1948 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
1949 | 0 |
|
1950 | 0 | if (frame) { |
1951 | 0 | NumberPairAttributesInfo info = GetNumberPairInfo(); |
1952 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
1953 | 0 | *info.mNumberPairInfo[aAttrEnum].mName, |
1954 | 0 | MutationEvent_Binding::SMIL); |
1955 | 0 | } |
1956 | 0 | } |
1957 | | |
1958 | | nsSVGElement::IntegerAttributesInfo |
1959 | | nsSVGElement::GetIntegerInfo() |
1960 | 0 | { |
1961 | 0 | return IntegerAttributesInfo(nullptr, nullptr, 0); |
1962 | 0 | } |
1963 | | |
1964 | | void |
1965 | | nsSVGElement::IntegerAttributesInfo::Reset(uint8_t aAttrEnum) |
1966 | 0 | { |
1967 | 0 | mIntegers[aAttrEnum].Init(aAttrEnum, |
1968 | 0 | mIntegerInfo[aAttrEnum].mDefaultValue); |
1969 | 0 | } |
1970 | | |
1971 | | void |
1972 | | nsSVGElement::DidChangeInteger(uint8_t aAttrEnum) |
1973 | 0 | { |
1974 | 0 | IntegerAttributesInfo info = GetIntegerInfo(); |
1975 | 0 |
|
1976 | 0 | NS_ASSERTION(info.mIntegerCount > 0, |
1977 | 0 | "DidChangeInteger on element with no integer attribs"); |
1978 | 0 | NS_ASSERTION(aAttrEnum < info.mIntegerCount, "aAttrEnum out of range"); |
1979 | 0 |
|
1980 | 0 | nsAttrValue attrValue; |
1981 | 0 | attrValue.SetTo(info.mIntegers[aAttrEnum].GetBaseValue(), nullptr); |
1982 | 0 |
|
1983 | 0 | SetParsedAttr(kNameSpaceID_None, *info.mIntegerInfo[aAttrEnum].mName, nullptr, |
1984 | 0 | attrValue, true); |
1985 | 0 | } |
1986 | | |
1987 | | void |
1988 | | nsSVGElement::DidAnimateInteger(uint8_t aAttrEnum) |
1989 | 0 | { |
1990 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
1991 | 0 |
|
1992 | 0 | if (frame) { |
1993 | 0 | IntegerAttributesInfo info = GetIntegerInfo(); |
1994 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
1995 | 0 | *info.mIntegerInfo[aAttrEnum].mName, |
1996 | 0 | MutationEvent_Binding::SMIL); |
1997 | 0 | } |
1998 | 0 | } |
1999 | | |
2000 | | void |
2001 | | nsSVGElement::GetAnimatedIntegerValues(int32_t *aFirst, ...) |
2002 | 0 | { |
2003 | 0 | IntegerAttributesInfo info = GetIntegerInfo(); |
2004 | 0 |
|
2005 | 0 | NS_ASSERTION(info.mIntegerCount > 0, |
2006 | 0 | "GetAnimatedIntegerValues on element with no integer attribs"); |
2007 | 0 |
|
2008 | 0 | int32_t *n = aFirst; |
2009 | 0 | uint32_t i = 0; |
2010 | 0 |
|
2011 | 0 | va_list args; |
2012 | 0 | va_start(args, aFirst); |
2013 | 0 |
|
2014 | 0 | while (n && i < info.mIntegerCount) { |
2015 | 0 | *n = info.mIntegers[i++].GetAnimValue(); |
2016 | 0 | n = va_arg(args, int32_t*); |
2017 | 0 | } |
2018 | 0 | va_end(args); |
2019 | 0 | } |
2020 | | |
2021 | | nsSVGElement::IntegerPairAttributesInfo |
2022 | | nsSVGElement::GetIntegerPairInfo() |
2023 | 0 | { |
2024 | 0 | return IntegerPairAttributesInfo(nullptr, nullptr, 0); |
2025 | 0 | } |
2026 | | |
2027 | | void |
2028 | | nsSVGElement::IntegerPairAttributesInfo::Reset(uint8_t aAttrEnum) |
2029 | 0 | { |
2030 | 0 | mIntegerPairs[aAttrEnum].Init(aAttrEnum, |
2031 | 0 | mIntegerPairInfo[aAttrEnum].mDefaultValue1, |
2032 | 0 | mIntegerPairInfo[aAttrEnum].mDefaultValue2); |
2033 | 0 | } |
2034 | | |
2035 | | nsAttrValue |
2036 | | nsSVGElement::WillChangeIntegerPair(uint8_t aAttrEnum) |
2037 | 0 | { |
2038 | 0 | return WillChangeValue( |
2039 | 0 | *GetIntegerPairInfo().mIntegerPairInfo[aAttrEnum].mName); |
2040 | 0 | } |
2041 | | |
2042 | | void |
2043 | | nsSVGElement::DidChangeIntegerPair(uint8_t aAttrEnum, |
2044 | | const nsAttrValue& aEmptyOrOldValue) |
2045 | 0 | { |
2046 | 0 | IntegerPairAttributesInfo info = GetIntegerPairInfo(); |
2047 | 0 |
|
2048 | 0 | NS_ASSERTION(info.mIntegerPairCount > 0, |
2049 | 0 | "DidChangeIntegerPair on element with no integer pair attribs"); |
2050 | 0 | NS_ASSERTION(aAttrEnum < info.mIntegerPairCount, "aAttrEnum out of range"); |
2051 | 0 |
|
2052 | 0 | nsAttrValue newValue; |
2053 | 0 | newValue.SetTo(info.mIntegerPairs[aAttrEnum], nullptr); |
2054 | 0 |
|
2055 | 0 | DidChangeValue(*info.mIntegerPairInfo[aAttrEnum].mName, aEmptyOrOldValue, |
2056 | 0 | newValue); |
2057 | 0 | } |
2058 | | |
2059 | | void |
2060 | | nsSVGElement::DidAnimateIntegerPair(uint8_t aAttrEnum) |
2061 | 0 | { |
2062 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
2063 | 0 |
|
2064 | 0 | if (frame) { |
2065 | 0 | IntegerPairAttributesInfo info = GetIntegerPairInfo(); |
2066 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
2067 | 0 | *info.mIntegerPairInfo[aAttrEnum].mName, |
2068 | 0 | MutationEvent_Binding::SMIL); |
2069 | 0 | } |
2070 | 0 | } |
2071 | | |
2072 | | nsSVGElement::AngleAttributesInfo |
2073 | | nsSVGElement::GetAngleInfo() |
2074 | 0 | { |
2075 | 0 | return AngleAttributesInfo(nullptr, nullptr, 0); |
2076 | 0 | } |
2077 | | |
2078 | | void |
2079 | | nsSVGElement::AngleAttributesInfo::Reset(uint8_t aAttrEnum) |
2080 | 0 | { |
2081 | 0 | mAngles[aAttrEnum].Init(aAttrEnum, |
2082 | 0 | mAngleInfo[aAttrEnum].mDefaultValue, |
2083 | 0 | mAngleInfo[aAttrEnum].mDefaultUnitType); |
2084 | 0 | } |
2085 | | |
2086 | | nsAttrValue |
2087 | | nsSVGElement::WillChangeAngle(uint8_t aAttrEnum) |
2088 | 0 | { |
2089 | 0 | return WillChangeValue(*GetAngleInfo().mAngleInfo[aAttrEnum].mName); |
2090 | 0 | } |
2091 | | |
2092 | | void |
2093 | | nsSVGElement::DidChangeAngle(uint8_t aAttrEnum, |
2094 | | const nsAttrValue& aEmptyOrOldValue) |
2095 | 0 | { |
2096 | 0 | AngleAttributesInfo info = GetAngleInfo(); |
2097 | 0 |
|
2098 | 0 | NS_ASSERTION(info.mAngleCount > 0, |
2099 | 0 | "DidChangeAngle on element with no angle attribs"); |
2100 | 0 | NS_ASSERTION(aAttrEnum < info.mAngleCount, "aAttrEnum out of range"); |
2101 | 0 |
|
2102 | 0 | nsAttrValue newValue; |
2103 | 0 | newValue.SetTo(info.mAngles[aAttrEnum], nullptr); |
2104 | 0 |
|
2105 | 0 | DidChangeValue(*info.mAngleInfo[aAttrEnum].mName, aEmptyOrOldValue, newValue); |
2106 | 0 | } |
2107 | | |
2108 | | void |
2109 | | nsSVGElement::DidAnimateAngle(uint8_t aAttrEnum) |
2110 | 0 | { |
2111 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
2112 | 0 |
|
2113 | 0 | if (frame) { |
2114 | 0 | AngleAttributesInfo info = GetAngleInfo(); |
2115 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
2116 | 0 | *info.mAngleInfo[aAttrEnum].mName, |
2117 | 0 | MutationEvent_Binding::SMIL); |
2118 | 0 | } |
2119 | 0 | } |
2120 | | |
2121 | | nsSVGElement::BooleanAttributesInfo |
2122 | | nsSVGElement::GetBooleanInfo() |
2123 | 0 | { |
2124 | 0 | return BooleanAttributesInfo(nullptr, nullptr, 0); |
2125 | 0 | } |
2126 | | |
2127 | | void |
2128 | | nsSVGElement::BooleanAttributesInfo::Reset(uint8_t aAttrEnum) |
2129 | 0 | { |
2130 | 0 | mBooleans[aAttrEnum].Init(aAttrEnum, |
2131 | 0 | mBooleanInfo[aAttrEnum].mDefaultValue); |
2132 | 0 | } |
2133 | | |
2134 | | void |
2135 | | nsSVGElement::DidChangeBoolean(uint8_t aAttrEnum) |
2136 | 0 | { |
2137 | 0 | BooleanAttributesInfo info = GetBooleanInfo(); |
2138 | 0 |
|
2139 | 0 | NS_ASSERTION(info.mBooleanCount > 0, |
2140 | 0 | "DidChangeBoolean on element with no boolean attribs"); |
2141 | 0 | NS_ASSERTION(aAttrEnum < info.mBooleanCount, "aAttrEnum out of range"); |
2142 | 0 |
|
2143 | 0 | nsAttrValue attrValue(info.mBooleans[aAttrEnum].GetBaseValueAtom()); |
2144 | 0 | SetParsedAttr(kNameSpaceID_None, *info.mBooleanInfo[aAttrEnum].mName, nullptr, |
2145 | 0 | attrValue, true); |
2146 | 0 | } |
2147 | | |
2148 | | void |
2149 | | nsSVGElement::DidAnimateBoolean(uint8_t aAttrEnum) |
2150 | 0 | { |
2151 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
2152 | 0 |
|
2153 | 0 | if (frame) { |
2154 | 0 | BooleanAttributesInfo info = GetBooleanInfo(); |
2155 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
2156 | 0 | *info.mBooleanInfo[aAttrEnum].mName, |
2157 | 0 | MutationEvent_Binding::SMIL); |
2158 | 0 | } |
2159 | 0 | } |
2160 | | |
2161 | | nsSVGElement::EnumAttributesInfo |
2162 | | nsSVGElement::GetEnumInfo() |
2163 | 0 | { |
2164 | 0 | return EnumAttributesInfo(nullptr, nullptr, 0); |
2165 | 0 | } |
2166 | | |
2167 | | void |
2168 | | nsSVGElement::EnumAttributesInfo::Reset(uint8_t aAttrEnum) |
2169 | 0 | { |
2170 | 0 | mEnums[aAttrEnum].Init(aAttrEnum, |
2171 | 0 | mEnumInfo[aAttrEnum].mDefaultValue); |
2172 | 0 | } |
2173 | | |
2174 | | void |
2175 | | nsSVGElement::EnumAttributesInfo::SetUnknownValue(uint8_t aAttrEnum) |
2176 | 0 | { |
2177 | 0 | // Fortunately in SVG every enum's unknown value is 0 |
2178 | 0 | mEnums[aAttrEnum].Init(aAttrEnum, 0); |
2179 | 0 | } |
2180 | | |
2181 | | void |
2182 | | nsSVGElement::DidChangeEnum(uint8_t aAttrEnum) |
2183 | 0 | { |
2184 | 0 | EnumAttributesInfo info = GetEnumInfo(); |
2185 | 0 |
|
2186 | 0 | NS_ASSERTION(info.mEnumCount > 0, |
2187 | 0 | "DidChangeEnum on element with no enum attribs"); |
2188 | 0 | NS_ASSERTION(aAttrEnum < info.mEnumCount, "aAttrEnum out of range"); |
2189 | 0 |
|
2190 | 0 | nsAttrValue attrValue(info.mEnums[aAttrEnum].GetBaseValueAtom(this)); |
2191 | 0 | SetParsedAttr(kNameSpaceID_None, *info.mEnumInfo[aAttrEnum].mName, nullptr, |
2192 | 0 | attrValue, true); |
2193 | 0 | } |
2194 | | |
2195 | | void |
2196 | | nsSVGElement::DidAnimateEnum(uint8_t aAttrEnum) |
2197 | 0 | { |
2198 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
2199 | 0 |
|
2200 | 0 | if (frame) { |
2201 | 0 | EnumAttributesInfo info = GetEnumInfo(); |
2202 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
2203 | 0 | *info.mEnumInfo[aAttrEnum].mName, |
2204 | 0 | MutationEvent_Binding::SMIL); |
2205 | 0 | } |
2206 | 0 | } |
2207 | | |
2208 | | nsSVGViewBox * |
2209 | | nsSVGElement::GetViewBox() |
2210 | 0 | { |
2211 | 0 | return nullptr; |
2212 | 0 | } |
2213 | | |
2214 | | nsAttrValue |
2215 | | nsSVGElement::WillChangeViewBox() |
2216 | 0 | { |
2217 | 0 | return WillChangeValue(nsGkAtoms::viewBox); |
2218 | 0 | } |
2219 | | |
2220 | | void |
2221 | | nsSVGElement::DidChangeViewBox(const nsAttrValue& aEmptyOrOldValue) |
2222 | 0 | { |
2223 | 0 | nsSVGViewBox *viewBox = GetViewBox(); |
2224 | 0 |
|
2225 | 0 | NS_ASSERTION(viewBox, "DidChangeViewBox on element with no viewBox attrib"); |
2226 | 0 |
|
2227 | 0 | nsAttrValue newValue; |
2228 | 0 | newValue.SetTo(*viewBox, nullptr); |
2229 | 0 |
|
2230 | 0 | DidChangeValue(nsGkAtoms::viewBox, aEmptyOrOldValue, newValue); |
2231 | 0 | } |
2232 | | |
2233 | | void |
2234 | | nsSVGElement::DidAnimateViewBox() |
2235 | 0 | { |
2236 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
2237 | 0 |
|
2238 | 0 | if (frame) { |
2239 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
2240 | 0 | nsGkAtoms::viewBox, |
2241 | 0 | MutationEvent_Binding::SMIL); |
2242 | 0 | } |
2243 | 0 | } |
2244 | | |
2245 | | SVGAnimatedPreserveAspectRatio * |
2246 | | nsSVGElement::GetPreserveAspectRatio() |
2247 | 0 | { |
2248 | 0 | return nullptr; |
2249 | 0 | } |
2250 | | |
2251 | | nsAttrValue |
2252 | | nsSVGElement::WillChangePreserveAspectRatio() |
2253 | 0 | { |
2254 | 0 | return WillChangeValue(nsGkAtoms::preserveAspectRatio); |
2255 | 0 | } |
2256 | | |
2257 | | void |
2258 | | nsSVGElement::DidChangePreserveAspectRatio(const nsAttrValue& aEmptyOrOldValue) |
2259 | 0 | { |
2260 | 0 | SVGAnimatedPreserveAspectRatio *preserveAspectRatio = |
2261 | 0 | GetPreserveAspectRatio(); |
2262 | 0 |
|
2263 | 0 | NS_ASSERTION(preserveAspectRatio, |
2264 | 0 | "DidChangePreserveAspectRatio on element with no " |
2265 | 0 | "preserveAspectRatio attrib"); |
2266 | 0 |
|
2267 | 0 | nsAttrValue newValue; |
2268 | 0 | newValue.SetTo(*preserveAspectRatio, nullptr); |
2269 | 0 |
|
2270 | 0 | DidChangeValue(nsGkAtoms::preserveAspectRatio, aEmptyOrOldValue, newValue); |
2271 | 0 | } |
2272 | | |
2273 | | void |
2274 | | nsSVGElement::DidAnimatePreserveAspectRatio() |
2275 | 0 | { |
2276 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
2277 | 0 |
|
2278 | 0 | if (frame) { |
2279 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
2280 | 0 | nsGkAtoms::preserveAspectRatio, |
2281 | 0 | MutationEvent_Binding::SMIL); |
2282 | 0 | } |
2283 | 0 | } |
2284 | | |
2285 | | nsAttrValue |
2286 | | nsSVGElement::WillChangeTransformList() |
2287 | 0 | { |
2288 | 0 | return WillChangeValue(GetTransformListAttrName()); |
2289 | 0 | } |
2290 | | |
2291 | | void |
2292 | | nsSVGElement::DidChangeTransformList(const nsAttrValue& aEmptyOrOldValue) |
2293 | 0 | { |
2294 | 0 | MOZ_ASSERT(GetTransformListAttrName(), |
2295 | 0 | "Changing non-existent transform list?"); |
2296 | 0 |
|
2297 | 0 | // The transform attribute is being set, so we must ensure that the |
2298 | 0 | // SVGAnimatedTransformList is/has been allocated: |
2299 | 0 | nsAttrValue newValue; |
2300 | 0 | newValue.SetTo(GetAnimatedTransformList(DO_ALLOCATE)->GetBaseValue(), nullptr); |
2301 | 0 |
|
2302 | 0 | DidChangeValue(GetTransformListAttrName(), aEmptyOrOldValue, newValue); |
2303 | 0 | } |
2304 | | |
2305 | | void |
2306 | | nsSVGElement::DidAnimateTransformList(int32_t aModType) |
2307 | 0 | { |
2308 | 0 | MOZ_ASSERT(GetTransformListAttrName(), |
2309 | 0 | "Animating non-existent transform data?"); |
2310 | 0 |
|
2311 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
2312 | 0 |
|
2313 | 0 | if (frame) { |
2314 | 0 | nsAtom *transformAttr = GetTransformListAttrName(); |
2315 | 0 | frame->AttributeChanged(kNameSpaceID_None, |
2316 | 0 | transformAttr, |
2317 | 0 | aModType); |
2318 | 0 | // When script changes the 'transform' attribute, Element::SetAttrAndNotify |
2319 | 0 | // will call nsNodeUtils::AttributeChanged, under which |
2320 | 0 | // SVGTransformableElement::GetAttributeChangeHint will be called and an |
2321 | 0 | // appropriate change event posted to update our frame's overflow rects. |
2322 | 0 | // The SetAttrAndNotify doesn't happen for transform changes caused by |
2323 | 0 | // 'animateTransform' though (and sending out the mutation events that |
2324 | 0 | // nsNodeUtils::AttributeChanged dispatches would be inappropriate |
2325 | 0 | // anyway), so we need to post the change event ourself. |
2326 | 0 | nsChangeHint changeHint = GetAttributeChangeHint(transformAttr, aModType); |
2327 | 0 | if (changeHint) { |
2328 | 0 | nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint); |
2329 | 0 | } |
2330 | 0 | } |
2331 | 0 | } |
2332 | | |
2333 | | nsSVGElement::StringAttributesInfo |
2334 | | nsSVGElement::GetStringInfo() |
2335 | 0 | { |
2336 | 0 | return StringAttributesInfo(nullptr, nullptr, 0); |
2337 | 0 | } |
2338 | | |
2339 | | void |
2340 | | nsSVGElement::StringAttributesInfo::Reset(uint8_t aAttrEnum) |
2341 | 0 | { |
2342 | 0 | mStrings[aAttrEnum].Init(aAttrEnum); |
2343 | 0 | } |
2344 | | |
2345 | | void |
2346 | | nsSVGElement::GetStringBaseValue(uint8_t aAttrEnum, nsAString& aResult) const |
2347 | 0 | { |
2348 | 0 | nsSVGElement::StringAttributesInfo info = const_cast<nsSVGElement*>(this)->GetStringInfo(); |
2349 | 0 |
|
2350 | 0 | NS_ASSERTION(info.mStringCount > 0, |
2351 | 0 | "GetBaseValue on element with no string attribs"); |
2352 | 0 |
|
2353 | 0 | NS_ASSERTION(aAttrEnum < info.mStringCount, "aAttrEnum out of range"); |
2354 | 0 |
|
2355 | 0 | GetAttr(info.mStringInfo[aAttrEnum].mNamespaceID, |
2356 | 0 | *info.mStringInfo[aAttrEnum].mName, aResult); |
2357 | 0 | } |
2358 | | |
2359 | | void |
2360 | | nsSVGElement::SetStringBaseValue(uint8_t aAttrEnum, const nsAString& aValue) |
2361 | 0 | { |
2362 | 0 | nsSVGElement::StringAttributesInfo info = GetStringInfo(); |
2363 | 0 |
|
2364 | 0 | NS_ASSERTION(info.mStringCount > 0, |
2365 | 0 | "SetBaseValue on element with no string attribs"); |
2366 | 0 |
|
2367 | 0 | NS_ASSERTION(aAttrEnum < info.mStringCount, "aAttrEnum out of range"); |
2368 | 0 |
|
2369 | 0 | SetAttr(info.mStringInfo[aAttrEnum].mNamespaceID, |
2370 | 0 | *info.mStringInfo[aAttrEnum].mName, aValue, true); |
2371 | 0 | } |
2372 | | |
2373 | | void |
2374 | | nsSVGElement::DidAnimateString(uint8_t aAttrEnum) |
2375 | 0 | { |
2376 | 0 | nsIFrame* frame = GetPrimaryFrame(); |
2377 | 0 |
|
2378 | 0 | if (frame) { |
2379 | 0 | StringAttributesInfo info = GetStringInfo(); |
2380 | 0 | frame->AttributeChanged(info.mStringInfo[aAttrEnum].mNamespaceID, |
2381 | 0 | *info.mStringInfo[aAttrEnum].mName, |
2382 | 0 | MutationEvent_Binding::SMIL); |
2383 | 0 | } |
2384 | 0 | } |
2385 | | |
2386 | | nsSVGElement::StringListAttributesInfo |
2387 | | nsSVGElement::GetStringListInfo() |
2388 | 0 | { |
2389 | 0 | return StringListAttributesInfo(nullptr, nullptr, 0); |
2390 | 0 | } |
2391 | | |
2392 | | nsAttrValue |
2393 | | nsSVGElement::WillChangeStringList(bool aIsConditionalProcessingAttribute, |
2394 | | uint8_t aAttrEnum) |
2395 | 0 | { |
2396 | 0 | nsAtom* name; |
2397 | 0 | if (aIsConditionalProcessingAttribute) { |
2398 | 0 | nsCOMPtr<SVGTests> tests(do_QueryInterface(this)); |
2399 | 0 | name = tests->GetAttrName(aAttrEnum); |
2400 | 0 | } else { |
2401 | 0 | name = *GetStringListInfo().mStringListInfo[aAttrEnum].mName; |
2402 | 0 | } |
2403 | 0 | return WillChangeValue(name); |
2404 | 0 | } |
2405 | | |
2406 | | void |
2407 | | nsSVGElement::DidChangeStringList(bool aIsConditionalProcessingAttribute, |
2408 | | uint8_t aAttrEnum, |
2409 | | const nsAttrValue& aEmptyOrOldValue) |
2410 | 0 | { |
2411 | 0 | nsAtom* name; |
2412 | 0 | nsAttrValue newValue; |
2413 | 0 | nsCOMPtr<SVGTests> tests; |
2414 | 0 |
|
2415 | 0 | if (aIsConditionalProcessingAttribute) { |
2416 | 0 | tests = do_QueryObject(this); |
2417 | 0 | name = tests->GetAttrName(aAttrEnum); |
2418 | 0 | tests->GetAttrValue(aAttrEnum, newValue); |
2419 | 0 | } else { |
2420 | 0 | StringListAttributesInfo info = GetStringListInfo(); |
2421 | 0 |
|
2422 | 0 | NS_ASSERTION(info.mStringListCount > 0, |
2423 | 0 | "DidChangeStringList on element with no string list attribs"); |
2424 | 0 | NS_ASSERTION(aAttrEnum < info.mStringListCount, "aAttrEnum out of range"); |
2425 | 0 |
|
2426 | 0 | name = *info.mStringListInfo[aAttrEnum].mName; |
2427 | 0 | newValue.SetTo(info.mStringLists[aAttrEnum], nullptr); |
2428 | 0 | } |
2429 | 0 |
|
2430 | 0 | DidChangeValue(name, aEmptyOrOldValue, newValue); |
2431 | 0 |
|
2432 | 0 | if (aIsConditionalProcessingAttribute) { |
2433 | 0 | tests->MaybeInvalidate(); |
2434 | 0 | } |
2435 | 0 | } |
2436 | | |
2437 | | void |
2438 | | nsSVGElement::StringListAttributesInfo::Reset(uint8_t aAttrEnum) |
2439 | 0 | { |
2440 | 0 | mStringLists[aAttrEnum].Clear(); |
2441 | 0 | // caller notifies |
2442 | 0 | } |
2443 | | |
2444 | | nsresult |
2445 | | nsSVGElement::ReportAttributeParseFailure(nsIDocument* aDocument, |
2446 | | nsAtom* aAttribute, |
2447 | | const nsAString& aValue) |
2448 | 0 | { |
2449 | 0 | const nsString& attributeValue = PromiseFlatString(aValue); |
2450 | 0 | const char16_t *strings[] = { aAttribute->GetUTF16String(), |
2451 | 0 | attributeValue.get() }; |
2452 | 0 | return SVGContentUtils::ReportToConsole(aDocument, |
2453 | 0 | "AttributeParseWarning", |
2454 | 0 | strings, ArrayLength(strings)); |
2455 | 0 | } |
2456 | | |
2457 | | void |
2458 | | nsSVGElement::RecompileScriptEventListeners() |
2459 | 0 | { |
2460 | 0 | int32_t i, count = mAttrs.AttrCount(); |
2461 | 0 | for (i = 0; i < count; ++i) { |
2462 | 0 | const nsAttrName *name = mAttrs.AttrNameAt(i); |
2463 | 0 |
|
2464 | 0 | // Eventlistenener-attributes are always in the null namespace |
2465 | 0 | if (!name->IsAtom()) { |
2466 | 0 | continue; |
2467 | 0 | } |
2468 | 0 | |
2469 | 0 | nsAtom *attr = name->Atom(); |
2470 | 0 | if (!IsEventAttributeName(attr)) { |
2471 | 0 | continue; |
2472 | 0 | } |
2473 | 0 | |
2474 | 0 | nsAutoString value; |
2475 | 0 | GetAttr(attr, value); |
2476 | 0 | SetEventHandler(GetEventNameForAttr(attr), value, true); |
2477 | 0 | } |
2478 | 0 | } |
2479 | | |
2480 | | UniquePtr<nsISMILAttr> |
2481 | | nsSVGElement::GetAnimatedAttr(int32_t aNamespaceID, nsAtom* aName) |
2482 | 0 | { |
2483 | 0 | if (aNamespaceID == kNameSpaceID_None) { |
2484 | 0 | // Transforms: |
2485 | 0 | if (GetTransformListAttrName() == aName) { |
2486 | 0 | // The transform attribute is being animated, so we must ensure that the |
2487 | 0 | // SVGAnimatedTransformList is/has been allocated: |
2488 | 0 | return GetAnimatedTransformList(DO_ALLOCATE)->ToSMILAttr(this); |
2489 | 0 | } |
2490 | 0 | |
2491 | 0 | // Motion (fake 'attribute' for animateMotion) |
2492 | 0 | if (aName == nsGkAtoms::mozAnimateMotionDummyAttr) { |
2493 | 0 | return MakeUnique<SVGMotionSMILAttr>(this); |
2494 | 0 | } |
2495 | 0 | |
2496 | 0 | // Lengths: |
2497 | 0 | LengthAttributesInfo info = GetLengthInfo(); |
2498 | 0 | for (uint32_t i = 0; i < info.mLengthCount; i++) { |
2499 | 0 | if (aName == *info.mLengthInfo[i].mName) { |
2500 | 0 | return info.mLengths[i].ToSMILAttr(this); |
2501 | 0 | } |
2502 | 0 | } |
2503 | 0 |
|
2504 | 0 | // Numbers: |
2505 | 0 | { |
2506 | 0 | NumberAttributesInfo info = GetNumberInfo(); |
2507 | 0 | for (uint32_t i = 0; i < info.mNumberCount; i++) { |
2508 | 0 | if (aName == *info.mNumberInfo[i].mName) { |
2509 | 0 | return info.mNumbers[i].ToSMILAttr(this); |
2510 | 0 | } |
2511 | 0 | } |
2512 | 0 | } |
2513 | 0 |
|
2514 | 0 | // Number Pairs: |
2515 | 0 | { |
2516 | 0 | NumberPairAttributesInfo info = GetNumberPairInfo(); |
2517 | 0 | for (uint32_t i = 0; i < info.mNumberPairCount; i++) { |
2518 | 0 | if (aName == *info.mNumberPairInfo[i].mName) { |
2519 | 0 | return info.mNumberPairs[i].ToSMILAttr(this); |
2520 | 0 | } |
2521 | 0 | } |
2522 | 0 | } |
2523 | 0 |
|
2524 | 0 | // Integers: |
2525 | 0 | { |
2526 | 0 | IntegerAttributesInfo info = GetIntegerInfo(); |
2527 | 0 | for (uint32_t i = 0; i < info.mIntegerCount; i++) { |
2528 | 0 | if (aName == *info.mIntegerInfo[i].mName) { |
2529 | 0 | return info.mIntegers[i].ToSMILAttr(this); |
2530 | 0 | } |
2531 | 0 | } |
2532 | 0 | } |
2533 | 0 |
|
2534 | 0 | // Integer Pairs: |
2535 | 0 | { |
2536 | 0 | IntegerPairAttributesInfo info = GetIntegerPairInfo(); |
2537 | 0 | for (uint32_t i = 0; i < info.mIntegerPairCount; i++) { |
2538 | 0 | if (aName == *info.mIntegerPairInfo[i].mName) { |
2539 | 0 | return info.mIntegerPairs[i].ToSMILAttr(this); |
2540 | 0 | } |
2541 | 0 | } |
2542 | 0 | } |
2543 | 0 |
|
2544 | 0 | // Enumerations: |
2545 | 0 | { |
2546 | 0 | EnumAttributesInfo info = GetEnumInfo(); |
2547 | 0 | for (uint32_t i = 0; i < info.mEnumCount; i++) { |
2548 | 0 | if (aName == *info.mEnumInfo[i].mName) { |
2549 | 0 | return info.mEnums[i].ToSMILAttr(this); |
2550 | 0 | } |
2551 | 0 | } |
2552 | 0 | } |
2553 | 0 |
|
2554 | 0 | // Booleans: |
2555 | 0 | { |
2556 | 0 | BooleanAttributesInfo info = GetBooleanInfo(); |
2557 | 0 | for (uint32_t i = 0; i < info.mBooleanCount; i++) { |
2558 | 0 | if (aName == *info.mBooleanInfo[i].mName) { |
2559 | 0 | return info.mBooleans[i].ToSMILAttr(this); |
2560 | 0 | } |
2561 | 0 | } |
2562 | 0 | } |
2563 | 0 |
|
2564 | 0 | // Angles: |
2565 | 0 | { |
2566 | 0 | AngleAttributesInfo info = GetAngleInfo(); |
2567 | 0 | for (uint32_t i = 0; i < info.mAngleCount; i++) { |
2568 | 0 | if (aName == *info.mAngleInfo[i].mName) { |
2569 | 0 | return info.mAngles[i].ToSMILAttr(this); |
2570 | 0 | } |
2571 | 0 | } |
2572 | 0 | } |
2573 | 0 |
|
2574 | 0 | // viewBox: |
2575 | 0 | if (aName == nsGkAtoms::viewBox) { |
2576 | 0 | nsSVGViewBox *viewBox = GetViewBox(); |
2577 | 0 | return viewBox ? viewBox->ToSMILAttr(this) : nullptr; |
2578 | 0 | } |
2579 | 0 |
|
2580 | 0 | // preserveAspectRatio: |
2581 | 0 | if (aName == nsGkAtoms::preserveAspectRatio) { |
2582 | 0 | SVGAnimatedPreserveAspectRatio *preserveAspectRatio = |
2583 | 0 | GetPreserveAspectRatio(); |
2584 | 0 | return preserveAspectRatio ? |
2585 | 0 | preserveAspectRatio->ToSMILAttr(this) : nullptr; |
2586 | 0 | } |
2587 | 0 |
|
2588 | 0 | // NumberLists: |
2589 | 0 | { |
2590 | 0 | NumberListAttributesInfo info = GetNumberListInfo(); |
2591 | 0 | for (uint32_t i = 0; i < info.mNumberListCount; i++) { |
2592 | 0 | if (aName == *info.mNumberListInfo[i].mName) { |
2593 | 0 | MOZ_ASSERT(i <= UCHAR_MAX, "Too many attributes"); |
2594 | 0 | return info.mNumberLists[i].ToSMILAttr(this, uint8_t(i)); |
2595 | 0 | } |
2596 | 0 | } |
2597 | 0 | } |
2598 | 0 |
|
2599 | 0 | // LengthLists: |
2600 | 0 | { |
2601 | 0 | LengthListAttributesInfo info = GetLengthListInfo(); |
2602 | 0 | for (uint32_t i = 0; i < info.mLengthListCount; i++) { |
2603 | 0 | if (aName == *info.mLengthListInfo[i].mName) { |
2604 | 0 | MOZ_ASSERT(i <= UCHAR_MAX, "Too many attributes"); |
2605 | 0 | return info.mLengthLists[i].ToSMILAttr(this, |
2606 | 0 | uint8_t(i), |
2607 | 0 | info.mLengthListInfo[i].mAxis, |
2608 | 0 | info.mLengthListInfo[i].mCouldZeroPadList); |
2609 | 0 | } |
2610 | 0 | } |
2611 | 0 | } |
2612 | 0 |
|
2613 | 0 | // PointLists: |
2614 | 0 | { |
2615 | 0 | if (GetPointListAttrName() == aName) { |
2616 | 0 | SVGAnimatedPointList *pointList = GetAnimatedPointList(); |
2617 | 0 | if (pointList) { |
2618 | 0 | return pointList->ToSMILAttr(this); |
2619 | 0 | } |
2620 | 0 | } |
2621 | 0 | } |
2622 | 0 | |
2623 | 0 | // PathSegLists: |
2624 | 0 | { |
2625 | 0 | if (GetPathDataAttrName() == aName) { |
2626 | 0 | SVGAnimatedPathSegList *segList = GetAnimPathSegList(); |
2627 | 0 | if (segList) { |
2628 | 0 | return segList->ToSMILAttr(this); |
2629 | 0 | } |
2630 | 0 | } |
2631 | 0 | } |
2632 | 0 | |
2633 | 0 | if (aName == nsGkAtoms::_class) { |
2634 | 0 | return mClassAttribute.ToSMILAttr(this); |
2635 | 0 | } |
2636 | 0 | } |
2637 | 0 | |
2638 | 0 | // Strings |
2639 | 0 | { |
2640 | 0 | StringAttributesInfo info = GetStringInfo(); |
2641 | 0 | for (uint32_t i = 0; i < info.mStringCount; i++) { |
2642 | 0 | if (aNamespaceID == info.mStringInfo[i].mNamespaceID && |
2643 | 0 | aName == *info.mStringInfo[i].mName) { |
2644 | 0 | return info.mStrings[i].ToSMILAttr(this); |
2645 | 0 | } |
2646 | 0 | } |
2647 | 0 | } |
2648 | 0 |
|
2649 | 0 | return nullptr; |
2650 | 0 | } |
2651 | | |
2652 | | void |
2653 | | nsSVGElement::AnimationNeedsResample() |
2654 | 0 | { |
2655 | 0 | nsIDocument* doc = GetComposedDoc(); |
2656 | 0 | if (doc && doc->HasAnimationController()) { |
2657 | 0 | doc->GetAnimationController()->SetResampleNeeded(); |
2658 | 0 | } |
2659 | 0 | } |
2660 | | |
2661 | | void |
2662 | | nsSVGElement::FlushAnimations() |
2663 | 0 | { |
2664 | 0 | nsIDocument* doc = GetComposedDoc(); |
2665 | 0 | if (doc && doc->HasAnimationController()) { |
2666 | 0 | doc->GetAnimationController()->FlushResampleRequests(); |
2667 | 0 | } |
2668 | 0 | } |