Chromium Code Reviews| 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/layout/LayoutObject.h" | 32 #include "core/layout/LayoutObject.h" |
| 32 #include "core/layout/LayoutQuote.h" | 33 #include "core/layout/LayoutQuote.h" |
| 33 #include "core/probe/CoreProbes.h" | 34 #include "core/probe/CoreProbes.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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 document().adoptIfNeeded(*this); | 115 document().adoptIfNeeded(*this); |
| 115 setParentOrShadowHostNode(0); | 116 setParentOrShadowHostNode(0); |
| 116 removedFrom(parent); | 117 removedFrom(parent); |
| 117 } | 118 } |
| 118 | 119 |
| 119 void PseudoElement::attachLayoutTree(const AttachContext& context) { | 120 void PseudoElement::attachLayoutTree(const AttachContext& context) { |
| 120 DCHECK(!layoutObject()); | 121 DCHECK(!layoutObject()); |
| 121 | 122 |
| 122 Element::attachLayoutTree(context); | 123 Element::attachLayoutTree(context); |
| 123 | 124 |
| 124 LayoutObject* layoutObject = this->layoutObject(); | 125 ComputedStyle* style = mutableComputedStyle(); |
| 125 if (!layoutObject) | 126 if (!style || (style->styleType() != PseudoIdBefore && |
| 127 style->styleType() != PseudoIdAfter)) | |
| 126 return; | 128 return; |
| 127 | 129 |
| 128 ComputedStyle& style = layoutObject->mutableStyleRef(); | 130 DCHECK(style->contentData()); |
| 129 if (style.styleType() != PseudoIdBefore && style.styleType() != PseudoIdAfter) | |
| 130 return; | |
| 131 DCHECK(style.contentData()); | |
| 132 | 131 |
| 133 for (const ContentData* content = style.contentData(); content; | 132 LayoutObject* parentLayoutObject = layoutObject(); |
| 133 if (!parentLayoutObject) | |
| 134 parentLayoutObject = LayoutTreeBuilderTraversal::parentLayoutObject(*this); | |
| 135 | |
| 136 for (const ContentData* content = style->contentData(); content; | |
| 134 content = content->next()) { | 137 content = content->next()) { |
| 135 LayoutObject* child = content->createLayoutObject(*this, style); | 138 LayoutObject* child = content->createLayoutObject(*this, *style); |
| 136 if (layoutObject->isChildAllowed(child, style)) { | 139 if (parentLayoutObject->isChildAllowed(child, *style)) { |
| 137 layoutObject->addChild(child); | 140 parentLayoutObject->addChild(child); |
| 141 DCHECK(child->isPseudoElementGeneratedContentFor(*this)); | |
| 138 if (child->isQuote()) | 142 if (child->isQuote()) |
| 139 toLayoutQuote(child)->attachQuote(); | 143 toLayoutQuote(child)->attachQuote(); |
| 140 } else { | 144 } else { |
| 141 child->destroy(); | 145 child->destroy(); |
| 142 } | 146 } |
| 143 } | 147 } |
| 144 } | 148 } |
| 145 | 149 |
| 146 bool PseudoElement::layoutObjectIsNeeded(const ComputedStyle& style) { | 150 bool PseudoElement::layoutObjectIsNeeded(const ComputedStyle& style) { |
| 147 return pseudoElementLayoutObjectIsNeeded(&style); | 151 return pseudoElementLayoutObjectIsNeeded(&style); |
| 148 } | 152 } |
| 149 | 153 |
| 154 static bool isGeneratedContentLike(LayoutObject* layoutObject) { | |
|
rune
2017/04/04 14:23:41
Why not call it isGeneratedContent?
emilio
2017/04/04 15:09:18
Sounds good to me, yeah.
| |
| 155 if (!layoutObject->isAnonymous()) | |
| 156 return false; | |
| 157 return layoutObject->isText() || layoutObject->isQuote() || | |
| 158 layoutObject->isImage(); | |
| 159 } | |
| 160 | |
| 161 static void updateGeneratedContentStyleIn(LayoutObject* root, | |
| 162 ComputedStyle* style) { | |
| 163 for (LayoutObject* child = root; child; child = child->nextInPreOrder(root)) { | |
| 164 if (isGeneratedContentLike(child)) | |
| 165 child->setPseudoStyle(style); | |
| 166 } | |
| 167 } | |
| 168 | |
| 150 void PseudoElement::didRecalcStyle() { | 169 void PseudoElement::didRecalcStyle() { |
| 151 if (!layoutObject()) | |
| 152 return; | |
| 153 | |
| 154 // The layoutObjects inside pseudo elements are anonymous so they don't get | 170 // The layoutObjects inside pseudo elements are anonymous so they don't get |
| 155 // notified of recalcStyle and must have the style propagated downward | 171 // notified of recalcStyle and must have the style propagated downward |
| 156 // manually similar to LayoutObject::propagateStyleToAnonymousChildren. | 172 // manually similar to LayoutObject::propagateStyleToAnonymousChildren. |
| 157 LayoutObject* layoutObject = this->layoutObject(); | 173 if (LayoutObject* layoutObject = this->layoutObject()) { |
| 158 for (LayoutObject* child = layoutObject->nextInPreOrder(layoutObject); child; | 174 updateGeneratedContentStyleIn(layoutObject, layoutObject->mutableStyle()); |
| 159 child = child->nextInPreOrder(layoutObject)) { | 175 } else if (hasDisplayContentsStyle()) { |
| 160 // We only manage the style for the generated content items. | 176 DCHECK(m_pseudoId == PseudoIdBefore || m_pseudoId == PseudoIdAfter); |
| 161 if (!child->isText() && !child->isQuote() && !child->isImage()) | |
| 162 continue; | |
| 163 | 177 |
| 164 child->setPseudoStyle(layoutObject->mutableStyle()); | 178 LayoutObject* layoutParent = |
| 179 LayoutTreeBuilderTraversal::parentLayoutObject(*this); | |
| 180 if (!layoutParent) | |
| 181 return; | |
| 182 | |
| 183 const bool isBefore = m_pseudoId == PseudoIdBefore; | |
| 184 ComputedStyle* style = mutableComputedStyle(); | |
| 185 LayoutObject* child = isBefore ? layoutParent->slowFirstChild() | |
| 186 : layoutParent->slowLastChild(); | |
| 187 | |
| 188 bool foundGeneratedContent = false; | |
| 189 while (child) { | |
| 190 bool isThisPseudoContent = | |
| 191 child->isPseudoElementGeneratedContentFor(*this); | |
| 192 if (isThisPseudoContent) | |
| 193 foundGeneratedContent = true; | |
| 194 else if (foundGeneratedContent) | |
| 195 break; | |
| 196 | |
| 197 if (isThisPseudoContent) { | |
| 198 updateGeneratedContentStyleIn(child, style); | |
| 199 child = isBefore ? child->nextSibling() : child->previousSibling(); | |
| 200 } else { | |
| 201 child = isBefore ? child->nextInPreOrder(layoutParent) | |
| 202 : child->previousInPreOrder(layoutParent); | |
|
rune
2017/04/04 14:23:41
Why do you need to to walk descendants here?
In g
emilio
2017/04/04 15:09:18
The idea is to handle them, yeah. Right now I don'
| |
| 203 } | |
| 204 } | |
| 205 | |
| 206 DCHECK(foundGeneratedContent); | |
| 165 } | 207 } |
| 166 } | 208 } |
| 167 | 209 |
| 168 // With PseudoElements the DOM tree and Layout tree can differ. When you attach | 210 // 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 | 211 // 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 | 212 // 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 | 213 // means if we ask for the parentOrShadowHost Node from the first-letter |
| 172 // pseudo element we will get some arbitrary ancestor of the LayoutObject. | 214 // pseudo element we will get some arbitrary ancestor of the LayoutObject. |
| 173 // | 215 // |
| 174 // For hit testing, we need the parent Node of the LayoutObject for the | 216 // 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(); | 231 LayoutObject* ancestor = layoutObject()->parent(); |
| 190 while (ancestor->isAnonymous() || | 232 while (ancestor->isAnonymous() || |
| 191 (ancestor->node() && ancestor->node()->isPseudoElement())) { | 233 (ancestor->node() && ancestor->node()->isPseudoElement())) { |
| 192 DCHECK(ancestor->parent()); | 234 DCHECK(ancestor->parent()); |
| 193 ancestor = ancestor->parent(); | 235 ancestor = ancestor->parent(); |
| 194 } | 236 } |
| 195 return ancestor->node(); | 237 return ancestor->node(); |
| 196 } | 238 } |
| 197 | 239 |
| 198 } // namespace blink | 240 } // namespace blink |
| OLD | NEW |