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
28namespace WebCore {
29
30class HitTestRequest;
31class HitTestResult;
32class 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).
36class InlineBox {
37public:
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
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
115    virtual bool isLineBreak() const { return false; }
116
117    virtual void adjustPosition(float dx, float dy);
118    void adjustLineDirectionPosition(float delta)
119    {
120        if (isHorizontal())
121            adjustPosition(delta, 0);
122        else
123            adjustPosition(0, delta);
124    }
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
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
144private:
145    // The normal operator new is disallowed.
146    void* operator new(size_t) throw();
147
148public:
149#ifndef NDEBUG
150    void showTreeForThis() const;
151#endif
152
153    bool isText() const { return m_isText; }
154    void setIsText(bool b) { m_isText = b; }
155
156    virtual bool isInlineFlowBox() const { return false; }
157    virtual bool isInlineTextBox() const { return false; }
158    virtual bool isRootInlineBox() const { return false; }
159#if ENABLE(SVG)
160    virtual bool isSVGInlineTextBox() const { return false; }
161    virtual bool isSVGInlineFlowBox() const { return false; }
162    virtual bool isSVGRootInlineBox() const { return false; }
163#endif
164
165    bool hasVirtualLogicalHeight() const { return m_hasVirtualLogicalHeight; }
166    void setHasVirtualLogicalHeight() { m_hasVirtualLogicalHeight = true; }
167    virtual int virtualLogicalHeight() const
168    {
169        ASSERT_NOT_REACHED();
170        return 0;
171    }
172
173    bool isHorizontal() const { return m_isHorizontal; }
174    void setIsHorizontal(bool horizontal) { m_isHorizontal = horizontal; }
175
176    virtual IntRect calculateBoundaries() const
177    {
178        ASSERT_NOT_REACHED();
179        return IntRect();
180    }
181
182    bool isConstructed() { return m_constructed; }
183    virtual void setConstructed() { m_constructed = true; }
184
185    void setExtracted(bool b = true) { m_extracted = b; }
186
187    void setFirstLineStyleBit(bool f) { m_firstLine = f; }
188    bool isFirstLineStyle() const { return m_firstLine; }
189
190    void remove();
191
192    InlineBox* nextOnLine() const { return m_next; }
193    InlineBox* prevOnLine() const { return m_prev; }
194    void setNextOnLine(InlineBox* next)
195    {
196        ASSERT(m_parent || !next);
197        m_next = next;
198    }
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
207    virtual bool isLeaf() const { return true; }
208
209    InlineBox* nextLeafChild() const;
210    InlineBox* prevLeafChild() const;
211
212    RenderObject* renderer() const { return m_renderer; }
213
214    InlineFlowBox* parent() const
215    {
216        ASSERT(!m_hasBadParent);
217        return m_parent;
218    }
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.
225    void setX(float x) { m_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.
229    void setY(float y) { m_y = y; }
230    float y() const { return m_y; }
231
232    float width() const { return isHorizontal() ? logicalWidth() : logicalHeight(); }
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.
236    float logicalLeft() const { return isHorizontal() ? m_x : m_y; }
237    float logicalRight() const { return logicalLeft() + logicalWidth(); }
238    void setLogicalLeft(float left)
239    {
240        if (isHorizontal())
241            m_x = left;
242        else
243            m_y = left;
244    }
245    int pixelSnappedLogicalLeft() const { return logicalLeft(); }
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.
249    int logicalTop() const { return isHorizontal() ? m_y : m_x; }
250    int logicalBottom() const { return logicalTop() + logicalHeight(); }
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.
260    void setLogicalWidth(float w) { m_logicalWidth = w; }
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
266    FloatRect logicalFrameRect() const { return isHorizontal() ? IntRect(m_x, m_y, m_logicalWidth, logicalHeight()) : IntRect(m_y, m_x, m_logicalWidth, logicalHeight()); }
267
268    virtual int baselinePosition(FontBaseline baselineType) const { return boxModelObject()->baselinePosition(baselineType, m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); }
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
275    unsigned char bidiLevel() const { return m_bidiEmbeddingLevel; }
276    void setBidiLevel(unsigned char level) { m_bidiEmbeddingLevel = level; }
277    TextDirection direction() const { return m_bidiEmbeddingLevel % 2 ? RTL : LTR; }
278    bool isLeftToRightDirection() const { return direction() == LTR; }
279    int caretLeftmostOffset() const { return isLeftToRightDirection() ? caretMinOffset() : caretMaxOffset(); }
280    int caretRightmostOffset() const { return isLeftToRightDirection() ? caretMaxOffset() : caretMinOffset(); }
281
282    virtual void clearTruncation() { }
283
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
297    int expansion() const { return m_expansion; }
298
299    bool visibleToHitTesting() const { return renderer()->style()->visibility() == VISIBLE && renderer()->style()->pointerEvents() != PE_NONE; }
300
301    EVerticalAlign verticalAlign() const { return renderer()->style(m_firstLine)->verticalAlign(); }
302
303    // Use with caution! The type is not checked!
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
317    bool knownToHaveNoOverflow() const { return m_knownToHaveNoOverflow; }
318    void clearKnownToHaveNoOverflow();
319
320private:
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
326public:
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
336protected:
337    bool m_firstLine : 1;
338private:
339    bool m_constructed : 1;
340    unsigned char m_bidiEmbeddingLevel : 6;
341protected:
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
356public:
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.
359protected:
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
367private:
368    bool m_hasBadParent;
369#endif
370};
371
372#ifdef NDEBUG
373inline InlineBox::~InlineBox()
374{
375}
376#endif
377
378inline 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.
389void showTree(const WebCore::InlineBox*);
390#endif
391
392#endif // InlineBox_h
393