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