196c230fdd8196f8d3670c516aad32133d0cd9a5
[WebKit-https.git] / Source / WebCore / rendering / InlineBox.h
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011 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 InlineBox_h
22 #define InlineBox_h
23
24 #include "RenderBoxModelObject.h"
25 #include "TextDirection.h"
26
27 namespace WebCore {
28
29 class HitTestRequest;
30 class HitTestResult;
31 class RootInlineBox;
32
33 // InlineBox represents a rectangle that occurs on a line.  It corresponds to
34 // some RenderObject (i.e., it represents a portion of that RenderObject).
35 class InlineBox {
36 public:
37     InlineBox(RenderObject* obj)
38         : m_next(0)
39         , m_prev(0)
40         , m_parent(0)
41         , m_renderer(obj)
42         , m_logicalWidth(0)
43         , m_firstLine(false)
44         , m_constructed(false)
45         , m_bidiEmbeddingLevel(0)
46         , m_dirty(false)
47         , m_extracted(false)
48         , m_hasVirtualLogicalHeight(false)
49         , m_isHorizontal(true)
50         , m_endsWithBreak(false)
51         , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false)
52         , m_knownToHaveNoOverflow(true)
53         , m_hasEllipsisBoxOrHyphen(false)
54         , m_dirOverride(false)
55         , m_isText(false)
56         , m_determinedIfNextOnLineExists(false)
57         , m_nextOnLineExists(false)
58         , m_expansion(0)
59 #ifndef NDEBUG
60         , m_hasBadParent(false)
61 #endif
62     {
63     }
64
65     InlineBox(RenderObject* obj, FloatPoint topLeft, float logicalWidth, bool firstLine, bool constructed,
66               bool dirty, bool extracted, bool isHorizontal, InlineBox* next, InlineBox* prev, InlineFlowBox* parent)
67         : m_next(next)
68         , m_prev(prev)
69         , m_parent(parent)
70         , m_renderer(obj)
71         , m_topLeft(topLeft)
72         , m_logicalWidth(logicalWidth)
73         , m_firstLine(firstLine)
74         , m_constructed(constructed)
75         , m_bidiEmbeddingLevel(0)
76         , m_dirty(dirty)
77         , m_extracted(extracted)
78         , m_hasVirtualLogicalHeight(false)
79         , m_isHorizontal(isHorizontal)
80         , m_endsWithBreak(false)
81         , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false)
82         , m_knownToHaveNoOverflow(true)  
83         , m_hasEllipsisBoxOrHyphen(false)
84         , m_dirOverride(false)
85         , m_isText(false)
86         , m_determinedIfNextOnLineExists(false)
87         , m_nextOnLineExists(false)
88         , m_expansion(0)
89 #ifndef NDEBUG
90         , m_hasBadParent(false)
91 #endif
92     {
93     }
94
95     virtual ~InlineBox();
96
97     virtual void destroy(RenderArena*);
98
99     virtual void deleteLine(RenderArena*);
100     virtual void extractLine();
101     virtual void attachLine();
102
103     virtual bool isLineBreak() const { return false; }
104
105     virtual void adjustPosition(float dx, float dy);
106     void adjustLineDirectionPosition(float delta)
107     {
108         if (isHorizontal())
109             adjustPosition(delta, 0);
110         else
111             adjustPosition(0, delta);
112     }
113     void adjustBlockDirectionPosition(float delta)
114     {
115         if (isHorizontal())
116             adjustPosition(0, delta);
117         else
118             adjustPosition(delta, 0);
119     }
120
121     virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom);
122     virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom);
123
124     InlineBox* next() const { return m_next; }
125
126     // Overloaded new operator.
127     void* operator new(size_t, RenderArena*);
128
129     // Overridden to prevent the normal delete from being called.
130     void operator delete(void*, size_t);
131
132 private:
133     // The normal operator new is disallowed.
134     void* operator new(size_t) throw();
135
136 public:
137 #ifndef NDEBUG
138     void showTreeForThis() const;
139     void showLineTreeForThis() const;
140     
141     virtual void showBox(int = 0) const;
142     virtual void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0, int = 0) const;
143     virtual const char* boxName() const;
144 #endif
145
146     bool isText() const { return m_isText; }
147     void setIsText(bool b) { m_isText = b; }
148  
149     virtual bool isInlineFlowBox() const { return false; }
150     virtual bool isInlineTextBox() const { return false; }
151     virtual bool isRootInlineBox() const { return false; }
152 #if ENABLE(SVG)
153     virtual bool isSVGInlineTextBox() const { return false; }
154     virtual bool isSVGInlineFlowBox() const { return false; }
155     virtual bool isSVGRootInlineBox() const { return false; }
156 #endif
157
158     bool hasVirtualLogicalHeight() const { return m_hasVirtualLogicalHeight; }
159     void setHasVirtualLogicalHeight() { m_hasVirtualLogicalHeight = true; }
160     virtual float virtualLogicalHeight() const
161     {
162         ASSERT_NOT_REACHED();
163         return 0;
164     }
165
166     bool isHorizontal() const { return m_isHorizontal; }
167     void setIsHorizontal(bool horizontal) { m_isHorizontal = horizontal; }
168
169     virtual FloatRect calculateBoundaries() const
170     {
171         ASSERT_NOT_REACHED();
172         return FloatRect();
173     }
174
175     bool isConstructed() { return m_constructed; }
176     virtual void setConstructed() { m_constructed = true; }
177
178     void setExtracted(bool b = true) { m_extracted = b; }
179     
180     void setFirstLineStyleBit(bool f) { m_firstLine = f; }
181     bool isFirstLineStyle() const { return m_firstLine; }
182
183     void remove();
184
185     InlineBox* nextOnLine() const { return m_next; }
186     InlineBox* prevOnLine() const { return m_prev; }
187     void setNextOnLine(InlineBox* next)
188     {
189         ASSERT(m_parent || !next);
190         m_next = next;
191     }
192     void setPrevOnLine(InlineBox* prev)
193     {
194         ASSERT(m_parent || !prev);
195         m_prev = prev;
196     }
197     bool nextOnLineExists() const;
198
199     virtual bool isLeaf() const { return true; }
200     
201     InlineBox* nextLeafChild() const;
202     InlineBox* prevLeafChild() const;
203
204     // Helper functions for editing and hit-testing code.
205     // FIXME: These two functions should be moved to RenderedPosition once the code to convert between
206     // Position and inline box, offset pair is moved to RenderedPosition.
207     InlineBox* nextLeafChildIgnoringLineBreak() const;
208     InlineBox* prevLeafChildIgnoringLineBreak() const;
209
210     RenderObject* renderer() const { return m_renderer; }
211
212     InlineFlowBox* parent() const
213     {
214         ASSERT(!m_hasBadParent);
215         return m_parent;
216     }
217     void setParent(InlineFlowBox* par) { m_parent = par; }
218
219     const RootInlineBox* root() const;
220     RootInlineBox* root();
221
222     // x() is the left side of the box in the containing block's coordinate system.
223     void setX(float x) { m_topLeft.setX(x); }
224     float x() const { return m_topLeft.x(); }
225     float left() const { return m_topLeft.x(); }
226
227     // y() is the top side of the box in the containing block's coordinate system.
228     void setY(float y) { m_topLeft.setY(y); }
229     float y() const { return m_topLeft.y(); }
230     float top() const { return m_topLeft.y(); }
231
232     const FloatPoint& topLeft() const { return m_topLeft; }
233
234     float width() const { return isHorizontal() ? logicalWidth() : logicalHeight(); }
235     float height() const { return isHorizontal() ? logicalHeight() : logicalWidth(); }
236     FloatSize size() const { return IntSize(width(), height()); }
237     float right() const { return left() + width(); }
238     float bottom() const { return top() + height(); }
239
240     // The logicalLeft position is the left edge of the line box in a horizontal line and the top edge in a vertical line.
241     float logicalLeft() const { return isHorizontal() ? m_topLeft.x() : m_topLeft.y(); }
242     float logicalRight() const { return logicalLeft() + logicalWidth(); }
243     void setLogicalLeft(float left)
244     {
245         if (isHorizontal())
246             setX(left);
247         else
248             setY(left);
249     }
250     int pixelSnappedLogicalLeft() const { return logicalLeft(); }
251     int pixelSnappedLogicalRight() const { return ceilf(logicalRight()); }
252     int pixelSnappedLogicalTop() const { return logicalTop(); }
253     int pixelSnappedLogicalBottom() const { return ceilf(logicalBottom()); }
254
255     // The logicalTop[ position is the top edge of the line box in a horizontal line and the left edge in a vertical line.
256     float logicalTop() const { return isHorizontal() ? m_topLeft.y() : m_topLeft.x(); }
257     float logicalBottom() const { return logicalTop() + logicalHeight(); }
258     void setLogicalTop(float top)
259     {
260         if (isHorizontal())
261             setY(top);
262         else
263             setX(top);
264     }
265
266     // The logical width is our extent in the line's overall inline direction, i.e., width for horizontal text and height for vertical text.
267     void setLogicalWidth(float w) { m_logicalWidth = w; }
268     float logicalWidth() const { return m_logicalWidth; }
269
270     // The logical height is our extent in the block flow direction, i.e., height for horizontal text and width for vertical text.
271     float logicalHeight() const;
272
273     FloatRect logicalFrameRect() const { return isHorizontal() ? FloatRect(m_topLeft.x(), m_topLeft.y(), m_logicalWidth, logicalHeight()) : FloatRect(m_topLeft.y(), m_topLeft.x(), m_logicalWidth, logicalHeight()); }
274
275     virtual LayoutUnit baselinePosition(FontBaseline baselineType) const { return boxModelObject()->baselinePosition(baselineType, m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); }
276     virtual LayoutUnit lineHeight() const { return boxModelObject()->lineHeight(m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); }
277     
278     virtual int caretMinOffset() const;
279     virtual int caretMaxOffset() const;
280
281     unsigned char bidiLevel() const { return m_bidiEmbeddingLevel; }
282     void setBidiLevel(unsigned char level) { m_bidiEmbeddingLevel = level; }
283     TextDirection direction() const { return m_bidiEmbeddingLevel % 2 ? RTL : LTR; }
284     bool isLeftToRightDirection() const { return direction() == LTR; }
285     int caretLeftmostOffset() const { return isLeftToRightDirection() ? caretMinOffset() : caretMaxOffset(); }
286     int caretRightmostOffset() const { return isLeftToRightDirection() ? caretMaxOffset() : caretMinOffset(); }
287
288     virtual void clearTruncation() { }
289
290     bool isDirty() const { return m_dirty; }
291     void markDirty(bool dirty = true) { m_dirty = dirty; }
292
293     void dirtyLineBoxes();
294     
295     virtual RenderObject::SelectionState selectionState();
296
297     virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth);
298     // visibleLeftEdge, visibleRightEdge are in the parent's coordinate system.
299     virtual float placeEllipsisBox(bool ltr, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, bool&);
300
301     void setHasBadParent();
302
303     int expansion() const { return m_expansion; }
304     
305     bool visibleToHitTesting() const { return renderer()->style()->visibility() == VISIBLE && renderer()->style()->pointerEvents() != PE_NONE; }
306     
307     EVerticalAlign verticalAlign() const { return renderer()->style(m_firstLine)->verticalAlign(); }
308
309     // Use with caution! The type is not checked!
310     RenderBoxModelObject* boxModelObject() const
311     { 
312         if (!m_renderer->isText())
313             return toRenderBoxModelObject(m_renderer);
314         return 0;
315     }
316
317     FloatPoint locationIncludingFlipping();
318     void flipForWritingMode(FloatRect&);
319     FloatPoint flipForWritingMode(const FloatPoint&);
320     void flipForWritingMode(LayoutRect&);
321     LayoutPoint flipForWritingMode(const LayoutPoint&);
322
323     bool knownToHaveNoOverflow() const { return m_knownToHaveNoOverflow; }
324     void clearKnownToHaveNoOverflow();
325
326 private:
327     InlineBox* m_next; // The next element on the same line as us.
328     InlineBox* m_prev; // The previous element on the same line as us.
329
330     InlineFlowBox* m_parent; // The box that contains us.
331
332 public:
333     RenderObject* m_renderer;
334
335     FloatPoint m_topLeft;
336     float m_logicalWidth;
337     
338     // Some of these bits are actually for subclasses and moved here to compact the structures.
339
340     // for this class
341 protected:
342     bool m_firstLine : 1;
343 private:
344     bool m_constructed : 1;
345     unsigned char m_bidiEmbeddingLevel : 6;
346 protected:
347     bool m_dirty : 1;
348     bool m_extracted : 1;
349     bool m_hasVirtualLogicalHeight : 1;
350
351     bool m_isHorizontal : 1;
352
353     // for RootInlineBox
354     bool m_endsWithBreak : 1;  // Whether the line ends with a <br>.
355     // shared between RootInlineBox and InlineTextBox
356     bool m_hasSelectedChildrenOrCanHaveLeadingExpansion : 1; // Whether we have any children selected (this bit will also be set if the <br> that terminates our line is selected).
357     bool m_knownToHaveNoOverflow : 1;
358     bool m_hasEllipsisBoxOrHyphen : 1;
359
360     // for InlineTextBox
361 public:
362     bool m_dirOverride : 1;
363     bool m_isText : 1; // Whether or not this object represents text with a non-zero height. Includes non-image list markers, text boxes.
364 protected:
365     mutable bool m_determinedIfNextOnLineExists : 1;
366     mutable bool m_nextOnLineExists : 1;
367     signed m_expansion : 12; // for justified text
368
369 #ifndef NDEBUG
370 private:
371     bool m_hasBadParent;
372 #endif
373 };
374
375 #ifdef NDEBUG
376 inline InlineBox::~InlineBox()
377 {
378 }
379 #endif
380
381 inline void InlineBox::setHasBadParent()
382 {
383 #ifndef NDEBUG
384     m_hasBadParent = true;
385 #endif
386 }
387
388 } // namespace WebCore
389
390 #ifndef NDEBUG
391 // Outside the WebCore namespace for ease of invocation from gdb.
392 void showTree(const WebCore::InlineBox*);
393 void showLineTree(const WebCore::InlineBox*);
394 #endif
395
396 #endif // InlineBox_h