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 "RenderArena.h"
26 #include "RenderBox.h"
27 #include "RootInlineBox.h"
28
29 using namespace std;
30
31 namespace WebCore {
32
33 #ifndef NDEBUG
34 static bool inInlineBoxDetach;
35 #endif
36
37 #ifndef NDEBUG
38
~InlineBox()39 InlineBox::~InlineBox()
40 {
41 if (!m_hasBadParent && m_parent)
42 m_parent->setHasBadChildList();
43 }
44
45 #endif
46
remove()47 void InlineBox::remove()
48 {
49 if (parent())
50 parent()->removeChild(this);
51 }
52
destroy(RenderArena * renderArena)53 void InlineBox::destroy(RenderArena* renderArena)
54 {
55 #ifndef NDEBUG
56 inInlineBoxDetach = true;
57 #endif
58 delete this;
59 #ifndef NDEBUG
60 inInlineBoxDetach = false;
61 #endif
62
63 // Recover the size left there for us by operator delete and free the memory.
64 renderArena->free(*(size_t *)this, this);
65 }
66
operator new(size_t sz,RenderArena * renderArena)67 void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw()
68 {
69 return renderArena->allocate(sz);
70 }
71
operator delete(void * ptr,size_t sz)72 void InlineBox::operator delete(void* ptr, size_t sz)
73 {
74 ASSERT(inInlineBoxDetach);
75
76 // Stash size where destroy can find it.
77 *(size_t *)ptr = sz;
78 }
79
80 #ifndef NDEBUG
showTreeForThis() const81 void InlineBox::showTreeForThis() const
82 {
83 if (m_renderer)
84 m_renderer->showTreeForThis();
85 }
86 #endif
87
height() const88 int InlineBox::height() const
89 {
90 #if ENABLE(SVG)
91 if (hasVirtualHeight())
92 return virtualHeight();
93 #endif
94
95 if (renderer()->isText())
96 return m_isText ? renderer()->style(m_firstLine)->font().height() : 0;
97 if (renderer()->isBox() && parent())
98 return toRenderBox(m_renderer)->height();
99
100 ASSERT(isInlineFlowBox());
101 const InlineFlowBox* flowBox = static_cast<const InlineFlowBox*>(this);
102 RenderBoxModelObject* flowObject = boxModelObject();
103 const Font& font = renderer()->style(m_firstLine)->font();
104 int result = font.height();
105 bool strictMode = renderer()->document()->inStrictMode();
106 if (parent())
107 result += flowObject->borderTop() + flowObject->paddingTop() + flowObject->borderBottom() + flowObject->paddingBottom();
108 if (strictMode || flowBox->hasTextChildren() || flowObject->hasHorizontalBordersOrPadding())
109 return result;
110 int bottom = root()->bottomOverflow();
111 if (y() + result > bottom)
112 result = bottom - y();
113 return result;
114 }
115
caretMinOffset() const116 int InlineBox::caretMinOffset() const
117 {
118 return m_renderer->caretMinOffset();
119 }
120
caretMaxOffset() const121 int InlineBox::caretMaxOffset() const
122 {
123 return m_renderer->caretMaxOffset();
124 }
125
caretMaxRenderedOffset() const126 unsigned InlineBox::caretMaxRenderedOffset() const
127 {
128 return 1;
129 }
130
dirtyLineBoxes()131 void InlineBox::dirtyLineBoxes()
132 {
133 markDirty();
134 for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
135 curr->markDirty();
136 }
137
deleteLine(RenderArena * arena)138 void InlineBox::deleteLine(RenderArena* arena)
139 {
140 if (!m_extracted && m_renderer->isBox())
141 toRenderBox(m_renderer)->setInlineBoxWrapper(0);
142 destroy(arena);
143 }
144
extractLine()145 void InlineBox::extractLine()
146 {
147 m_extracted = true;
148 if (m_renderer->isBox())
149 toRenderBox(m_renderer)->setInlineBoxWrapper(0);
150 }
151
attachLine()152 void InlineBox::attachLine()
153 {
154 m_extracted = false;
155 if (m_renderer->isBox())
156 toRenderBox(m_renderer)->setInlineBoxWrapper(this);
157 }
158
adjustPosition(int dx,int dy)159 void InlineBox::adjustPosition(int dx, int dy)
160 {
161 m_x += dx;
162 m_y += dy;
163 if (m_renderer->isReplaced()) {
164 RenderBox* box = toRenderBox(m_renderer);
165 box->move(dx, dy);
166 }
167 }
168
paint(RenderObject::PaintInfo & paintInfo,int tx,int ty)169 void InlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
170 {
171 if (!renderer()->shouldPaintWithinRoot(paintInfo) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
172 return;
173
174 // Paint all phases of replaced elements atomically, as though the replaced element established its
175 // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
176 // specification.)
177 bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
178 RenderObject::PaintInfo info(paintInfo);
179 info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
180 renderer()->paint(info, tx, ty);
181 if (!preservePhase) {
182 info.phase = PaintPhaseChildBlockBackgrounds;
183 renderer()->paint(info, tx, ty);
184 info.phase = PaintPhaseFloat;
185 renderer()->paint(info, tx, ty);
186 info.phase = PaintPhaseForeground;
187 renderer()->paint(info, tx, ty);
188 info.phase = PaintPhaseOutline;
189 renderer()->paint(info, tx, ty);
190 }
191 }
192
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty)193 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
194 {
195 // Hit test all phases of replaced elements atomically, as though the replaced element established its
196 // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
197 // specification.)
198 return renderer()->hitTest(request, result, IntPoint(x, y), tx, ty);
199 }
200
root() const201 const RootInlineBox* InlineBox::root() const
202 {
203 if (m_parent)
204 return m_parent->root();
205 ASSERT(isRootInlineBox());
206 return static_cast<const RootInlineBox*>(this);
207 }
208
root()209 RootInlineBox* InlineBox::root()
210 {
211 if (m_parent)
212 return m_parent->root();
213 ASSERT(isRootInlineBox());
214 return static_cast<RootInlineBox*>(this);
215 }
216
nextOnLineExists() const217 bool InlineBox::nextOnLineExists() const
218 {
219 if (!m_determinedIfNextOnLineExists) {
220 m_determinedIfNextOnLineExists = true;
221
222 if (!parent())
223 m_nextOnLineExists = false;
224 else if (nextOnLine())
225 m_nextOnLineExists = true;
226 else
227 m_nextOnLineExists = parent()->nextOnLineExists();
228 }
229 return m_nextOnLineExists;
230 }
231
prevOnLineExists() const232 bool InlineBox::prevOnLineExists() const
233 {
234 if (!m_determinedIfPrevOnLineExists) {
235 m_determinedIfPrevOnLineExists = true;
236
237 if (!parent())
238 m_prevOnLineExists = false;
239 else if (prevOnLine())
240 m_prevOnLineExists = true;
241 else
242 m_prevOnLineExists = parent()->prevOnLineExists();
243 }
244 return m_prevOnLineExists;
245 }
246
nextLeafChild() const247 InlineBox* InlineBox::nextLeafChild() const
248 {
249 InlineBox* leaf = 0;
250 for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
251 leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->firstLeafChild();
252 if (!leaf && parent())
253 leaf = parent()->nextLeafChild();
254 return leaf;
255 }
256
prevLeafChild() const257 InlineBox* InlineBox::prevLeafChild() const
258 {
259 InlineBox* leaf = 0;
260 for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
261 leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->lastLeafChild();
262 if (!leaf && parent())
263 leaf = parent()->prevLeafChild();
264 return leaf;
265 }
266
selectionState()267 RenderObject::SelectionState InlineBox::selectionState()
268 {
269 return renderer()->selectionState();
270 }
271
canAccommodateEllipsis(bool ltr,int blockEdge,int ellipsisWidth)272 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
273 {
274 // Non-replaced elements can always accommodate an ellipsis.
275 if (!m_renderer || !m_renderer->isReplaced())
276 return true;
277
278 IntRect boxRect(m_x, 0, m_width, 10);
279 IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
280 return !(boxRect.intersects(ellipsisRect));
281 }
282
placeEllipsisBox(bool,int,int,int,bool &)283 int InlineBox::placeEllipsisBox(bool, int, int, int, bool&)
284 {
285 // Use -1 to mean "we didn't set the position."
286 return -1;
287 }
288
289 } // namespace WebCore
290
291 #ifndef NDEBUG
292
showTree(const WebCore::InlineBox * b)293 void showTree(const WebCore::InlineBox* b)
294 {
295 if (b)
296 b->showTreeForThis();
297 }
298
299 #endif
300