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 VerticalPositionCache;
35
36typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap;
37
38class InlineFlowBox : public InlineBox {
39public:
40    InlineFlowBox(RenderObject* obj)
41        : InlineBox(obj)
42        , m_firstChild(0)
43        , m_lastChild(0)
44        , m_prevLineBox(0)
45        , m_nextLineBox(0)
46        , m_includeLogicalLeftEdge(false)
47        , m_includeLogicalRightEdge(false)
48        , m_descendantsHaveSameLineHeightAndBaseline(true)
49#ifndef NDEBUG
50        , m_hasBadChildList(false)
51#endif
52    {
53        // 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
54        // 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
55        // an invisible marker exists.  The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no
56        // text children must not apply.  This change also means that gaps will exist between image bullet list items.  Even when the list bullet
57        // is an image, the line is still considered to be immune from the quirk.
58        m_hasTextChildren = obj->style()->display() == LIST_ITEM;
59        m_hasTextDescendants = m_hasTextChildren;
60    }
61
62#ifndef NDEBUG
63    virtual ~InlineFlowBox();
64#endif
65
66    InlineFlowBox* prevLineBox() const { return m_prevLineBox; }
67    InlineFlowBox* nextLineBox() const { return m_nextLineBox; }
68    void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; }
69    void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; }
70
71    InlineBox* firstChild() const { checkConsistency(); return m_firstChild; }
72    InlineBox* lastChild() const { checkConsistency(); return m_lastChild; }
73
74    virtual bool isLeaf() const { return false; }
75
76    InlineBox* firstLeafChild() const;
77    InlineBox* lastLeafChild() const;
78
79    typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last);
80    void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const;
81
82    virtual void setConstructed()
83    {
84        InlineBox::setConstructed();
85        for (InlineBox* child = firstChild(); child; child = child->next())
86            child->setConstructed();
87    }
88
89    void addToLine(InlineBox* child);
90    virtual void deleteLine(RenderArena*);
91    virtual void extractLine();
92    virtual void attachLine();
93    virtual void adjustPosition(float dx, float dy);
94
95    virtual void extractLineBoxFromRenderObject();
96    virtual void attachLineBoxToRenderObject();
97    virtual void removeLineBoxFromRenderObject();
98
99    virtual void clearTruncation();
100
101    IntRect roundedFrameRect() const;
102
103    virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
104    virtual void paintMask(PaintInfo&, int tx, int ty);
105    void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver);
106    void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver);
107    void paintBoxShadow(GraphicsContext*, RenderStyle*, ShadowStyle, int tx, int ty, int w, int h);
108    virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom);
109    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, int lineTop, int lineBottom);
110
111    virtual RenderLineBoxList* rendererLineBoxes() const;
112
113    // logicalLeft = left in a horizontal line and top in a vertical line.
114    int marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); }
115    int marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); }
116    int marginLogicalLeft() const
117    {
118        if (!includeLogicalLeftEdge())
119            return 0;
120        return isHorizontal() ? boxModelObject()->marginLeft() : boxModelObject()->marginTop();
121    }
122    int marginLogicalRight() const
123    {
124        if (!includeLogicalRightEdge())
125            return 0;
126        return isHorizontal() ? boxModelObject()->marginRight() : boxModelObject()->marginBottom();
127    }
128    int borderLogicalLeft() const
129    {
130        if (!includeLogicalLeftEdge())
131            return 0;
132        return isHorizontal() ? renderer()->style()->borderLeftWidth() : renderer()->style()->borderTopWidth();
133    }
134    int borderLogicalRight() const
135    {
136        if (!includeLogicalRightEdge())
137            return 0;
138        return isHorizontal() ? renderer()->style()->borderRightWidth() : renderer()->style()->borderBottomWidth();
139    }
140    int paddingLogicalLeft() const
141    {
142        if (!includeLogicalLeftEdge())
143            return 0;
144        return isHorizontal() ? boxModelObject()->paddingLeft() : boxModelObject()->paddingTop();
145    }
146    int paddingLogicalRight() const
147    {
148        if (!includeLogicalRightEdge())
149            return 0;
150        return isHorizontal() ? boxModelObject()->paddingRight() : boxModelObject()->paddingBottom();
151    }
152
153    bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; }
154    bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; }
155    void setEdges(bool includeLeft, bool includeRight)
156    {
157        m_includeLogicalLeftEdge = includeLeft;
158        m_includeLogicalRightEdge = includeRight;
159    }
160
161    // Helper functions used during line construction and placement.
162    void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer);
163    int getFlowSpacingLogicalWidth();
164    float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
165    void computeLogicalBoxHeights(RootInlineBox*, int& maxPositionTop, int& maxPositionBottom,
166                                  int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
167                                  bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&);
168    void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
169                                   int maxPositionTop, int maxPositionBottom);
170    void placeBoxesInBlockDirection(int logicalTop, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop,
171                                    int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline);
172    void flipLinesInBlockDirection(int lineTop, int lineBottom);
173    bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const;
174
175    int computeOverAnnotationAdjustment(int allowedPosition) const;
176    int computeUnderAnnotationAdjustment(int allowedPosition) const;
177
178    void computeOverflow(int lineTop, int lineBottom, GlyphOverflowAndFallbackFontsMap&);
179
180    void removeChild(InlineBox* child);
181
182    virtual RenderObject::SelectionState selectionState();
183
184    virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth);
185    virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool&);
186
187    bool hasTextChildren() const { return m_hasTextChildren; }
188    bool hasTextDescendants() const { return m_hasTextDescendants; }
189
190    void checkConsistency() const;
191    void setHasBadChildList();
192
193    // Line visual and layout overflow are in the coordinate space of the block.  This means that they aren't purely physical directions.
194    // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right
195    // 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.
196    IntRect layoutOverflowRect(int lineTop, int lineBottom) const
197    {
198        return m_overflow ? m_overflow->layoutOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom));
199    }
200    int logicalLeftLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXLayoutOverflow() : m_overflow->minYLayoutOverflow()) : logicalLeft(); }
201    int logicalRightLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXLayoutOverflow() : m_overflow->maxYLayoutOverflow()) : ceilf(logicalRight()); }
202    int logicalTopLayoutOverflow(int lineTop) const
203    {
204        if (m_overflow)
205            return isHorizontal() ? m_overflow->minYLayoutOverflow() : m_overflow->minXLayoutOverflow();
206        return lineTop;
207    }
208    int logicalBottomLayoutOverflow(int lineBottom) const
209    {
210        if (m_overflow)
211            return isHorizontal() ? m_overflow->maxYLayoutOverflow() : m_overflow->maxXLayoutOverflow();
212        return lineBottom;
213    }
214    IntRect logicalLayoutOverflowRect(int lineTop, int lineBottom) const
215    {
216        IntRect result = layoutOverflowRect(lineTop, lineBottom);
217        if (!renderer()->isHorizontalWritingMode())
218            result = result.transposedRect();
219        return result;
220    }
221
222    IntRect visualOverflowRect(int lineTop, int lineBottom) const
223    {
224        return m_overflow ? m_overflow->visualOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom));
225    }
226    int logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXVisualOverflow() : m_overflow->minYVisualOverflow()) : logicalLeft(); }
227    int logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXVisualOverflow() : m_overflow->maxYVisualOverflow()) : ceilf(logicalRight()); }
228    int logicalTopVisualOverflow(int lineTop) const
229    {
230        if (m_overflow)
231            return isHorizontal() ? m_overflow->minYVisualOverflow() : m_overflow->minXVisualOverflow();
232        return lineTop;
233    }
234    int logicalBottomVisualOverflow(int lineBottom) const
235    {
236        if (m_overflow)
237            return isHorizontal() ? m_overflow->maxYVisualOverflow() : m_overflow->maxXVisualOverflow();
238        return lineBottom;
239    }
240    IntRect logicalVisualOverflowRect(int lineTop, int lineBottom) const
241    {
242        IntRect result = visualOverflowRect(lineTop, lineBottom);
243        if (!renderer()->isHorizontalWritingMode())
244            result = result.transposedRect();
245        return result;
246    }
247
248    void setOverflowFromLogicalRects(const IntRect& logicalLayoutOverflow, const IntRect& logicalVisualOverflow, int lineTop, int lineBottom);
249    void setLayoutOverflow(const IntRect&, int lineTop, int lineBottom);
250    void setVisualOverflow(const IntRect&, int lineTop, int lineBottom);
251
252    FloatRect frameRectIncludingLineHeight(int lineTop, int lineBottom) const
253    {
254        if (isHorizontal())
255            return FloatRect(m_x, lineTop, width(), lineBottom - lineTop);
256        return FloatRect(lineTop, m_y, lineBottom - lineTop, height());
257    }
258
259    FloatRect logicalFrameRectIncludingLineHeight(int lineTop, int lineBottom) const
260    {
261        return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop);
262    }
263
264    bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; }
265    void clearDescendantsHaveSameLineHeightAndBaseline()
266    {
267        m_descendantsHaveSameLineHeightAndBaseline = false;
268        if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline())
269            parent()->clearDescendantsHaveSameLineHeightAndBaseline();
270    }
271
272private:
273    void addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow);
274    void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, IntRect& logicalVisualOverflow);
275    void addReplacedChildOverflow(const InlineBox*, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow);
276
277protected:
278    OwnPtr<RenderOverflow> m_overflow;
279
280    virtual bool isInlineFlowBox() const { return true; }
281
282    InlineBox* m_firstChild;
283    InlineBox* m_lastChild;
284
285    InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject
286    InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject
287
288    bool m_includeLogicalLeftEdge : 1;
289    bool m_includeLogicalRightEdge : 1;
290    bool m_hasTextChildren : 1;
291    bool m_hasTextDescendants : 1;
292    bool m_descendantsHaveSameLineHeightAndBaseline : 1;
293
294#ifndef NDEBUG
295    bool m_hasBadChildList;
296#endif
297};
298
299#ifdef NDEBUG
300inline void InlineFlowBox::checkConsistency() const
301{
302}
303#endif
304
305inline void InlineFlowBox::setHasBadChildList()
306{
307#ifndef NDEBUG
308    m_hasBadChildList = true;
309#endif
310}
311
312} // namespace WebCore
313
314#ifndef NDEBUG
315// Outside the WebCore namespace for ease of invocation from gdb.
316void showTree(const WebCore::InlineFlowBox*);
317#endif
318
319#endif // InlineFlowBox_h
320