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 "InlineBox.h"
22
23 #include "HitTestResult.h"
24 #include "InlineFlowBox.h"
25 #include "PaintInfo.h"
26 #include "RenderArena.h"
27 #include "RenderBlock.h"
28 #include "RootInlineBox.h"
29
30 using namespace std;
31
32 namespace WebCore {
33
34 #ifndef NDEBUG
35 static bool inInlineBoxDetach;
36 #endif
37
38 #ifndef NDEBUG
39
~InlineBox()40 InlineBox::~InlineBox()
41 {
42 if (!m_hasBadParent && m_parent)
43 m_parent->setHasBadChildList();
44 }
45
46 #endif
47
remove()48 void InlineBox::remove()
49 {
50 if (parent())
51 parent()->removeChild(this);
52 }
53
destroy(RenderArena * renderArena)54 void InlineBox::destroy(RenderArena* renderArena)
55 {
56 #ifndef NDEBUG
57 inInlineBoxDetach = true;
58 #endif
59 delete this;
60 #ifndef NDEBUG
61 inInlineBoxDetach = false;
62 #endif
63
64 // Recover the size left there for us by operator delete and free the memory.
65 renderArena->free(*(size_t *)this, this);
66 }
67
operator new(size_t sz,RenderArena * renderArena)68 void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw()
69 {
70 return renderArena->allocate(sz);
71 }
72
operator delete(void * ptr,size_t sz)73 void InlineBox::operator delete(void* ptr, size_t sz)
74 {
75 ASSERT(inInlineBoxDetach);
76
77 // Stash size where destroy can find it.
78 *(size_t *)ptr = sz;
79 }
80
81 #ifndef NDEBUG
boxName() const82 const char* InlineBox::boxName() const
83 {
84 return "InlineBox";
85 }
86
showTreeForThis() const87 void InlineBox::showTreeForThis() const
88 {
89 if (m_renderer)
90 m_renderer->showTreeForThis();
91 }
92
showLineTreeForThis() const93 void InlineBox::showLineTreeForThis() const
94 {
95 if (m_renderer)
96 m_renderer->containingBlock()->showLineTreeAndMark(this, "*");
97 }
98
showLineTreeAndMark(const InlineBox * markedBox1,const char * markedLabel1,const InlineBox * markedBox2,const char * markedLabel2,const RenderObject * obj,int depth) const99 void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
100 {
101 int printedCharacters = 0;
102 if (this == markedBox1)
103 printedCharacters += fprintf(stderr, "%s", markedLabel1);
104 if (this == markedBox2)
105 printedCharacters += fprintf(stderr, "%s", markedLabel2);
106 if (renderer() == obj)
107 printedCharacters += fprintf(stderr, "*");
108 for (; printedCharacters < depth * 2; printedCharacters++)
109 fputc(' ', stderr);
110
111 showBox(printedCharacters);
112 }
113
showBox(int printedCharacters) const114 void InlineBox::showBox(int printedCharacters) const
115 {
116 printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
117 for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
118 fputc(' ', stderr);
119 fprintf(stderr, "\t%s %p\n", renderer() ? renderer()->renderName() : "No Renderer", renderer());
120 }
121 #endif
122
logicalHeight() const123 int InlineBox::logicalHeight() const
124 {
125 #if ENABLE(SVG)
126 if (hasVirtualLogicalHeight())
127 return virtualLogicalHeight();
128 #endif
129
130 if (renderer()->isText())
131 return m_isText ? renderer()->style(m_firstLine)->fontMetrics().height() : 0;
132 if (renderer()->isBox() && parent())
133 return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width();
134
135 ASSERT(isInlineFlowBox());
136 RenderBoxModelObject* flowObject = boxModelObject();
137 const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics();
138 int result = fontMetrics.height();
139 if (parent())
140 result += flowObject->borderAndPaddingLogicalHeight();
141 return result;
142 }
143
caretMinOffset() const144 int InlineBox::caretMinOffset() const
145 {
146 return m_renderer->caretMinOffset();
147 }
148
caretMaxOffset() const149 int InlineBox::caretMaxOffset() const
150 {
151 return m_renderer->caretMaxOffset();
152 }
153
caretMaxRenderedOffset() const154 unsigned InlineBox::caretMaxRenderedOffset() const
155 {
156 return 1;
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(RenderArena * arena)166 void InlineBox::deleteLine(RenderArena* arena)
167 {
168 if (!m_extracted && m_renderer->isBox())
169 toRenderBox(m_renderer)->setInlineBoxWrapper(0);
170 destroy(arena);
171 }
172
extractLine()173 void InlineBox::extractLine()
174 {
175 m_extracted = true;
176 if (m_renderer->isBox())
177 toRenderBox(m_renderer)->setInlineBoxWrapper(0);
178 }
179
attachLine()180 void InlineBox::attachLine()
181 {
182 m_extracted = false;
183 if (m_renderer->isBox())
184 toRenderBox(m_renderer)->setInlineBoxWrapper(this);
185 }
186
adjustPosition(float dx,float dy)187 void InlineBox::adjustPosition(float dx, float dy)
188 {
189 m_x += dx;
190 m_y += dy;
191
192 if (m_renderer->isReplaced())
193 toRenderBox(m_renderer)->move(dx, dy);
194 }
195
paint(PaintInfo & paintInfo,int tx,int ty,int,int)196 void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty, int /* lineTop */, int /*lineBottom*/)
197 {
198 if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
199 return;
200
201 IntPoint childPoint = IntPoint(tx, ty);
202 if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
203 childPoint = renderer()->containingBlock()->flipForWritingMode(toRenderBox(renderer()), childPoint, RenderBox::ParentToChildFlippingAdjustment);
204
205 // Paint all phases of replaced elements atomically, as though the replaced element established its
206 // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
207 // specification.)
208 bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
209 PaintInfo info(paintInfo);
210 info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
211 renderer()->paint(info, childPoint.x(), childPoint.y());
212 if (!preservePhase) {
213 info.phase = PaintPhaseChildBlockBackgrounds;
214 renderer()->paint(info, childPoint.x(), childPoint.y());
215 info.phase = PaintPhaseFloat;
216 renderer()->paint(info, childPoint.x(), childPoint.y());
217 info.phase = PaintPhaseForeground;
218 renderer()->paint(info, childPoint.x(), childPoint.y());
219 info.phase = PaintPhaseOutline;
220 renderer()->paint(info, childPoint.x(), childPoint.y());
221 }
222 }
223
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,int,int)224 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, int /* lineTop */, int /*lineBottom*/)
225 {
226 // Hit test all phases of replaced elements atomically, as though the replaced element established its
227 // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
228 // specification.)
229 return renderer()->hitTest(request, result, IntPoint(x, y), tx, ty);
230 }
231
root() const232 const RootInlineBox* InlineBox::root() const
233 {
234 if (m_parent)
235 return m_parent->root();
236 ASSERT(isRootInlineBox());
237 return static_cast<const RootInlineBox*>(this);
238 }
239
root()240 RootInlineBox* InlineBox::root()
241 {
242 if (m_parent)
243 return m_parent->root();
244 ASSERT(isRootInlineBox());
245 return static_cast<RootInlineBox*>(this);
246 }
247
nextOnLineExists() const248 bool InlineBox::nextOnLineExists() const
249 {
250 if (!m_determinedIfNextOnLineExists) {
251 m_determinedIfNextOnLineExists = true;
252
253 if (!parent())
254 m_nextOnLineExists = false;
255 else if (nextOnLine())
256 m_nextOnLineExists = true;
257 else
258 m_nextOnLineExists = parent()->nextOnLineExists();
259 }
260 return m_nextOnLineExists;
261 }
262
prevOnLineExists() const263 bool InlineBox::prevOnLineExists() const
264 {
265 if (!m_determinedIfPrevOnLineExists) {
266 m_determinedIfPrevOnLineExists = true;
267
268 if (!parent())
269 m_prevOnLineExists = false;
270 else if (prevOnLine())
271 m_prevOnLineExists = true;
272 else
273 m_prevOnLineExists = parent()->prevOnLineExists();
274 }
275 return m_prevOnLineExists;
276 }
277
nextLeafChild() const278 InlineBox* InlineBox::nextLeafChild() const
279 {
280 InlineBox* leaf = 0;
281 for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
282 leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->firstLeafChild();
283 if (!leaf && parent())
284 leaf = parent()->nextLeafChild();
285 return leaf;
286 }
287
prevLeafChild() const288 InlineBox* InlineBox::prevLeafChild() const
289 {
290 InlineBox* leaf = 0;
291 for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
292 leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->lastLeafChild();
293 if (!leaf && parent())
294 leaf = parent()->prevLeafChild();
295 return leaf;
296 }
297
selectionState()298 RenderObject::SelectionState InlineBox::selectionState()
299 {
300 return renderer()->selectionState();
301 }
302
canAccommodateEllipsis(bool ltr,int blockEdge,int ellipsisWidth)303 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
304 {
305 // Non-replaced elements can always accommodate an ellipsis.
306 if (!m_renderer || !m_renderer->isReplaced())
307 return true;
308
309 IntRect boxRect(m_x, 0, m_logicalWidth, 10);
310 IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
311 return !(boxRect.intersects(ellipsisRect));
312 }
313
placeEllipsisBox(bool,float,float,float,bool &)314 float InlineBox::placeEllipsisBox(bool, float, float, float, bool&)
315 {
316 // Use -1 to mean "we didn't set the position."
317 return -1;
318 }
319
clearKnownToHaveNoOverflow()320 void InlineBox::clearKnownToHaveNoOverflow()
321 {
322 m_knownToHaveNoOverflow = false;
323 if (parent() && parent()->knownToHaveNoOverflow())
324 parent()->clearKnownToHaveNoOverflow();
325 }
326
locationIncludingFlipping()327 FloatPoint InlineBox::locationIncludingFlipping()
328 {
329 if (!renderer()->style()->isFlippedBlocksWritingMode())
330 return FloatPoint(x(), y());
331 RenderBlock* block = root()->block();
332 if (block->style()->isHorizontalWritingMode())
333 return FloatPoint(x(), block->height() - height() - y());
334 else
335 return FloatPoint(block->width() - width() - x(), y());
336 }
337
flipForWritingMode(FloatRect & rect)338 void InlineBox::flipForWritingMode(FloatRect& rect)
339 {
340 if (!renderer()->style()->isFlippedBlocksWritingMode())
341 return;
342 root()->block()->flipForWritingMode(rect);
343 }
344
flipForWritingMode(const FloatPoint & point)345 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
346 {
347 if (!renderer()->style()->isFlippedBlocksWritingMode())
348 return point;
349 return root()->block()->flipForWritingMode(point);
350 }
351
flipForWritingMode(IntRect & rect)352 void InlineBox::flipForWritingMode(IntRect& rect)
353 {
354 if (!renderer()->style()->isFlippedBlocksWritingMode())
355 return;
356 root()->block()->flipForWritingMode(rect);
357 }
358
flipForWritingMode(const IntPoint & point)359 IntPoint InlineBox::flipForWritingMode(const IntPoint& point)
360 {
361 if (!renderer()->style()->isFlippedBlocksWritingMode())
362 return point;
363 return root()->block()->flipForWritingMode(point);
364 }
365
366 } // namespace WebCore
367
368 #ifndef NDEBUG
369
showTree(const WebCore::InlineBox * b)370 void showTree(const WebCore::InlineBox* b)
371 {
372 if (b)
373 b->showTreeForThis();
374 }
375
showLineTree(const WebCore::InlineBox * b)376 void showLineTree(const WebCore::InlineBox* b)
377 {
378 if (b)
379 b->showLineTreeForThis();
380 }
381
382 #endif
383