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 SVGElement_h
23#define SVGElement_h
24
25#include "core/SVGNames.h"
26#include "core/dom/Element.h"
27#include "core/svg/SVGAnimatedString.h"
28#include "core/svg/SVGParsingError.h"
29#include "core/svg/properties/SVGPropertyInfo.h"
30#include "platform/Timer.h"
31#include "wtf/HashMap.h"
32#include "wtf/OwnPtr.h"
33
34namespace blink {
35
36class AffineTransform;
37class CSSCursorImageValue;
38class Document;
39class SVGAnimatedPropertyBase;
40class SubtreeLayoutScope;
41class SVGCursorElement;
42class SVGDocumentExtensions;
43class SVGElement;
44class SVGElementRareData;
45class SVGFitToViewBox;
46class SVGSVGElement;
47class SVGUseElement;
48
49void mapAttributeToCSSProperty(HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap, const QualifiedName& attrName);
50
51typedef WillBeHeapHashSet<RawPtrWillBeMember<SVGElement> > SVGElementSet;
52
53class SVGElement : public Element {
54    DEFINE_WRAPPERTYPEINFO();
55public:
56    virtual ~SVGElement();
57    virtual void attach(const AttachContext&) OVERRIDE;
58    virtual void detach(const AttachContext&) OVERRIDE;
59
60    virtual short tabIndex() const OVERRIDE;
61    virtual bool supportsFocus() const OVERRIDE { return false; }
62
63    bool isOutermostSVGSVGElement() const;
64
65    bool hasTagName(const SVGQualifiedName& name) const { return hasLocalName(name.localName()); }
66
67    virtual String title() const OVERRIDE;
68    bool hasRelativeLengths() const { return !m_elementsWithRelativeLengths.isEmpty(); }
69    static bool isAnimatableCSSProperty(const QualifiedName&);
70    enum CTMScope {
71        NearestViewportScope, // Used by SVGGraphicsElement::getCTM()
72        ScreenScope, // Used by SVGGraphicsElement::getScreenCTM()
73        AncestorScope // Used by SVGSVGElement::get{Enclosure|Intersection}List()
74    };
75    virtual AffineTransform localCoordinateSpaceTransform(CTMScope) const;
76    virtual bool needsPendingResourceHandling() const { return true; }
77
78    bool instanceUpdatesBlocked() const;
79    void setInstanceUpdatesBlocked(bool);
80
81    SVGSVGElement* ownerSVGElement() const;
82    SVGElement* viewportElement() const;
83
84    SVGDocumentExtensions& accessDocumentSVGExtensions();
85
86    virtual bool isSVGGraphicsElement() const { return false; }
87    virtual bool isFilterEffect() const { return false; }
88    virtual bool isTextContent() const { return false; }
89    virtual bool isTextPositioning() const { return false; }
90    virtual bool isStructurallyExternal() const { return false; }
91
92    // For SVGTests
93    virtual bool isValid() const { return true; }
94
95    virtual void svgAttributeChanged(const QualifiedName&);
96
97    PassRefPtr<SVGAnimatedPropertyBase> propertyFromAttribute(const QualifiedName& attributeName);
98    static AnimatedPropertyType animatedPropertyTypeForCSSAttribute(const QualifiedName& attributeName);
99
100    void sendSVGLoadEventToSelfAndAncestorChainIfPossible();
101    bool sendSVGLoadEventIfPossible();
102    void sendSVGLoadEventIfPossibleAsynchronously();
103    void svgLoadEventTimerFired(Timer<SVGElement>*);
104    virtual Timer<SVGElement>* svgLoadEventTimer();
105
106    virtual AffineTransform* supplementalTransform() { return 0; }
107
108    void invalidateSVGAttributes() { ensureUniqueElementData().m_animatedSVGAttributesAreDirty = true; }
109    void invalidateSVGPresentationAttributeStyle() { ensureUniqueElementData().m_presentationAttributeStyleIsDirty = true; }
110
111    const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instancesForElement() const;
112    void mapInstanceToElement(SVGElement*);
113    void removeInstanceMapping(SVGElement*);
114
115    bool getBoundingBox(FloatRect&);
116
117    void setCursorElement(SVGCursorElement*);
118    void setCursorImageValue(CSSCursorImageValue*);
119
120#if !ENABLE(OILPAN)
121    void cursorElementRemoved();
122    void cursorImageValueRemoved();
123#endif
124
125    SVGElement* correspondingElement();
126    void setCorrespondingElement(SVGElement*);
127    SVGUseElement* correspondingUseElement() const;
128
129    void synchronizeAnimatedSVGAttribute(const QualifiedName&) const;
130
131    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE FINAL;
132
133    virtual void synchronizeRequiredFeatures() { }
134    virtual void synchronizeRequiredExtensions() { }
135    virtual void synchronizeSystemLanguage() { }
136
137#if ENABLE(ASSERT)
138    virtual bool isAnimatableAttribute(const QualifiedName&) const;
139#endif
140
141    MutableStylePropertySet* animatedSMILStyleProperties() const;
142    MutableStylePropertySet* ensureAnimatedSMILStyleProperties();
143    void setUseOverrideComputedStyle(bool);
144
145    virtual bool haveLoadedRequiredResources();
146
147    virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture = false) OVERRIDE FINAL;
148    virtual bool removeEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture = false) OVERRIDE FINAL;
149
150    void invalidateRelativeLengthClients(SubtreeLayoutScope* = 0);
151
152    void addToPropertyMap(PassRefPtr<SVGAnimatedPropertyBase>);
153
154    SVGAnimatedString* className() { return m_className.get(); }
155
156    bool inUseShadowTree() const;
157
158    SVGElementSet* setOfIncomingReferences() const;
159    void addReferenceTo(SVGElement*);
160    void rebuildAllIncomingReferences();
161    void removeAllIncomingReferences();
162    void removeAllOutgoingReferences();
163
164    class InvalidationGuard {
165        STACK_ALLOCATED();
166        WTF_MAKE_NONCOPYABLE(InvalidationGuard);
167    public:
168        InvalidationGuard(SVGElement* element) : m_element(element) { }
169        ~InvalidationGuard() { m_element->invalidateInstances(); }
170
171    private:
172        RawPtrWillBeMember<SVGElement> m_element;
173    };
174
175    class InstanceUpdateBlocker {
176        STACK_ALLOCATED();
177        WTF_MAKE_NONCOPYABLE(InstanceUpdateBlocker);
178    public:
179        InstanceUpdateBlocker(SVGElement* targetElement);
180        ~InstanceUpdateBlocker();
181
182    private:
183        RawPtrWillBeMember<SVGElement> m_targetElement;
184    };
185
186    void invalidateInstances();
187
188    virtual void trace(Visitor*) OVERRIDE;
189
190    static const AtomicString& eventParameterName();
191
192protected:
193    SVGElement(const QualifiedName&, Document&, ConstructionType = CreateSVGElement);
194
195    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
196
197    // FIXME: |parseAttributeNew| is a new implementation of parseAttribute
198    // which maps attribute using |m_attributeToPropertyMap|.
199    // This is to replace |parseAttribute()| after all derived class switch to call this.
200    void parseAttributeNew(const QualifiedName&, const AtomicString&);
201
202    virtual void attributeChanged(const QualifiedName&, const AtomicString&, AttributeModificationReason = ModifiedDirectly) OVERRIDE;
203
204    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
205    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
206
207    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
208    virtual void removedFrom(ContainerNode*) OVERRIDE;
209    virtual void childrenChanged(const ChildrenChange&) OVERRIDE;
210
211    static CSSPropertyID cssPropertyIdForSVGAttributeName(const QualifiedName&);
212    void updateRelativeLengthsInformation() { updateRelativeLengthsInformation(selfHasRelativeLengths(), this); }
213    void updateRelativeLengthsInformation(bool hasRelativeLengths, SVGElement*);
214
215    virtual bool selfHasRelativeLengths() const { return false; }
216
217    SVGElementRareData* ensureSVGRareData();
218    inline bool hasSVGRareData() const { return m_SVGRareData; }
219    inline SVGElementRareData* svgRareData() const
220    {
221        ASSERT(m_SVGRareData);
222        return m_SVGRareData.get();
223    }
224
225    // SVGFitToViewBox::parseAttribute uses reportAttributeParsingError.
226    friend class SVGFitToViewBox;
227    void reportAttributeParsingError(SVGParsingError, const QualifiedName&, const AtomicString&);
228    bool hasFocusEventListeners() const;
229
230private:
231    // FIXME: Author shadows should be allowed
232    // https://bugs.webkit.org/show_bug.cgi?id=77938
233    virtual bool areAuthorShadowsAllowed() const OVERRIDE FINAL { return false; }
234
235    bool isSVGElement() const WTF_DELETED_FUNCTION; // This will catch anyone doing an unnecessary check.
236    bool isStyledElement() const WTF_DELETED_FUNCTION; // This will catch anyone doing an unnecessary check.
237
238    RenderStyle* computedStyle(PseudoId = NOPSEUDO);
239    virtual RenderStyle* virtualComputedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO) OVERRIDE FINAL { return computedStyle(pseudoElementSpecifier); }
240    virtual void willRecalcStyle(StyleRecalcChange) OVERRIDE;
241
242    void buildPendingResourcesIfNeeded();
243
244    WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > m_elementsWithRelativeLengths;
245
246    typedef HashMap<QualifiedName, RefPtr<SVGAnimatedPropertyBase> > AttributeToPropertyMap;
247    AttributeToPropertyMap m_attributeToPropertyMap;
248
249#if ENABLE(ASSERT)
250    bool m_inRelativeLengthClientsInvalidation;
251#endif
252
253    OwnPtrWillBeMember<SVGElementRareData> m_SVGRareData;
254    RefPtr<SVGAnimatedString> m_className;
255};
256
257struct SVGAttributeHashTranslator {
258    static unsigned hash(const QualifiedName& key)
259    {
260        if (key.hasPrefix()) {
261            QualifiedNameComponents components = { nullAtom.impl(), key.localName().impl(), key.namespaceURI().impl() };
262            return hashComponents(components);
263        }
264        return DefaultHash<QualifiedName>::Hash::hash(key);
265    }
266    static bool equal(const QualifiedName& a, const QualifiedName& b) { return a.matches(b); }
267};
268
269DEFINE_ELEMENT_TYPE_CASTS(SVGElement, isSVGElement());
270
271template <typename T> bool isElementOfType(const SVGElement&);
272template <> inline bool isElementOfType<const SVGElement>(const SVGElement&) { return true; }
273
274inline bool Node::hasTagName(const SVGQualifiedName& name) const
275{
276    return isSVGElement() && toSVGElement(*this).hasTagName(name);
277}
278
279// This requires isSVG*Element(const SVGElement&).
280#define DEFINE_SVGELEMENT_TYPE_CASTS_WITH_FUNCTION(thisType) \
281    inline bool is##thisType(const thisType* element); \
282    inline bool is##thisType(const thisType& element); \
283    inline bool is##thisType(const SVGElement* element) { return element && is##thisType(*element); } \
284    inline bool is##thisType(const Node& node) { return node.isSVGElement() ? is##thisType(toSVGElement(node)) : false; } \
285    inline bool is##thisType(const Node* node) { return node && is##thisType(*node); } \
286    template<typename T> inline bool is##thisType(const PassRefPtr<T>& node) { return is##thisType(node.get()); } \
287    template<typename T> inline bool is##thisType(const RefPtr<T>& node) { return is##thisType(node.get()); } \
288    template <> inline bool isElementOfType<const thisType>(const SVGElement& element) { return is##thisType(element); } \
289    DEFINE_ELEMENT_TYPE_CASTS_WITH_FUNCTION(thisType)
290
291} // namespace blink
292
293#include "core/SVGElementTypeHelpers.h"
294
295#endif // SVGElement_h
296