#ifndef InlineFlowBox_h
#define InlineFlowBox_h
#include "InlineBox.h"
#include "RenderOverflow.h"
#include "ShadowData.h"
namespace WebCore {
class HitTestRequest;
class HitTestResult;
class InlineTextBox;
class RenderLineBoxList;
class SimpleFontData;
class VerticalPositionCache;
struct GlyphOverflow;
typedef HashMap<const InlineTextBox*, std::pair<Vector<const SimpleFontData*>, GlyphOverflow>> GlyphOverflowAndFallbackFontsMap;
class InlineFlowBox : public InlineBox {
public:
explicit InlineFlowBox(RenderBoxModelObject& renderer)
: InlineBox(renderer)
, m_firstChild(0)
, m_lastChild(0)
, m_prevLineBox(0)
, m_nextLineBox(0)
, m_includeLogicalLeftEdge(false)
, m_includeLogicalRightEdge(false)
, m_descendantsHaveSameLineHeightAndBaseline(true)
, m_baselineType(AlphabeticBaseline)
, m_hasAnnotationsBefore(false)
, m_hasAnnotationsAfter(false)
, m_isFirstAfterPageBreak(false)
#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
, m_hasBadChildList(false)
#endif
{
m_hasTextChildren = renderer.style().display() == LIST_ITEM;
m_hasTextDescendants = m_hasTextChildren;
}
#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
virtual ~InlineFlowBox();
#endif
#ifndef NDEBUG
virtual void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0, int = 0) const override;
virtual const char* boxName() const override;
#endif
RenderBoxModelObject& renderer() const { return toRenderBoxModelObject(InlineBox::renderer()); }
const RenderStyle& lineStyle() const { return isFirstLine() ? renderer().firstLineStyle() : renderer().style(); }
InlineFlowBox* prevLineBox() const { return m_prevLineBox; }
InlineFlowBox* nextLineBox() const { return m_nextLineBox; }
void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; }
void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; }
InlineBox* firstChild() const { checkConsistency(); return m_firstChild; }
InlineBox* lastChild() const { checkConsistency(); return m_lastChild; }
virtual bool isLeaf() const override final { return false; }
InlineBox* firstLeafChild() const;
InlineBox* lastLeafChild() const;
typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last);
void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const;
virtual void setConstructed() override final
{
InlineBox::setConstructed();
for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
child->setConstructed();
}
void addToLine(InlineBox* child);
virtual void deleteLine() override final;
virtual void extractLine() override final;
virtual void attachLine() override final;
virtual void adjustPosition(float dx, float dy) override;
virtual void extractLineBoxFromRenderObject();
virtual void attachLineBoxToRenderObject();
virtual void removeLineBoxFromRenderObject();
virtual void clearTruncation() override;
void paintBoxDecorations(PaintInfo&, const LayoutPoint&);
void paintMask(PaintInfo&, const LayoutPoint&);
void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
void paintBoxShadow(const PaintInfo&, const RenderStyle&, ShadowStyle, const LayoutRect&);
virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override;
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) override;
bool boxShadowCanBeAppliedToBackground(const FillLayer&) const;
LayoutUnit marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); }
LayoutUnit marginBorderPaddingLogicalRight() const { return 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;
}
void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer);
LayoutUnit getFlowSpacingLogicalWidth();
float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing);
float placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* 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(RootInlineBox&, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom,
int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&);
void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
int maxPositionTop, int 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(InlineBox* child);
virtual RenderObject::SelectionState selectionState() override;
virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const override final;
virtual 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; }
void setHasTextChildren() { m_hasTextChildren = true; setHasTextDescendants(); }
void setHasTextDescendants() { m_hasTextDescendants = true; }
void checkConsistency() const;
void setHasBadChildList();
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(m_topLeft.x(), lineTop, width(), lineBottom - lineTop);
return FloatRect(lineTop, m_topLeft.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;
void maxLogicalBottomForTextDecorationLine(float& maxLogicalBottom, const RenderElement* decorationRenderer, TextDecoration) const;
void minLogicalTopForTextDecorationLine(float& minLogicalTop, const RenderElement* decorationRenderer, TextDecoration) const;
private:
virtual bool isInlineFlowBox() const override final { return true; }
void boxModelObject() const = delete;
void addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow);
void addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow);
void addTextBoxVisualOverflow(InlineTextBox&, GlyphOverflowAndFallbackFontsMap&, LayoutRect& logicalVisualOverflow);
void addReplacedChildOverflow(const InlineBox*, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow);
void constrainToLineTopAndBottomIfNeeded(LayoutRect&) const;
protected:
RefPtr<RenderOverflow> m_overflow;
InlineBox* m_firstChild;
InlineBox* m_lastChild;
InlineFlowBox* m_prevLineBox; InlineFlowBox* m_nextLineBox;
private:
unsigned m_includeLogicalLeftEdge : 1;
unsigned m_includeLogicalRightEdge : 1;
unsigned m_hasTextChildren : 1;
unsigned m_hasTextDescendants : 1;
unsigned m_descendantsHaveSameLineHeightAndBaseline : 1;
protected:
unsigned m_baselineType : 1;
unsigned m_hasAnnotationsBefore : 1;
unsigned m_hasAnnotationsAfter : 1;
unsigned m_lineBreakBidiStatusEor : 5; unsigned m_lineBreakBidiStatusLastStrong : 5; unsigned m_lineBreakBidiStatusLast : 5;
unsigned m_isFirstAfterPageBreak : 1;
#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
private:
unsigned m_hasBadChildList : 1;
#endif
};
INLINE_BOX_OBJECT_TYPE_CASTS(InlineFlowBox, isInlineFlowBox())
#ifdef NDEBUG
inline void InlineFlowBox::checkConsistency() const
{
}
#endif
#if ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
inline void InlineFlowBox::setHasBadChildList()
{
}
#endif
}
#ifndef NDEBUG
void showTree(const WebCore::InlineFlowBox*);
#endif
#endif // InlineFlowBox_h