/* * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * * 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. * */ #pragma once #include "LegacyInlineBox.h" #include "RenderOverflow.h" #include "ShadowData.h" namespace WebCore { class HitTestRequest; class HitTestResult; class LegacyInlineTextBox; class RenderLineBoxList; class Font; class VerticalPositionCache; struct GlyphOverflow; typedef HashMap, GlyphOverflow>> GlyphOverflowAndFallbackFontsMap; class LegacyInlineFlowBox : public LegacyInlineBox { WTF_MAKE_ISO_ALLOCATED(LegacyInlineFlowBox); public: explicit LegacyInlineFlowBox(RenderBoxModelObject& renderer) : LegacyInlineBox(renderer) , m_includeLogicalLeftEdge(false) , m_includeLogicalRightEdge(false) , m_hasHardLinebreak(false) , m_descendantsHaveSameLineHeightAndBaseline(true) , m_baselineType(AlphabeticBaseline) , m_hasAnnotationsBefore(false) , m_hasAnnotationsAfter(false) , m_isFirstAfterPageBreak(false) , m_isForTrailingFloats(false) #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED , m_hasBadChildList(false) #endif , m_firstChild(nullptr) , m_lastChild(nullptr) , m_prevLineBox(nullptr) , m_nextLineBox(nullptr) { // Internet Explorer and Firefox always create a marker for list items, even when the list-style-type is none. We do not make a marker // in the list-style-type: none case, since it is wasteful to do so. However, in order to match other browsers we have to pretend like // an invisible marker exists. The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no // text children must not apply. This change also means that gaps will exist between image bullet list items. Even when the list bullet // is an image, the line is still considered to be immune from the quirk. m_hasTextChildren = renderer.style().display() == DisplayType::ListItem; m_hasTextDescendants = m_hasTextChildren; } #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED virtual ~LegacyInlineFlowBox(); #endif #if ENABLE(TREE_DEBUGGING) void outputLineTreeAndMark(WTF::TextStream&, const LegacyInlineBox* markedBox, int depth) const override; const char* boxName() const override; #endif RenderBoxModelObject& renderer() const { return downcast(LegacyInlineBox::renderer()); } const RenderStyle& lineStyle() const { return isFirstLine() ? renderer().firstLineStyle() : renderer().style(); } LegacyInlineFlowBox* prevLineBox() const { return m_prevLineBox; } LegacyInlineFlowBox* nextLineBox() const { return m_nextLineBox; } void setNextLineBox(LegacyInlineFlowBox* n) { m_nextLineBox = n; } void setPreviousLineBox(LegacyInlineFlowBox* p) { m_prevLineBox = p; } LegacyInlineBox* firstChild() const { checkConsistency(); return m_firstChild; } LegacyInlineBox* lastChild() const { checkConsistency(); return m_lastChild; } bool isLeaf() const final { return false; } LegacyInlineBox* firstLeafDescendant() const; LegacyInlineBox* lastLeafDescendant() const; typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector::iterator first, Vector::iterator last); void collectLeafBoxesInLogicalOrder(Vector&, CustomInlineBoxRangeReverse customReverseImplementation = nullptr, void* userData = nullptr) const; void setConstructed() final { LegacyInlineBox::setConstructed(); for (auto* child = firstChild(); child; child = child->nextOnLine()) child->setConstructed(); } void addToLine(LegacyInlineBox* child); void deleteLine() final; void extractLine() final; void attachLine() final; void adjustPosition(float dx, float dy) override; virtual void extractLineBoxFromRenderObject(); virtual void attachLineBoxToRenderObject(); virtual void removeLineBoxFromRenderObject(); void clearTruncation() override; void paintBoxDecorations(PaintInfo&, const LayoutPoint&); void paintMask(PaintInfo&, const LayoutPoint&); void paintFillLayers(const PaintInfo&, const Color&, const FillLayer&, const LayoutRect&, CompositeOperator = CompositeOperator::SourceOver); void paintFillLayer(const PaintInfo&, const Color&, const FillLayer&, const LayoutRect&, CompositeOperator = CompositeOperator::SourceOver); void paintBoxShadow(const PaintInfo&, const RenderStyle&, ShadowStyle, const LayoutRect&); void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override; bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom, HitTestAction) override; bool boxShadowCanBeAppliedToBackground(const FillLayer&) const; // logicalLeft = left in a horizontal line and top in a vertical line. LayoutUnit marginBorderPaddingLogicalLeft() const { return LayoutUnit(marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft()); } LayoutUnit marginBorderPaddingLogicalRight() const { return LayoutUnit(marginLogicalRight() + borderLogicalRight() + paddingLogicalRight()); } LayoutUnit marginLogicalLeft() const { if (!includeLogicalLeftEdge()) return 0; return isHorizontal() ? renderer().marginLeft() : renderer().marginTop(); } LayoutUnit marginLogicalRight() const { if (!includeLogicalRightEdge()) return 0; return isHorizontal() ? renderer().marginRight() : renderer().marginBottom(); } float borderLogicalLeft() const { if (!includeLogicalLeftEdge()) return 0; return isHorizontal() ? lineStyle().borderLeftWidth() : lineStyle().borderTopWidth(); } float borderLogicalRight() const { if (!includeLogicalRightEdge()) return 0; return isHorizontal() ? lineStyle().borderRightWidth() : lineStyle().borderBottomWidth(); } float paddingLogicalLeft() const { if (!includeLogicalLeftEdge()) return 0; return isHorizontal() ? renderer().paddingLeft() : renderer().paddingTop(); } float paddingLogicalRight() const { if (!includeLogicalRightEdge()) return 0; return isHorizontal() ? renderer().paddingRight() : renderer().paddingBottom(); } bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; } bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; } void setEdges(bool includeLeft, bool includeRight) { m_includeLogicalLeftEdge = includeLeft; m_includeLogicalRightEdge = includeRight; } // Helper functions used during line construction and placement. void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer); LayoutUnit getFlowSpacingLogicalWidth(); float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing); float placeBoxRangeInInlineDirection(LegacyInlineBox* firstChild, LegacyInlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing); void beginPlacingBoxRangesInInlineDirection(float logicalLeft) { setLogicalLeft(logicalLeft); } void endPlacingBoxRangesInInlineDirection(float logicalLeft, float logicalRight, float minLogicalLeft, float maxLogicalRight) { setLogicalWidth(logicalRight - logicalLeft); if (knownToHaveNoOverflow() && (minLogicalLeft < logicalLeft || maxLogicalRight > logicalRight)) clearKnownToHaveNoOverflow(); } void computeLogicalBoxHeights(LegacyRootInlineBox&, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom, LayoutUnit& maxAscent, LayoutUnit& maxDescent, bool& setMaxAscent, bool& setMaxDescent, bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&); void adjustMaxAscentAndDescent(LayoutUnit& maxAscent, LayoutUnit& maxDescent, LayoutUnit maxPositionTop, LayoutUnit maxPositionBottom); void placeBoxesInBlockDirection(LayoutUnit logicalTop, LayoutUnit maxHeight, int maxAscent, bool strictMode, LayoutUnit& lineTop, LayoutUnit& lineBottom, bool& setLineTop, LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline); void flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lineBottom); bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const; LayoutUnit computeOverAnnotationAdjustment(LayoutUnit allowedPosition) const; LayoutUnit computeUnderAnnotationAdjustment(LayoutUnit allowedPosition) const; void computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap&); void removeChild(LegacyInlineBox* child); RenderObject::HighlightState selectionState() override; bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const final; float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool&) override; bool hasTextChildren() const { return m_hasTextChildren; } bool hasTextDescendants() const { return m_hasTextDescendants; } bool hasHardLinebreak() const { return m_hasHardLinebreak; } void setHasTextChildren() { m_hasTextChildren = true; setHasTextDescendants(); } void setHasTextDescendants() { m_hasTextDescendants = true; } void checkConsistency() const; void setHasBadChildList(); // Line visual and layout overflow are in the coordinate space of the block. This means that they aren't purely physical directions. // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right // respectively are flipped when compared to their physical counterparts. For example minX is on the left in vertical-lr, but it is on the right in vertical-rl. LayoutRect layoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const { return m_overflow ? m_overflow->layoutOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom)); } LayoutUnit logicalTopLayoutOverflow(LayoutUnit lineTop) const { if (m_overflow) return isHorizontal() ? m_overflow->layoutOverflowRect().y() : m_overflow->layoutOverflowRect().x(); return lineTop; } LayoutUnit logicalBottomLayoutOverflow(LayoutUnit lineBottom) const { if (m_overflow) return isHorizontal() ? m_overflow->layoutOverflowRect().maxY() : m_overflow->layoutOverflowRect().maxX(); return lineBottom; } LayoutRect logicalLayoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const { LayoutRect result = layoutOverflowRect(lineTop, lineBottom); if (!renderer().isHorizontalWritingMode()) result = result.transposedRect(); return result; } LayoutRect visualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const { return m_overflow ? m_overflow->visualOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom)); } LayoutUnit logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().x() : m_overflow->visualOverflowRect().y()) : LayoutUnit(logicalLeft()); } LayoutUnit logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().maxX() : m_overflow->visualOverflowRect().maxY()) : LayoutUnit(ceilf(logicalRight())); } LayoutUnit logicalTopVisualOverflow(LayoutUnit lineTop) const { if (m_overflow) return isHorizontal() ? m_overflow->visualOverflowRect().y() : m_overflow->visualOverflowRect().x(); return lineTop; } LayoutUnit logicalBottomVisualOverflow(LayoutUnit lineBottom) const { if (m_overflow) return isHorizontal() ? m_overflow->visualOverflowRect().maxY() : m_overflow->visualOverflowRect().maxX(); return lineBottom; } LayoutRect logicalVisualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const { LayoutRect result = visualOverflowRect(lineTop, lineBottom); if (!renderer().isHorizontalWritingMode()) result = result.transposedRect(); return result; } void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom); void setLayoutOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom); void setVisualOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom); FloatRect frameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const { if (isHorizontal()) return FloatRect(x(), lineTop, width(), lineBottom - lineTop); return FloatRect(lineTop, y(), lineBottom - lineTop, height()); } FloatRect logicalFrameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const { return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop); } bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; } void clearDescendantsHaveSameLineHeightAndBaseline() { m_descendantsHaveSameLineHeightAndBaseline = false; if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline()) parent()->clearDescendantsHaveSameLineHeightAndBaseline(); } void computeReplacedAndTextLineTopAndBottom(LayoutUnit& lineTop, LayoutUnit& lineBottom) const; private: bool isInlineFlowBox() const final { return true; } void boxModelObject() const = delete; void addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow); void addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow); void addTextBoxVisualOverflow(LegacyInlineTextBox&, GlyphOverflowAndFallbackFontsMap&, LayoutRect& logicalVisualOverflow); void addOutlineVisualOverflow(LayoutRect& logicalVisualOverflow); void addReplacedChildOverflow(const LegacyInlineBox*, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow); void constrainToLineTopAndBottomIfNeeded(LayoutRect&) const; private: unsigned m_includeLogicalLeftEdge : 1; unsigned m_includeLogicalRightEdge : 1; unsigned m_hasTextChildren : 1; unsigned m_hasTextDescendants : 1; unsigned m_hasHardLinebreak : 1; unsigned m_descendantsHaveSameLineHeightAndBaseline : 1; protected: // The following members are only used by RootInlineBox but moved here to keep the bits packed. // Whether or not this line uses alphabetic or ideographic baselines by default. unsigned m_baselineType : 1; // FontBaseline // If the line contains any ruby runs, then this will be true. unsigned m_hasAnnotationsBefore : 1; unsigned m_hasAnnotationsAfter : 1; unsigned m_lineBreakBidiStatusEor : 5; // UCharDirection unsigned m_lineBreakBidiStatusLastStrong : 5; // UCharDirection unsigned m_lineBreakBidiStatusLast : 5; // UCharDirection unsigned m_isFirstAfterPageBreak : 1; unsigned m_isForTrailingFloats : 1; // End of RootInlineBox-specific members. #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED private: unsigned m_hasBadChildList : 1; #endif protected: RefPtr m_overflow; LegacyInlineBox* m_firstChild; LegacyInlineBox* m_lastChild; LegacyInlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject LegacyInlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject }; #ifdef NDEBUG inline void LegacyInlineFlowBox::checkConsistency() const { } #endif #if ASSERT_WITH_SECURITY_IMPLICATION_DISABLED inline void LegacyInlineFlowBox::setHasBadChildList() { } #endif } // namespace WebCore SPECIALIZE_TYPE_TRAITS_INLINE_BOX(LegacyInlineFlowBox, isInlineFlowBox()) #if ENABLE(TREE_DEBUGGING) // Outside the WebCore namespace for ease of invocation from the debugger. void showTree(const WebCore::LegacyInlineFlowBox*); #endif