SameSizeAsInlineBox mismatch on ARMV7.
[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 #pragma once
22
23 #include "RenderBoxModelObject.h"
24 #include "RenderText.h"
25 #include "TextFlags.h"
26 #include <wtf/TypeCasts.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     WTF_MAKE_FAST_ALLOCATED;
38 public:
39     virtual ~InlineBox();
40
41     void assertNotDeleted() const;
42
43     virtual void deleteLine() = 0;
44     virtual void extractLine() = 0;
45     virtual void attachLine() = 0;
46
47     virtual bool isLineBreak() const { return renderer().isLineBreak(); }
48
49     WEBCORE_EXPORT virtual void adjustPosition(float dx, float dy);
50     void adjustLogicalPosition(float deltaLogicalLeft, float deltaLogicalTop)
51     {
52         if (isHorizontal())
53             adjustPosition(deltaLogicalLeft, deltaLogicalTop);
54         else
55             adjustPosition(deltaLogicalTop, deltaLogicalLeft);
56     }
57     void adjustLineDirectionPosition(float delta)
58     {
59         if (isHorizontal())
60             adjustPosition(delta, 0);
61         else
62             adjustPosition(0, delta);
63     }
64     void adjustBlockDirectionPosition(float delta)
65     {
66         if (isHorizontal())
67             adjustPosition(0, delta);
68         else
69             adjustPosition(delta, 0);
70     }
71
72     virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) = 0;
73     virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom, HitTestAction) = 0;
74
75 #if ENABLE(TREE_DEBUGGING)
76     void showNodeTreeForThis() const;
77     void showLineTreeForThis() const;
78     
79     virtual void showLineTreeAndMark(const InlineBox* markedBox, int depth) const;
80     virtual void showLineBox(bool mark, int depth) const;
81     virtual const char* boxName() const;
82 #endif
83
84     bool behavesLikeText() const { return m_bitfields.behavesLikeText(); }
85     void setBehavesLikeText(bool behavesLikeText) { m_bitfields.setBehavesLikeText(behavesLikeText); }
86
87     virtual bool isInlineElementBox() const { return false; }
88     virtual bool isInlineFlowBox() const { return false; }
89     virtual bool isInlineTextBox() const { return false; }
90     virtual bool isRootInlineBox() const { return false; }
91     virtual bool isSVGInlineTextBox() const { return false; }
92     virtual bool isSVGInlineFlowBox() const { return false; }
93     virtual bool isSVGRootInlineBox() const { return false; }
94
95     bool hasVirtualLogicalHeight() const { return m_bitfields.hasVirtualLogicalHeight(); }
96     void setHasVirtualLogicalHeight() { m_bitfields.setHasVirtualLogicalHeight(true); }
97     virtual float virtualLogicalHeight() const
98     {
99         ASSERT_NOT_REACHED();
100         return 0;
101     }
102
103     bool isHorizontal() const { return m_bitfields.isHorizontal(); }
104     void setIsHorizontal(bool isHorizontal) { m_bitfields.setIsHorizontal(isHorizontal); }
105
106     virtual FloatRect calculateBoundaries() const
107     {
108         ASSERT_NOT_REACHED();
109         return FloatRect();
110     }
111
112     bool isConstructed() { return m_bitfields.constructed(); }
113     virtual void setConstructed() { m_bitfields.setConstructed(true); }
114
115     void setExtracted(bool extracted = true) { m_bitfields.setExtracted(extracted); }
116     
117     void setIsFirstLine(bool firstLine) { m_bitfields.setFirstLine(firstLine); }
118     bool isFirstLine() const { return m_bitfields.firstLine(); }
119
120     void removeFromParent();
121
122     InlineBox* nextOnLine() const { return m_next; }
123     InlineBox* prevOnLine() const { return m_prev; }
124     void setNextOnLine(InlineBox* next)
125     {
126         ASSERT(m_parent || !next);
127         m_next = next;
128     }
129     void setPrevOnLine(InlineBox* prev)
130     {
131         ASSERT(m_parent || !prev);
132         m_prev = prev;
133     }
134     bool nextOnLineExists() const;
135     bool previousOnLineExists() const;
136
137     virtual bool isLeaf() const { return true; }
138     
139     InlineBox* nextLeafChild() const;
140     InlineBox* prevLeafChild() const;
141
142     // Helper functions for editing and hit-testing code.
143     // FIXME: These two functions should be moved to RenderedPosition once the code to convert between
144     // Position and inline box, offset pair is moved to RenderedPosition.
145     InlineBox* nextLeafChildIgnoringLineBreak() const;
146     InlineBox* prevLeafChildIgnoringLineBreak() const;
147
148     // FIXME: Hide this once all callers are using tighter types.
149     RenderObject& renderer() const { return m_renderer; }
150
151     InlineFlowBox* parent() const
152     {
153         assertNotDeleted();
154         ASSERT_WITH_SECURITY_IMPLICATION(!m_hasBadParent);
155         return m_parent;
156     }
157     void setParent(InlineFlowBox* par) { m_parent = par; }
158
159     const RootInlineBox& root() const;
160     RootInlineBox& root();
161
162     // x() is the left side of the box in the containing block's coordinate system.
163     void setX(float x) { m_topLeft.setX(x); }
164     float x() const { return m_topLeft.x(); }
165     float left() const { return m_topLeft.x(); }
166
167     // y() is the top side of the box in the containing block's coordinate system.
168     void setY(float y) { m_topLeft.setY(y); }
169     float y() const { return m_topLeft.y(); }
170     float top() const { return m_topLeft.y(); }
171
172     const FloatPoint& topLeft() const { return m_topLeft; }
173
174     float width() const { return isHorizontal() ? logicalWidth() : logicalHeight(); }
175     float height() const { return isHorizontal() ? logicalHeight() : logicalWidth(); }
176     FloatSize size() const { return FloatSize(width(), height()); }
177     float right() const { return left() + width(); }
178     float bottom() const { return top() + height(); }
179
180     // The logicalLeft position is the left edge of the line box in a horizontal line and the top edge in a vertical line.
181     float logicalLeft() const { return isHorizontal() ? m_topLeft.x() : m_topLeft.y(); }
182     float logicalRight() const { return logicalLeft() + logicalWidth(); }
183     void setLogicalLeft(float left)
184     {
185         if (isHorizontal())
186             setX(left);
187         else
188             setY(left);
189     }
190
191     // The logicalTop[ position is the top edge of the line box in a horizontal line and the left edge in a vertical line.
192     float logicalTop() const { return isHorizontal() ? m_topLeft.y() : m_topLeft.x(); }
193     float logicalBottom() const { return logicalTop() + logicalHeight(); }
194     void setLogicalTop(float top)
195     {
196         if (isHorizontal())
197             setY(top);
198         else
199             setX(top);
200     }
201
202     // The logical width is our extent in the line's overall inline direction, i.e., width for horizontal text and height for vertical text.
203     void setLogicalWidth(float w) { m_logicalWidth = w; }
204     float logicalWidth() const { return m_logicalWidth; }
205
206     // The logical height is our extent in the block flow direction, i.e., height for horizontal text and width for vertical text.
207     float logicalHeight() const;
208
209     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()); }
210     FloatRect frameRect() const { return FloatRect(topLeft(), size()); }
211
212     WEBCORE_EXPORT virtual int baselinePosition(FontBaseline baselineType) const;
213     WEBCORE_EXPORT virtual LayoutUnit lineHeight() const;
214
215     WEBCORE_EXPORT virtual int caretMinOffset() const;
216     WEBCORE_EXPORT virtual int caretMaxOffset() const;
217
218     unsigned char bidiLevel() const { return m_bitfields.bidiEmbeddingLevel(); }
219     void setBidiLevel(unsigned char level) { m_bitfields.setBidiEmbeddingLevel(level); }
220     TextDirection direction() const { return bidiLevel() % 2 ? RTL : LTR; }
221     bool isLeftToRightDirection() const { return direction() == LTR; }
222     int caretLeftmostOffset() const { return isLeftToRightDirection() ? caretMinOffset() : caretMaxOffset(); }
223     int caretRightmostOffset() const { return isLeftToRightDirection() ? caretMaxOffset() : caretMinOffset(); }
224
225     virtual void clearTruncation() { }
226
227     bool isDirty() const { return m_bitfields.dirty(); }
228     virtual void markDirty(bool dirty = true) { m_bitfields.setDirty(dirty); }
229
230     WEBCORE_EXPORT virtual void dirtyLineBoxes();
231     
232     WEBCORE_EXPORT virtual RenderObject::SelectionState selectionState();
233
234     WEBCORE_EXPORT virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const;
235     // visibleLeftEdge, visibleRightEdge are in the parent's coordinate system.
236     WEBCORE_EXPORT virtual float placeEllipsisBox(bool ltr, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, float &truncatedWidth, bool&);
237
238 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
239     void setHasBadParent();
240     void invalidateParentChildList();
241 #endif
242
243     bool visibleToHitTesting() const { return renderer().style().visibility() == VISIBLE && renderer().style().pointerEvents() != PE_NONE; }
244
245     const RenderStyle& lineStyle() const { return m_bitfields.firstLine() ? renderer().firstLineStyle() : renderer().style(); }
246     
247     EVerticalAlign verticalAlign() const { return lineStyle().verticalAlign(); }
248
249     // Use with caution! The type is not checked!
250     RenderBoxModelObject* boxModelObject() const
251     { 
252         if (!is<RenderText>(m_renderer))
253             return &downcast<RenderBoxModelObject>(m_renderer);
254         return nullptr;
255     }
256
257     FloatPoint locationIncludingFlipping();
258     void flipForWritingMode(FloatRect&);
259     FloatPoint flipForWritingMode(const FloatPoint&);
260     void flipForWritingMode(LayoutRect&);
261     LayoutPoint flipForWritingMode(const LayoutPoint&);
262
263     bool knownToHaveNoOverflow() const { return m_bitfields.knownToHaveNoOverflow(); }
264     void clearKnownToHaveNoOverflow();
265
266     bool dirOverride() const { return m_bitfields.dirOverride(); }
267     void setDirOverride(bool dirOverride) { m_bitfields.setDirOverride(dirOverride); }
268
269     void setExpansion(float newExpansion)
270     {
271         m_logicalWidth -= m_expansion;
272         m_expansion = newExpansion;
273         m_logicalWidth += m_expansion;
274     }
275     void setExpansionWithoutGrowing(float newExpansion)
276     {
277         ASSERT(!m_expansion);
278         m_expansion = newExpansion;
279     }
280     float expansion() const { return m_expansion; }
281
282 private:
283     InlineBox* m_next { nullptr }; // The next element on the same line as us.
284     InlineBox* m_prev { nullptr }; // The previous element on the same line as us.
285
286     InlineFlowBox* m_parent { nullptr }; // The box that contains us.
287
288     RenderObject& m_renderer;
289
290 public:
291     FloatPoint m_topLeft;
292     float m_logicalWidth { 0 };
293
294 #define ADD_BOOLEAN_BITFIELD(name, Name) \
295     private:\
296     unsigned m_##name : 1;\
297     public:\
298     bool name() const { return m_##name; }\
299     void set##Name(bool name) { m_##name = name; }\
300
301     class InlineBoxBitfields {
302     public:
303         explicit InlineBoxBitfields(bool firstLine = false, bool constructed = false, bool dirty = false, bool extracted = false, bool isHorizontal = true)
304             : m_firstLine(firstLine)
305             , m_constructed(constructed)
306             , m_bidiEmbeddingLevel(0)
307             , m_dirty(dirty)
308             , m_extracted(extracted)
309             , m_hasVirtualLogicalHeight(false)
310             , m_isHorizontal(isHorizontal)
311             , m_endsWithBreak(false)
312             , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false)
313             , m_canHaveTrailingExpansion(false)
314             , m_knownToHaveNoOverflow(true)  
315             , m_hasEllipsisBoxOrHyphen(false)
316             , m_dirOverride(false)
317             , m_behavesLikeText(false)
318             , m_forceTrailingExpansion(false)
319             , m_forceLeadingExpansion(false)
320             , m_determinedIfNextOnLineExists(false)
321             , m_nextOnLineExists(false)
322         {
323         }
324
325         // Some of these bits are actually for subclasses and moved here to compact the structures.
326         // for this class
327         ADD_BOOLEAN_BITFIELD(firstLine, FirstLine);
328         ADD_BOOLEAN_BITFIELD(constructed, Constructed);
329
330     private:
331         unsigned m_bidiEmbeddingLevel : 6; // The maximium bidi level is 62: http://unicode.org/reports/tr9/#Explicit_Levels_and_Directions
332
333     public:
334         unsigned char bidiEmbeddingLevel() const { return m_bidiEmbeddingLevel; }
335         void setBidiEmbeddingLevel(unsigned char bidiEmbeddingLevel) { m_bidiEmbeddingLevel = bidiEmbeddingLevel; }
336
337         ADD_BOOLEAN_BITFIELD(dirty, Dirty);
338         ADD_BOOLEAN_BITFIELD(extracted, Extracted);
339         ADD_BOOLEAN_BITFIELD(hasVirtualLogicalHeight, HasVirtualLogicalHeight);
340         ADD_BOOLEAN_BITFIELD(isHorizontal, IsHorizontal);
341         // for RootInlineBox
342         ADD_BOOLEAN_BITFIELD(endsWithBreak, EndsWithBreak); // Whether the line ends with a <br>.
343         // shared between RootInlineBox and InlineTextBox
344         ADD_BOOLEAN_BITFIELD(hasSelectedChildrenOrCanHaveLeadingExpansion, HasSelectedChildrenOrCanHaveLeadingExpansion);
345         ADD_BOOLEAN_BITFIELD(canHaveTrailingExpansion, CanHaveTrailingExpansion);
346         ADD_BOOLEAN_BITFIELD(knownToHaveNoOverflow, KnownToHaveNoOverflow);
347         ADD_BOOLEAN_BITFIELD(hasEllipsisBoxOrHyphen, HasEllipsisBoxOrHyphen);
348         // for InlineTextBox
349         ADD_BOOLEAN_BITFIELD(dirOverride, DirOverride);
350         ADD_BOOLEAN_BITFIELD(behavesLikeText, BehavesLikeText); // Whether or not this object represents text with a non-zero height. Includes non-image list markers, text boxes, br.
351         ADD_BOOLEAN_BITFIELD(forceTrailingExpansion, ForceTrailingExpansion);
352         ADD_BOOLEAN_BITFIELD(forceLeadingExpansion, ForceLeadingExpansion);
353
354     private:
355         mutable unsigned m_determinedIfNextOnLineExists : 1;
356
357     public:
358         bool determinedIfNextOnLineExists() const { return m_determinedIfNextOnLineExists; }
359         void setDeterminedIfNextOnLineExists(bool determinedIfNextOnLineExists) const { m_determinedIfNextOnLineExists = determinedIfNextOnLineExists; }
360
361     private:
362         mutable unsigned m_nextOnLineExists : 1;
363         
364     public:
365         bool nextOnLineExists() const { return m_nextOnLineExists; }
366         void setNextOnLineExists(bool nextOnLineExists) const { m_nextOnLineExists = nextOnLineExists; }
367     };
368 #undef ADD_BOOLEAN_BITFIELD
369
370 private:
371     float m_expansion { 0 };
372     InlineBoxBitfields m_bitfields;
373
374 protected:
375     explicit InlineBox(RenderObject& renderer)
376         : m_renderer(renderer)
377     {
378     }
379
380     InlineBox(RenderObject& renderer, FloatPoint topLeft, float logicalWidth, bool firstLine, bool constructed, bool dirty, bool extracted, bool isHorizontal, InlineBox* next, InlineBox* prev, InlineFlowBox* parent)
381         : m_next(next)
382         , m_prev(prev)
383         , m_parent(parent)
384         , m_renderer(renderer)
385         , m_topLeft(topLeft)
386         , m_logicalWidth(logicalWidth)
387         , m_bitfields(firstLine, constructed, dirty, extracted, isHorizontal)
388     {
389     }
390
391     // For RootInlineBox
392     bool endsWithBreak() const { return m_bitfields.endsWithBreak(); }
393     void setEndsWithBreak(bool endsWithBreak) { m_bitfields.setEndsWithBreak(endsWithBreak); }
394     bool hasEllipsisBox() const { return m_bitfields.hasEllipsisBoxOrHyphen(); }
395     bool hasSelectedChildren() const { return m_bitfields.hasSelectedChildrenOrCanHaveLeadingExpansion(); }
396     void setHasSelectedChildren(bool hasSelectedChildren) { m_bitfields.setHasSelectedChildrenOrCanHaveLeadingExpansion(hasSelectedChildren); }
397     void setHasEllipsisBox(bool hasEllipsisBox) { m_bitfields.setHasEllipsisBoxOrHyphen(hasEllipsisBox); }
398
399     // For InlineTextBox
400     bool hasHyphen() const { return m_bitfields.hasEllipsisBoxOrHyphen(); }
401     void setHasHyphen(bool hasHyphen) { m_bitfields.setHasEllipsisBoxOrHyphen(hasHyphen); }    
402     bool canHaveLeadingExpansion() const { return m_bitfields.hasSelectedChildrenOrCanHaveLeadingExpansion(); }
403     void setCanHaveLeadingExpansion(bool canHaveLeadingExpansion) { m_bitfields.setHasSelectedChildrenOrCanHaveLeadingExpansion(canHaveLeadingExpansion); }
404     bool canHaveTrailingExpansion() const { return m_bitfields.canHaveTrailingExpansion(); }
405     void setCanHaveTrailingExpansion(bool canHaveTrailingExpansion) { m_bitfields.setCanHaveTrailingExpansion(canHaveTrailingExpansion); }
406     void setForceTrailingExpansion() { m_bitfields.setForceTrailingExpansion(true); }
407     bool forceTrailingExpansion() const { return m_bitfields.forceTrailingExpansion(); }
408     void setForceLeadingExpansion() { m_bitfields.setForceLeadingExpansion(true); }
409     bool forceLeadingExpansion() const { return m_bitfields.forceLeadingExpansion(); }
410     
411     // For InlineFlowBox and InlineTextBox
412     bool extracted() const { return m_bitfields.extracted(); }
413
414 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
415 private:
416     static constexpr unsigned deletionSentinelNotDeletedValue = 0xF0F0F0F0U;
417     static constexpr unsigned deletionSentinelDeletedValue = 0xF0DEADF0U;
418     unsigned m_deletionSentinel { deletionSentinelNotDeletedValue };
419     bool m_hasBadParent { false };
420 protected:
421     bool m_isEverInChildList { true };
422 #endif
423 };
424
425 #if ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
426
427 inline InlineBox::~InlineBox()
428 {
429 }
430
431 inline void InlineBox::assertNotDeleted() const
432 {
433 }
434
435 #endif
436
437 } // namespace WebCore
438
439 #define SPECIALIZE_TYPE_TRAITS_INLINE_BOX(ToValueTypeName, predicate) \
440 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \
441     static bool isType(const WebCore::InlineBox& box) { return box.predicate; } \
442 SPECIALIZE_TYPE_TRAITS_END()
443
444 #if ENABLE(TREE_DEBUGGING)
445 // Outside the WebCore namespace for ease of invocation from the debugger.
446 void showNodeTree(const WebCore::InlineBox*);
447 void showLineTree(const WebCore::InlineBox*);
448 #endif