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 #include "config.h"
21 #include "core/rendering/InlineBox.h"
22
23 #include "core/paint/BlockPainter.h"
24 #include "core/rendering/InlineFlowBox.h"
25 #include "core/rendering/PaintInfo.h"
26 #include "core/rendering/RenderBlockFlow.h"
27 #include "core/rendering/RenderObjectInlines.h"
28 #include "core/rendering/RootInlineBox.h"
29 #include "platform/Partitions.h"
30 #include "platform/fonts/FontMetrics.h"
31
32 #ifndef NDEBUG
33 #include <stdio.h>
34 #endif
35
36 namespace blink {
37
38 struct SameSizeAsInlineBox {
~SameSizeAsInlineBoxblink::SameSizeAsInlineBox39 virtual ~SameSizeAsInlineBox() { }
40 void* a[4];
41 FloatPoint b;
42 float c;
43 uint32_t d : 32;
44 #if ENABLE(ASSERT)
45 bool f;
46 #endif
47 };
48
49 COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard);
50
51 #if ENABLE(ASSERT)
52
~InlineBox()53 InlineBox::~InlineBox()
54 {
55 if (!m_hasBadParent && m_parent)
56 m_parent->setHasBadChildList();
57 }
58
59 #endif
60
remove(MarkLineBoxes markLineBoxes)61 void InlineBox::remove(MarkLineBoxes markLineBoxes)
62 {
63 if (parent())
64 parent()->removeChild(this, markLineBoxes);
65 }
66
operator new(size_t sz)67 void* InlineBox::operator new(size_t sz)
68 {
69 return partitionAlloc(Partitions::getRenderingPartition(), sz);
70 }
71
operator delete(void * ptr)72 void InlineBox::operator delete(void* ptr)
73 {
74 partitionFree(ptr);
75 }
76
77 #ifndef NDEBUG
boxName() const78 const char* InlineBox::boxName() const
79 {
80 return "InlineBox";
81 }
82
showTreeForThis() const83 void InlineBox::showTreeForThis() const
84 {
85 renderer().showTreeForThis();
86 }
87
showLineTreeForThis() const88 void InlineBox::showLineTreeForThis() const
89 {
90 renderer().containingBlock()->showLineTreeAndMark(this, "*");
91 }
92
showLineTreeAndMark(const InlineBox * markedBox1,const char * markedLabel1,const InlineBox * markedBox2,const char * markedLabel2,const RenderObject * obj,int depth) const93 void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
94 {
95 int printedCharacters = 0;
96 if (this == markedBox1)
97 printedCharacters += fprintf(stderr, "%s", markedLabel1);
98 if (this == markedBox2)
99 printedCharacters += fprintf(stderr, "%s", markedLabel2);
100 if (&renderer() == obj)
101 printedCharacters += fprintf(stderr, "*");
102 for (; printedCharacters < depth * 2; printedCharacters++)
103 fputc(' ', stderr);
104
105 showBox(printedCharacters);
106 }
107
showBox(int printedCharacters) const108 void InlineBox::showBox(int printedCharacters) const
109 {
110 printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
111 for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
112 fputc(' ', stderr);
113 fprintf(stderr, "\t%s %p {pos=%g,%g size=%g,%g} baseline=%i/%i\n",
114 renderer().renderName(), &renderer(), x(), y(), width(), height(),
115 baselinePosition(AlphabeticBaseline),
116 baselinePosition(IdeographicBaseline));
117 }
118 #endif
119
logicalHeight() const120 float InlineBox::logicalHeight() const
121 {
122 if (hasVirtualLogicalHeight())
123 return virtualLogicalHeight();
124
125 if (renderer().isText())
126 return m_bitfields.isText() ? renderer().style(isFirstLineStyle())->fontMetrics().height() : 0;
127 if (renderer().isBox() && parent())
128 return isHorizontal() ? toRenderBox(renderer()).height().toFloat() : toRenderBox(renderer()).width().toFloat();
129
130 ASSERT(isInlineFlowBox());
131 RenderBoxModelObject* flowObject = boxModelObject();
132 const FontMetrics& fontMetrics = renderer().style(isFirstLineStyle())->fontMetrics();
133 float result = fontMetrics.height();
134 if (parent())
135 result += flowObject->borderAndPaddingLogicalHeight();
136 return result;
137 }
138
baselinePosition(FontBaseline baselineType) const139 int InlineBox::baselinePosition(FontBaseline baselineType) const
140 {
141 return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
142 }
143
lineHeight() const144 LayoutUnit InlineBox::lineHeight() const
145 {
146 return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
147 }
148
caretMinOffset() const149 int InlineBox::caretMinOffset() const
150 {
151 return renderer().caretMinOffset();
152 }
153
caretMaxOffset() const154 int InlineBox::caretMaxOffset() const
155 {
156 return renderer().caretMaxOffset();
157 }
158
dirtyLineBoxes()159 void InlineBox::dirtyLineBoxes()
160 {
161 markDirty();
162 for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
163 curr->markDirty();
164 }
165
deleteLine()166 void InlineBox::deleteLine()
167 {
168 if (!m_bitfields.extracted() && renderer().isBox())
169 toRenderBox(renderer()).setInlineBoxWrapper(0);
170 destroy();
171 }
172
extractLine()173 void InlineBox::extractLine()
174 {
175 m_bitfields.setExtracted(true);
176 if (renderer().isBox())
177 toRenderBox(renderer()).setInlineBoxWrapper(0);
178 }
179
attachLine()180 void InlineBox::attachLine()
181 {
182 m_bitfields.setExtracted(false);
183 if (renderer().isBox())
184 toRenderBox(renderer()).setInlineBoxWrapper(this);
185 }
186
adjustPosition(float dx,float dy)187 void InlineBox::adjustPosition(float dx, float dy)
188 {
189 m_topLeft.move(dx, dy);
190
191 if (renderer().isReplaced())
192 toRenderBox(renderer()).move(dx, dy);
193 }
194
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset,LayoutUnit,LayoutUnit)195 void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
196 {
197 BlockPainter::paintInlineBox(*this, paintInfo, paintOffset);
198 }
199
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset,LayoutUnit,LayoutUnit)200 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
201 {
202 // Hit test all phases of replaced elements atomically, as though the replaced element established its
203 // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
204 // specification.)
205 LayoutPoint childPoint = accumulatedOffset;
206 if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
207 childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint);
208
209 return renderer().hitTest(request, result, locationInContainer, childPoint);
210 }
211
root() const212 const RootInlineBox& InlineBox::root() const
213 {
214 if (m_parent)
215 return m_parent->root();
216 ASSERT(isRootInlineBox());
217 return static_cast<const RootInlineBox&>(*this);
218 }
219
root()220 RootInlineBox& InlineBox::root()
221 {
222 if (m_parent)
223 return m_parent->root();
224 ASSERT(isRootInlineBox());
225 return static_cast<RootInlineBox&>(*this);
226 }
227
nextOnLineExists() const228 bool InlineBox::nextOnLineExists() const
229 {
230 if (!m_bitfields.determinedIfNextOnLineExists()) {
231 m_bitfields.setDeterminedIfNextOnLineExists(true);
232
233 if (!parent())
234 m_bitfields.setNextOnLineExists(false);
235 else if (nextOnLine())
236 m_bitfields.setNextOnLineExists(true);
237 else
238 m_bitfields.setNextOnLineExists(parent()->nextOnLineExists());
239 }
240 return m_bitfields.nextOnLineExists();
241 }
242
nextLeafChild() const243 InlineBox* InlineBox::nextLeafChild() const
244 {
245 InlineBox* leaf = 0;
246 for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
247 leaf = box->isLeaf() ? box : toInlineFlowBox(box)->firstLeafChild();
248 if (!leaf && parent())
249 leaf = parent()->nextLeafChild();
250 return leaf;
251 }
252
prevLeafChild() const253 InlineBox* InlineBox::prevLeafChild() const
254 {
255 InlineBox* leaf = 0;
256 for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
257 leaf = box->isLeaf() ? box : toInlineFlowBox(box)->lastLeafChild();
258 if (!leaf && parent())
259 leaf = parent()->prevLeafChild();
260 return leaf;
261 }
262
nextLeafChildIgnoringLineBreak() const263 InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const
264 {
265 InlineBox* leaf = nextLeafChild();
266 if (leaf && leaf->isLineBreak())
267 return 0;
268 return leaf;
269 }
270
prevLeafChildIgnoringLineBreak() const271 InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const
272 {
273 InlineBox* leaf = prevLeafChild();
274 if (leaf && leaf->isLineBreak())
275 return 0;
276 return leaf;
277 }
278
selectionState() const279 RenderObject::SelectionState InlineBox::selectionState() const
280 {
281 return renderer().selectionState();
282 }
283
canAccommodateEllipsis(bool ltr,int blockEdge,int ellipsisWidth) const284 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
285 {
286 // Non-replaced elements can always accommodate an ellipsis.
287 if (!renderer().isReplaced())
288 return true;
289
290 IntRect boxRect(left(), 0, m_logicalWidth, 10);
291 IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
292 return !(boxRect.intersects(ellipsisRect));
293 }
294
placeEllipsisBox(bool,float,float,float,float & truncatedWidth,bool &)295 float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&)
296 {
297 // Use -1 to mean "we didn't set the position."
298 truncatedWidth += logicalWidth();
299 return -1;
300 }
301
clearKnownToHaveNoOverflow()302 void InlineBox::clearKnownToHaveNoOverflow()
303 {
304 m_bitfields.setKnownToHaveNoOverflow(false);
305 if (parent() && parent()->knownToHaveNoOverflow())
306 parent()->clearKnownToHaveNoOverflow();
307 }
308
locationIncludingFlipping()309 FloatPoint InlineBox::locationIncludingFlipping()
310 {
311 if (!renderer().style()->isFlippedBlocksWritingMode())
312 return FloatPoint(x(), y());
313 RenderBlockFlow& block = root().block();
314 if (block.style()->isHorizontalWritingMode())
315 return FloatPoint(x(), block.height() - height() - y());
316
317 return FloatPoint(block.width() - width() - x(), y());
318 }
319
flipForWritingMode(FloatRect & rect)320 void InlineBox::flipForWritingMode(FloatRect& rect)
321 {
322 if (!renderer().style()->isFlippedBlocksWritingMode())
323 return;
324 root().block().flipForWritingMode(rect);
325 }
326
flipForWritingMode(const FloatPoint & point)327 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
328 {
329 if (!renderer().style()->isFlippedBlocksWritingMode())
330 return point;
331 return root().block().flipForWritingMode(point);
332 }
333
flipForWritingMode(LayoutRect & rect)334 void InlineBox::flipForWritingMode(LayoutRect& rect)
335 {
336 if (!renderer().style()->isFlippedBlocksWritingMode())
337 return;
338 root().block().flipForWritingMode(rect);
339 }
340
flipForWritingMode(const LayoutPoint & point)341 LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point)
342 {
343 if (!renderer().style()->isFlippedBlocksWritingMode())
344 return point;
345 return root().block().flipForWritingMode(point);
346 }
347
348 } // namespace blink
349
350 #ifndef NDEBUG
351
showTree(const blink::InlineBox * b)352 void showTree(const blink::InlineBox* b)
353 {
354 if (b)
355 b->showTreeForThis();
356 }
357
showLineTree(const blink::InlineBox * b)358 void showLineTree(const blink::InlineBox* b)
359 {
360 if (b)
361 b->showLineTreeForThis();
362 }
363
364 #endif
365