1/*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21#ifndef InlineFlowBox_h
22#define InlineFlowBox_h
23
24#include "InlineBox.h"
25#include "RenderOverflow.h"
26#include "ShadowData.h"
27
28namespace WebCore {
29
30class HitTestRequest;
31class HitTestResult;
32class InlineTextBox;
33class RenderLineBoxList;
34class SimpleFontData;
35class VerticalPositionCache;
36
37struct GlyphOverflow;
38
39typedef HashMap<const InlineTextBox*, std::pair<Vector<const SimpleFontData*>, GlyphOverflow>> GlyphOverflowAndFallbackFontsMap;
40
41class InlineFlowBox : public InlineBox {
42public:
43    explicit InlineFlowBox(RenderBoxModelObject& renderer)
44        : InlineBox(renderer)
45        , m_firstChild(0)
46        , m_lastChild(0)
47        , m_prevLineBox(0)
48        , m_nextLineBox(0)
49        , m_includeLogicalLeftEdge(false)
50        , m_includeLogicalRightEdge(false)
51        , m_descendantsHaveSameLineHeightAndBaseline(true)
52        , m_baselineType(AlphabeticBaseline)
53        , m_hasAnnotationsBefore(false)
54        , m_hasAnnotationsAfter(false)
55        , m_isFirstAfterPageBreak(false)
56#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
57        , m_hasBadChildList(false)
58#endif
59    {
60        // 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
61        // 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
62        // an invisible marker exists.  The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no
63        // text children must not apply.  This change also means that gaps will exist between image bullet list items.  Even when the list bullet
64        // is an image, the line is still considered to be immune from the quirk.
65        m_hasTextChildren = renderer.style().display() == LIST_ITEM;
66        m_hasTextDescendants = m_hasTextChildren;
67    }
68
69#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
70    virtual ~InlineFlowBox();
71#endif
72
73#ifndef NDEBUG
74    virtual void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0, int = 0) const override;
75    virtual const char* boxName() const override;
76#endif
77
78    RenderBoxModelObject& renderer() const { return toRenderBoxModelObject(InlineBox::renderer()); }
79    const RenderStyle& lineStyle() const { return isFirstLine() ? renderer().firstLineStyle() : renderer().style(); }
80
81    InlineFlowBox* prevLineBox() const { return m_prevLineBox; }
82    InlineFlowBox* nextLineBox() const { return m_nextLineBox; }
83    void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; }
84    void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; }
85
86    InlineBox* firstChild() const { checkConsistency(); return m_firstChild; }
87    InlineBox* lastChild() const { checkConsistency(); return m_lastChild; }
88
89    virtual bool isLeaf() const override final { return false; }
90
91    InlineBox* firstLeafChild() const;
92    InlineBox* lastLeafChild() const;
93
94    typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last);
95    void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const;
96
97    virtual void setConstructed() override final
98    {
99        InlineBox::setConstructed();
100        for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
101            child->setConstructed();
102    }
103
104    void addToLine(InlineBox* child);
105    virtual void deleteLine() override final;
106    virtual void extractLine() override final;
107    virtual void attachLine() override final;
108    virtual void adjustPosition(float dx, float dy) override;
109
110    virtual void extractLineBoxFromRenderObject();
111    virtual void attachLineBoxToRenderObject();
112    virtual void removeLineBoxFromRenderObject();
113
114    virtual void clearTruncation() override;
115
116    void paintBoxDecorations(PaintInfo&, const LayoutPoint&);
117    void paintMask(PaintInfo&, const LayoutPoint&);
118    void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
119    void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
120    void paintBoxShadow(const PaintInfo&, const RenderStyle&, ShadowStyle, const LayoutRect&);
121    virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override;
122    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) override;
123
124    bool boxShadowCanBeAppliedToBackground(const FillLayer&) const;
125
126    // logicalLeft = left in a horizontal line and top in a vertical line.
127    LayoutUnit marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); }
128    LayoutUnit marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); }
129    LayoutUnit marginLogicalLeft() const
130    {
131        if (!includeLogicalLeftEdge())
132            return 0;
133        return isHorizontal() ? renderer().marginLeft() : renderer().marginTop();
134    }
135    LayoutUnit marginLogicalRight() const
136    {
137        if (!includeLogicalRightEdge())
138            return 0;
139        return isHorizontal() ? renderer().marginRight() : renderer().marginBottom();
140    }
141    float borderLogicalLeft() const
142    {
143        if (!includeLogicalLeftEdge())
144            return 0;
145        return isHorizontal() ? lineStyle().borderLeftWidth() : lineStyle().borderTopWidth();
146    }
147    float borderLogicalRight() const
148    {
149        if (!includeLogicalRightEdge())
150            return 0;
151        return isHorizontal() ? lineStyle().borderRightWidth() : lineStyle().borderBottomWidth();
152    }
153    float paddingLogicalLeft() const
154    {
155        if (!includeLogicalLeftEdge())
156            return 0;
157        return isHorizontal() ? renderer().paddingLeft() : renderer().paddingTop();
158    }
159    float paddingLogicalRight() const
160    {
161        if (!includeLogicalRightEdge())
162            return 0;
163        return isHorizontal() ? renderer().paddingRight() : renderer().paddingBottom();
164    }
165
166    bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; }
167    bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; }
168    void setEdges(bool includeLeft, bool includeRight)
169    {
170        m_includeLogicalLeftEdge = includeLeft;
171        m_includeLogicalRightEdge = includeRight;
172    }
173
174    // Helper functions used during line construction and placement.
175    void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer);
176    LayoutUnit getFlowSpacingLogicalWidth();
177    float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing);
178    float placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing);
179    void beginPlacingBoxRangesInInlineDirection(float logicalLeft) { setLogicalLeft(logicalLeft); }
180    void endPlacingBoxRangesInInlineDirection(float logicalLeft, float logicalRight, float minLogicalLeft, float maxLogicalRight)
181    {
182        setLogicalWidth(logicalRight - logicalLeft);
183        if (knownToHaveNoOverflow() && (minLogicalLeft < logicalLeft || maxLogicalRight > logicalRight))
184            clearKnownToHaveNoOverflow();
185    }
186
187    void computeLogicalBoxHeights(RootInlineBox&, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom,
188        int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
189        bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&);
190    void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
191        int maxPositionTop, int maxPositionBottom);
192    void placeBoxesInBlockDirection(LayoutUnit logicalTop, LayoutUnit maxHeight, int maxAscent, bool strictMode, LayoutUnit& lineTop, LayoutUnit& lineBottom, bool& setLineTop,
193        LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline);
194    void flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lineBottom);
195    bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const;
196
197    LayoutUnit computeOverAnnotationAdjustment(LayoutUnit allowedPosition) const;
198    LayoutUnit computeUnderAnnotationAdjustment(LayoutUnit allowedPosition) const;
199
200    void computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap&);
201
202    void removeChild(InlineBox* child);
203
204    virtual RenderObject::SelectionState selectionState() override;
205
206    virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const override final;
207    virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool&) override;
208
209    bool hasTextChildren() const { return m_hasTextChildren; }
210    bool hasTextDescendants() const { return m_hasTextDescendants; }
211    void setHasTextChildren() { m_hasTextChildren = true; setHasTextDescendants(); }
212    void setHasTextDescendants() { m_hasTextDescendants = true; }
213
214    void checkConsistency() const;
215    void setHasBadChildList();
216
217    // Line visual and layout overflow are in the coordinate space of the block.  This means that they aren't purely physical directions.
218    // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right
219    // 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.
220    LayoutRect layoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
221    {
222        return m_overflow ? m_overflow->layoutOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
223    }
224    LayoutUnit logicalTopLayoutOverflow(LayoutUnit lineTop) const
225    {
226        if (m_overflow)
227            return isHorizontal() ? m_overflow->layoutOverflowRect().y() : m_overflow->layoutOverflowRect().x();
228        return lineTop;
229    }
230    LayoutUnit logicalBottomLayoutOverflow(LayoutUnit lineBottom) const
231    {
232        if (m_overflow)
233            return isHorizontal() ? m_overflow->layoutOverflowRect().maxY() : m_overflow->layoutOverflowRect().maxX();
234        return lineBottom;
235    }
236    LayoutRect logicalLayoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
237    {
238        LayoutRect result = layoutOverflowRect(lineTop, lineBottom);
239        if (!renderer().isHorizontalWritingMode())
240            result = result.transposedRect();
241        return result;
242    }
243
244    LayoutRect visualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
245    {
246        return m_overflow ? m_overflow->visualOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
247    }
248    LayoutUnit logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().x() : m_overflow->visualOverflowRect().y()) : LayoutUnit(logicalLeft()); }
249    LayoutUnit logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().maxX() : m_overflow->visualOverflowRect().maxY()) : LayoutUnit(ceilf(logicalRight())); }
250    LayoutUnit logicalTopVisualOverflow(LayoutUnit lineTop) const
251    {
252        if (m_overflow)
253            return isHorizontal() ? m_overflow->visualOverflowRect().y() : m_overflow->visualOverflowRect().x();
254        return lineTop;
255    }
256    LayoutUnit logicalBottomVisualOverflow(LayoutUnit lineBottom) const
257    {
258        if (m_overflow)
259            return isHorizontal() ? m_overflow->visualOverflowRect().maxY() : m_overflow->visualOverflowRect().maxX();
260        return lineBottom;
261    }
262    LayoutRect logicalVisualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
263    {
264        LayoutRect result = visualOverflowRect(lineTop, lineBottom);
265        if (!renderer().isHorizontalWritingMode())
266            result = result.transposedRect();
267        return result;
268    }
269
270    void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom);
271    void setLayoutOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom);
272    void setVisualOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom);
273
274    FloatRect frameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const
275    {
276        if (isHorizontal())
277            return FloatRect(m_topLeft.x(), lineTop, width(), lineBottom - lineTop);
278        return FloatRect(lineTop, m_topLeft.y(), lineBottom - lineTop, height());
279    }
280
281    FloatRect logicalFrameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const
282    {
283        return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop);
284    }
285
286    bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; }
287    void clearDescendantsHaveSameLineHeightAndBaseline()
288    {
289        m_descendantsHaveSameLineHeightAndBaseline = false;
290        if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline())
291            parent()->clearDescendantsHaveSameLineHeightAndBaseline();
292    }
293
294private:
295    virtual bool isInlineFlowBox() const override final { return true; }
296    void boxModelObject() const = delete;
297
298    void addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow);
299    void addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow);
300    void addTextBoxVisualOverflow(InlineTextBox&, GlyphOverflowAndFallbackFontsMap&, LayoutRect& logicalVisualOverflow);
301    void addReplacedChildOverflow(const InlineBox*, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow);
302    void constrainToLineTopAndBottomIfNeeded(LayoutRect&) const;
303
304protected:
305    RefPtr<RenderOverflow> m_overflow;
306
307    InlineBox* m_firstChild;
308    InlineBox* m_lastChild;
309
310    InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject
311    InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject
312
313    // Maximum logicalTop among all children of an InlineFlowBox. Used to
314    // calculate the offset for TextUnderlinePositionUnder.
315    void computeMaxLogicalTop(float& maxLogicalTop) const;
316private:
317    unsigned m_includeLogicalLeftEdge : 1;
318    unsigned m_includeLogicalRightEdge : 1;
319    unsigned m_hasTextChildren : 1;
320    unsigned m_hasTextDescendants : 1;
321    unsigned m_descendantsHaveSameLineHeightAndBaseline : 1;
322
323protected:
324    // The following members are only used by RootInlineBox but moved here to keep the bits packed.
325
326    // Whether or not this line uses alphabetic or ideographic baselines by default.
327    unsigned m_baselineType : 1; // FontBaseline
328
329    // If the line contains any ruby runs, then this will be true.
330    unsigned m_hasAnnotationsBefore : 1;
331    unsigned m_hasAnnotationsAfter : 1;
332
333    unsigned m_lineBreakBidiStatusEor : 5; // UCharDirection
334    unsigned m_lineBreakBidiStatusLastStrong : 5; // UCharDirection
335    unsigned m_lineBreakBidiStatusLast : 5; // UCharDirection
336
337    unsigned m_isFirstAfterPageBreak : 1;
338
339    // End of RootInlineBox-specific members.
340
341#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
342private:
343    unsigned m_hasBadChildList : 1;
344#endif
345};
346
347INLINE_BOX_OBJECT_TYPE_CASTS(InlineFlowBox, isInlineFlowBox())
348
349#ifdef NDEBUG
350
351inline void InlineFlowBox::checkConsistency() const
352{
353}
354
355#endif
356
357#if ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
358
359inline void InlineFlowBox::setHasBadChildList()
360{
361}
362
363#endif
364
365} // namespace WebCore
366
367#ifndef NDEBUG
368// Outside the WebCore namespace for ease of invocation from gdb.
369void showTree(const WebCore::InlineFlowBox*);
370#endif
371
372#endif // InlineFlowBox_h
373