• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
showTreeForThis() const82 void InlineBox::showTreeForThis() const
83 {
84     if (m_renderer)
85         m_renderer->showTreeForThis();
86 }
87 #endif
88 
logicalHeight() const89 int InlineBox::logicalHeight() const
90 {
91 #if ENABLE(SVG)
92     if (hasVirtualLogicalHeight())
93         return virtualLogicalHeight();
94 #endif
95 
96     if (renderer()->isText())
97         return m_isText ? renderer()->style(m_firstLine)->fontMetrics().height() : 0;
98     if (renderer()->isBox() && parent())
99         return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width();
100 
101     ASSERT(isInlineFlowBox());
102     RenderBoxModelObject* flowObject = boxModelObject();
103     const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics();
104     int result = fontMetrics.height();
105     if (parent())
106         result += flowObject->borderAndPaddingLogicalHeight();
107     return result;
108 }
109 
caretMinOffset() const110 int InlineBox::caretMinOffset() const
111 {
112     return m_renderer->caretMinOffset();
113 }
114 
caretMaxOffset() const115 int InlineBox::caretMaxOffset() const
116 {
117     return m_renderer->caretMaxOffset();
118 }
119 
caretMaxRenderedOffset() const120 unsigned InlineBox::caretMaxRenderedOffset() const
121 {
122     return 1;
123 }
124 
dirtyLineBoxes()125 void InlineBox::dirtyLineBoxes()
126 {
127     markDirty();
128     for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
129         curr->markDirty();
130 }
131 
deleteLine(RenderArena * arena)132 void InlineBox::deleteLine(RenderArena* arena)
133 {
134     if (!m_extracted && m_renderer->isBox())
135         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
136     destroy(arena);
137 }
138 
extractLine()139 void InlineBox::extractLine()
140 {
141     m_extracted = true;
142     if (m_renderer->isBox())
143         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
144 }
145 
attachLine()146 void InlineBox::attachLine()
147 {
148     m_extracted = false;
149     if (m_renderer->isBox())
150         toRenderBox(m_renderer)->setInlineBoxWrapper(this);
151 }
152 
adjustPosition(float dx,float dy)153 void InlineBox::adjustPosition(float dx, float dy)
154 {
155     m_x += dx;
156     m_y += dy;
157 
158     if (m_renderer->isReplaced())
159         toRenderBox(m_renderer)->move(dx, dy);
160 }
161 
paint(PaintInfo & paintInfo,int tx,int ty,int,int)162 void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty, int /* lineTop */, int /*lineBottom*/)
163 {
164     if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
165         return;
166 
167     IntPoint childPoint = IntPoint(tx, ty);
168     if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
169         childPoint = renderer()->containingBlock()->flipForWritingMode(toRenderBox(renderer()), childPoint, RenderBox::ParentToChildFlippingAdjustment);
170 
171     // Paint all phases of replaced elements atomically, as though the replaced element established its
172     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
173     // specification.)
174     bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
175     PaintInfo info(paintInfo);
176     info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
177     renderer()->paint(info, childPoint.x(), childPoint.y());
178     if (!preservePhase) {
179         info.phase = PaintPhaseChildBlockBackgrounds;
180         renderer()->paint(info, childPoint.x(), childPoint.y());
181         info.phase = PaintPhaseFloat;
182         renderer()->paint(info, childPoint.x(), childPoint.y());
183         info.phase = PaintPhaseForeground;
184         renderer()->paint(info, childPoint.x(), childPoint.y());
185         info.phase = PaintPhaseOutline;
186         renderer()->paint(info, childPoint.x(), childPoint.y());
187     }
188 }
189 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,int,int)190 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, int /* lineTop */, int /*lineBottom*/)
191 {
192     // Hit test all phases of replaced elements atomically, as though the replaced element established its
193     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
194     // specification.)
195     return renderer()->hitTest(request, result, IntPoint(x, y), tx, ty);
196 }
197 
root() const198 const RootInlineBox* InlineBox::root() const
199 {
200     if (m_parent)
201         return m_parent->root();
202     ASSERT(isRootInlineBox());
203     return static_cast<const RootInlineBox*>(this);
204 }
205 
root()206 RootInlineBox* InlineBox::root()
207 {
208     if (m_parent)
209         return m_parent->root();
210     ASSERT(isRootInlineBox());
211     return static_cast<RootInlineBox*>(this);
212 }
213 
nextOnLineExists() const214 bool InlineBox::nextOnLineExists() const
215 {
216     if (!m_determinedIfNextOnLineExists) {
217         m_determinedIfNextOnLineExists = true;
218 
219         if (!parent())
220             m_nextOnLineExists = false;
221         else if (nextOnLine())
222             m_nextOnLineExists = true;
223         else
224             m_nextOnLineExists = parent()->nextOnLineExists();
225     }
226     return m_nextOnLineExists;
227 }
228 
prevOnLineExists() const229 bool InlineBox::prevOnLineExists() const
230 {
231     if (!m_determinedIfPrevOnLineExists) {
232         m_determinedIfPrevOnLineExists = true;
233 
234         if (!parent())
235             m_prevOnLineExists = false;
236         else if (prevOnLine())
237             m_prevOnLineExists = true;
238         else
239             m_prevOnLineExists = parent()->prevOnLineExists();
240     }
241     return m_prevOnLineExists;
242 }
243 
nextLeafChild() const244 InlineBox* InlineBox::nextLeafChild() const
245 {
246     InlineBox* leaf = 0;
247     for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
248         leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->firstLeafChild();
249     if (!leaf && parent())
250         leaf = parent()->nextLeafChild();
251     return leaf;
252 }
253 
prevLeafChild() const254 InlineBox* InlineBox::prevLeafChild() const
255 {
256     InlineBox* leaf = 0;
257     for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
258         leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->lastLeafChild();
259     if (!leaf && parent())
260         leaf = parent()->prevLeafChild();
261     return leaf;
262 }
263 
selectionState()264 RenderObject::SelectionState InlineBox::selectionState()
265 {
266     return renderer()->selectionState();
267 }
268 
canAccommodateEllipsis(bool ltr,int blockEdge,int ellipsisWidth)269 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
270 {
271     // Non-replaced elements can always accommodate an ellipsis.
272     if (!m_renderer || !m_renderer->isReplaced())
273         return true;
274 
275     IntRect boxRect(m_x, 0, m_logicalWidth, 10);
276     IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
277     return !(boxRect.intersects(ellipsisRect));
278 }
279 
placeEllipsisBox(bool,float,float,float,bool &)280 float InlineBox::placeEllipsisBox(bool, float, float, float, bool&)
281 {
282     // Use -1 to mean "we didn't set the position."
283     return -1;
284 }
285 
clearKnownToHaveNoOverflow()286 void InlineBox::clearKnownToHaveNoOverflow()
287 {
288     m_knownToHaveNoOverflow = false;
289     if (parent() && parent()->knownToHaveNoOverflow())
290         parent()->clearKnownToHaveNoOverflow();
291 }
292 
locationIncludingFlipping()293 FloatPoint InlineBox::locationIncludingFlipping()
294 {
295     if (!renderer()->style()->isFlippedBlocksWritingMode())
296         return FloatPoint(x(), y());
297     RenderBlock* block = root()->block();
298     if (block->style()->isHorizontalWritingMode())
299         return FloatPoint(x(), block->height() - height() - y());
300     else
301         return FloatPoint(block->width() - width() - x(), y());
302 }
303 
flipForWritingMode(FloatRect & rect)304 void InlineBox::flipForWritingMode(FloatRect& rect)
305 {
306     if (!renderer()->style()->isFlippedBlocksWritingMode())
307         return;
308     root()->block()->flipForWritingMode(rect);
309 }
310 
flipForWritingMode(const FloatPoint & point)311 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
312 {
313     if (!renderer()->style()->isFlippedBlocksWritingMode())
314         return point;
315     return root()->block()->flipForWritingMode(point);
316 }
317 
flipForWritingMode(IntRect & rect)318 void InlineBox::flipForWritingMode(IntRect& rect)
319 {
320     if (!renderer()->style()->isFlippedBlocksWritingMode())
321         return;
322     root()->block()->flipForWritingMode(rect);
323 }
324 
flipForWritingMode(const IntPoint & point)325 IntPoint InlineBox::flipForWritingMode(const IntPoint& point)
326 {
327     if (!renderer()->style()->isFlippedBlocksWritingMode())
328         return point;
329     return root()->block()->flipForWritingMode(point);
330 }
331 
332 } // namespace WebCore
333 
334 #ifndef NDEBUG
335 
showTree(const WebCore::InlineBox * b)336 void showTree(const WebCore::InlineBox* b)
337 {
338     if (b)
339         b->showTreeForThis();
340 }
341 
342 #endif
343