Index: Source/core/dom/MarkerPseudoElement.cpp |
diff --git a/Source/core/dom/MarkerPseudoElement.cpp b/Source/core/dom/MarkerPseudoElement.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..96b836d5c91493da815da82928f510edf9f2e48b |
--- /dev/null |
+++ b/Source/core/dom/MarkerPseudoElement.cpp |
@@ -0,0 +1,145 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+#include "core/dom/MarkerPseudoElement.h" |
+ |
+#include "core/layout/LayoutBlockFlow.h" |
+#include "core/layout/LayoutListItem.h" |
+#include "core/layout/LayoutListMarker.h" |
+ |
+namespace blink { |
+ |
+MarkerPseudoElement::MarkerPseudoElement(Element* parent) |
+ : PseudoElement(parent, MARKER) |
+{ |
+} |
+ |
+MarkerPseudoElement::~MarkerPseudoElement() |
+{ |
+} |
+ |
+LayoutObject* MarkerPseudoElement::parentOfFirstLineBox(LayoutObject* curr, const LayoutObject* marker) |
+{ |
+ ASSERT(curr->isLayoutBlockFlow()); |
+ |
+ LayoutObject* firstChild = toLayoutBlockFlow(curr)->firstChild(); |
+ if (!firstChild) |
+ return nullptr; |
+ |
+ bool inQuirksMode = curr->document().inQuirksMode(); |
+ for (LayoutObject* currChild = firstChild; currChild; currChild = currChild->nextSibling()) { |
+ if (currChild == marker) |
+ continue; |
+ |
+ if (currChild->isInline() && (!currChild->isLayoutInline() || toLayoutBlockFlow(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; |
+ |
+ if (LayoutObject* lineBox = parentOfFirstLineBox(toLayoutBlockFlow(currChild), marker)) |
+ return lineBox; |
+ } |
+ |
+ return nullptr; |
+} |
+ |
+PassRefPtr<ComputedStyle> MarkerPseudoElement::styleForListMarker(LayoutObject& parent, const ComputedStyle* style) |
+{ |
+ RefPtr<ComputedStyle> newStyle = ComputedStyle::create(); |
+ |
+ // The marker always inherits from the list item, regardless of where it might end |
+ // up (e.g., in some deeply nested line box). See CSS3 spec. |
+ newStyle->inheritFrom(*parent.style()); |
+ if (style) { |
+ // Reuse the current margins. Otherwise resetting the margins to initial values |
+ // would trigger unnecessary layout. |
+ newStyle->setMarginStart(style->marginStart()); |
+ newStyle->setMarginEnd(style->marginRight()); |
+ } |
+ return newStyle; |
+} |
+ |
+LayoutObject* MarkerPseudoElement::firstNonMarkerChild(LayoutObject* parent) |
+{ |
+ LayoutObject* result = parent->slowFirstChild(); |
+ while (result && result->isListMarker()) |
+ result = result->nextSibling(); |
+ return result; |
+} |
+ |
+LayoutObject* MarkerPseudoElement::createLayoutObject(const ComputedStyle& style) |
+{ |
+ ASSERT(parentElement()->layoutObject()); |
+ return new LayoutListMarker(this, toLayoutListItem(parentElement()->layoutObject())); |
+} |
+ |
+void MarkerPseudoElement::attachListMarker() |
+{ |
+ LayoutListItem* parentLayoutObject = toLayoutListItem(parentElement()->layoutObject()); |
+ ASSERT(parentLayoutObject); |
+ ASSERT(layoutObject()); |
+ |
+ LayoutListMarker* marker = toLayoutListMarker(layoutObject()); |
+ parentLayoutObject->setMarker(marker); |
+ |
+ LayoutObject* markerParent = marker->parent(); |
+ |
+ LayoutObject* insertionLayoutObject = MarkerPseudoElement::parentOfFirstLineBox(parentLayoutObject, marker); |
+ |
+ // We didn't find any line boxes so make the insertion point the LI layoutObject. |
+ if (!insertionLayoutObject) |
+ insertionLayoutObject = parentLayoutObject; |
+ ASSERT(insertionLayoutObject); |
+ |
+ // Check if we're already inserted into the right parent as the first child. |
+ if (markerParent && marker == markerParent->slowFirstChild() |
+ && (markerParent == insertionLayoutObject || markerParent == insertionLayoutObject->slowFirstChild())) |
+ return; |
+ |
+ marker->remove(); |
+ insertionLayoutObject->addChild(marker, MarkerPseudoElement::firstNonMarkerChild(insertionLayoutObject)); |
+ marker->updateMarginsAndContent(); |
+ |
+ // If markerParent is an anonymous block with no children, destroy it. |
+ if (markerParent && markerParent->isAnonymousBlock() && !toLayoutBlock(markerParent)->firstChild() |
+ && !toLayoutBlock(markerParent)->continuation()) { |
+ markerParent->destroy(); |
+ } |
+ |
+ if (marker->isInside()) |
+ parentLayoutObject->containingBlock()->setPreferredLogicalWidthsDirty(); |
+} |
+ |
+void MarkerPseudoElement::attach(const AttachContext& context) |
+{ |
+ PseudoElement::attach(context); |
+ ASSERT(layoutObject()); |
+ |
+ LayoutObject* parent = layoutObject()->parent(); |
+ if (!parent) |
+ return; |
+ |
+ LayoutListMarker* marker = toLayoutListMarker(layoutObject()); |
+ |
+ RefPtr<ComputedStyle> newStyle = MarkerPseudoElement::styleForListMarker(*(marker->mutableListItem()), marker->style()); |
+ marker->setStyle(newStyle.release()); |
+ |
+ attachListMarker(); |
+} |
+ |
+void MarkerPseudoElement::didRecalcStyle(StyleRecalcChange) |
+{ |
+ attachListMarker(); |
+} |
+ |
+} // namespace blink |