1 /*
2  * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4  * Copyright (C) 2009, 2014 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_ELEMENT_H_
23 #define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_ELEMENT_H_
24 
25 #include "base/macros.h"
26 #include "third_party/blink/renderer/core/core_export.h"
27 #include "third_party/blink/renderer/core/dom/element.h"
28 #include "third_party/blink/renderer/core/svg/properties/svg_property_info.h"
29 #include "third_party/blink/renderer/core/svg/svg_parsing_error.h"
30 #include "third_party/blink/renderer/core/svg_names.h"
31 #include "third_party/blink/renderer/platform/heap/handle.h"
32 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
33 #include "third_party/blink/renderer/platform/wtf/casting.h"
34 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
35 
36 namespace blink {
37 
38 class AffineTransform;
39 class Document;
40 class ElementSMILAnimations;
41 class ExecutionContext;
42 class SVGAnimatedPropertyBase;
43 class SubtreeLayoutScope;
44 class SVGAnimatedString;
45 class SVGElement;
46 class SVGElementRareData;
47 class SVGElementResourceClient;
48 class SVGPropertyBase;
49 class SVGSVGElement;
50 class SVGUseElement;
51 
52 typedef HeapHashSet<Member<SVGElement>> SVGElementSet;
53 
54 class CORE_EXPORT SVGElement : public Element {
55   DEFINE_WRAPPERTYPEINFO();
56 
57  public:
58   ~SVGElement() override;
59 
SupportsFocus()60   bool SupportsFocus() const override { return false; }
61 
62   bool IsOutermostSVGSVGElement() const;
63 
HasTagName(const SVGQualifiedName & name)64   bool HasTagName(const SVGQualifiedName& name) const {
65     return HasLocalName(name.LocalName());
66   }
67 
68   String title() const override;
HasRelativeLengths()69   bool HasRelativeLengths() const {
70     return !elements_with_relative_lengths_.IsEmpty();
71   }
72   static bool IsAnimatableCSSProperty(const QualifiedName&);
73 
74   enum ApplyMotionTransform {
75     kExcludeMotionTransform,
76     kIncludeMotionTransform
77   };
78   bool HasTransform(ApplyMotionTransform) const;
79   AffineTransform CalculateTransform(ApplyMotionTransform) const;
80 
81   enum CTMScope {
82     kNearestViewportScope,  // Used by SVGGraphicsElement::getCTM()
83     kScreenScope,           // Used by SVGGraphicsElement::getScreenCTM()
84     kAncestorScope  // Used by SVGSVGElement::get{Enclosure|Intersection}List()
85   };
86   virtual AffineTransform LocalCoordinateSpaceTransform(CTMScope) const;
87 
88   bool InstanceUpdatesBlocked() const;
89   void SetInstanceUpdatesBlocked(bool);
90 
91   // Records the SVG element as having a Web Animation on an SVG attribute that
92   // needs applying.
93   void SetWebAnimationsPending();
94   void ApplyActiveWebAnimations();
95 
96   void EnsureAttributeAnimValUpdated();
97 
98   void SetWebAnimatedAttribute(const QualifiedName& attribute,
99                                SVGPropertyBase*);
100   void ClearWebAnimatedAttributes();
101 
102   ElementSMILAnimations* GetSMILAnimations();
103   ElementSMILAnimations& EnsureSMILAnimations();
104 
105   void SetAnimatedAttribute(const QualifiedName&, SVGPropertyBase*);
106   void ClearAnimatedAttribute(const QualifiedName&);
107 
108   SVGSVGElement* ownerSVGElement() const;
109   SVGElement* viewportElement() const;
110 
IsSVGGeometryElement()111   virtual bool IsSVGGeometryElement() const { return false; }
IsSVGGraphicsElement()112   virtual bool IsSVGGraphicsElement() const { return false; }
IsFilterEffect()113   virtual bool IsFilterEffect() const { return false; }
IsTextContent()114   virtual bool IsTextContent() const { return false; }
IsTextPositioning()115   virtual bool IsTextPositioning() const { return false; }
IsStructurallyExternal()116   virtual bool IsStructurallyExternal() const { return false; }
117 
118   // For SVGTests
IsValid()119   virtual bool IsValid() const { return true; }
120 
121   virtual void SvgAttributeChanged(const QualifiedName&);
122   void SvgAttributeBaseValChanged(const QualifiedName&);
123 
124   SVGAnimatedPropertyBase* PropertyFromAttribute(
125       const QualifiedName& attribute_name) const;
126   static AnimatedPropertyType AnimatedPropertyTypeForCSSAttribute(
127       const QualifiedName& attribute_name);
128 
129   void SendSVGLoadEventToSelfAndAncestorChainIfPossible();
130   bool SendSVGLoadEventIfPossible();
131 
AnimateMotionTransform()132   virtual AffineTransform* AnimateMotionTransform() { return nullptr; }
133 
InvalidateSVGAttributes()134   void InvalidateSVGAttributes() {
135     EnsureUniqueElementData().SetAnimatedSvgAttributesAreDirty(true);
136   }
InvalidateSVGPresentationAttributeStyle()137   void InvalidateSVGPresentationAttributeStyle() {
138     EnsureUniqueElementData().SetPresentationAttributeStyleIsDirty(true);
139   }
140 
141   const HeapHashSet<WeakMember<SVGElement>>& InstancesForElement() const;
142   void MapInstanceToElement(SVGElement*);
143   void RemoveInstanceMapping(SVGElement*);
144 
145   SVGElement* CorrespondingElement() const;
146   void SetCorrespondingElement(SVGElement*);
147   SVGUseElement* GeneratingUseElement() const;
148 
149   void SynchronizeAnimatedSVGAttribute(const QualifiedName&) const;
150 
151   scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() final;
152   bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
153 
154 #if DCHECK_IS_ON()
155   virtual bool IsAnimatableAttribute(const QualifiedName&) const;
156 #endif
157 
158   MutableCSSPropertyValueSet* AnimatedSMILStyleProperties() const;
159   MutableCSSPropertyValueSet* EnsureAnimatedSMILStyleProperties();
160   void SetUseOverrideComputedStyle(bool);
161 
162   virtual bool HaveLoadedRequiredResources();
163 
164   void InvalidateRelativeLengthClients(SubtreeLayoutScope* = nullptr);
165 
166   void AddToPropertyMap(SVGAnimatedPropertyBase*);
167 
className()168   SVGAnimatedString* className() { return class_name_.Get(); }
169 
170   bool InUseShadowTree() const;
171 
172   void AddReferenceTo(SVGElement*);
173   template <typename InvalidationFunction>
174   void NotifyIncomingReferences(InvalidationFunction&&);
175   void RebuildAllIncomingReferences();
176   void RemoveAllIncomingReferences();
177   void RemoveAllOutgoingReferences();
178 
179   SVGElementResourceClient* GetSVGResourceClient();
180   SVGElementResourceClient& EnsureSVGResourceClient();
181 
182   class InvalidationGuard {
183     STACK_ALLOCATED();
184 
185    public:
InvalidationGuard(SVGElement * element)186     InvalidationGuard(SVGElement* element) : element_(element) {}
~InvalidationGuard()187     ~InvalidationGuard() { element_->InvalidateInstances(); }
188 
189    private:
190     SVGElement* element_;
191     DISALLOW_COPY_AND_ASSIGN(InvalidationGuard);
192   };
193 
194   class InstanceUpdateBlocker {
195     STACK_ALLOCATED();
196 
197    public:
198     InstanceUpdateBlocker(SVGElement* target_element);
199     ~InstanceUpdateBlocker();
200 
201    private:
202     SVGElement* target_element_;
203     DISALLOW_COPY_AND_ASSIGN(InstanceUpdateBlocker);
204   };
205 
206   void InvalidateInstances();
207   void SetNeedsStyleRecalcForInstances(StyleChangeType,
208                                        const StyleChangeReasonForTracing&);
209 
210   void Trace(Visitor*) override;
211 
212   static const AtomicString& EventParameterName();
213 
214   bool IsPresentationAttribute(const QualifiedName&) const override;
215 
216   bool HasSVGParent() const;
217 
218  protected:
219   SVGElement(const QualifiedName&,
220              Document&,
221              ConstructionType = kCreateSVGElement);
222 
223   void ParseAttribute(const AttributeModificationParams&) override;
224   void AttributeChanged(const AttributeModificationParams&) override;
225 
226   void CollectStyleForPresentationAttribute(
227       const QualifiedName&,
228       const AtomicString&,
229       MutableCSSPropertyValueSet*) override;
230 
231   InsertionNotificationRequest InsertedInto(ContainerNode&) override;
232   void RemovedFrom(ContainerNode&) override;
233   void ChildrenChanged(const ChildrenChange&) override;
234 
235   void DetachLayoutTree(bool performing_reattach) override;
236 
237   static CSSPropertyID CssPropertyIdForSVGAttributeName(const ExecutionContext*,
238                                                         const QualifiedName&);
UpdateRelativeLengthsInformation()239   void UpdateRelativeLengthsInformation() {
240     UpdateRelativeLengthsInformation(SelfHasRelativeLengths(), this);
241   }
242   void UpdateRelativeLengthsInformation(bool has_relative_lengths, SVGElement*);
243   static void MarkForLayoutAndParentResourceInvalidation(LayoutObject&);
244 
SelfHasRelativeLengths()245   virtual bool SelfHasRelativeLengths() const { return false; }
246 
247   SVGElementSet* SetOfIncomingReferences() const;
248 
249   SVGElementRareData* EnsureSVGRareData();
HasSVGRareData()250   inline bool HasSVGRareData() const { return svg_rare_data_; }
SvgRareData()251   inline SVGElementRareData* SvgRareData() const {
252     DCHECK(svg_rare_data_);
253     return svg_rare_data_.Get();
254   }
255 
256   void ReportAttributeParsingError(SVGParsingError,
257                                    const QualifiedName&,
258                                    const AtomicString&);
259   bool HasFocusEventListeners() const;
260 
261   void AddedEventListener(const AtomicString& event_type,
262                           RegisteredEventListener&) final;
263   void RemovedEventListener(const AtomicString& event_type,
264                             const RegisteredEventListener&) final;
265 
266   void AccessKeyAction(bool send_mouse_events) override;
267 
268  private:
269   bool IsSVGElement() const =
270       delete;  // This will catch anyone doing an unnecessary check.
271   bool IsStyledElement() const =
272       delete;  // This will catch anyone doing an unnecessary check.
273 
274   const ComputedStyle* EnsureComputedStyle(PseudoId = kPseudoIdNone);
275   const ComputedStyle* VirtualEnsureComputedStyle(
276       PseudoId pseudo_element_specifier = kPseudoIdNone) final {
277     return EnsureComputedStyle(pseudo_element_specifier);
278   }
279   void WillRecalcStyle(const StyleRecalcChange) override;
280   static SVGElementSet& GetDependencyTraversalVisitedSet();
281 
282   HeapHashSet<WeakMember<SVGElement>> elements_with_relative_lengths_;
283 
284   typedef HeapHashMap<QualifiedName, Member<SVGAnimatedPropertyBase>>
285       AttributeToPropertyMap;
286   AttributeToPropertyMap attribute_to_property_map_;
287 
288 #if DCHECK_IS_ON()
289   bool in_relative_length_clients_invalidation_ = false;
290 #endif
291 
292   Member<SVGElementRareData> svg_rare_data_;
293   Member<SVGAnimatedString> class_name_;
294 };
295 
296 template <typename InvalidationFunction>
NotifyIncomingReferences(InvalidationFunction && invalidation_function)297 void SVGElement::NotifyIncomingReferences(
298     InvalidationFunction&& invalidation_function) {
299   SVGElementSet* dependencies = SetOfIncomingReferences();
300   if (!dependencies)
301     return;
302 
303   // We allow cycles in the reference graph in order to avoid expensive
304   // adjustments on changes, so we need to break possible cycles here.
305   SVGElementSet& invalidating_dependencies = GetDependencyTraversalVisitedSet();
306 
307   for (SVGElement* element : *dependencies) {
308     if (!element->GetLayoutObject())
309       continue;
310     if (UNLIKELY(!invalidating_dependencies.insert(element).is_new_entry)) {
311       // Reference cycle: we are in process of invalidating this dependant.
312       continue;
313     }
314     invalidation_function(*element);
315     invalidating_dependencies.erase(element);
316   }
317 }
318 
319 struct SVGAttributeHashTranslator {
320   STATIC_ONLY(SVGAttributeHashTranslator);
GetHashSVGAttributeHashTranslator321   static unsigned GetHash(const QualifiedName& key) {
322     if (key.HasPrefix()) {
323       QualifiedNameComponents components = {g_null_atom.Impl(),
324                                             key.LocalName().Impl(),
325                                             key.NamespaceURI().Impl()};
326       return HashComponents(components);
327     }
328     return DefaultHash<QualifiedName>::Hash::GetHash(key);
329   }
EqualSVGAttributeHashTranslator330   static bool Equal(const QualifiedName& a, const QualifiedName& b) {
331     return a.Matches(b);
332   }
333 };
334 
335 template <typename T>
336 bool IsElementOfType(const SVGElement&);
337 template <>
338 inline bool IsElementOfType<const SVGElement>(const SVGElement&) {
339   return true;
340 }
341 template <>
342 inline bool IsElementOfType<const SVGElement>(const Node& node) {
343   return IsA<SVGElement>(node);
344 }
345 template <>
346 struct DowncastTraits<SVGElement> {
347   static bool AllowFrom(const Node& node) { return node.IsSVGElement(); }
348 };
349 inline bool Node::HasTagName(const SVGQualifiedName& name) const {
350   auto* svg_element = DynamicTo<SVGElement>(this);
351   return svg_element && svg_element->HasTagName(name);
352 }
353 
354 }  // namespace blink
355 
356 #include "third_party/blink/renderer/core/svg_element_type_helpers.h"
357 
358 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_ELEMENT_H_
359