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