1/*
2 * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 David Smith <catfish.man@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB.  If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22#ifndef ElementRareData_h
23#define ElementRareData_h
24
25#include "ClassList.h"
26#include "DatasetDOMStringMap.h"
27#include "ElementShadow.h"
28#include "NamedNodeMap.h"
29#include "NodeRareData.h"
30#include "PseudoElement.h"
31#include "StyleInheritedData.h"
32#include <wtf/OwnPtr.h>
33
34namespace WebCore {
35
36class ElementRareData : public NodeRareData {
37public:
38    static PassOwnPtr<ElementRareData> create(RenderObject* renderer) { return adoptPtr(new ElementRareData(renderer)); }
39
40    ~ElementRareData();
41
42    void setPseudoElement(PseudoId, PassRefPtr<PseudoElement>);
43    PseudoElement* pseudoElement(PseudoId) const;
44    bool hasPseudoElements() const { return m_generatedBefore || m_generatedAfter; }
45
46    void resetComputedStyle();
47    void resetDynamicRestyleObservations();
48
49    short tabIndex() const { return m_tabIndex; }
50    void setTabIndexExplicitly(short index) { m_tabIndex = index; m_tabIndexWasSetExplicitly = true; }
51    bool tabIndexSetExplicitly() const { return m_tabIndexWasSetExplicitly; }
52    void clearTabIndexExplicitly() { m_tabIndex = 0; m_tabIndexWasSetExplicitly = false; }
53
54    bool needsFocusAppearanceUpdateSoonAfterAttach() const { return m_needsFocusAppearanceUpdateSoonAfterAttach; }
55    void setNeedsFocusAppearanceUpdateSoonAfterAttach(bool needs) { m_needsFocusAppearanceUpdateSoonAfterAttach = needs; }
56
57    bool styleAffectedByEmpty() const { return m_styleAffectedByEmpty; }
58    void setStyleAffectedByEmpty(bool value) { m_styleAffectedByEmpty = value; }
59
60    bool isInCanvasSubtree() const { return m_isInCanvasSubtree; }
61    void setIsInCanvasSubtree(bool value) { m_isInCanvasSubtree = value; }
62
63    bool isInsideRegion() const { return m_isInsideRegion; }
64    void setIsInsideRegion(bool value) { m_isInsideRegion = value; }
65
66#if ENABLE(FULLSCREEN_API)
67    bool containsFullScreenElement() { return m_containsFullScreenElement; }
68    void setContainsFullScreenElement(bool value) { m_containsFullScreenElement = value; }
69#endif
70
71#if ENABLE(DIALOG_ELEMENT)
72    bool isInTopLayer() const { return m_isInTopLayer; }
73    void setIsInTopLayer(bool value) { m_isInTopLayer = value; }
74#endif
75
76    bool childrenAffectedByHover() const { return m_childrenAffectedByHover; }
77    void setChildrenAffectedByHover(bool value) { m_childrenAffectedByHover = value; }
78    bool childrenAffectedByActive() const { return m_childrenAffectedByActive; }
79    void setChildrenAffectedByActive(bool value) { m_childrenAffectedByActive = value; }
80    bool childrenAffectedByDrag() const { return m_childrenAffectedByDrag; }
81    void setChildrenAffectedByDrag(bool value) { m_childrenAffectedByDrag = value; }
82
83    bool childrenAffectedByFirstChildRules() const { return m_childrenAffectedByFirstChildRules; }
84    void setChildrenAffectedByFirstChildRules(bool value) { m_childrenAffectedByFirstChildRules = value; }
85    bool childrenAffectedByLastChildRules() const { return m_childrenAffectedByLastChildRules; }
86    void setChildrenAffectedByLastChildRules(bool value) { m_childrenAffectedByLastChildRules = value; }
87    bool childrenAffectedByDirectAdjacentRules() const { return m_childrenAffectedByDirectAdjacentRules; }
88    void setChildrenAffectedByDirectAdjacentRules(bool value) { m_childrenAffectedByDirectAdjacentRules = value; }
89    bool childrenAffectedByForwardPositionalRules() const { return m_childrenAffectedByForwardPositionalRules; }
90    void setChildrenAffectedByForwardPositionalRules(bool value) { m_childrenAffectedByForwardPositionalRules = value; }
91    bool childrenAffectedByBackwardPositionalRules() const { return m_childrenAffectedByBackwardPositionalRules; }
92    void setChildrenAffectedByBackwardPositionalRules(bool value) { m_childrenAffectedByBackwardPositionalRules = value; }
93    unsigned childIndex() const { return m_childIndex; }
94    void setChildIndex(unsigned index) { m_childIndex = index; }
95
96    void clearShadow() { m_shadow = nullptr; }
97    ElementShadow* shadow() const { return m_shadow.get(); }
98    ElementShadow* ensureShadow()
99    {
100        if (!m_shadow)
101            m_shadow = ElementShadow::create();
102        return m_shadow.get();
103    }
104
105    NamedNodeMap* attributeMap() const { return m_attributeMap.get(); }
106    void setAttributeMap(PassOwnPtr<NamedNodeMap> attributeMap) { m_attributeMap = attributeMap; }
107
108    RenderStyle* computedStyle() const { return m_computedStyle.get(); }
109    void setComputedStyle(PassRefPtr<RenderStyle> computedStyle) { m_computedStyle = computedStyle; }
110
111    ClassList* classList() const { return m_classList.get(); }
112    void setClassList(PassOwnPtr<ClassList> classList) { m_classList = classList; }
113    void clearClassListValueForQuirksMode()
114    {
115        if (!m_classList)
116            return;
117        m_classList->clearValueForQuirksMode();
118    }
119
120    DatasetDOMStringMap* dataset() const { return m_dataset.get(); }
121    void setDataset(PassOwnPtr<DatasetDOMStringMap> dataset) { m_dataset = dataset; }
122
123    LayoutSize minimumSizeForResizing() const { return m_minimumSizeForResizing; }
124    void setMinimumSizeForResizing(LayoutSize size) { m_minimumSizeForResizing = size; }
125
126    IntSize savedLayerScrollOffset() const { return m_savedLayerScrollOffset; }
127    void setSavedLayerScrollOffset(IntSize size) { m_savedLayerScrollOffset = size; }
128
129#if ENABLE(SVG)
130    bool hasPendingResources() const { return m_hasPendingResources; }
131    void setHasPendingResources(bool has) { m_hasPendingResources = has; }
132#endif
133
134private:
135    short m_tabIndex;
136    unsigned short m_childIndex;
137    unsigned m_tabIndexWasSetExplicitly : 1;
138    unsigned m_needsFocusAppearanceUpdateSoonAfterAttach : 1;
139    unsigned m_styleAffectedByEmpty : 1;
140    unsigned m_isInCanvasSubtree : 1;
141#if ENABLE(FULLSCREEN_API)
142    unsigned m_containsFullScreenElement : 1;
143#endif
144#if ENABLE(DIALOG_ELEMENT)
145    unsigned m_isInTopLayer : 1;
146#endif
147#if ENABLE(SVG)
148    unsigned m_hasPendingResources : 1;
149#endif
150    unsigned m_childrenAffectedByHover : 1;
151    unsigned m_childrenAffectedByActive : 1;
152    unsigned m_childrenAffectedByDrag : 1;
153    // Bits for dynamic child matching.
154    // We optimize for :first-child and :last-child. The other positional child selectors like nth-child or
155    // *-child-of-type, we will just give up and re-evaluate whenever children change at all.
156    unsigned m_childrenAffectedByFirstChildRules : 1;
157    unsigned m_childrenAffectedByLastChildRules : 1;
158    unsigned m_childrenAffectedByDirectAdjacentRules : 1;
159    unsigned m_childrenAffectedByForwardPositionalRules : 1;
160    unsigned m_childrenAffectedByBackwardPositionalRules : 1;
161
162    unsigned m_isInsideRegion : 1;
163    LayoutSize m_minimumSizeForResizing;
164    IntSize m_savedLayerScrollOffset;
165    RefPtr<RenderStyle> m_computedStyle;
166
167    OwnPtr<DatasetDOMStringMap> m_dataset;
168    OwnPtr<ClassList> m_classList;
169    OwnPtr<ElementShadow> m_shadow;
170    OwnPtr<NamedNodeMap> m_attributeMap;
171
172    RefPtr<PseudoElement> m_generatedBefore;
173    RefPtr<PseudoElement> m_generatedAfter;
174
175    ElementRareData(RenderObject*);
176    void releasePseudoElement(PseudoElement*);
177};
178
179inline IntSize defaultMinimumSizeForResizing()
180{
181    return IntSize(LayoutUnit::max(), LayoutUnit::max());
182}
183
184inline ElementRareData::ElementRareData(RenderObject* renderer)
185    : NodeRareData(renderer)
186    , m_tabIndex(0)
187    , m_childIndex(0)
188    , m_tabIndexWasSetExplicitly(false)
189    , m_needsFocusAppearanceUpdateSoonAfterAttach(false)
190    , m_styleAffectedByEmpty(false)
191    , m_isInCanvasSubtree(false)
192#if ENABLE(FULLSCREEN_API)
193    , m_containsFullScreenElement(false)
194#endif
195#if ENABLE(DIALOG_ELEMENT)
196    , m_isInTopLayer(false)
197#endif
198#if ENABLE(SVG)
199    , m_hasPendingResources(false)
200#endif
201    , m_childrenAffectedByHover(false)
202    , m_childrenAffectedByActive(false)
203    , m_childrenAffectedByDrag(false)
204    , m_childrenAffectedByFirstChildRules(false)
205    , m_childrenAffectedByLastChildRules(false)
206    , m_childrenAffectedByDirectAdjacentRules(false)
207    , m_childrenAffectedByForwardPositionalRules(false)
208    , m_childrenAffectedByBackwardPositionalRules(false)
209    , m_isInsideRegion(false)
210    , m_minimumSizeForResizing(defaultMinimumSizeForResizing())
211{
212}
213
214inline ElementRareData::~ElementRareData()
215{
216    ASSERT(!m_shadow);
217    ASSERT(!m_generatedBefore);
218    ASSERT(!m_generatedAfter);
219}
220
221inline void ElementRareData::setPseudoElement(PseudoId pseudoId, PassRefPtr<PseudoElement> element)
222{
223    switch (pseudoId) {
224    case BEFORE:
225        releasePseudoElement(m_generatedBefore.get());
226        m_generatedBefore = element;
227        break;
228    case AFTER:
229        releasePseudoElement(m_generatedAfter.get());
230        m_generatedAfter = element;
231        break;
232    default:
233        ASSERT_NOT_REACHED();
234    }
235}
236
237inline PseudoElement* ElementRareData::pseudoElement(PseudoId pseudoId) const
238{
239    switch (pseudoId) {
240    case BEFORE:
241        return m_generatedBefore.get();
242    case AFTER:
243        return m_generatedAfter.get();
244    default:
245        return 0;
246    }
247}
248
249inline void ElementRareData::releasePseudoElement(PseudoElement* element)
250{
251    if (!element)
252        return;
253
254    if (element->attached())
255        element->detach();
256
257    ASSERT(!element->nextSibling());
258    ASSERT(!element->previousSibling());
259
260    element->setParentOrShadowHostNode(0);
261}
262
263inline void ElementRareData::resetComputedStyle()
264{
265    setComputedStyle(0);
266    setStyleAffectedByEmpty(false);
267    setChildIndex(0);
268}
269
270inline void ElementRareData::resetDynamicRestyleObservations()
271{
272    setChildrenAffectedByHover(false);
273    setChildrenAffectedByActive(false);
274    setChildrenAffectedByDrag(false);
275    setChildrenAffectedByFirstChildRules(false);
276    setChildrenAffectedByLastChildRules(false);
277    setChildrenAffectedByDirectAdjacentRules(false);
278    setChildrenAffectedByForwardPositionalRules(false);
279    setChildrenAffectedByBackwardPositionalRules(false);
280}
281
282} // namespace
283
284#endif // ElementRareData_h
285