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 "core/rendering/InlineBox.h"
25#include "core/rendering/RenderObjectInlines.h"
26#include "core/rendering/RenderOverflow.h"
27#include "core/rendering/style/ShadowData.h"
28
29namespace blink {
30
31class HitTestRequest;
32class HitTestResult;
33class InlineTextBox;
34class RenderLineBoxList;
35class SimpleFontData;
36class VerticalPositionCache;
37
38struct GlyphOverflow;
39
40typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap;
41
42class InlineFlowBox : public InlineBox {
43public:
44    InlineFlowBox(RenderObject& obj)
45        : InlineBox(obj)
46        , m_firstChild(0)
47        , m_lastChild(0)
48        , m_prevLineBox(0)
49        , m_nextLineBox(0)
50        , m_includeLogicalLeftEdge(false)
51        , m_includeLogicalRightEdge(false)
52        , m_descendantsHaveSameLineHeightAndBaseline(true)
53        , m_baselineType(AlphabeticBaseline)
54        , m_hasAnnotationsBefore(false)
55        , m_hasAnnotationsAfter(false)
56        , m_lineBreakBidiStatusEor(WTF::Unicode::LeftToRight)
57        , m_lineBreakBidiStatusLastStrong(WTF::Unicode::LeftToRight)
58        , m_lineBreakBidiStatusLast(WTF::Unicode::LeftToRight)
59#if ENABLE(ASSERT)
60        , m_hasBadChildList(false)
61#endif
62    {
63        // 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
64        // 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
65        // an invisible marker exists.  The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no
66        // text children must not apply.  This change also means that gaps will exist between image bullet list items.  Even when the list bullet
67        // is an image, the line is still considered to be immune from the quirk.
68        m_hasTextChildren = obj.style()->display() == LIST_ITEM;
69        m_hasTextDescendants = m_hasTextChildren;
70    }
71
72#if ENABLE(ASSERT)
73    virtual ~InlineFlowBox();
74#endif
75
76#ifndef NDEBUG
77    virtual void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0, int = 0) const OVERRIDE;
78    virtual const char* boxName() const OVERRIDE;
79#endif
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    IntRect roundedFrameRect() const;
117
118    virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE;
119    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE;
120
121    bool boxShadowCanBeAppliedToBackground(const FillLayer&) const;
122
123    virtual RenderLineBoxList* rendererLineBoxes() const;
124
125    // logicalLeft = left in a horizontal line and top in a vertical line.
126    LayoutUnit marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); }
127    LayoutUnit marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); }
128    LayoutUnit marginLogicalLeft() const
129    {
130        if (!includeLogicalLeftEdge())
131            return 0;
132        return isHorizontal() ? boxModelObject()->marginLeft() : boxModelObject()->marginTop();
133    }
134    LayoutUnit marginLogicalRight() const
135    {
136        if (!includeLogicalRightEdge())
137            return 0;
138        return isHorizontal() ? boxModelObject()->marginRight() : boxModelObject()->marginBottom();
139    }
140    int borderLogicalLeft() const
141    {
142        if (!includeLogicalLeftEdge())
143            return 0;
144        return isHorizontal() ? renderer().style(isFirstLineStyle())->borderLeftWidth() : renderer().style(isFirstLineStyle())->borderTopWidth();
145    }
146    int borderLogicalRight() const
147    {
148        if (!includeLogicalRightEdge())
149            return 0;
150        return isHorizontal() ? renderer().style(isFirstLineStyle())->borderRightWidth() : renderer().style(isFirstLineStyle())->borderBottomWidth();
151    }
152    int paddingLogicalLeft() const
153    {
154        if (!includeLogicalLeftEdge())
155            return 0;
156        return isHorizontal() ? boxModelObject()->paddingLeft() : boxModelObject()->paddingTop();
157    }
158    int paddingLogicalRight() const
159    {
160        if (!includeLogicalRightEdge())
161            return 0;
162        return isHorizontal() ? boxModelObject()->paddingRight() : boxModelObject()->paddingBottom();
163    }
164
165    bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; }
166    bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; }
167    void setEdges(bool includeLeft, bool includeRight)
168    {
169        m_includeLogicalLeftEdge = includeLeft;
170        m_includeLogicalRightEdge = includeRight;
171    }
172
173    // Helper functions used during line construction and placement.
174    void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer);
175    LayoutUnit getFlowSpacingLogicalWidth();
176    float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing);
177    float placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild,
178        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, LayoutUnit& selectionBottom, 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, MarkLineBoxes);
203
204    virtual RenderObject::SelectionState selectionState() const 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 logicalLeftLayoutOverflow() const
225    {
226        return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().x() : m_overflow->layoutOverflowRect().y()) :
227                            static_cast<LayoutUnit>(logicalLeft());
228    }
229    LayoutUnit logicalRightLayoutOverflow() const
230    {
231        return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().maxX() : m_overflow->layoutOverflowRect().maxY()) :
232                            static_cast<LayoutUnit>(ceilf(logicalRight()));
233    }
234    LayoutUnit logicalTopLayoutOverflow(LayoutUnit lineTop) const
235    {
236        if (m_overflow)
237            return isHorizontal() ? m_overflow->layoutOverflowRect().y() : m_overflow->layoutOverflowRect().x();
238        return lineTop;
239    }
240    LayoutUnit logicalBottomLayoutOverflow(LayoutUnit lineBottom) const
241    {
242        if (m_overflow)
243            return isHorizontal() ? m_overflow->layoutOverflowRect().maxY() : m_overflow->layoutOverflowRect().maxX();
244        return lineBottom;
245    }
246    LayoutRect logicalLayoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
247    {
248        LayoutRect result = layoutOverflowRect(lineTop, lineBottom);
249        if (!renderer().isHorizontalWritingMode())
250            result = result.transposedRect();
251        return result;
252    }
253
254    LayoutRect visualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
255    {
256        return m_overflow ? m_overflow->visualOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
257    }
258    LayoutUnit logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().x() : m_overflow->visualOverflowRect().y()) : static_cast<LayoutUnit>(logicalLeft()); }
259    LayoutUnit logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().maxX() : m_overflow->visualOverflowRect().maxY()) : static_cast<LayoutUnit>(ceilf(logicalRight())); }
260    LayoutUnit logicalTopVisualOverflow(LayoutUnit lineTop) const
261    {
262        if (m_overflow)
263            return isHorizontal() ? m_overflow->visualOverflowRect().y() : m_overflow->visualOverflowRect().x();
264        return lineTop;
265    }
266    LayoutUnit logicalBottomVisualOverflow(LayoutUnit lineBottom) const
267    {
268        if (m_overflow)
269            return isHorizontal() ? m_overflow->visualOverflowRect().maxY() : m_overflow->visualOverflowRect().maxX();
270        return lineBottom;
271    }
272    LayoutRect logicalVisualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
273    {
274        LayoutRect result = visualOverflowRect(lineTop, lineBottom);
275        if (!renderer().isHorizontalWritingMode())
276            result = result.transposedRect();
277        return result;
278    }
279
280    void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom);
281
282    FloatRect frameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const
283    {
284        if (isHorizontal())
285            return FloatRect(m_topLeft.x(), lineTop.toFloat(), width(), (lineBottom - lineTop).toFloat());
286        return FloatRect(lineTop.toFloat(), m_topLeft.y(), (lineBottom - lineTop).toFloat(), height());
287    }
288
289    FloatRect logicalFrameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const
290    {
291        return FloatRect(logicalLeft(), lineTop.toFloat(), logicalWidth(), (lineBottom - lineTop).toFloat());
292    }
293
294    bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; }
295    void clearDescendantsHaveSameLineHeightAndBaseline()
296    {
297        m_descendantsHaveSameLineHeightAndBaseline = false;
298        if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline())
299            parent()->clearDescendantsHaveSameLineHeightAndBaseline();
300    }
301
302private:
303    void addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow);
304    void addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow);
305    void addOutlineVisualOverflow(LayoutRect& logicalVisualOverflow);
306    void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, LayoutRect& logicalVisualOverflow);
307    void addReplacedChildOverflow(const InlineBox*, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow);
308    void constrainToLineTopAndBottomIfNeeded(LayoutRect&) const;
309
310    void setLayoutOverflow(const LayoutRect&, const LayoutRect&);
311    void setVisualOverflow(const LayoutRect&, const LayoutRect&);
312
313protected:
314    OwnPtr<RenderOverflow> m_overflow;
315
316    virtual bool isInlineFlowBox() const OVERRIDE FINAL { return true; }
317
318    InlineBox* m_firstChild;
319    InlineBox* m_lastChild;
320
321    InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject
322    InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject
323
324    // Maximum logicalTop among all children of an InlineFlowBox. Used to
325    // calculate the offset for TextUnderlinePositionUnder.
326    void computeMaxLogicalTop(float& maxLogicalTop) const;
327
328private:
329    unsigned m_includeLogicalLeftEdge : 1;
330    unsigned m_includeLogicalRightEdge : 1;
331    unsigned m_hasTextChildren : 1;
332    unsigned m_hasTextDescendants : 1;
333    unsigned m_descendantsHaveSameLineHeightAndBaseline : 1;
334
335protected:
336    // The following members are only used by RootInlineBox but moved here to keep the bits packed.
337
338    // Whether or not this line uses alphabetic or ideographic baselines by default.
339    unsigned m_baselineType : 1; // FontBaseline
340
341    // If the line contains any ruby runs, then this will be true.
342    unsigned m_hasAnnotationsBefore : 1;
343    unsigned m_hasAnnotationsAfter : 1;
344
345    unsigned m_lineBreakBidiStatusEor : 5; // WTF::Unicode::Direction
346    unsigned m_lineBreakBidiStatusLastStrong : 5; // WTF::Unicode::Direction
347    unsigned m_lineBreakBidiStatusLast : 5; // WTF::Unicode::Direction
348
349    // End of RootInlineBox-specific members.
350
351#if ENABLE(ASSERT)
352private:
353    unsigned m_hasBadChildList : 1;
354#endif
355};
356
357DEFINE_INLINE_BOX_TYPE_CASTS(InlineFlowBox);
358
359#if !ENABLE(ASSERT)
360inline void InlineFlowBox::checkConsistency() const
361{
362}
363#endif
364
365inline void InlineFlowBox::setHasBadChildList()
366{
367#if ENABLE(ASSERT)
368    m_hasBadChildList = true;
369#endif
370}
371
372} // namespace blink
373
374#ifndef NDEBUG
375// Outside the WebCore namespace for ease of invocation from gdb.
376void showTree(const blink::InlineFlowBox*);
377#endif
378
379#endif // InlineFlowBox_h
380