OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Neither the name of Google Inc. nor the names of its | 10 * * Neither the name of Google Inc. nor the names of its |
11 * contributors may be used to endorse or promote products derived from | 11 * contributors may be used to endorse or promote products derived from |
12 * this software without specific prior written permission. | 12 * this software without specific prior written permission. |
13 * | 13 * |
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 */ | 25 */ |
26 | 26 |
27 #include "core/dom/PseudoElement.h" | 27 #include "core/dom/PseudoElement.h" |
28 | 28 |
29 #include "core/dom/FirstLetterPseudoElement.h" | 29 #include "core/dom/FirstLetterPseudoElement.h" |
| 30 #include "core/dom/NodeComputedStyle.h" |
30 #include "core/frame/UseCounter.h" | 31 #include "core/frame/UseCounter.h" |
31 #include "core/inspector/InspectorInstrumentation.h" | 32 #include "core/inspector/InspectorInstrumentation.h" |
32 #include "core/layout/LayoutObject.h" | 33 #include "core/layout/LayoutObject.h" |
33 #include "core/layout/LayoutQuote.h" | 34 #include "core/layout/LayoutQuote.h" |
34 #include "core/style/ContentData.h" | 35 #include "core/style/ContentData.h" |
35 | 36 |
36 namespace blink { | 37 namespace blink { |
37 | 38 |
38 PseudoElement* PseudoElement::create(Element* parent, PseudoId pseudoId) { | 39 PseudoElement* PseudoElement::create(Element* parent, PseudoId pseudoId) { |
39 return new PseudoElement(parent, pseudoId); | 40 return new PseudoElement(parent, pseudoId); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 parent->treeScope().adoptIfNeeded(*this); | 91 parent->treeScope().adoptIfNeeded(*this); |
91 setParentOrShadowHostNode(parent); | 92 setParentOrShadowHostNode(parent); |
92 setHasCustomStyleCallbacks(); | 93 setHasCustomStyleCallbacks(); |
93 if ((pseudoId == PseudoIdBefore || pseudoId == PseudoIdAfter) && | 94 if ((pseudoId == PseudoIdBefore || pseudoId == PseudoIdAfter) && |
94 parent->hasTagName(HTMLNames::inputTag)) | 95 parent->hasTagName(HTMLNames::inputTag)) |
95 UseCounter::count(parent->document(), | 96 UseCounter::count(parent->document(), |
96 UseCounter::PseudoBeforeAfterForInputElement); | 97 UseCounter::PseudoBeforeAfterForInputElement); |
97 } | 98 } |
98 | 99 |
99 PassRefPtr<ComputedStyle> PseudoElement::customStyleForLayoutObject() { | 100 PassRefPtr<ComputedStyle> PseudoElement::customStyleForLayoutObject() { |
100 return parentOrShadowHostElement()->layoutObject()->getCachedPseudoStyle( | 101 return parentOrShadowHostElement()->pseudoStyle(m_pseudoId); |
101 m_pseudoId); | |
102 } | 102 } |
103 | 103 |
104 void PseudoElement::dispose() { | 104 void PseudoElement::dispose() { |
105 DCHECK(parentOrShadowHostElement()); | 105 DCHECK(parentOrShadowHostElement()); |
106 | 106 |
107 probe::pseudoElementDestroyed(this); | 107 probe::pseudoElementDestroyed(this); |
108 | 108 |
109 DCHECK(!nextSibling()); | 109 DCHECK(!nextSibling()); |
110 DCHECK(!previousSibling()); | 110 DCHECK(!previousSibling()); |
111 | 111 |
112 detachLayoutTree(); | 112 detachLayoutTree(); |
113 Element* parent = parentOrShadowHostElement(); | 113 Element* parent = parentOrShadowHostElement(); |
114 document().adoptIfNeeded(*this); | 114 document().adoptIfNeeded(*this); |
115 setParentOrShadowHostNode(0); | 115 setParentOrShadowHostNode(0); |
116 removedFrom(parent); | 116 removedFrom(parent); |
117 } | 117 } |
118 | 118 |
119 void PseudoElement::attachLayoutTree(const AttachContext& context) { | 119 void PseudoElement::attachLayoutTree(const AttachContext& context) { |
120 DCHECK(!layoutObject()); | 120 DCHECK(!layoutObject()); |
121 | 121 |
122 Element::attachLayoutTree(context); | 122 Element::attachLayoutTree(context); |
123 | 123 |
124 LayoutObject* layoutObject = this->layoutObject(); | 124 ComputedStyle* style = mutableComputedStyle(); |
125 if (!layoutObject) | 125 if (!style || (style->styleType() != PseudoIdBefore && |
| 126 style->styleType() != PseudoIdAfter)) |
126 return; | 127 return; |
127 | 128 |
128 ComputedStyle& style = layoutObject->mutableStyleRef(); | 129 DCHECK(style->contentData()); |
129 if (style.styleType() != PseudoIdBefore && style.styleType() != PseudoIdAfter) | |
130 return; | |
131 DCHECK(style.contentData()); | |
132 | 130 |
133 for (const ContentData* content = style.contentData(); content; | 131 LayoutObject* parentLayoutObject = layoutObject(); |
| 132 if (!parentLayoutObject) |
| 133 parentLayoutObject = LayoutTreeBuilderTraversal::parentLayoutObject(*this); |
| 134 |
| 135 for (const ContentData* content = style->contentData(); content; |
134 content = content->next()) { | 136 content = content->next()) { |
135 LayoutObject* child = content->createLayoutObject(document(), style); | 137 LayoutObject* child = content->createLayoutObject(*this, *style); |
136 if (layoutObject->isChildAllowed(child, style)) { | 138 if (parentLayoutObject->isChildAllowed(child, *style)) { |
137 layoutObject->addChild(child); | 139 parentLayoutObject->addChild(child); |
| 140 DCHECK(child->isPseudoElementGeneratedContentFor(*this)); |
138 if (child->isQuote()) | 141 if (child->isQuote()) |
139 toLayoutQuote(child)->attachQuote(); | 142 toLayoutQuote(child)->attachQuote(); |
140 } else { | 143 } else { |
141 child->destroy(); | 144 child->destroy(); |
142 } | 145 } |
143 } | 146 } |
144 } | 147 } |
145 | 148 |
| 149 void PseudoElement::detachLayoutTree(const AttachContext& context) { |
| 150 Element::detachLayoutTree(context); |
| 151 } |
| 152 |
146 bool PseudoElement::layoutObjectIsNeeded(const ComputedStyle& style) { | 153 bool PseudoElement::layoutObjectIsNeeded(const ComputedStyle& style) { |
147 return pseudoElementLayoutObjectIsNeeded(&style); | 154 return pseudoElementLayoutObjectIsNeeded(&style); |
148 } | 155 } |
149 | 156 |
| 157 static bool isGeneratedContentLike(LayoutObject* layoutObject) { |
| 158 if (!layoutObject->isAnonymous()) |
| 159 return false; |
| 160 return layoutObject->isText() || layoutObject->isQuote() || |
| 161 layoutObject->isImage(); |
| 162 } |
| 163 |
| 164 static void updateGeneratedContentStyleIn(LayoutObject* root, |
| 165 ComputedStyle* style) { |
| 166 for (LayoutObject* child = root; child; child = child->nextInPreOrder(root)) { |
| 167 if (isGeneratedContentLike(child)) |
| 168 child->setPseudoStyle(style); |
| 169 } |
| 170 } |
| 171 |
150 void PseudoElement::didRecalcStyle() { | 172 void PseudoElement::didRecalcStyle() { |
151 if (!layoutObject()) | |
152 return; | |
153 | |
154 // The layoutObjects inside pseudo elements are anonymous so they don't get | 173 // The layoutObjects inside pseudo elements are anonymous so they don't get |
155 // notified of recalcStyle and must have the style propagated downward | 174 // notified of recalcStyle and must have the style propagated downward |
156 // manually similar to LayoutObject::propagateStyleToAnonymousChildren. | 175 // manually similar to LayoutObject::propagateStyleToAnonymousChildren. |
157 LayoutObject* layoutObject = this->layoutObject(); | 176 if (LayoutObject* layoutObject = this->layoutObject()) { |
158 for (LayoutObject* child = layoutObject->nextInPreOrder(layoutObject); child; | 177 updateGeneratedContentStyleIn(layoutObject, layoutObject->mutableStyle()); |
159 child = child->nextInPreOrder(layoutObject)) { | 178 } else if (hasDisplayContentsStyle()) { |
160 // We only manage the style for the generated content items. | 179 DCHECK(m_pseudoId == PseudoIdBefore || m_pseudoId == PseudoIdAfter); |
161 if (!child->isText() && !child->isQuote() && !child->isImage()) | |
162 continue; | |
163 | 180 |
164 child->setPseudoStyle(layoutObject->mutableStyle()); | 181 LayoutObject* layoutParent = |
| 182 LayoutTreeBuilderTraversal::parentLayoutObject(*this); |
| 183 if (!layoutParent) |
| 184 return; |
| 185 |
| 186 const bool isBefore = m_pseudoId == PseudoIdBefore; |
| 187 ComputedStyle* style = mutableComputedStyle(); |
| 188 LayoutObject* child = isBefore ? layoutParent->slowFirstChild() |
| 189 : layoutParent->slowLastChild(); |
| 190 |
| 191 bool foundGeneratedContent = false; |
| 192 while (child) { |
| 193 bool isThisPseudoContent = |
| 194 child->isPseudoElementGeneratedContentFor(*this); |
| 195 if (isThisPseudoContent) |
| 196 foundGeneratedContent = true; |
| 197 else if (foundGeneratedContent) |
| 198 break; |
| 199 |
| 200 if (isThisPseudoContent) { |
| 201 updateGeneratedContentStyleIn(child, style); |
| 202 child = isBefore ? child->nextSibling() : child->previousSibling(); |
| 203 } else { |
| 204 child = isBefore ? child->nextInPreOrder(layoutParent) |
| 205 : child->previousInPreOrder(layoutParent); |
| 206 } |
| 207 } |
| 208 |
| 209 DCHECK(foundGeneratedContent); |
165 } | 210 } |
166 } | 211 } |
167 | 212 |
168 // With PseudoElements the DOM tree and Layout tree can differ. When you attach | 213 // With PseudoElements the DOM tree and Layout tree can differ. When you attach |
169 // a, first-letter for example, into the DOM we walk down the Layout | 214 // a, first-letter for example, into the DOM we walk down the Layout |
170 // tree to find the correct insertion point for the LayoutObject. But, this | 215 // tree to find the correct insertion point for the LayoutObject. But, this |
171 // means if we ask for the parentOrShadowHost Node from the first-letter | 216 // means if we ask for the parentOrShadowHost Node from the first-letter |
172 // pseudo element we will get some arbitrary ancestor of the LayoutObject. | 217 // pseudo element we will get some arbitrary ancestor of the LayoutObject. |
173 // | 218 // |
174 // For hit testing, we need the parent Node of the LayoutObject for the | 219 // For hit testing, we need the parent Node of the LayoutObject for the |
(...skipping 14 matching lines...) Expand all Loading... |
189 LayoutObject* ancestor = layoutObject()->parent(); | 234 LayoutObject* ancestor = layoutObject()->parent(); |
190 while (ancestor->isAnonymous() || | 235 while (ancestor->isAnonymous() || |
191 (ancestor->node() && ancestor->node()->isPseudoElement())) { | 236 (ancestor->node() && ancestor->node()->isPseudoElement())) { |
192 DCHECK(ancestor->parent()); | 237 DCHECK(ancestor->parent()); |
193 ancestor = ancestor->parent(); | 238 ancestor = ancestor->parent(); |
194 } | 239 } |
195 return ancestor->node(); | 240 return ancestor->node(); |
196 } | 241 } |
197 | 242 |
198 } // namespace blink | 243 } // namespace blink |
OLD | NEW |