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