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