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/RenderOverflow.h"
26#include "core/rendering/style/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*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap;
40
41class InlineFlowBox : public InlineBox {
42public:
43    InlineFlowBox(RenderObject* obj)
44        : InlineBox(obj)
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#ifndef NDEBUG
56        , m_hasBadChildList(false)
57#endif
58    {
59        // 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
60        // 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
61        // an invisible marker exists.  The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no
62        // text children must not apply.  This change also means that gaps will exist between image bullet list items.  Even when the list bullet
63        // is an image, the line is still considered to be immune from the quirk.
64        m_hasTextChildren = obj->style()->display() == LIST_ITEM;
65        m_hasTextDescendants = m_hasTextChildren;
66    }
67
68#ifndef NDEBUG
69    virtual ~InlineFlowBox();
70
71    virtual void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0, int = 0) const;
72    virtual const char* boxName() const;
73#endif
74
75    InlineFlowBox* prevLineBox() const { return m_prevLineBox; }
76    InlineFlowBox* nextLineBox() const { return m_nextLineBox; }
77    void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; }
78    void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; }
79
80    InlineBox* firstChild() const { checkConsistency(); return m_firstChild; }
81    InlineBox* lastChild() const { checkConsistency(); return m_lastChild; }
82
83    virtual bool isLeaf() const OVERRIDE FINAL { return false; }
84
85    InlineBox* firstLeafChild() const;
86    InlineBox* lastLeafChild() const;
87
88    typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last);
89    void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const;
90
91    virtual void setConstructed() OVERRIDE FINAL
92    {
93        InlineBox::setConstructed();
94        for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
95            child->setConstructed();
96    }
97
98    void addToLine(InlineBox* child);
99    virtual void deleteLine() OVERRIDE FINAL;
100    virtual void extractLine() OVERRIDE FINAL;
101    virtual void attachLine() OVERRIDE FINAL;
102    virtual void adjustPosition(float dx, float dy);
103
104    virtual void extractLineBoxFromRenderObject();
105    virtual void attachLineBoxToRenderObject();
106    virtual void removeLineBoxFromRenderObject();
107
108    virtual void clearTruncation() OVERRIDE;
109
110    IntRect roundedFrameRect() const;
111
112    void paintBoxDecorations(PaintInfo&, const LayoutPoint&);
113    void paintMask(PaintInfo&, const LayoutPoint&);
114    void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
115    void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
116    void paintBoxShadow(const PaintInfo&, RenderStyle*, ShadowStyle, const LayoutRect&);
117    virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom);
118    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE;
119
120    bool boxShadowCanBeAppliedToBackground(const FillLayer&) const;
121
122    virtual RenderLineBoxList* rendererLineBoxes() const;
123
124    // logicalLeft = left in a horizontal line and top in a vertical line.
125    LayoutUnit marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); }
126    LayoutUnit marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); }
127    LayoutUnit marginLogicalLeft() const
128    {
129        if (!includeLogicalLeftEdge())
130            return 0;
131        return isHorizontal() ? boxModelObject()->marginLeft() : boxModelObject()->marginTop();
132    }
133    LayoutUnit marginLogicalRight() const
134    {
135        if (!includeLogicalRightEdge())
136            return 0;
137        return isHorizontal() ? boxModelObject()->marginRight() : boxModelObject()->marginBottom();
138    }
139    int borderLogicalLeft() const
140    {
141        if (!includeLogicalLeftEdge())
142            return 0;
143        return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderLeftWidth() : renderer()->style(isFirstLineStyle())->borderTopWidth();
144    }
145    int borderLogicalRight() const
146    {
147        if (!includeLogicalRightEdge())
148            return 0;
149        return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderRightWidth() : renderer()->style(isFirstLineStyle())->borderBottomWidth();
150    }
151    int paddingLogicalLeft() const
152    {
153        if (!includeLogicalLeftEdge())
154            return 0;
155        return isHorizontal() ? boxModelObject()->paddingLeft() : boxModelObject()->paddingTop();
156    }
157    int paddingLogicalRight() const
158    {
159        if (!includeLogicalRightEdge())
160            return 0;
161        return isHorizontal() ? boxModelObject()->paddingRight() : boxModelObject()->paddingBottom();
162    }
163
164    bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; }
165    bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; }
166    void setEdges(bool includeLeft, bool includeRight)
167    {
168        m_includeLogicalLeftEdge = includeLeft;
169        m_includeLogicalRightEdge = includeRight;
170    }
171
172    // Helper functions used during line construction and placement.
173    void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer);
174    LayoutUnit getFlowSpacingLogicalWidth();
175    float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
176    float placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
177    void beginPlacingBoxRangesInInlineDirection(float logicalLeft) { setLogicalLeft(logicalLeft); }
178    void endPlacingBoxRangesInInlineDirection(float logicalLeft, float logicalRight, float minLogicalLeft, float maxLogicalRight)
179    {
180        setLogicalWidth(logicalRight - logicalLeft);
181        if (knownToHaveNoOverflow() && (minLogicalLeft < logicalLeft || maxLogicalRight > logicalRight))
182            clearKnownToHaveNoOverflow();
183    }
184
185    void computeLogicalBoxHeights(RootInlineBox*, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom,
186                                  int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
187                                  bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&);
188    void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
189                                   int maxPositionTop, int maxPositionBottom);
190    void placeBoxesInBlockDirection(LayoutUnit logicalTop, LayoutUnit maxHeight, int maxAscent, bool strictMode, LayoutUnit& lineTop, LayoutUnit& lineBottom, bool& setLineTop,
191                                    LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline);
192    void flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lineBottom);
193    bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const;
194
195    LayoutUnit computeOverAnnotationAdjustment(LayoutUnit allowedPosition) const;
196    LayoutUnit computeUnderAnnotationAdjustment(LayoutUnit allowedPosition) const;
197
198    void computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap&);
199
200    void removeChild(InlineBox* child);
201
202    virtual RenderObject::SelectionState selectionState();
203
204    virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const OVERRIDE FINAL;
205    virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool&) OVERRIDE;
206
207    bool hasTextChildren() const { return m_hasTextChildren; }
208    bool hasTextDescendants() const { return m_hasTextDescendants; }
209    void setHasTextChildren() { m_hasTextChildren = true; setHasTextDescendants(); }
210    void setHasTextDescendants() { m_hasTextDescendants = true; }
211
212    void checkConsistency() const;
213    void setHasBadChildList();
214
215    // Line visual and layout overflow are in the coordinate space of the block.  This means that they aren't purely physical directions.
216    // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right
217    // 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.
218    LayoutRect layoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
219    {
220        return m_overflow ? m_overflow->layoutOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
221    }
222    LayoutUnit logicalLeftLayoutOverflow() const
223    {
224        return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().x() : m_overflow->layoutOverflowRect().y()) :
225                            static_cast<LayoutUnit>(logicalLeft());
226    }
227    LayoutUnit logicalRightLayoutOverflow() const
228    {
229        return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().maxX() : m_overflow->layoutOverflowRect().maxY()) :
230                            static_cast<LayoutUnit>(ceilf(logicalRight()));
231    }
232    LayoutUnit logicalTopLayoutOverflow(LayoutUnit lineTop) const
233    {
234        if (m_overflow)
235            return isHorizontal() ? m_overflow->layoutOverflowRect().y() : m_overflow->layoutOverflowRect().x();
236        return lineTop;
237    }
238    LayoutUnit logicalBottomLayoutOverflow(LayoutUnit lineBottom) const
239    {
240        if (m_overflow)
241            return isHorizontal() ? m_overflow->layoutOverflowRect().maxY() : m_overflow->layoutOverflowRect().maxX();
242        return lineBottom;
243    }
244    LayoutRect logicalLayoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
245    {
246        LayoutRect result = layoutOverflowRect(lineTop, lineBottom);
247        if (!renderer()->isHorizontalWritingMode())
248            result = result.transposedRect();
249        return result;
250    }
251
252    LayoutRect visualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
253    {
254        return m_overflow ? m_overflow->visualOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
255    }
256    LayoutUnit logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().x() : m_overflow->visualOverflowRect().y()) : static_cast<LayoutUnit>(logicalLeft()); }
257    LayoutUnit logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().maxX() : m_overflow->visualOverflowRect().maxY()) : static_cast<LayoutUnit>(ceilf(logicalRight())); }
258    LayoutUnit logicalTopVisualOverflow(LayoutUnit lineTop) const
259    {
260        if (m_overflow)
261            return isHorizontal() ? m_overflow->visualOverflowRect().y() : m_overflow->visualOverflowRect().x();
262        return lineTop;
263    }
264    LayoutUnit logicalBottomVisualOverflow(LayoutUnit lineBottom) const
265    {
266        if (m_overflow)
267            return isHorizontal() ? m_overflow->visualOverflowRect().maxY() : m_overflow->visualOverflowRect().maxX();
268        return lineBottom;
269    }
270    LayoutRect logicalVisualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
271    {
272        LayoutRect result = visualOverflowRect(lineTop, lineBottom);
273        if (!renderer()->isHorizontalWritingMode())
274            result = result.transposedRect();
275        return result;
276    }
277
278    void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom);
279    void setLayoutOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom);
280    void setVisualOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom);
281
282    FloatRect frameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const
283    {
284        if (isHorizontal())
285            return FloatRect(m_topLeft.x(), lineTop, width(), lineBottom - lineTop);
286        return FloatRect(lineTop, m_topLeft.y(), lineBottom - lineTop, height());
287    }
288
289    FloatRect logicalFrameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const
290    {
291        return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop);
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 addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, LayoutRect& logicalVisualOverflow);
306    void addReplacedChildOverflow(const InlineBox*, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow);
307    void constrainToLineTopAndBottomIfNeeded(LayoutRect&) const;
308
309protected:
310    OwnPtr<RenderOverflow> m_overflow;
311
312    virtual bool isInlineFlowBox() const OVERRIDE FINAL { return true; }
313
314    InlineBox* m_firstChild;
315    InlineBox* m_lastChild;
316
317    InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject
318    InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject
319
320#if ENABLE(CSS3_TEXT)
321    // Maximum logicalTop among all children of an InlineFlowBox. Used to
322    // calculate the offset for TextUnderlinePositionUnder.
323    void computeMaxLogicalTop(float& maxLogicalTop) const;
324#endif // CSS3_TEXT
325private:
326    unsigned m_includeLogicalLeftEdge : 1;
327    unsigned m_includeLogicalRightEdge : 1;
328    unsigned m_hasTextChildren : 1;
329    unsigned m_hasTextDescendants : 1;
330    unsigned m_descendantsHaveSameLineHeightAndBaseline : 1;
331
332protected:
333    // The following members are only used by RootInlineBox but moved here to keep the bits packed.
334
335    // Whether or not this line uses alphabetic or ideographic baselines by default.
336    unsigned m_baselineType : 1; // FontBaseline
337
338    // If the line contains any ruby runs, then this will be true.
339    unsigned m_hasAnnotationsBefore : 1;
340    unsigned m_hasAnnotationsAfter : 1;
341
342    unsigned m_lineBreakBidiStatusEor : 5; // WTF::Unicode::Direction
343    unsigned m_lineBreakBidiStatusLastStrong : 5; // WTF::Unicode::Direction
344    unsigned m_lineBreakBidiStatusLast : 5; // WTF::Unicode::Direction
345
346    // End of RootInlineBox-specific members.
347
348#ifndef NDEBUG
349private:
350    unsigned m_hasBadChildList : 1;
351#endif
352};
353
354inline InlineFlowBox* toInlineFlowBox(InlineBox* object)
355{
356    ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isInlineFlowBox());
357    return static_cast<InlineFlowBox*>(object);
358}
359
360inline const InlineFlowBox* toInlineFlowBox(const InlineBox* object)
361{
362    ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isInlineFlowBox());
363    return static_cast<const InlineFlowBox*>(object);
364}
365
366// This will catch anyone doing an unnecessary cast.
367void toInlineFlowBox(const InlineFlowBox*);
368
369#ifdef NDEBUG
370inline void InlineFlowBox::checkConsistency() const
371{
372}
373#endif
374
375inline void InlineFlowBox::setHasBadChildList()
376{
377#ifndef NDEBUG
378    m_hasBadChildList = true;
379#endif
380}
381
382} // namespace WebCore
383
384#ifndef NDEBUG
385// Outside the WebCore namespace for ease of invocation from gdb.
386void showTree(const WebCore::InlineFlowBox*);
387#endif
388
389#endif // InlineFlowBox_h
390