• 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 "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