| 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 |