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

Unified Diff: Source/core/layout/LayoutListItem.cpp

Issue 778003003: List marker pseudo elements. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: Source/core/layout/LayoutListItem.cpp
diff --git a/Source/core/layout/LayoutListItem.cpp b/Source/core/layout/LayoutListItem.cpp
index 1403114b69e6994b696544076744ff57bca58042..f9361048e4f7ccbed6b3476e9eb7590c9bfb8841 100644
--- a/Source/core/layout/LayoutListItem.cpp
+++ b/Source/core/layout/LayoutListItem.cpp
@@ -25,12 +25,14 @@
#include "core/layout/LayoutListItem.h"
#include "core/HTMLNames.h"
+#include "core/dom/MarkerPseudoElement.h"
#include "core/dom/shadow/ComposedTreeTraversal.h"
#include "core/html/HTMLOListElement.h"
#include "core/layout/LayoutListMarker.h"
#include "core/layout/LayoutView.h"
#include "core/layout/TextAutosizer.h"
#include "wtf/StdLibExtras.h"
+#include "wtf/TemporaryChange.h"
#include "wtf/text/StringBuilder.h"
namespace blink {
@@ -40,6 +42,7 @@ using namespace HTMLNames;
LayoutListItem::LayoutListItem(Element* element)
: LayoutBlockFlow(element)
, m_marker(nullptr)
+ , m_inSubtreeChanged(false)
, m_hasExplicitValue(false)
, m_isValueUpToDate(false)
, m_notInList(false)
@@ -51,6 +54,9 @@ void LayoutListItem::styleDidChange(StyleDifference diff, const ComputedStyle* o
{
LayoutBlockFlow::styleDidChange(diff, oldStyle);
+ if (RuntimeEnabledFeatures::listMarkerPseudoElementEnabled())
+ return;
+
if (style()->listStyleType() != NoneListStyle
|| (style()->listStyleImage() && !style()->listStyleImage()->errorOccurred())) {
if (!m_marker)
@@ -74,17 +80,66 @@ void LayoutListItem::willBeDestroyed()
void LayoutListItem::insertedIntoTree()
{
LayoutBlockFlow::insertedIntoTree();
-
updateListMarkerNumbers();
}
void LayoutListItem::willBeRemovedFromTree()
{
LayoutBlockFlow::willBeRemovedFromTree();
-
updateListMarkerNumbers();
}
+void LayoutListItem::subtreeChangedNotification()
+{
+ if (!document().lifecycle().isActive())
+ return;
+
+ if (m_inSubtreeChanged)
+ return;
+
+ TemporaryChange<bool> changed(m_inSubtreeChanged, true);
+
esprehn 2015/04/20 16:04:08 This is an example why you can't do this, it's ver
dsinclair 2015/04/21 20:23:10 Done.
+ if (PseudoElement* element = toElement(node())->pseudoElement(MARKER))
esprehn 2015/04/20 16:04:08 You can't do synchronous subtree notifications lik
dsinclair 2015/04/21 20:23:10 Done.
+ toMarkerPseudoElement(element)->attachListMarkerLayoutObject();
+
+ LayoutBlockFlow::subtreeChangedNotification();
+}
+
+void LayoutListItem::addChild(LayoutObject* newChild, LayoutObject* beforeChild)
+{
+ LayoutBlockFlow::addChild(newChild, beforeChild);
+
+ if (!RuntimeEnabledFeatures::listMarkerPseudoElementEnabled())
+ return;
+
+ newChild->setNotifyAncestorsOfSubtreeChangeRecursive(true);
+
+ // If we've inserted a new child we, possibly, have to move the list marker
+ // into that child. Nothing to do if it's the marker we're inserting.
+ if (PseudoElement* element = toElement(node())->pseudoElement(MARKER)) {
+ if (newChild != element->layoutObject())
+ toMarkerPseudoElement(element)->attachListMarkerLayoutObject();
+ }
+}
+
+void LayoutListItem::removeChild(LayoutObject* child)
+{
+ LayoutBlockFlow::removeChild(child);
+
+ if (!RuntimeEnabledFeatures::listMarkerPseudoElementEnabled())
+ return;
+
+ child->setNotifyAncestorsOfSubtreeChangeRecursive(false);
+
+ // If we've removed a child we, possibly, have to move the list marker
+ // into a new parent. Don't try to update the marker when it's the
+ // marker that was removed.
+ if (PseudoElement* element = toElement(node())->pseudoElement(MARKER)) {
+ if (child != element->layoutObject())
+ toMarkerPseudoElement(element)->attachListMarkerLayoutObject();
+ }
+}
+
static bool isList(const Node& node)
{
return isHTMLUListElement(node) || isHTMLOListElement(node);
@@ -129,11 +184,11 @@ static LayoutListItem* nextListItem(const Node* listNode, const LayoutListItem*
continue;
}
- LayoutObject* renderer = current->layoutObject();
- if (renderer && renderer->isListItem())
- return toLayoutListItem(renderer);
+ LayoutObject* layoutObject = current->layoutObject();
+ if (layoutObject && layoutObject->isListItem())
+ return toLayoutListItem(layoutObject);
- // FIXME: Can this be optimized to skip the children of the elements without a renderer?
+ // FIXME: Can this be optimized to skip the children of the elements without a layoutObject?
current = LayoutTreeBuilderTraversal::next(*current, listNode);
}
@@ -146,14 +201,17 @@ static LayoutListItem* previousListItem(const Node* listNode, const LayoutListIt
Node* current = item->node();
ASSERT(current);
ASSERT(!current->document().childNeedsDistributionRecalc());
- for (current = LayoutTreeBuilderTraversal::previous(*current, listNode); current && current != listNode; current = LayoutTreeBuilderTraversal::previous(*current, listNode)) {
- LayoutObject* renderer = current->layoutObject();
- if (!renderer || (renderer && !renderer->isListItem()))
+ for (current = LayoutTreeBuilderTraversal::previous(*current, listNode);
+ current && current != listNode;
+ current = LayoutTreeBuilderTraversal::previous(*current, listNode)) {
+
+ LayoutObject* layoutObject = current->layoutObject();
+ if (!layoutObject || (layoutObject && !layoutObject->isListItem()))
continue;
- Node* otherList = enclosingList(toLayoutListItem(renderer));
+ Node* otherList = enclosingList(toLayoutListItem(layoutObject));
// This item is part of our current list, so it's what we're looking for.
if (listNode == otherList)
- return toLayoutListItem(renderer);
+ return toLayoutListItem(layoutObject);
// We found ourself inside another list; lets skip the rest of it.
// Use nextIncludingPseudo() here because the other list itself may actually
// be a list item itself. We need to examine it, so we do this to counteract
@@ -213,60 +271,31 @@ void LayoutListItem::updateValueNow() const
bool LayoutListItem::isEmpty() const
{
+ if (RuntimeEnabledFeatures::listMarkerPseudoElementEnabled()) {
+ PseudoElement* element = toElement(node())->pseudoElement(MARKER);
+ return !(element && lastChild() != element->layoutObject());
+ }
return lastChild() == m_marker;
}
-static LayoutObject* getParentOfFirstLineBox(LayoutBlockFlow* curr, LayoutObject* marker)
+void LayoutListItem::updateValue()
{
- LayoutObject* firstChild = curr->firstChild();
- if (!firstChild)
- return 0;
-
- bool inQuirksMode = curr->document().inQuirksMode();
- for (LayoutObject* currChild = firstChild; currChild; currChild = currChild->nextSibling()) {
- if (currChild == marker)
- continue;
-
- if (currChild->isInline() && (!currChild->isLayoutInline() || curr->generatesLineBoxesForInlineChild(currChild)))
- return curr;
-
- if (currChild->isFloating() || currChild->isOutOfFlowPositioned())
- continue;
-
- if (!currChild->isLayoutBlockFlow() || (currChild->isBox() && toLayoutBox(currChild)->isWritingModeRoot()))
- break;
-
- if (curr->isListItem() && inQuirksMode && currChild->node()
- && (isHTMLUListElement(*currChild->node()) || isHTMLOListElement(*currChild->node())))
- break;
-
- LayoutObject* lineBox = getParentOfFirstLineBox(toLayoutBlockFlow(currChild), marker);
- if (lineBox)
- return lineBox;
- }
+ if (m_hasExplicitValue)
+ return;
- return 0;
-}
+ m_isValueUpToDate = false;
-void LayoutListItem::updateValue()
-{
- if (!m_hasExplicitValue) {
- m_isValueUpToDate = false;
- if (m_marker)
- m_marker->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::ListValueChange);
+ if (RuntimeEnabledFeatures::listMarkerPseudoElementEnabled()) {
+ if (PseudoElement* element = toElement(node())->pseudoElement(MARKER))
+ element->layoutObject()->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::ListValueChange);
+ } else if (m_marker) {
+ m_marker->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::ListValueChange);
}
}
-static LayoutObject* firstNonMarkerChild(LayoutObject* parent)
-{
- LayoutObject* result = parent->slowFirstChild();
- while (result && result->isListMarker())
- result = result->nextSibling();
- return result;
-}
-
void LayoutListItem::updateMarkerLocationAndInvalidateWidth()
{
+ ASSERT(!RuntimeEnabledFeatures::listMarkerPseudoElementEnabled());
ASSERT(m_marker);
// FIXME: We should not modify the structure of the render tree
@@ -296,9 +325,11 @@ void LayoutListItem::updateMarkerLocationAndInvalidateWidth()
bool LayoutListItem::updateMarkerLocation()
{
+ ASSERT(!RuntimeEnabledFeatures::listMarkerPseudoElementEnabled());
ASSERT(m_marker);
+
LayoutObject* markerParent = m_marker->parent();
- LayoutObject* lineBoxParent = getParentOfFirstLineBox(this, m_marker);
+ LayoutObject* lineBoxParent = MarkerPseudoElement::getParentOfFirstLineBox(this, m_marker);
if (!lineBoxParent) {
// If the marker is currently contained inside an anonymous box, then we
// are the only item in that anonymous box (since no line box parent was
@@ -311,10 +342,11 @@ bool LayoutListItem::updateMarkerLocation()
if (markerParent != lineBoxParent) {
m_marker->remove();
- lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent));
+ lineBoxParent->addChild(m_marker, MarkerPseudoElement::firstNonMarkerChild(lineBoxParent));
m_marker->updateMarginsAndContent();
// If markerParent is an anonymous block with no children, destroy it.
- if (markerParent && markerParent->isAnonymousBlock() && !toLayoutBlock(markerParent)->firstChild() && !toLayoutBlock(markerParent)->continuation())
+ if (markerParent && markerParent->isAnonymousBlock() && !toLayoutBlock(markerParent)->firstChild()
+ && !toLayoutBlock(markerParent)->continuation())
markerParent->destroy();
return true;
}
@@ -326,7 +358,16 @@ void LayoutListItem::layout()
{
ASSERT(needsLayout());
- if (m_marker) {
+ if (RuntimeEnabledFeatures::listMarkerPseudoElementEnabled()) {
+ PseudoElement* element = toElement(node())->pseudoElement(MARKER);
+ if (element && element->layoutObject()) {
+ ASSERT(element->layoutObject()->isListMarker());
+ LayoutListMarker* marker = toLayoutListMarker(element->layoutObject());
+
+ marker->updateMarginsAndContent();
+ }
+
+ } else if (m_marker) {
// The marker must be autosized before calling
// updateMarkerLocationAndInvalidateWidth. It cannot be done in the
// parent's beginLayout because it is not yet in the render tree.
@@ -342,23 +383,36 @@ void LayoutListItem::layout()
void LayoutListItem::addOverflowFromChildren()
{
LayoutBlockFlow::addOverflowFromChildren();
- positionListMarker();
+
+ if (RuntimeEnabledFeatures::listMarkerPseudoElementEnabled()) {
+ MarkerPseudoElement* markerElement = toMarkerPseudoElement(toElement(node())->pseudoElement(MARKER));
+ if (markerElement && markerElement->layoutObject()) {
+ ASSERT(markerElement->layoutObject()->isListMarker());
+ positionListMarker(toLayoutListMarker(markerElement->layoutObject()));
+ }
+ } else {
+ positionListMarker(m_marker);
+ }
}
-void LayoutListItem::positionListMarker()
+void LayoutListItem::positionListMarker(LayoutListMarker* marker)
{
- if (m_marker && m_marker->parent()->isBox() && !m_marker->isInside() && m_marker->inlineBoxWrapper()) {
- LayoutUnit markerOldLogicalLeft = m_marker->logicalLeft();
+ if (!marker)
+ return;
+
+ ASSERT(marker->parent());
+ if (marker->parent()->isBox() && !marker->isInside() && marker->inlineBoxWrapper()) {
+ LayoutUnit markerOldLogicalLeft = marker->logicalLeft();
LayoutUnit blockOffset = 0;
LayoutUnit lineOffset = 0;
- for (LayoutBox* o = m_marker->parentBox(); o != this; o = o->parentBox()) {
+ for (LayoutBox* o = marker->parentBox(); o != this; o = o->parentBox()) {
blockOffset += o->logicalTop();
lineOffset += o->logicalLeft();
}
bool adjustOverflow = false;
LayoutUnit markerLogicalLeft;
- RootInlineBox& root = m_marker->inlineBoxWrapper()->root();
+ RootInlineBox& root = marker->inlineBoxWrapper()->root();
bool hitSelfPaintingLayer = false;
LayoutUnit lineTop = root.lineTop();
@@ -367,9 +421,9 @@ void LayoutListItem::positionListMarker()
// FIXME: Need to account for relative positioning in the layout overflow.
if (style()->isLeftToRightDirection()) {
LayoutUnit leftLineOffset = logicalLeftOffsetForLine(blockOffset, logicalLeftOffsetForLine(blockOffset, false), false);
- markerLogicalLeft = leftLineOffset - lineOffset - paddingStart() - borderStart() + m_marker->marginStart();
- m_marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLogicalLeft - markerOldLogicalLeft).toFloat());
- for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) {
+ markerLogicalLeft = leftLineOffset - lineOffset - paddingStart() - borderStart() + marker->marginStart();
+ marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLogicalLeft - markerOldLogicalLeft).toFloat());
+ for (InlineFlowBox* box = marker->inlineBoxWrapper()->parent(); box; box = box->parent()) {
LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom);
LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom);
if (markerLogicalLeft < newLogicalVisualOverflowRect.x() && !hitSelfPaintingLayer) {
@@ -390,18 +444,18 @@ void LayoutListItem::positionListMarker()
}
} else {
LayoutUnit rightLineOffset = logicalRightOffsetForLine(blockOffset, logicalRightOffsetForLine(blockOffset, false), false);
- markerLogicalLeft = rightLineOffset - lineOffset + paddingStart() + borderStart() + m_marker->marginEnd();
- m_marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLogicalLeft - markerOldLogicalLeft).toFloat());
- for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) {
+ markerLogicalLeft = rightLineOffset - lineOffset + paddingStart() + borderStart() + marker->marginEnd();
+ marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLogicalLeft - markerOldLogicalLeft).toFloat());
+ for (InlineFlowBox* box = marker->inlineBoxWrapper()->parent(); box; box = box->parent()) {
LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom);
LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom);
- if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalVisualOverflowRect.maxX() && !hitSelfPaintingLayer) {
- newLogicalVisualOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - newLogicalVisualOverflowRect.x());
+ if (markerLogicalLeft + marker->logicalWidth() > newLogicalVisualOverflowRect.maxX() && !hitSelfPaintingLayer) {
+ newLogicalVisualOverflowRect.setWidth(markerLogicalLeft + marker->logicalWidth() - newLogicalVisualOverflowRect.x());
if (box == root)
adjustOverflow = true;
}
- if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalLayoutOverflowRect.maxX()) {
- newLogicalLayoutOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - newLogicalLayoutOverflowRect.x());
+ if (markerLogicalLeft + marker->logicalWidth() > newLogicalLayoutOverflowRect.maxX()) {
+ newLogicalLayoutOverflowRect.setWidth(markerLogicalLeft + marker->logicalWidth() - newLogicalLayoutOverflowRect.x());
if (box == root)
adjustOverflow = true;
}
@@ -413,10 +467,10 @@ void LayoutListItem::positionListMarker()
}
if (adjustOverflow) {
- LayoutRect markerRect(LayoutPoint(markerLogicalLeft + lineOffset, blockOffset), m_marker->size());
+ LayoutRect markerRect(LayoutPoint(markerLogicalLeft + lineOffset, blockOffset), marker->size());
if (!style()->isHorizontalWritingMode())
markerRect = markerRect.transposedRect();
- LayoutBox* o = m_marker;
+ LayoutBox* o = marker;
bool propagateVisualOverflow = true;
bool propagateLayoutOverflow = true;
do {
@@ -449,15 +503,28 @@ void LayoutListItem::paint(const PaintInfo& paintInfo, const LayoutPoint& paintO
const String& LayoutListItem::markerText() const
{
- if (m_marker)
+ if (RuntimeEnabledFeatures::listMarkerPseudoElementEnabled()) {
+ if (PseudoElement* element = toElement(node())->pseudoElement(MARKER)) {
+ if (element->layoutObject()) {
+ ASSERT(element->layoutObject()->isListMarker());
+ return toLayoutListMarker(element->layoutObject())->text();
+ }
+ }
+ } else if (m_marker) {
return m_marker->text();
+ }
return nullAtom.string();
}
void LayoutListItem::explicitValueChanged()
{
- if (m_marker)
+ if (RuntimeEnabledFeatures::listMarkerPseudoElementEnabled()) {
+ if (PseudoElement* element = toElement(node())->pseudoElement(MARKER))
+ element->layoutObject()->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::ListValueChange);
+ } else if (m_marker) {
m_marker->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::ListValueChange);
+ }
+
Node* listNode = enclosingList(this);
for (LayoutListItem* item = this; item; item = nextListItem(listNode, item))
item->updateValue();
@@ -489,8 +556,15 @@ void LayoutListItem::clearExplicitValue()
void LayoutListItem::setNotInList(bool notInList)
{
m_notInList = notInList;
- if (m_marker)
+ if (RuntimeEnabledFeatures::listMarkerPseudoElementEnabled()) {
+ if (PseudoElement* element = toElement(node())->pseudoElement(MARKER)) {
+ ASSERT(element->layoutObject());
+ ASSERT(element->layoutObject()->isListMarker());
+ toLayoutListMarker(element->layoutObject())->updateMarginsAndContent();
+ }
+ } else if (m_marker) {
updateMarkerLocation();
+ }
}
static LayoutListItem* previousOrNextItem(bool isListReversed, Node* list, LayoutListItem* item)

Powered by Google App Engine
This is Rietveld 408576698