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