Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: third_party/WebKit/Source/core/dom/Element.cpp

Issue 2727853002: [css-display] Support display: contents pseudo-elements.
Patch Set: [css-display] Support display: contents pseudo-elements. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Peter Kelly (pmk@post.com) 4 * (C) 2001 Peter Kelly (pmk@post.com)
5 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * (C) 2001 Dirk Mueller (mueller@kde.org)
6 * (C) 2007 David Smith (catfish.man@gmail.com) 6 * (C) 2007 David Smith (catfish.man@gmail.com)
7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. 7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc.
8 * All rights reserved. 8 * All rights reserved.
9 * (C) 2007 Eric Seidel (eric@webkit.org) 9 * (C) 2007 Eric Seidel (eric@webkit.org)
10 * 10 *
(...skipping 1556 matching lines...) Expand 10 before | Expand all | Expand 10 after
1567 return parent->locateNamespacePrefix(namespaceToLocate); 1567 return parent->locateNamespacePrefix(namespaceToLocate);
1568 1568
1569 return nullAtom; 1569 return nullAtom;
1570 } 1570 }
1571 1571
1572 const AtomicString Element::imageSourceURL() const { 1572 const AtomicString Element::imageSourceURL() const {
1573 return getAttribute(srcAttr); 1573 return getAttribute(srcAttr);
1574 } 1574 }
1575 1575
1576 bool Element::layoutObjectIsNeeded(const ComputedStyle& style) { 1576 bool Element::layoutObjectIsNeeded(const ComputedStyle& style) {
1577 return style.display() != EDisplay::None && 1577 if (style.display() == EDisplay::None)
1578 style.display() != EDisplay::Contents; 1578 return false;
1579
1580 if (style.display() == EDisplay::Contents)
1581 return isPseudoElement();
rune 2017/03/06 10:13:33 Why? Pseudo elements on which display applies can
emilio 2017/03/06 16:52:09 Well, that's definitely not what Gecko does fwiw.
rune 2017/03/07 13:46:01 This case below fails in Gecko. I think that's a b
1582
1583 return true;
1579 } 1584 }
1580 1585
1581 LayoutObject* Element::createLayoutObject(const ComputedStyle& style) { 1586 LayoutObject* Element::createLayoutObject(const ComputedStyle& style) {
1582 return LayoutObject::createObject(this, style); 1587 return LayoutObject::createObject(this, style);
1583 } 1588 }
1584 1589
1585 Node::InsertionNotificationRequest Element::insertedInto( 1590 Node::InsertionNotificationRequest Element::insertedInto(
1586 ContainerNode* insertionPoint) { 1591 ContainerNode* insertionPoint) {
1587 // need to do superclass processing first so isConnected() is true 1592 // need to do superclass processing first so isConnected() is true
1588 // by the time we reach updateId 1593 // by the time we reach updateId
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
1802 1807
1803 if (context.clearInvalidation) 1808 if (context.clearInvalidation)
1804 document().styleEngine().styleInvalidator().clearInvalidation(*this); 1809 document().styleEngine().styleInvalidator().clearInvalidation(*this);
1805 1810
1806 setNeedsResizeObserverUpdate(); 1811 setNeedsResizeObserverUpdate();
1807 1812
1808 DCHECK(needsAttach()); 1813 DCHECK(needsAttach());
1809 } 1814 }
1810 1815
1811 bool Element::pseudoStyleCacheIsInvalid(const ComputedStyle* currentStyle, 1816 bool Element::pseudoStyleCacheIsInvalid(const ComputedStyle* currentStyle,
1812 ComputedStyle* newStyle) { 1817 ComputedStyle* newStyle) {
rune 2017/03/06 10:13:33 This method has a terrible name and an incomprehen
emilio 2017/03/06 16:52:09 lol, fun.
1813 DCHECK_EQ(currentStyle, computedStyle()); 1818 DCHECK_EQ(currentStyle, computedStyle());
1814 DCHECK(layoutObject());
1815 1819
1816 if (!currentStyle) 1820 if (!currentStyle)
1817 return false; 1821 return false;
1818 1822
1819 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles(); 1823 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1820 if (!pseudoStyleCache) 1824 if (!pseudoStyleCache)
1821 return false; 1825 return false;
1822 1826
1827 if (!layoutObject() && currentStyle->display() != EDisplay::Contents)
1828 return true;
1829
1830 const ComputedStyle* layoutParentStyle = newStyle;
1831 if (!layoutObject()) {
1832 LayoutObject* parentLayoutObject =
1833 LayoutTreeBuilderTraversal::parentLayoutObject(*this);
1834 DCHECK(parentLayoutObject);
1835 layoutParentStyle = parentLayoutObject->style();
1836 }
1837
1823 size_t cacheSize = pseudoStyleCache->size(); 1838 size_t cacheSize = pseudoStyleCache->size();
1824 for (size_t i = 0; i < cacheSize; ++i) { 1839 for (size_t i = 0; i < cacheSize; ++i) {
1825 RefPtr<ComputedStyle> newPseudoStyle; 1840 RefPtr<ComputedStyle> newPseudoStyle;
1826 RefPtr<ComputedStyle> oldPseudoStyle = pseudoStyleCache->at(i); 1841 RefPtr<ComputedStyle> oldPseudoStyle = pseudoStyleCache->at(i);
1827 PseudoId pseudoId = oldPseudoStyle->styleType(); 1842 PseudoId pseudoId = oldPseudoStyle->styleType();
1828 if (pseudoId == PseudoIdFirstLine || pseudoId == PseudoIdFirstLineInherited) 1843 if (!isPseudoElementAllowed(pseudoId))
1844 return true;
rune 2017/03/06 10:13:33 This method is buggy in the first place in that it
1845 if (pseudoId == PseudoIdBefore || pseudoId == PseudoIdAfter) {
1846 newPseudoStyle = document().ensureStyleResolver().pseudoStyleForElement(
1847 this, PseudoStyleRequest(pseudoId), newStyle, layoutParentStyle);
1848 } else if (pseudoId == PseudoIdFirstLine ||
1849 pseudoId == PseudoIdFirstLineInherited) {
1829 newPseudoStyle = layoutObject()->uncachedFirstLineStyle(newStyle); 1850 newPseudoStyle = layoutObject()->uncachedFirstLineStyle(newStyle);
1830 else 1851 } else {
1831 newPseudoStyle = layoutObject()->getUncachedPseudoStyle( 1852 newPseudoStyle = layoutObject()->getUncachedPseudoStyle(
1832 PseudoStyleRequest(pseudoId), newStyle, newStyle); 1853 PseudoStyleRequest(pseudoId), newStyle, newStyle);
1854 }
1833 if (!newPseudoStyle) 1855 if (!newPseudoStyle)
1834 return true; 1856 return true;
1835 if (*oldPseudoStyle != *newPseudoStyle || 1857 if (*oldPseudoStyle != *newPseudoStyle ||
1836 oldPseudoStyle->font().loadingCustomFonts() != 1858 oldPseudoStyle->font().loadingCustomFonts() !=
1837 newPseudoStyle->font().loadingCustomFonts()) { 1859 newPseudoStyle->font().loadingCustomFonts()) {
1838 if (pseudoId < FirstInternalPseudoId) 1860 if (pseudoId < FirstInternalPseudoId)
1839 newStyle->setHasPseudoStyle(pseudoId); 1861 newStyle->setHasPseudoStyle(pseudoId);
1840 newStyle->addCachedPseudoStyle(newPseudoStyle); 1862 newStyle->addCachedPseudoStyle(newPseudoStyle);
1841 if (pseudoId == PseudoIdFirstLine || 1863 if (pseudoId == PseudoIdFirstLine ||
1842 pseudoId == PseudoIdFirstLineInherited) 1864 pseudoId == PseudoIdFirstLineInherited) {
1843 layoutObject()->firstLineStyleDidChange(*oldPseudoStyle, 1865 layoutObject()->firstLineStyleDidChange(*oldPseudoStyle,
1844 *newPseudoStyle); 1866 *newPseudoStyle);
1867 }
1845 return true; 1868 return true;
1846 } 1869 }
1847 } 1870 }
1848 return false; 1871 return false;
1849 } 1872 }
1850 1873
1851 PassRefPtr<ComputedStyle> Element::styleForLayoutObject() { 1874 PassRefPtr<ComputedStyle> Element::styleForLayoutObject() {
1852 DCHECK(document().inStyleRecalc()); 1875 DCHECK(document().inStyleRecalc());
1853 1876
1854 RefPtr<ComputedStyle> style; 1877 RefPtr<ComputedStyle> style;
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
2036 pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get())) { 2059 pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get())) {
2037 layoutObject->setStyle(newStyle.get()); 2060 layoutObject->setStyle(newStyle.get());
2038 } else { 2061 } else {
2039 // Although no change occurred, we use the new style so that the cousin 2062 // Although no change occurred, we use the new style so that the cousin
2040 // style sharing code won't get fooled into believing this style is the 2063 // style sharing code won't get fooled into believing this style is the
2041 // same. 2064 // same.
2042 // FIXME: We may be able to remove this hack, see discussion in 2065 // FIXME: We may be able to remove this hack, see discussion in
2043 // https://codereview.chromium.org/30453002/ 2066 // https://codereview.chromium.org/30453002/
2044 layoutObject->setStyleInternal(newStyle.get()); 2067 layoutObject->setStyleInternal(newStyle.get());
2045 } 2068 }
2046 } else if (localChange != NoChange && 2069 } else {
2047 shouldStoreNonLayoutObjectComputedStyle(*newStyle)) { 2070 if (localChange != NoChange ||
2048 storeNonLayoutObjectComputedStyle(newStyle); 2071 pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get())) {
2072 if (shouldStoreNonLayoutObjectComputedStyle(*newStyle))
2073 storeNonLayoutObjectComputedStyle(newStyle);
2074 else if (hasRareData())
2075 elementRareData()->clearComputedStyle();
rune 2017/03/06 10:13:33 Is the clearComputedStyle() here a fix made necess
emilio 2017/03/06 17:03:46 I made it thinking on pseudos. It doesn't fix any
rune 2017/03/07 13:46:01 Acknowledged.
2076 }
2049 } 2077 }
2050 2078
2051 if (getStyleChangeType() >= SubtreeStyleChange) 2079 if (getStyleChangeType() >= SubtreeStyleChange)
2052 return Force; 2080 return Force;
2053 2081
2054 if (change > Inherit || localChange > Inherit) 2082 if (change > Inherit || localChange > Inherit)
2055 return max(localChange, change); 2083 return max(localChange, change);
2056 2084
2057 if (localChange < IndependentInherit) { 2085 if (localChange < IndependentInherit) {
2058 if (oldStyle->hasChildDependentFlags()) { 2086 if (oldStyle->hasChildDependentFlags()) {
(...skipping 1131 matching lines...) Expand 10 before | Expand all | Expand 10 after
3190 ElementRareData& rareData = ensureElementRareData(); 3218 ElementRareData& rareData = ensureElementRareData();
3191 if (!rareData.computedStyle()) 3219 if (!rareData.computedStyle())
3192 rareData.setComputedStyle( 3220 rareData.setComputedStyle(
3193 document().styleForElementIgnoringPendingStylesheets(this)); 3221 document().styleForElementIgnoringPendingStylesheets(this));
3194 elementStyle = rareData.computedStyle(); 3222 elementStyle = rareData.computedStyle();
3195 } 3223 }
3196 3224
3197 if (!pseudoElementSpecifier) 3225 if (!pseudoElementSpecifier)
3198 return elementStyle; 3226 return elementStyle;
3199 3227
3200 if (ComputedStyle* pseudoElementStyle = 3228 if (ComputedStyle* cached =
3201 elementStyle->getCachedPseudoStyle(pseudoElementSpecifier)) 3229 elementStyle->getCachedPseudoStyle(pseudoElementSpecifier))
3202 return pseudoElementStyle; 3230 return cached;
3203 3231
3204 // TODO(ecobos): Passing two times elementStyle may be wrong, though we don't 3232 const ComputedStyle* layoutParentStyle = elementStyle;
3205 // support display: contents elements' pseudo-elements yet, so this is not a 3233 if (hasDisplayContentsStyle()) {
3206 // problem for now. 3234 LayoutObject* parentLayoutObject =
3235 LayoutTreeBuilderTraversal::parentLayoutObject(*this);
3236 if (parentLayoutObject)
3237 layoutParentStyle = parentLayoutObject->style();
3238 }
3239
3207 RefPtr<ComputedStyle> result = 3240 RefPtr<ComputedStyle> result =
3208 document().ensureStyleResolver().pseudoStyleForElement( 3241 document().ensureStyleResolver().pseudoStyleForElement(
3209 this, PseudoStyleRequest(pseudoElementSpecifier, 3242 this,
3210 PseudoStyleRequest::ForComputedStyle), 3243 PseudoStyleRequest(pseudoElementSpecifier,
3211 elementStyle, elementStyle); 3244 PseudoStyleRequest::ForComputedStyle),
3245 elementStyle, layoutParentStyle);
3212 DCHECK(result); 3246 DCHECK(result);
3213 return elementStyle->addCachedPseudoStyle(result.release()); 3247 return elementStyle->addCachedPseudoStyle(result.release());
3214 } 3248 }
3215 3249
3216 const ComputedStyle* Element::nonLayoutObjectComputedStyle() const { 3250 const ComputedStyle* Element::nonLayoutObjectComputedStyle() const {
3217 if (layoutObject() || !hasRareData()) 3251 if (layoutObject() || !hasRareData())
3218 return nullptr; 3252 return nullptr;
3219 3253
3220 return elementRareData()->computedStyle(); 3254 return elementRareData()->computedStyle();
3221 } 3255 }
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
3285 PseudoElement* element = pseudoElement(pseudoId); 3319 PseudoElement* element = pseudoElement(pseudoId);
3286 3320
3287 if (element && (change == UpdatePseudoElements || 3321 if (element && (change == UpdatePseudoElements ||
3288 element->shouldCallRecalcStyle(change))) { 3322 element->shouldCallRecalcStyle(change))) {
3289 if (pseudoId == PseudoIdFirstLetter && updateFirstLetter(element)) 3323 if (pseudoId == PseudoIdFirstLetter && updateFirstLetter(element))
3290 return; 3324 return;
3291 3325
3292 // Need to clear the cached style if the PseudoElement wants a recalc so it 3326 // Need to clear the cached style if the PseudoElement wants a recalc so it
3293 // computes a new style. 3327 // computes a new style.
3294 if (element->needsStyleRecalc()) 3328 if (element->needsStyleRecalc())
3295 layoutObject()->mutableStyle()->removeCachedPseudoStyle(pseudoId); 3329 mutableComputedStyle()->removeCachedPseudoStyle(pseudoId);
3296 3330
3297 // PseudoElement styles hang off their parent element's style so if we 3331 // PseudoElement styles hang off their parent element's style so if we
3298 // needed a style recalc we should Force one on the pseudo. FIXME: We 3332 // needed a style recalc we should Force one on the pseudo. FIXME: We
3299 // should figure out the right text sibling to pass. 3333 // should figure out the right text sibling to pass.
3300 element->recalcStyle(change == UpdatePseudoElements ? Force : change); 3334 element->recalcStyle(change == UpdatePseudoElements ? Force : change);
3301 3335
3302 // Wait until our parent is not displayed or 3336 // Wait until our parent is not displayed or
3303 // pseudoElementLayoutObjectIsNeeded is false, otherwise we could 3337 // pseudoElementLayoutObjectIsNeeded is false, otherwise we could
3304 // continuously create and destroy PseudoElements when 3338 // continuously create and destroy PseudoElements when
3305 // LayoutObject::isChildAllowed on our parent returns false for the 3339 // LayoutObject::isChildAllowed on our parent returns false for the
3306 // PseudoElement's layoutObject for each style recalc. 3340 // PseudoElement's layoutObject for each style recalc.
3307 if (!layoutObject() || 3341 if (!isPseudoElementAllowed(pseudoId) ||
3308 !pseudoElementLayoutObjectIsNeeded( 3342 !pseudoElementLayoutObjectIsNeeded(
3309 layoutObject()->getCachedPseudoStyle(pseudoId))) 3343 getCachedPseudoStyleOrCache(pseudoId)))
3310 elementRareData()->setPseudoElement(pseudoId, nullptr); 3344 elementRareData()->setPseudoElement(pseudoId, nullptr);
3311 } else if (pseudoId == PseudoIdFirstLetter && element && 3345 } else if (pseudoId == PseudoIdFirstLetter && element &&
3312 change >= UpdatePseudoElements && 3346 change >= UpdatePseudoElements &&
3313 !FirstLetterPseudoElement::firstLetterTextLayoutObject(*element)) { 3347 !FirstLetterPseudoElement::firstLetterTextLayoutObject(*element)) {
3314 // This can happen if we change to a float, for example. We need to cleanup 3348 // This can happen if we change to a float, for example. We need to cleanup
3315 // the first-letter pseudoElement and then fix the text of the original 3349 // the first-letter pseudoElement and then fix the text of the original
3316 // remaining text layoutObject. This can be seen in Test 7 of 3350 // remaining text layoutObject. This can be seen in Test 7 of
3317 // fast/css/first-letter-removed-added.html 3351 // fast/css/first-letter-removed-added.html
3318 elementRareData()->setPseudoElement(pseudoId, nullptr); 3352 elementRareData()->setPseudoElement(pseudoId, nullptr);
3319 } else if (change >= UpdatePseudoElements) { 3353 } else if (change >= UpdatePseudoElements) {
(...skipping 16 matching lines...) Expand all
3336 // incorrect results due to setting the first letter back. 3370 // incorrect results due to setting the first letter back.
3337 if (remainingTextLayoutObject) 3371 if (remainingTextLayoutObject)
3338 element->reattachLayoutTree(); 3372 element->reattachLayoutTree();
3339 else 3373 else
3340 elementRareData()->setPseudoElement(PseudoIdFirstLetter, nullptr); 3374 elementRareData()->setPseudoElement(PseudoIdFirstLetter, nullptr);
3341 return true; 3375 return true;
3342 } 3376 }
3343 return false; 3377 return false;
3344 } 3378 }
3345 3379
3380 ComputedStyle* Element::getCachedPseudoStyleOrCache(PseudoId pseudoId) const {
rune 2017/03/06 10:13:33 I don't understand the name of this method.
emilio 2017/03/06 16:52:09 It explicitly states what getCachedPseudoStyle did
rune 2017/03/07 13:46:01 I read that name as "return the cached pseudo styl
3381 ComputedStyle* style = mutableComputedStyle();
3382 if (pseudoId < FirstInternalPseudoId && !style->hasPseudoStyle(pseudoId))
3383 return nullptr;
rune 2017/03/07 13:46:01 I don't think we use cache entries for internal ps
3384
3385 if (ComputedStyle* cached = style->getCachedPseudoStyle(pseudoId))
3386 return cached;
3387 RefPtr<ComputedStyle> uncached = getUncachedPseudoStyle(pseudoId);
3388 if (uncached)
3389 return style->addCachedPseudoStyle(uncached.release());
3390 return nullptr;
3391 }
3392
3393 PassRefPtr<ComputedStyle> Element::getUncachedPseudoStyle(
3394 PseudoId pseudoId) const {
3395 if (pseudoId == PseudoIdBefore || pseudoId == PseudoIdAfter) {
3396 LayoutObject* parentLayoutObject = layoutObject();
3397 if (!parentLayoutObject && hasDisplayContentsStyle()) {
3398 parentLayoutObject =
3399 LayoutTreeBuilderTraversal::parentLayoutObject(*this);
3400 }
3401 if (!parentLayoutObject)
3402 return nullptr;
3403 return document().ensureStyleResolver().pseudoStyleForElement(
3404 const_cast<Element*>(this), PseudoStyleRequest(pseudoId),
3405 computedStyle(), parentLayoutObject->style());
3406 }
3407 if (!layoutObject())
3408 return nullptr;
3409 return layoutObject()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId));
3410 }
3411
3412 // For display: contents elements, we still need to generate ::before and
3413 // ::after, but the rest of the pseudo-elements should only be used for elements
3414 // with an actual layout object.
rune 2017/03/06 10:13:33 I was just thinking about this in relation to ::se
emilio 2017/03/06 16:52:09 Note that this works with this patch, because I in
rune 2017/03/07 13:46:01 I find it hard to understand what "allowed" means
3415 bool Element::isPseudoElementAllowed(PseudoId pseudoId) const {
3416 if (hasDisplayContentsStyle())
3417 return pseudoId == PseudoIdBefore || pseudoId == PseudoIdAfter;
3418 return !!layoutObject();
3419 }
3420
3346 void Element::createPseudoElementIfNeeded(PseudoId pseudoId) { 3421 void Element::createPseudoElementIfNeeded(PseudoId pseudoId) {
3347 if (isPseudoElement()) 3422 if (isPseudoElement())
3348 return; 3423 return;
3349 3424
3350 // Document::ensureStyleResolver is not inlined and shows up on profiles, 3425 // Document::ensureStyleResolver is not inlined and shows up on profiles,
3351 // avoid it here. 3426 // avoid it here.
3352 PseudoElement* element = 3427 PseudoElement* element =
3353 document().styleEngine().ensureResolver().createPseudoElementIfNeeded( 3428 document().styleEngine().ensureResolver().createPseudoElementIfNeeded(
3354 *this, pseudoId); 3429 *this, pseudoId);
3355 if (!element) 3430 if (!element)
(...skipping 845 matching lines...) Expand 10 before | Expand all | Expand 10 after
4201 } 4276 }
4202 4277
4203 DEFINE_TRACE_WRAPPERS(Element) { 4278 DEFINE_TRACE_WRAPPERS(Element) {
4204 if (hasRareData()) { 4279 if (hasRareData()) {
4205 visitor->traceWrappers(elementRareData()); 4280 visitor->traceWrappers(elementRareData());
4206 } 4281 }
4207 ContainerNode::traceWrappers(visitor); 4282 ContainerNode::traceWrappers(visitor);
4208 } 4283 }
4209 4284
4210 } // namespace blink 4285 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/dom/Element.h ('k') | third_party/WebKit/Source/core/dom/PseudoElement.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698