/** * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "core/layout/LayoutListItem.h" #include "core/HTMLNames.h" #include "core/dom/shadow/FlatTreeTraversal.h" #include "core/html/HTMLOListElement.h" #include "core/layout/LayoutListMarker.h" #include "core/layout/LayoutView.h" #include "core/paint/ListItemPainter.h" #include "wtf/StdLibExtras.h" #include "wtf/text/StringBuilder.h" namespace blink { using namespace HTMLNames; LayoutListItem::LayoutListItem(Element* element) : LayoutBlockFlow(element) , m_marker(nullptr) , m_hasExplicitValue(false) , m_isValueUpToDate(false) , m_notInList(false) { setInline(false); setConsumesSubtreeChangeNotification(); registerSubtreeChangeListenerOnDescendants(true); } void LayoutListItem::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) { LayoutBlockFlow::styleDidChange(diff, oldStyle); StyleImage* currentImage = style()->listStyleImage(); if (style()->listStyleType() != NoneListStyle || (currentImage && !currentImage->errorOccurred())) { if (!m_marker) m_marker = LayoutListMarker::createAnonymous(this); m_marker->listItemStyleDidChange(); notifyOfSubtreeChange(); } else if (m_marker) { m_marker->destroy(); m_marker = nullptr; } StyleImage* oldImage = oldStyle ? oldStyle->listStyleImage() : nullptr; if (oldImage != currentImage) { if (oldImage) oldImage->removeClient(this); if (currentImage) currentImage->addClient(this); } } void LayoutListItem::willBeDestroyed() { if (m_marker) { m_marker->destroy(); m_marker = nullptr; } LayoutBlockFlow::willBeDestroyed(); if (style() && style()->listStyleImage()) style()->listStyleImage()->removeClient(this); } void LayoutListItem::insertedIntoTree() { LayoutBlockFlow::insertedIntoTree(); updateListMarkerNumbers(); } void LayoutListItem::willBeRemovedFromTree() { LayoutBlockFlow::willBeRemovedFromTree(); updateListMarkerNumbers(); } void LayoutListItem::subtreeDidChange() { if (!m_marker) return; if (!updateMarkerLocation()) return; // If the marker is inside we need to redo the preferred width calculations // as the size of the item now includes the size of the list marker. if (m_marker->isInside()) setPreferredLogicalWidthsDirty(); } static bool isList(const Node& node) { return isHTMLUListElement(node) || isHTMLOListElement(node); } // Returns the enclosing list with respect to the DOM order. static Node* enclosingList(const LayoutListItem* listItem) { Node* listItemNode = listItem->node(); if (!listItemNode) return nullptr; Node* firstNode = nullptr; // We use parentNode because the enclosing list could be a ShadowRoot that's not Element. for (Node* parent = FlatTreeTraversal::parent(*listItemNode); parent; parent = FlatTreeTraversal::parent(*parent)) { if (isList(*parent)) return parent; if (!firstNode) firstNode = parent; } // If there's no actual