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