• 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(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     if (!paintInfo.shouldPaintWithinRoot(&renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
198         return;
199 
200     LayoutPoint childPoint = paintOffset;
201     if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
202         childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint);
203 
204     RenderBlock::paintAsInlineBlock(&renderer(), paintInfo, childPoint);
205 }
206 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset,LayoutUnit,LayoutUnit)207 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
208 {
209     // Hit test all phases of replaced elements atomically, as though the replaced element established its
210     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
211     // specification.)
212     LayoutPoint childPoint = accumulatedOffset;
213     if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
214         childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint);
215 
216     return renderer().hitTest(request, result, locationInContainer, childPoint);
217 }
218 
root() const219 const RootInlineBox& InlineBox::root() const
220 {
221     if (m_parent)
222         return m_parent->root();
223     ASSERT(isRootInlineBox());
224     return static_cast<const RootInlineBox&>(*this);
225 }
226 
root()227 RootInlineBox& InlineBox::root()
228 {
229     if (m_parent)
230         return m_parent->root();
231     ASSERT(isRootInlineBox());
232     return static_cast<RootInlineBox&>(*this);
233 }
234 
nextOnLineExists() const235 bool InlineBox::nextOnLineExists() const
236 {
237     if (!m_bitfields.determinedIfNextOnLineExists()) {
238         m_bitfields.setDeterminedIfNextOnLineExists(true);
239 
240         if (!parent())
241             m_bitfields.setNextOnLineExists(false);
242         else if (nextOnLine())
243             m_bitfields.setNextOnLineExists(true);
244         else
245             m_bitfields.setNextOnLineExists(parent()->nextOnLineExists());
246     }
247     return m_bitfields.nextOnLineExists();
248 }
249 
nextLeafChild() const250 InlineBox* InlineBox::nextLeafChild() const
251 {
252     InlineBox* leaf = 0;
253     for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
254         leaf = box->isLeaf() ? box : toInlineFlowBox(box)->firstLeafChild();
255     if (!leaf && parent())
256         leaf = parent()->nextLeafChild();
257     return leaf;
258 }
259 
prevLeafChild() const260 InlineBox* InlineBox::prevLeafChild() const
261 {
262     InlineBox* leaf = 0;
263     for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
264         leaf = box->isLeaf() ? box : toInlineFlowBox(box)->lastLeafChild();
265     if (!leaf && parent())
266         leaf = parent()->prevLeafChild();
267     return leaf;
268 }
269 
nextLeafChildIgnoringLineBreak() const270 InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const
271 {
272     InlineBox* leaf = nextLeafChild();
273     if (leaf && leaf->isLineBreak())
274         return 0;
275     return leaf;
276 }
277 
prevLeafChildIgnoringLineBreak() const278 InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const
279 {
280     InlineBox* leaf = prevLeafChild();
281     if (leaf && leaf->isLineBreak())
282         return 0;
283     return leaf;
284 }
285 
selectionState()286 RenderObject::SelectionState InlineBox::selectionState()
287 {
288     return renderer().selectionState();
289 }
290 
canAccommodateEllipsis(bool ltr,int blockEdge,int ellipsisWidth) const291 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
292 {
293     // Non-replaced elements can always accommodate an ellipsis.
294     if (!renderer().isReplaced())
295         return true;
296 
297     IntRect boxRect(left(), 0, m_logicalWidth, 10);
298     IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
299     return !(boxRect.intersects(ellipsisRect));
300 }
301 
placeEllipsisBox(bool,float,float,float,float & truncatedWidth,bool &)302 float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&)
303 {
304     // Use -1 to mean "we didn't set the position."
305     truncatedWidth += logicalWidth();
306     return -1;
307 }
308 
clearKnownToHaveNoOverflow()309 void InlineBox::clearKnownToHaveNoOverflow()
310 {
311     m_bitfields.setKnownToHaveNoOverflow(false);
312     if (parent() && parent()->knownToHaveNoOverflow())
313         parent()->clearKnownToHaveNoOverflow();
314 }
315 
locationIncludingFlipping()316 FloatPoint InlineBox::locationIncludingFlipping()
317 {
318     if (!renderer().style()->isFlippedBlocksWritingMode())
319         return FloatPoint(x(), y());
320     RenderBlockFlow& block = root().block();
321     if (block.style()->isHorizontalWritingMode())
322         return FloatPoint(x(), block.height() - height() - y());
323 
324     return FloatPoint(block.width() - width() - x(), y());
325 }
326 
flipForWritingMode(FloatRect & rect)327 void InlineBox::flipForWritingMode(FloatRect& rect)
328 {
329     if (!renderer().style()->isFlippedBlocksWritingMode())
330         return;
331     root().block().flipForWritingMode(rect);
332 }
333 
flipForWritingMode(const FloatPoint & point)334 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
335 {
336     if (!renderer().style()->isFlippedBlocksWritingMode())
337         return point;
338     return root().block().flipForWritingMode(point);
339 }
340 
flipForWritingMode(LayoutRect & rect)341 void InlineBox::flipForWritingMode(LayoutRect& rect)
342 {
343     if (!renderer().style()->isFlippedBlocksWritingMode())
344         return;
345     root().block().flipForWritingMode(rect);
346 }
347 
flipForWritingMode(const LayoutPoint & point)348 LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point)
349 {
350     if (!renderer().style()->isFlippedBlocksWritingMode())
351         return point;
352     return root().block().flipForWritingMode(point);
353 }
354 
355 } // namespace WebCore
356 
357 #ifndef NDEBUG
358 
showTree(const WebCore::InlineBox * b)359 void showTree(const WebCore::InlineBox* b)
360 {
361     if (b)
362         b->showTreeForThis();
363 }
364 
showLineTree(const WebCore::InlineBox * b)365 void showLineTree(const WebCore::InlineBox* b)
366 {
367     if (b)
368         b->showLineTreeForThis();
369 }
370 
371 #endif
372