1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann
3 * <zimmermann@kde.org>
4 * Copyright (C) 2004, 2005, 2006, 2008 Rob Buis <buis@kde.org>
5 * Copyright (C) 2008 Apple Inc. All rights reserved.
6 * Copyright (C) 2008 Alp Toker <alp@atoker.com>
7 * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25 #include "third_party/blink/renderer/core/svg/svg_element.h"
26
27 #include "base/auto_reset.h"
28 #include "base/stl_util.h"
29 #include "third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.h"
30 #include "third_party/blink/renderer/core/animation/document_animations.h"
31 #include "third_party/blink/renderer/core/animation/effect_stack.h"
32 #include "third_party/blink/renderer/core/animation/element_animations.h"
33 #include "third_party/blink/renderer/core/animation/invalidatable_interpolation.h"
34 #include "third_party/blink/renderer/core/animation/keyframe_effect.h"
35 #include "third_party/blink/renderer/core/animation/svg_interpolation_environment.h"
36 #include "third_party/blink/renderer/core/animation/svg_interpolation_types_map.h"
37 #include "third_party/blink/renderer/core/css/css_property_id_templates.h"
38 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
39 #include "third_party/blink/renderer/core/dom/document.h"
40 #include "third_party/blink/renderer/core/dom/element_traversal.h"
41 #include "third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h"
42 #include "third_party/blink/renderer/core/dom/events/event.h"
43 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
44 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
45 #include "third_party/blink/renderer/core/dom/shadow_root.h"
46 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
47 #include "third_party/blink/renderer/core/frame/settings.h"
48 #include "third_party/blink/renderer/core/html/html_element.h"
49 #include "third_party/blink/renderer/core/html_names.h"
50 #include "third_party/blink/renderer/core/inspector/console_message.h"
51 #include "third_party/blink/renderer/core/layout/layout_object.h"
52 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
53 #include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
54 #include "third_party/blink/renderer/core/svg/animation/element_smil_animations.h"
55 #include "third_party/blink/renderer/core/svg/properties/svg_animated_property.h"
56 #include "third_party/blink/renderer/core/svg/properties/svg_property.h"
57 #include "third_party/blink/renderer/core/svg/svg_animated_string.h"
58 #include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
59 #include "third_party/blink/renderer/core/svg/svg_element_rare_data.h"
60 #include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
61 #include "third_party/blink/renderer/core/svg/svg_svg_element.h"
62 #include "third_party/blink/renderer/core/svg/svg_title_element.h"
63 #include "third_party/blink/renderer/core/svg/svg_use_element.h"
64 #include "third_party/blink/renderer/core/svg_names.h"
65 #include "third_party/blink/renderer/core/xml_names.h"
66 #include "third_party/blink/renderer/platform/heap/heap.h"
67 #include "third_party/blink/renderer/platform/wtf/threading.h"
68
69 namespace blink {
70
SVGElement(const QualifiedName & tag_name,Document & document,ConstructionType construction_type)71 SVGElement::SVGElement(const QualifiedName& tag_name,
72 Document& document,
73 ConstructionType construction_type)
74 : Element(tag_name, &document, construction_type),
75 svg_rare_data_(nullptr),
76 class_name_(
77 MakeGarbageCollected<SVGAnimatedString>(this,
78 html_names::kClassAttr)) {
79 AddToPropertyMap(class_name_);
80 SetHasCustomStyleCallbacks();
81 }
82
~SVGElement()83 SVGElement::~SVGElement() {
84 DCHECK(isConnected() || !HasRelativeLengths());
85 }
86
DetachLayoutTree(bool performing_reattach)87 void SVGElement::DetachLayoutTree(bool performing_reattach) {
88 Element::DetachLayoutTree(performing_reattach);
89 // To avoid a noncollectable Blink GC reference cycle, we must clear the
90 // ComputedStyle here. See http://crbug.com/878032#c11
91 if (HasSVGRareData())
92 SvgRareData()->ClearOverriddenComputedStyle();
93 }
94
WillRecalcStyle(const StyleRecalcChange change)95 void SVGElement::WillRecalcStyle(const StyleRecalcChange change) {
96 if (!HasSVGRareData())
97 return;
98 // If the style changes because of a regular property change (not induced by
99 // SMIL animations themselves) reset the "computed style without SMIL style
100 // properties", so the base value change gets reflected.
101 if (change.ShouldRecalcStyleFor(*this))
102 SvgRareData()->SetNeedsOverrideComputedStyleUpdate();
103 }
104
EnsureSVGRareData()105 SVGElementRareData* SVGElement::EnsureSVGRareData() {
106 if (!svg_rare_data_)
107 svg_rare_data_ = MakeGarbageCollected<SVGElementRareData>();
108 return svg_rare_data_.Get();
109 }
110
IsOutermostSVGSVGElement() const111 bool SVGElement::IsOutermostSVGSVGElement() const {
112 if (!IsA<SVGSVGElement>(*this))
113 return false;
114
115 // Element may not be in the document, pretend we're outermost for viewport(),
116 // getCTM(), etc.
117 if (!parentNode())
118 return true;
119
120 // We act like an outermost SVG element, if we're a direct child of a
121 // <foreignObject> element.
122 if (IsA<SVGForeignObjectElement>(*parentNode()))
123 return true;
124
125 // If we're living in a shadow tree, we're a <svg> element that got created as
126 // replacement for a <symbol> element or a cloned <svg> element in the
127 // referenced tree. In that case we're always an inner <svg> element.
128 if (InUseShadowTree() && ParentOrShadowHostElement() &&
129 ParentOrShadowHostElement()->IsSVGElement())
130 return false;
131
132 // This is true whenever this is the outermost SVG, even if there are HTML
133 // elements outside it
134 return !parentNode()->IsSVGElement();
135 }
136
ReportAttributeParsingError(SVGParsingError error,const QualifiedName & name,const AtomicString & value)137 void SVGElement::ReportAttributeParsingError(SVGParsingError error,
138 const QualifiedName& name,
139 const AtomicString& value) {
140 if (error == SVGParseStatus::kNoError)
141 return;
142 // Don't report any errors on attribute removal.
143 if (value.IsNull())
144 return;
145 GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
146 mojom::ConsoleMessageSource::kRendering,
147 mojom::ConsoleMessageLevel::kError,
148 "Error: " + error.Format(tagName(), name, value)));
149 }
150
title() const151 String SVGElement::title() const {
152 // According to spec, we should not return titles when hovering over root
153 // <svg> elements imported as a standalone document(those <title> elements
154 // are the title of the document, not a tooltip) so we instantly return.
155 if (IsA<SVGSVGElement>(*this) && this == GetDocument().documentElement())
156 return String();
157
158 if (InUseShadowTree()) {
159 String use_title(OwnerShadowHost()->title());
160 if (!use_title.IsEmpty())
161 return use_title;
162 }
163
164 // If we aren't an instance in a <use> or the <use> title was not found, then
165 // find the first <title> child of this element.
166 // If a title child was found, return the text contents.
167 if (Element* title_element = Traversal<SVGTitleElement>::FirstChild(*this))
168 return title_element->innerText();
169
170 // Otherwise return a null/empty string.
171 return String();
172 }
173
InstanceUpdatesBlocked() const174 bool SVGElement::InstanceUpdatesBlocked() const {
175 return HasSVGRareData() && SvgRareData()->InstanceUpdatesBlocked();
176 }
177
SetInstanceUpdatesBlocked(bool value)178 void SVGElement::SetInstanceUpdatesBlocked(bool value) {
179 if (HasSVGRareData())
180 SvgRareData()->SetInstanceUpdatesBlocked(value);
181 }
182
SetWebAnimationsPending()183 void SVGElement::SetWebAnimationsPending() {
184 GetDocument().AccessSVGExtensions().AddWebAnimationsPendingSVGElement(*this);
185 EnsureSVGRareData()->SetWebAnimatedAttributesDirty(true);
186 }
187
IsSVGAttributeHandle(const PropertyHandle & property_handle)188 static bool IsSVGAttributeHandle(const PropertyHandle& property_handle) {
189 return property_handle.IsSVGAttribute();
190 }
191
ApplyActiveWebAnimations()192 void SVGElement::ApplyActiveWebAnimations() {
193 ActiveInterpolationsMap active_interpolations_map =
194 EffectStack::ActiveInterpolations(
195 &GetElementAnimations()->GetEffectStack(), nullptr, nullptr,
196 KeyframeEffect::kDefaultPriority, IsSVGAttributeHandle);
197 for (auto& entry : active_interpolations_map) {
198 const QualifiedName& attribute = entry.key.SvgAttribute();
199 SVGInterpolationTypesMap map;
200 SVGInterpolationEnvironment environment(
201 map, *this, PropertyFromAttribute(attribute)->BaseValueBase());
202 InvalidatableInterpolation::ApplyStack(*entry.value, environment);
203 }
204 if (!HasSVGRareData())
205 return;
206 SvgRareData()->SetWebAnimatedAttributesDirty(false);
207 }
208
209 template <typename T>
ForSelfAndInstances(SVGElement * element,T callback)210 static void ForSelfAndInstances(SVGElement* element, T callback) {
211 SVGElement::InstanceUpdateBlocker blocker(element);
212 callback(element);
213 for (SVGElement* instance : element->InstancesForElement())
214 callback(instance);
215 }
216
SetWebAnimatedAttribute(const QualifiedName & attribute,SVGPropertyBase * value)217 void SVGElement::SetWebAnimatedAttribute(const QualifiedName& attribute,
218 SVGPropertyBase* value) {
219 SetAnimatedAttribute(attribute, value);
220 EnsureSVGRareData()->WebAnimatedAttributes().insert(attribute);
221 }
222
ClearWebAnimatedAttributes()223 void SVGElement::ClearWebAnimatedAttributes() {
224 if (!HasSVGRareData())
225 return;
226 HashSet<QualifiedName>& animated_attributes =
227 SvgRareData()->WebAnimatedAttributes();
228 for (const QualifiedName& attribute : animated_attributes)
229 ClearAnimatedAttribute(attribute);
230 animated_attributes.clear();
231 }
232
GetSMILAnimations() const233 ElementSMILAnimations* SVGElement::GetSMILAnimations() const {
234 if (!HasSVGRareData())
235 return nullptr;
236 return SvgRareData()->GetSMILAnimations();
237 }
238
EnsureSMILAnimations()239 ElementSMILAnimations& SVGElement::EnsureSMILAnimations() {
240 return EnsureSVGRareData()->EnsureSMILAnimations();
241 }
242
SetAnimatedAttribute(const QualifiedName & attribute,SVGPropertyBase * value)243 void SVGElement::SetAnimatedAttribute(const QualifiedName& attribute,
244 SVGPropertyBase* value) {
245 // When animating the 'class' attribute we need to have our own
246 // unique element data since we'll be altering the active class
247 // names for the element.
248 if (attribute == html_names::kClassAttr)
249 EnsureUniqueElementData();
250
251 ForSelfAndInstances(this, [&attribute, &value](SVGElement* element) {
252 if (SVGAnimatedPropertyBase* animated_property =
253 element->PropertyFromAttribute(attribute)) {
254 animated_property->SetAnimatedValue(value);
255 element->SvgAttributeChanged(attribute);
256 }
257 });
258 }
259
ClearAnimatedAttribute(const QualifiedName & attribute)260 void SVGElement::ClearAnimatedAttribute(const QualifiedName& attribute) {
261 ForSelfAndInstances(this, [&attribute](SVGElement* element) {
262 if (SVGAnimatedPropertyBase* animated_property =
263 element->PropertyFromAttribute(attribute)) {
264 animated_property->AnimationEnded();
265 element->SvgAttributeChanged(attribute);
266 }
267 });
268 }
269
SetAnimatedMotionTransform(const AffineTransform & motion_transform)270 void SVGElement::SetAnimatedMotionTransform(
271 const AffineTransform& motion_transform) {
272 ForSelfAndInstances(this, [&motion_transform](SVGElement* element) {
273 AffineTransform* transform = element->AnimateMotionTransform();
274 DCHECK(transform);
275 *transform = motion_transform;
276 if (LayoutObject* layout_object = element->GetLayoutObject()) {
277 layout_object->SetNeedsTransformUpdate();
278 // The transform paint property relies on the SVG transform value.
279 layout_object->SetNeedsPaintPropertyUpdate();
280 MarkForLayoutAndParentResourceInvalidation(*layout_object);
281 }
282 });
283 }
284
ClearAnimatedMotionTransform()285 void SVGElement::ClearAnimatedMotionTransform() {
286 SetAnimatedMotionTransform(AffineTransform());
287 }
288
HasNonCSSPropertyAnimations() const289 bool SVGElement::HasNonCSSPropertyAnimations() const {
290 if (HasSVGRareData() && !SvgRareData()->WebAnimatedAttributes().IsEmpty())
291 return true;
292 if (GetSMILAnimations() && GetSMILAnimations()->HasAnimations())
293 return true;
294 return false;
295 }
296
LocalCoordinateSpaceTransform(CTMScope) const297 AffineTransform SVGElement::LocalCoordinateSpaceTransform(CTMScope) const {
298 // To be overriden by SVGGraphicsElement (or as special case SVGTextElement
299 // and SVGPatternElement)
300 return AffineTransform();
301 }
302
HasTransform(ApplyMotionTransform apply_motion_transform) const303 bool SVGElement::HasTransform(
304 ApplyMotionTransform apply_motion_transform) const {
305 return (GetLayoutObject() && GetLayoutObject()->StyleRef().HasTransform()) ||
306 (apply_motion_transform == kIncludeMotionTransform &&
307 HasSVGRareData());
308 }
309
CalculateTransform(ApplyMotionTransform apply_motion_transform) const310 AffineTransform SVGElement::CalculateTransform(
311 ApplyMotionTransform apply_motion_transform) const {
312 const LayoutObject* layout_object = GetLayoutObject();
313
314 AffineTransform matrix;
315 if (layout_object && layout_object->StyleRef().HasTransform()) {
316 matrix = TransformHelper::ComputeTransform(
317 *layout_object, ComputedStyle::kIncludeTransformOrigin);
318 }
319
320 // Apply any "motion transform" contribution if requested (and existing.)
321 if (apply_motion_transform == kIncludeMotionTransform && HasSVGRareData())
322 matrix.PreMultiply(*SvgRareData()->AnimateMotionTransform());
323
324 return matrix;
325 }
326
InsertedInto(ContainerNode & root_parent)327 Node::InsertionNotificationRequest SVGElement::InsertedInto(
328 ContainerNode& root_parent) {
329 Element::InsertedInto(root_parent);
330 HideNonce();
331 UpdateRelativeLengthsInformation();
332 return kInsertionDone;
333 }
334
RemovedFrom(ContainerNode & root_parent)335 void SVGElement::RemovedFrom(ContainerNode& root_parent) {
336 bool was_in_document = root_parent.isConnected();
337 auto* root_parent_svg_element = DynamicTo<SVGElement>(
338 root_parent.IsShadowRoot() ? root_parent.ParentOrShadowHostElement()
339 : &root_parent);
340
341 if (was_in_document && HasRelativeLengths()) {
342 // The root of the subtree being removed should take itself out from its
343 // parent's relative length set. For the other nodes in the subtree we don't
344 // need to do anything: they will get their own removedFrom() notification
345 // and just clear their sets.
346 if (root_parent_svg_element && !ParentOrShadowHostElement()) {
347 DCHECK(root_parent_svg_element->elements_with_relative_lengths_.Contains(
348 this));
349 root_parent_svg_element->UpdateRelativeLengthsInformation(false, this);
350 }
351
352 elements_with_relative_lengths_.clear();
353 }
354
355 DCHECK(
356 !root_parent_svg_element ||
357 !root_parent_svg_element->elements_with_relative_lengths_.Contains(this));
358
359 Element::RemovedFrom(root_parent);
360
361 if (was_in_document) {
362 if (HasSVGRareData() && SvgRareData()->CorrespondingElement())
363 SvgRareData()->CorrespondingElement()->RemoveInstanceMapping(this);
364 RebuildAllIncomingReferences();
365 RemoveAllIncomingReferences();
366 }
367
368 InvalidateInstances();
369 }
370
ChildrenChanged(const ChildrenChange & change)371 void SVGElement::ChildrenChanged(const ChildrenChange& change) {
372 Element::ChildrenChanged(change);
373
374 // Invalidate all instances associated with us.
375 InvalidateInstances();
376 }
377
CssPropertyIdForSVGAttributeName(const ExecutionContext * execution_context,const QualifiedName & attr_name)378 CSSPropertyID SVGElement::CssPropertyIdForSVGAttributeName(
379 const ExecutionContext* execution_context,
380 const QualifiedName& attr_name) {
381 if (!attr_name.NamespaceURI().IsNull())
382 return CSSPropertyID::kInvalid;
383
384 static HashMap<StringImpl*, CSSPropertyID>* property_name_to_id_map = nullptr;
385 if (!property_name_to_id_map) {
386 property_name_to_id_map = new HashMap<StringImpl*, CSSPropertyID>;
387 // This is a list of all base CSS and SVG CSS properties which are exposed
388 // as SVG XML attributes
389 const QualifiedName* const attr_names[] = {
390 &svg_names::kAlignmentBaselineAttr,
391 &svg_names::kBaselineShiftAttr,
392 &svg_names::kBufferedRenderingAttr,
393 &svg_names::kClipAttr,
394 &svg_names::kClipPathAttr,
395 &svg_names::kClipRuleAttr,
396 &svg_names::kColorAttr,
397 &svg_names::kColorInterpolationAttr,
398 &svg_names::kColorInterpolationFiltersAttr,
399 &svg_names::kColorRenderingAttr,
400 &svg_names::kCursorAttr,
401 &svg_names::kDirectionAttr,
402 &svg_names::kDisplayAttr,
403 &svg_names::kDominantBaselineAttr,
404 &svg_names::kFillAttr,
405 &svg_names::kFillOpacityAttr,
406 &svg_names::kFillRuleAttr,
407 &svg_names::kFilterAttr,
408 &svg_names::kFloodColorAttr,
409 &svg_names::kFloodOpacityAttr,
410 &svg_names::kFontFamilyAttr,
411 &svg_names::kFontSizeAttr,
412 &svg_names::kFontStretchAttr,
413 &svg_names::kFontStyleAttr,
414 &svg_names::kFontVariantAttr,
415 &svg_names::kFontWeightAttr,
416 &svg_names::kImageRenderingAttr,
417 &svg_names::kLetterSpacingAttr,
418 &svg_names::kLightingColorAttr,
419 &svg_names::kMarkerEndAttr,
420 &svg_names::kMarkerMidAttr,
421 &svg_names::kMarkerStartAttr,
422 &svg_names::kMaskAttr,
423 &svg_names::kMaskTypeAttr,
424 &svg_names::kOpacityAttr,
425 &svg_names::kOverflowAttr,
426 &svg_names::kPaintOrderAttr,
427 &svg_names::kPointerEventsAttr,
428 &svg_names::kShapeRenderingAttr,
429 &svg_names::kStopColorAttr,
430 &svg_names::kStopOpacityAttr,
431 &svg_names::kStrokeAttr,
432 &svg_names::kStrokeDasharrayAttr,
433 &svg_names::kStrokeDashoffsetAttr,
434 &svg_names::kStrokeLinecapAttr,
435 &svg_names::kStrokeLinejoinAttr,
436 &svg_names::kStrokeMiterlimitAttr,
437 &svg_names::kStrokeOpacityAttr,
438 &svg_names::kStrokeWidthAttr,
439 &svg_names::kTextAnchorAttr,
440 &svg_names::kTextDecorationAttr,
441 &svg_names::kTextRenderingAttr,
442 &svg_names::kTransformOriginAttr,
443 &svg_names::kUnicodeBidiAttr,
444 &svg_names::kVectorEffectAttr,
445 &svg_names::kVisibilityAttr,
446 &svg_names::kWordSpacingAttr,
447 &svg_names::kWritingModeAttr,
448 };
449 for (size_t i = 0; i < base::size(attr_names); i++) {
450 CSSPropertyID property_id =
451 cssPropertyID(execution_context, attr_names[i]->LocalName());
452 DCHECK_GT(property_id, CSSPropertyID::kInvalid);
453 property_name_to_id_map->Set(attr_names[i]->LocalName().Impl(),
454 property_id);
455 }
456 }
457
458 return property_name_to_id_map->at(attr_name.LocalName().Impl());
459 }
460
UpdateRelativeLengthsInformation(bool client_has_relative_lengths,SVGElement * client_element)461 void SVGElement::UpdateRelativeLengthsInformation(
462 bool client_has_relative_lengths,
463 SVGElement* client_element) {
464 DCHECK(client_element);
465
466 // Through an unfortunate chain of events, we can end up calling this while a
467 // subtree is being removed, and before the subtree has been properly
468 // "disconnected". Hence check the entire ancestor chain to avoid propagating
469 // relative length clients up into ancestors that have already been
470 // disconnected.
471 // If we're not yet in a document, this function will be called again from
472 // insertedInto(). Do nothing now.
473 for (Node* current_node = this; current_node;
474 current_node = current_node->ParentOrShadowHostNode()) {
475 if (!current_node->isConnected())
476 return;
477 }
478
479 // An element wants to notify us that its own relative lengths state changed.
480 // Register it in the relative length map, and register us in the parent
481 // relative length map. Register the parent in the grandparents map, etc.
482 // Repeat procedure until the root of the SVG tree.
483 for (Element* current_node = this; current_node;
484 current_node = current_node->ParentOrShadowHostElement()) {
485 auto* current_element = DynamicTo<SVGElement>(current_node);
486 if (!current_element)
487 break;
488
489 #if DCHECK_IS_ON()
490 DCHECK(!current_element->in_relative_length_clients_invalidation_);
491 #endif
492
493 bool had_relative_lengths = current_element->HasRelativeLengths();
494 if (client_has_relative_lengths)
495 current_element->elements_with_relative_lengths_.insert(client_element);
496 else
497 current_element->elements_with_relative_lengths_.erase(client_element);
498
499 // If the relative length state hasn't changed, we can stop propagating the
500 // notification.
501 if (had_relative_lengths == current_element->HasRelativeLengths())
502 return;
503
504 client_element = current_element;
505 client_has_relative_lengths = client_element->HasRelativeLengths();
506 }
507
508 // Register root SVG elements for top level viewport change notifications.
509 if (auto* svg = DynamicTo<SVGSVGElement>(*client_element)) {
510 SVGDocumentExtensions& svg_extensions = GetDocument().AccessSVGExtensions();
511 if (client_element->HasRelativeLengths())
512 svg_extensions.AddSVGRootWithRelativeLengthDescendents(svg);
513 else
514 svg_extensions.RemoveSVGRootWithRelativeLengthDescendents(svg);
515 }
516 }
517
InvalidateRelativeLengthClients(SubtreeLayoutScope * layout_scope)518 void SVGElement::InvalidateRelativeLengthClients(
519 SubtreeLayoutScope* layout_scope) {
520 if (!isConnected())
521 return;
522
523 #if DCHECK_IS_ON()
524 DCHECK(!in_relative_length_clients_invalidation_);
525 base::AutoReset<bool> in_relative_length_clients_invalidation_change(
526 &in_relative_length_clients_invalidation_, true);
527 #endif
528
529 if (LayoutObject* layout_object = GetLayoutObject()) {
530 if (HasRelativeLengths() && layout_object->IsSVGResourceContainer()) {
531 To<LayoutSVGResourceContainer>(layout_object)
532 ->InvalidateCacheAndMarkForLayout(
533 layout_invalidation_reason::kSizeChanged, layout_scope);
534 } else if (SelfHasRelativeLengths()) {
535 layout_object->SetNeedsLayoutAndFullPaintInvalidation(
536 layout_invalidation_reason::kUnknown, kMarkContainerChain,
537 layout_scope);
538 }
539 }
540
541 for (SVGElement* element : elements_with_relative_lengths_) {
542 if (element != this)
543 element->InvalidateRelativeLengthClients(layout_scope);
544 }
545 }
546
ownerSVGElement() const547 SVGSVGElement* SVGElement::ownerSVGElement() const {
548 ContainerNode* n = ParentOrShadowHostNode();
549 while (n) {
550 if (auto* svg_svg_element = DynamicTo<SVGSVGElement>(n))
551 return svg_svg_element;
552
553 n = n->ParentOrShadowHostNode();
554 }
555
556 return nullptr;
557 }
558
viewportElement() const559 SVGElement* SVGElement::viewportElement() const {
560 // This function needs shadow tree support - as LayoutSVGContainer uses this
561 // function to determine the "overflow" property. <use> on <symbol> wouldn't
562 // work otherwhise.
563 ContainerNode* n = ParentOrShadowHostNode();
564 while (n) {
565 if (IsA<SVGSVGElement>(*n) || IsA<SVGImageElement>(*n) ||
566 IsA<SVGSymbolElement>(*n))
567 return To<SVGElement>(n);
568
569 n = n->ParentOrShadowHostNode();
570 }
571
572 return nullptr;
573 }
574
MapInstanceToElement(SVGElement * instance)575 void SVGElement::MapInstanceToElement(SVGElement* instance) {
576 DCHECK(instance);
577 DCHECK(instance->InUseShadowTree());
578
579 HeapHashSet<WeakMember<SVGElement>>& instances =
580 EnsureSVGRareData()->ElementInstances();
581 DCHECK(!instances.Contains(instance));
582
583 instances.insert(instance);
584 }
585
RemoveInstanceMapping(SVGElement * instance)586 void SVGElement::RemoveInstanceMapping(SVGElement* instance) {
587 DCHECK(instance);
588 // Called during instance->RemovedFrom() after removal from shadow tree
589 DCHECK(!instance->isConnected());
590
591 HeapHashSet<WeakMember<SVGElement>>& instances =
592 SvgRareData()->ElementInstances();
593
594 instances.erase(instance);
595 }
596
EmptyInstances()597 static HeapHashSet<WeakMember<SVGElement>>& EmptyInstances() {
598 DEFINE_STATIC_LOCAL(
599 Persistent<HeapHashSet<WeakMember<SVGElement>>>, empty_instances,
600 (MakeGarbageCollected<HeapHashSet<WeakMember<SVGElement>>>()));
601 return *empty_instances;
602 }
603
InstancesForElement() const604 const HeapHashSet<WeakMember<SVGElement>>& SVGElement::InstancesForElement()
605 const {
606 if (!HasSVGRareData())
607 return EmptyInstances();
608 return SvgRareData()->ElementInstances();
609 }
610
CorrespondingElement() const611 SVGElement* SVGElement::CorrespondingElement() const {
612 DCHECK(!HasSVGRareData() || !SvgRareData()->CorrespondingElement() ||
613 ContainingShadowRoot());
614 return HasSVGRareData() ? SvgRareData()->CorrespondingElement() : nullptr;
615 }
616
GeneratingUseElement() const617 SVGUseElement* SVGElement::GeneratingUseElement() const {
618 if (ShadowRoot* root = ContainingShadowRoot()) {
619 return DynamicTo<SVGUseElement>(root->host());
620 }
621 return nullptr;
622 }
623
SetCorrespondingElement(SVGElement * corresponding_element)624 void SVGElement::SetCorrespondingElement(SVGElement* corresponding_element) {
625 EnsureSVGRareData()->SetCorrespondingElement(corresponding_element);
626 }
627
InUseShadowTree() const628 bool SVGElement::InUseShadowTree() const {
629 return GeneratingUseElement();
630 }
631
ParseAttribute(const AttributeModificationParams & params)632 void SVGElement::ParseAttribute(const AttributeModificationParams& params) {
633 // Note about the 'class' attribute:
634 // The "special storage" (SVGAnimatedString) for the 'class' attribute (and
635 // the 'className' property) is updated by the follow block (|class_name_|
636 // registered in |attribute_to_property_map_|.). SvgAttributeChanged then
637 // triggers the resulting style updates (instead of
638 // Element::ParseAttribute). We don't tell Element about the change to avoid
639 // parsing the class list twice.
640 if (SVGAnimatedPropertyBase* property = PropertyFromAttribute(params.name)) {
641 SVGParsingError parse_error = property->AttributeChanged(params.new_value);
642 ReportAttributeParsingError(parse_error, params.name, params.new_value);
643 return;
644 }
645
646 // SVGElement and HTMLElement are handling "nonce" the same way.
647 if (params.name == html_names::kNonceAttr) {
648 if (params.new_value != g_empty_atom)
649 setNonce(params.new_value);
650 }
651
652 const AtomicString& event_name =
653 HTMLElement::EventNameForAttributeName(params.name);
654 if (!event_name.IsNull()) {
655 SetAttributeEventListener(
656 event_name, JSEventHandlerForContentAttribute::Create(
657 GetExecutionContext(), params.name, params.new_value));
658 return;
659 }
660
661 Element::ParseAttribute(params);
662 }
663
664 // If the attribute is not present in the map, the map will return the "empty
665 // value" - which is kAnimatedUnknown.
666 struct AnimatedPropertyTypeHashTraits : HashTraits<AnimatedPropertyType> {
667 static const bool kEmptyValueIsZero = true;
EmptyValueblink::AnimatedPropertyTypeHashTraits668 static AnimatedPropertyType EmptyValue() { return kAnimatedUnknown; }
669 };
670
671 using AttributeToPropertyTypeMap = HashMap<QualifiedName,
672 AnimatedPropertyType,
673 DefaultHash<QualifiedName>::Hash,
674 HashTraits<QualifiedName>,
675 AnimatedPropertyTypeHashTraits>;
AnimatedPropertyTypeForCSSAttribute(const QualifiedName & attribute_name)676 AnimatedPropertyType SVGElement::AnimatedPropertyTypeForCSSAttribute(
677 const QualifiedName& attribute_name) {
678 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, css_property_map, ());
679
680 if (css_property_map.IsEmpty()) {
681 // Fill the map for the first use.
682 struct AttrToTypeEntry {
683 const QualifiedName& attr;
684 const AnimatedPropertyType prop_type;
685 };
686 const AttrToTypeEntry attr_to_types[] = {
687 {svg_names::kAlignmentBaselineAttr, kAnimatedString},
688 {svg_names::kBaselineShiftAttr, kAnimatedString},
689 {svg_names::kBufferedRenderingAttr, kAnimatedString},
690 {svg_names::kClipPathAttr, kAnimatedString},
691 {svg_names::kClipRuleAttr, kAnimatedString},
692 {svg_names::kColorAttr, kAnimatedColor},
693 {svg_names::kColorInterpolationAttr, kAnimatedString},
694 {svg_names::kColorInterpolationFiltersAttr, kAnimatedString},
695 {svg_names::kColorRenderingAttr, kAnimatedString},
696 {svg_names::kCursorAttr, kAnimatedString},
697 {svg_names::kDisplayAttr, kAnimatedString},
698 {svg_names::kDominantBaselineAttr, kAnimatedString},
699 {svg_names::kFillAttr, kAnimatedColor},
700 {svg_names::kFillOpacityAttr, kAnimatedNumber},
701 {svg_names::kFillRuleAttr, kAnimatedString},
702 {svg_names::kFilterAttr, kAnimatedString},
703 {svg_names::kFloodColorAttr, kAnimatedColor},
704 {svg_names::kFloodOpacityAttr, kAnimatedNumber},
705 {svg_names::kFontFamilyAttr, kAnimatedString},
706 {svg_names::kFontSizeAttr, kAnimatedLength},
707 {svg_names::kFontStretchAttr, kAnimatedString},
708 {svg_names::kFontStyleAttr, kAnimatedString},
709 {svg_names::kFontVariantAttr, kAnimatedString},
710 {svg_names::kFontWeightAttr, kAnimatedString},
711 {svg_names::kImageRenderingAttr, kAnimatedString},
712 {svg_names::kLetterSpacingAttr, kAnimatedLength},
713 {svg_names::kLightingColorAttr, kAnimatedColor},
714 {svg_names::kMarkerEndAttr, kAnimatedString},
715 {svg_names::kMarkerMidAttr, kAnimatedString},
716 {svg_names::kMarkerStartAttr, kAnimatedString},
717 {svg_names::kMaskAttr, kAnimatedString},
718 {svg_names::kMaskTypeAttr, kAnimatedString},
719 {svg_names::kOpacityAttr, kAnimatedNumber},
720 {svg_names::kOverflowAttr, kAnimatedString},
721 {svg_names::kPaintOrderAttr, kAnimatedString},
722 {svg_names::kPointerEventsAttr, kAnimatedString},
723 {svg_names::kShapeRenderingAttr, kAnimatedString},
724 {svg_names::kStopColorAttr, kAnimatedColor},
725 {svg_names::kStopOpacityAttr, kAnimatedNumber},
726 {svg_names::kStrokeAttr, kAnimatedColor},
727 {svg_names::kStrokeDasharrayAttr, kAnimatedLengthList},
728 {svg_names::kStrokeDashoffsetAttr, kAnimatedLength},
729 {svg_names::kStrokeLinecapAttr, kAnimatedString},
730 {svg_names::kStrokeLinejoinAttr, kAnimatedString},
731 {svg_names::kStrokeMiterlimitAttr, kAnimatedNumber},
732 {svg_names::kStrokeOpacityAttr, kAnimatedNumber},
733 {svg_names::kStrokeWidthAttr, kAnimatedLength},
734 {svg_names::kTextAnchorAttr, kAnimatedString},
735 {svg_names::kTextDecorationAttr, kAnimatedString},
736 {svg_names::kTextRenderingAttr, kAnimatedString},
737 {svg_names::kVectorEffectAttr, kAnimatedString},
738 {svg_names::kVisibilityAttr, kAnimatedString},
739 {svg_names::kWordSpacingAttr, kAnimatedLength},
740 };
741 for (size_t i = 0; i < base::size(attr_to_types); i++)
742 css_property_map.Set(attr_to_types[i].attr, attr_to_types[i].prop_type);
743 }
744 return css_property_map.at(attribute_name);
745 }
746
AddToPropertyMap(SVGAnimatedPropertyBase * property)747 void SVGElement::AddToPropertyMap(SVGAnimatedPropertyBase* property) {
748 attribute_to_property_map_.Set(property->AttributeName(), property);
749 }
750
PropertyFromAttribute(const QualifiedName & attribute_name) const751 SVGAnimatedPropertyBase* SVGElement::PropertyFromAttribute(
752 const QualifiedName& attribute_name) const {
753 AttributeToPropertyMap::const_iterator it =
754 attribute_to_property_map_.Find<SVGAttributeHashTranslator>(
755 attribute_name);
756 if (it == attribute_to_property_map_.end())
757 return nullptr;
758
759 return it->value.Get();
760 }
761
IsAnimatableCSSProperty(const QualifiedName & attr_name)762 bool SVGElement::IsAnimatableCSSProperty(const QualifiedName& attr_name) {
763 return AnimatedPropertyTypeForCSSAttribute(attr_name) != kAnimatedUnknown;
764 }
765
IsPresentationAttribute(const QualifiedName & name) const766 bool SVGElement::IsPresentationAttribute(const QualifiedName& name) const {
767 if (const SVGAnimatedPropertyBase* property = PropertyFromAttribute(name))
768 return property->HasPresentationAttributeMapping();
769 return CssPropertyIdForSVGAttributeName(GetExecutionContext(), name) >
770 CSSPropertyID::kInvalid;
771 }
772
CollectStyleForPresentationAttribute(const QualifiedName & name,const AtomicString & value,MutableCSSPropertyValueSet * style)773 void SVGElement::CollectStyleForPresentationAttribute(
774 const QualifiedName& name,
775 const AtomicString& value,
776 MutableCSSPropertyValueSet* style) {
777 CSSPropertyID property_id =
778 CssPropertyIdForSVGAttributeName(GetExecutionContext(), name);
779 if (property_id > CSSPropertyID::kInvalid)
780 AddPropertyToPresentationAttributeStyle(style, property_id, value);
781 }
782
HaveLoadedRequiredResources()783 bool SVGElement::HaveLoadedRequiredResources() {
784 for (SVGElement* child = Traversal<SVGElement>::FirstChild(*this); child;
785 child = Traversal<SVGElement>::NextSibling(*child)) {
786 if (!child->HaveLoadedRequiredResources())
787 return false;
788 }
789 return true;
790 }
791
CollectInstancesForSVGElement(SVGElement * element,HeapHashSet<WeakMember<SVGElement>> & instances)792 static inline void CollectInstancesForSVGElement(
793 SVGElement* element,
794 HeapHashSet<WeakMember<SVGElement>>& instances) {
795 DCHECK(element);
796 if (element->ContainingShadowRoot())
797 return;
798
799 DCHECK(!element->InstanceUpdatesBlocked());
800
801 instances = element->InstancesForElement();
802 }
803
AddedEventListener(const AtomicString & event_type,RegisteredEventListener & registered_listener)804 void SVGElement::AddedEventListener(
805 const AtomicString& event_type,
806 RegisteredEventListener& registered_listener) {
807 // Add event listener to regular DOM element
808 Node::AddedEventListener(event_type, registered_listener);
809
810 // Add event listener to all shadow tree DOM element instances
811 HeapHashSet<WeakMember<SVGElement>> instances;
812 CollectInstancesForSVGElement(this, instances);
813 AddEventListenerOptionsResolved* options = registered_listener.Options();
814 EventListener* listener = registered_listener.Callback();
815 for (SVGElement* element : instances) {
816 bool result =
817 element->Node::AddEventListenerInternal(event_type, listener, options);
818 DCHECK(result);
819 }
820 }
821
RemovedEventListener(const AtomicString & event_type,const RegisteredEventListener & registered_listener)822 void SVGElement::RemovedEventListener(
823 const AtomicString& event_type,
824 const RegisteredEventListener& registered_listener) {
825 Node::RemovedEventListener(event_type, registered_listener);
826
827 // Remove event listener from all shadow tree DOM element instances
828 HeapHashSet<WeakMember<SVGElement>> instances;
829 CollectInstancesForSVGElement(this, instances);
830 EventListenerOptions* options = registered_listener.Options();
831 const EventListener* listener = registered_listener.Callback();
832 for (SVGElement* shadow_tree_element : instances) {
833 DCHECK(shadow_tree_element);
834
835 shadow_tree_element->Node::RemoveEventListenerInternal(event_type, listener,
836 options);
837 }
838 }
839
HasLoadListener(Element * element)840 static bool HasLoadListener(Element* element) {
841 if (element->HasEventListeners(event_type_names::kLoad))
842 return true;
843
844 for (element = element->ParentOrShadowHostElement(); element;
845 element = element->ParentOrShadowHostElement()) {
846 EventListenerVector* entry =
847 element->GetEventListeners(event_type_names::kLoad);
848 if (!entry)
849 continue;
850 for (wtf_size_t i = 0; i < entry->size(); ++i) {
851 if (entry->at(i).Capture())
852 return true;
853 }
854 }
855
856 return false;
857 }
858
SendSVGLoadEventIfPossible()859 bool SVGElement::SendSVGLoadEventIfPossible() {
860 if (!HaveLoadedRequiredResources())
861 return false;
862 if ((IsStructurallyExternal() || IsA<SVGSVGElement>(*this)) &&
863 HasLoadListener(this))
864 DispatchEvent(*Event::Create(event_type_names::kLoad));
865 return true;
866 }
867
SendSVGLoadEventToSelfAndAncestorChainIfPossible()868 void SVGElement::SendSVGLoadEventToSelfAndAncestorChainIfPossible() {
869 // Let Document::implicitClose() dispatch the 'load' to the outermost SVG
870 // root.
871 if (IsOutermostSVGSVGElement())
872 return;
873
874 // Save the next parent to dispatch to in case dispatching the event mutates
875 // the tree.
876 Element* parent = ParentOrShadowHostElement();
877 if (!SendSVGLoadEventIfPossible())
878 return;
879
880 // If document/window 'load' has been sent already, then only deliver to
881 // the element in question.
882 if (GetDocument().LoadEventFinished())
883 return;
884
885 auto* svg_element = DynamicTo<SVGElement>(parent);
886 if (!svg_element)
887 return;
888
889 svg_element->SendSVGLoadEventToSelfAndAncestorChainIfPossible();
890 }
891
AttributeChanged(const AttributeModificationParams & params)892 void SVGElement::AttributeChanged(const AttributeModificationParams& params) {
893 Element::AttributeChanged(params);
894
895 if (params.name == html_names::kIdAttr) {
896 RebuildAllIncomingReferences();
897 InvalidateInstances();
898 return;
899 }
900
901 // Changes to the style attribute are processed lazily (see
902 // Element::getAttribute() and related methods), so we don't want changes to
903 // the style attribute to result in extra work here.
904 if (params.name == html_names::kStyleAttr)
905 return;
906
907 SvgAttributeChanged(params.name);
908 UpdateWebAnimatedAttributeOnBaseValChange(params.name);
909 }
910
SvgAttributeChanged(const QualifiedName & attr_name)911 void SVGElement::SvgAttributeChanged(const QualifiedName& attr_name) {
912 CSSPropertyID prop_id = SVGElement::CssPropertyIdForSVGAttributeName(
913 GetExecutionContext(), attr_name);
914 if (prop_id > CSSPropertyID::kInvalid) {
915 InvalidateInstances();
916 return;
917 }
918
919 if (attr_name == html_names::kClassAttr) {
920 ClassAttributeChanged(AtomicString(class_name_->CurrentValue()->Value()));
921 InvalidateInstances();
922 return;
923 }
924 }
925
BaseValueChanged(const SVGAnimatedPropertyBase & animated_property)926 void SVGElement::BaseValueChanged(
927 const SVGAnimatedPropertyBase& animated_property) {
928 const QualifiedName& attribute = animated_property.AttributeName();
929 EnsureUniqueElementData().SetSvgAttributesAreDirty(true);
930 SvgAttributeChanged(attribute);
931 if (class_name_ == &animated_property) {
932 UpdateClassList(g_null_atom,
933 AtomicString(class_name_->BaseValue()->Value()));
934 }
935 UpdateWebAnimatedAttributeOnBaseValChange(attribute);
936 }
937
UpdateWebAnimatedAttributeOnBaseValChange(const QualifiedName & attribute)938 void SVGElement::UpdateWebAnimatedAttributeOnBaseValChange(
939 const QualifiedName& attribute) {
940 if (!HasSVGRareData())
941 return;
942 const auto& animated_attributes = SvgRareData()->WebAnimatedAttributes();
943 if (animated_attributes.IsEmpty() || !animated_attributes.Contains(attribute))
944 return;
945 // TODO(alancutter): Only mark attributes as dirty if their animation depends
946 // on the underlying value.
947 SvgRareData()->SetWebAnimatedAttributesDirty(true);
948 EnsureAttributeAnimValUpdated();
949 }
950
EnsureAttributeAnimValUpdated()951 void SVGElement::EnsureAttributeAnimValUpdated() {
952 if (!RuntimeEnabledFeatures::WebAnimationsSVGEnabled())
953 return;
954
955 if ((HasSVGRareData() && SvgRareData()->WebAnimatedAttributesDirty()) ||
956 (GetElementAnimations() &&
957 GetDocument().GetDocumentAnimations().NeedsAnimationTimingUpdate())) {
958 GetDocument().GetDocumentAnimations().UpdateAnimationTimingIfNeeded();
959 ApplyActiveWebAnimations();
960 }
961 }
962
SynchronizeSVGAttribute(const QualifiedName & name) const963 void SVGElement::SynchronizeSVGAttribute(const QualifiedName& name) const {
964 DCHECK(GetElementData());
965 DCHECK(GetElementData()->svg_attributes_are_dirty());
966 if (name == AnyQName()) {
967 for (SVGAnimatedPropertyBase* property :
968 attribute_to_property_map_.Values()) {
969 if (property->NeedsSynchronizeAttribute())
970 property->SynchronizeAttribute();
971 }
972 GetElementData()->SetSvgAttributesAreDirty(false);
973 } else {
974 SVGAnimatedPropertyBase* property = PropertyFromAttribute(name);
975 if (property && property->NeedsSynchronizeAttribute())
976 property->SynchronizeAttribute();
977 }
978 }
979
CollectStyleForAnimatedPresentationAttributes(MutableCSSPropertyValueSet * style)980 void SVGElement::CollectStyleForAnimatedPresentationAttributes(
981 MutableCSSPropertyValueSet* style) {
982 // TODO(fs): This re-applies all animating attributes that are also
983 // presentation attributes. The precise predicate that we want is animated
984 // attributes that are presentation attributes and do not have a content
985 // attribute.
986 // That last bit ("do not have a content attribute") would mean a linear
987 // search of the attribute collection per property.
988 // Maybe reversing the order of operations would be preferable here (i.e
989 // collect style for animating attributes first, stashing which in a map, and
990 // then selectively collecting the rest of the presentation attributes).
991 // Maintaining the presentation attribute style "manually" also seems like a
992 // reasonable scheme since that means we can avoid reparsing the presentation
993 // attributes that didn't change.
994 for (SVGAnimatedPropertyBase* property :
995 attribute_to_property_map_.Values()) {
996 if (!property->HasPresentationAttributeMapping() ||
997 !property->IsAnimating())
998 continue;
999 CollectStyleForPresentationAttribute(property->AttributeName(),
1000 g_empty_atom, style);
1001 }
1002 }
1003
CustomStyleForLayoutObject()1004 scoped_refptr<ComputedStyle> SVGElement::CustomStyleForLayoutObject() {
1005 SVGElement* corresponding_element = CorrespondingElement();
1006 if (!corresponding_element)
1007 return GetDocument().GetStyleResolver().StyleForElement(this);
1008
1009 const ComputedStyle* style = nullptr;
1010 if (Element* parent = ParentOrShadowHostElement())
1011 style = parent->GetComputedStyle();
1012
1013 return GetDocument().GetStyleResolver().StyleForElement(corresponding_element,
1014 style, style);
1015 }
1016
LayoutObjectIsNeeded(const ComputedStyle & style) const1017 bool SVGElement::LayoutObjectIsNeeded(const ComputedStyle& style) const {
1018 return IsValid() && HasSVGParent() && Element::LayoutObjectIsNeeded(style);
1019 }
1020
HasSVGParent() const1021 bool SVGElement::HasSVGParent() const {
1022 Element* parent = FlatTreeTraversal::ParentElement(*this);
1023 return parent && parent->IsSVGElement();
1024 }
1025
AnimatedSMILStyleProperties() const1026 MutableCSSPropertyValueSet* SVGElement::AnimatedSMILStyleProperties() const {
1027 if (HasSVGRareData())
1028 return SvgRareData()->AnimatedSMILStyleProperties();
1029 return nullptr;
1030 }
1031
EnsureAnimatedSMILStyleProperties()1032 MutableCSSPropertyValueSet* SVGElement::EnsureAnimatedSMILStyleProperties() {
1033 return EnsureSVGRareData()->EnsureAnimatedSMILStyleProperties();
1034 }
1035
BaseComputedStyleForSMIL()1036 const ComputedStyle* SVGElement::BaseComputedStyleForSMIL() {
1037 if (!HasSVGRareData())
1038 return EnsureComputedStyle();
1039 const ComputedStyle* parent_style = nullptr;
1040 if (ContainerNode* parent = LayoutTreeBuilderTraversal::Parent(*this))
1041 parent_style = parent->EnsureComputedStyle();
1042 return SvgRareData()->OverrideComputedStyle(this, parent_style);
1043 }
1044
HasFocusEventListeners() const1045 bool SVGElement::HasFocusEventListeners() const {
1046 return HasEventListeners(event_type_names::kFocusin) ||
1047 HasEventListeners(event_type_names::kFocusout) ||
1048 HasEventListeners(event_type_names::kFocus) ||
1049 HasEventListeners(event_type_names::kBlur);
1050 }
1051
MarkForLayoutAndParentResourceInvalidation(LayoutObject & layout_object)1052 void SVGElement::MarkForLayoutAndParentResourceInvalidation(
1053 LayoutObject& layout_object) {
1054 LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
1055 layout_object, true);
1056 }
1057
InvalidateInstances()1058 void SVGElement::InvalidateInstances() {
1059 if (InstanceUpdatesBlocked())
1060 return;
1061
1062 const HeapHashSet<WeakMember<SVGElement>>& set = InstancesForElement();
1063 if (set.IsEmpty())
1064 return;
1065
1066 // Mark all use elements referencing 'element' for rebuilding
1067 for (SVGElement* instance : set) {
1068 instance->SetCorrespondingElement(nullptr);
1069
1070 if (SVGUseElement* element = instance->GeneratingUseElement()) {
1071 DCHECK(element->isConnected());
1072 element->InvalidateShadowTree();
1073 }
1074 }
1075
1076 SvgRareData()->ElementInstances().clear();
1077 }
1078
SetNeedsStyleRecalcForInstances(StyleChangeType change_type,const StyleChangeReasonForTracing & reason)1079 void SVGElement::SetNeedsStyleRecalcForInstances(
1080 StyleChangeType change_type,
1081 const StyleChangeReasonForTracing& reason) {
1082 const HeapHashSet<WeakMember<SVGElement>>& set = InstancesForElement();
1083 if (set.IsEmpty())
1084 return;
1085
1086 for (SVGElement* instance : set)
1087 instance->SetNeedsStyleRecalc(change_type, reason);
1088 }
1089
InstanceUpdateBlocker(SVGElement * target_element)1090 SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(
1091 SVGElement* target_element)
1092 : target_element_(target_element) {
1093 if (target_element_)
1094 target_element_->SetInstanceUpdatesBlocked(true);
1095 }
1096
~InstanceUpdateBlocker()1097 SVGElement::InstanceUpdateBlocker::~InstanceUpdateBlocker() {
1098 if (target_element_)
1099 target_element_->SetInstanceUpdatesBlocked(false);
1100 }
1101
1102 #if DCHECK_IS_ON()
IsAnimatableAttribute(const QualifiedName & name) const1103 bool SVGElement::IsAnimatableAttribute(const QualifiedName& name) const {
1104 // This static is atomically initialized to dodge a warning about
1105 // a race when dumping debug data for a layer.
1106 DEFINE_THREAD_SAFE_STATIC_LOCAL(HashSet<QualifiedName>, animatable_attributes,
1107 ({
1108 svg_names::kAmplitudeAttr,
1109 svg_names::kAzimuthAttr,
1110 svg_names::kBaseFrequencyAttr,
1111 svg_names::kBiasAttr,
1112 svg_names::kClipPathUnitsAttr,
1113 svg_names::kCxAttr,
1114 svg_names::kCyAttr,
1115 svg_names::kDiffuseConstantAttr,
1116 svg_names::kDivisorAttr,
1117 svg_names::kDxAttr,
1118 svg_names::kDyAttr,
1119 svg_names::kEdgeModeAttr,
1120 svg_names::kElevationAttr,
1121 svg_names::kExponentAttr,
1122 svg_names::kFilterUnitsAttr,
1123 svg_names::kFxAttr,
1124 svg_names::kFyAttr,
1125 svg_names::kGradientTransformAttr,
1126 svg_names::kGradientUnitsAttr,
1127 svg_names::kHeightAttr,
1128 svg_names::kHrefAttr,
1129 svg_names::kIn2Attr,
1130 svg_names::kInAttr,
1131 svg_names::kInterceptAttr,
1132 svg_names::kK1Attr,
1133 svg_names::kK2Attr,
1134 svg_names::kK3Attr,
1135 svg_names::kK4Attr,
1136 svg_names::kKernelMatrixAttr,
1137 svg_names::kKernelUnitLengthAttr,
1138 svg_names::kLengthAdjustAttr,
1139 svg_names::kLimitingConeAngleAttr,
1140 svg_names::kMarkerHeightAttr,
1141 svg_names::kMarkerUnitsAttr,
1142 svg_names::kMarkerWidthAttr,
1143 svg_names::kMaskContentUnitsAttr,
1144 svg_names::kMaskUnitsAttr,
1145 svg_names::kMethodAttr,
1146 svg_names::kModeAttr,
1147 svg_names::kNumOctavesAttr,
1148 svg_names::kOffsetAttr,
1149 svg_names::kOperatorAttr,
1150 svg_names::kOrderAttr,
1151 svg_names::kOrientAttr,
1152 svg_names::kPathLengthAttr,
1153 svg_names::kPatternContentUnitsAttr,
1154 svg_names::kPatternTransformAttr,
1155 svg_names::kPatternUnitsAttr,
1156 svg_names::kPointsAtXAttr,
1157 svg_names::kPointsAtYAttr,
1158 svg_names::kPointsAtZAttr,
1159 svg_names::kPreserveAlphaAttr,
1160 svg_names::kPreserveAspectRatioAttr,
1161 svg_names::kPrimitiveUnitsAttr,
1162 svg_names::kRadiusAttr,
1163 svg_names::kRAttr,
1164 svg_names::kRefXAttr,
1165 svg_names::kRefYAttr,
1166 svg_names::kResultAttr,
1167 svg_names::kRotateAttr,
1168 svg_names::kRxAttr,
1169 svg_names::kRyAttr,
1170 svg_names::kScaleAttr,
1171 svg_names::kSeedAttr,
1172 svg_names::kSlopeAttr,
1173 svg_names::kSpacingAttr,
1174 svg_names::kSpecularConstantAttr,
1175 svg_names::kSpecularExponentAttr,
1176 svg_names::kSpreadMethodAttr,
1177 svg_names::kStartOffsetAttr,
1178 svg_names::kStdDeviationAttr,
1179 svg_names::kStitchTilesAttr,
1180 svg_names::kSurfaceScaleAttr,
1181 svg_names::kTableValuesAttr,
1182 svg_names::kTargetAttr,
1183 svg_names::kTargetXAttr,
1184 svg_names::kTargetYAttr,
1185 svg_names::kTransformAttr,
1186 svg_names::kTypeAttr,
1187 svg_names::kValuesAttr,
1188 svg_names::kViewBoxAttr,
1189 svg_names::kWidthAttr,
1190 svg_names::kX1Attr,
1191 svg_names::kX2Attr,
1192 svg_names::kXAttr,
1193 svg_names::kXChannelSelectorAttr,
1194 svg_names::kY1Attr,
1195 svg_names::kY2Attr,
1196 svg_names::kYAttr,
1197 svg_names::kYChannelSelectorAttr,
1198 svg_names::kZAttr,
1199 }));
1200
1201 if (name == html_names::kClassAttr)
1202 return true;
1203
1204 return animatable_attributes.Contains(name);
1205 }
1206 #endif // DCHECK_IS_ON()
1207
SetOfIncomingReferences() const1208 SVGElementSet* SVGElement::SetOfIncomingReferences() const {
1209 if (!HasSVGRareData())
1210 return nullptr;
1211 return &SvgRareData()->IncomingReferences();
1212 }
1213
AddReferenceTo(SVGElement * target_element)1214 void SVGElement::AddReferenceTo(SVGElement* target_element) {
1215 DCHECK(target_element);
1216
1217 EnsureSVGRareData()->OutgoingReferences().insert(target_element);
1218 target_element->EnsureSVGRareData()->IncomingReferences().insert(this);
1219 }
1220
GetDependencyTraversalVisitedSet()1221 SVGElementSet& SVGElement::GetDependencyTraversalVisitedSet() {
1222 // This strong reference is safe, as it is guaranteed that this set will be
1223 // emptied at the end of recursion in NotifyIncomingReferences.
1224 DEFINE_STATIC_LOCAL(Persistent<SVGElementSet>, invalidating_dependencies,
1225 (MakeGarbageCollected<SVGElementSet>()));
1226 return *invalidating_dependencies;
1227 }
1228
RebuildAllIncomingReferences()1229 void SVGElement::RebuildAllIncomingReferences() {
1230 if (!HasSVGRareData())
1231 return;
1232
1233 const SVGElementSet& incoming_references =
1234 SvgRareData()->IncomingReferences();
1235
1236 // Iterate on a snapshot as |incomingReferences| may be altered inside loop.
1237 HeapVector<Member<SVGElement>> incoming_references_snapshot;
1238 CopyToVector(incoming_references, incoming_references_snapshot);
1239
1240 // Force rebuilding the |sourceElement| so it knows about this change.
1241 for (SVGElement* source_element : incoming_references_snapshot) {
1242 // Before rebuilding |sourceElement| ensure it was not removed from under
1243 // us.
1244 if (incoming_references.Contains(source_element))
1245 source_element->SvgAttributeChanged(svg_names::kHrefAttr);
1246 }
1247 }
1248
RemoveAllIncomingReferences()1249 void SVGElement::RemoveAllIncomingReferences() {
1250 if (!HasSVGRareData())
1251 return;
1252
1253 SVGElementSet& incoming_references = SvgRareData()->IncomingReferences();
1254 for (SVGElement* source_element : incoming_references) {
1255 DCHECK(source_element->HasSVGRareData());
1256 source_element->EnsureSVGRareData()->OutgoingReferences().erase(this);
1257 }
1258 incoming_references.clear();
1259 }
1260
RemoveAllOutgoingReferences()1261 void SVGElement::RemoveAllOutgoingReferences() {
1262 if (!HasSVGRareData())
1263 return;
1264
1265 SVGElementSet& outgoing_references = SvgRareData()->OutgoingReferences();
1266 for (SVGElement* target_element : outgoing_references) {
1267 DCHECK(target_element->HasSVGRareData());
1268 target_element->EnsureSVGRareData()->IncomingReferences().erase(this);
1269 }
1270 outgoing_references.clear();
1271 }
1272
GetSVGResourceClient()1273 SVGElementResourceClient* SVGElement::GetSVGResourceClient() {
1274 if (!HasSVGRareData())
1275 return nullptr;
1276 return SvgRareData()->GetSVGResourceClient();
1277 }
1278
EnsureSVGResourceClient()1279 SVGElementResourceClient& SVGElement::EnsureSVGResourceClient() {
1280 return EnsureSVGRareData()->EnsureSVGResourceClient(this);
1281 }
1282
Trace(Visitor * visitor) const1283 void SVGElement::Trace(Visitor* visitor) const {
1284 visitor->Trace(elements_with_relative_lengths_);
1285 visitor->Trace(attribute_to_property_map_);
1286 visitor->Trace(svg_rare_data_);
1287 visitor->Trace(class_name_);
1288 Element::Trace(visitor);
1289 }
1290
AccessKeyAction(bool send_mouse_events)1291 void SVGElement::AccessKeyAction(bool send_mouse_events) {
1292 DispatchSimulatedClick(
1293 nullptr, send_mouse_events ? kSendMouseUpDownEvents : kSendNoEvents);
1294 }
1295
1296 } // namespace blink
1297