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