2 * This file is part of the html renderer for KDE.
4 * Copyright (C) 2003, 2006 Apple Computer, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include "RootInlineBox.h"
24 #include "EllipsisBox.h"
25 #include "RenderBlock.h"
31 void RootInlineBox::destroy(RenderArena* arena)
33 detachEllipsisBox(arena);
34 InlineFlowBox::destroy(arena);
37 void RootInlineBox::detachEllipsisBox(RenderArena* arena)
40 m_ellipsisBox->destroy(arena);
45 void RootInlineBox::clearTruncation()
48 detachEllipsisBox(m_object->renderArena());
49 InlineFlowBox::clearTruncation();
53 bool RootInlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth)
55 // First sanity-check the unoverflowed width of the whole line to see if there is sufficient room.
56 int delta = ltr ? lineBoxEdge - blockEdge : blockEdge - lineBoxEdge;
57 if (width() - delta < ellipsisWidth)
60 // Next iterate over all the line boxes on the line. If we find a replaced element that intersects
61 // then we refuse to accommodate the ellipsis. Otherwise we're ok.
62 return InlineFlowBox::canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth);
65 void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth,
68 // Create an ellipsis box.
69 m_ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this,
70 ellipsisWidth - (markupBox ? markupBox->width() : 0),
71 yPos(), height(), baseline(), !prevRootBox(),
74 if (ltr && (xPos() + width() + ellipsisWidth) <= blockEdge) {
75 m_ellipsisBox->m_x = xPos() + width();
79 // Now attempt to find the nearest glyph horizontally and place just to the right (or left in RTL)
80 // of that glyph. Mark all of the objects that intersect the ellipsis box as not painting (as being
82 bool foundBox = false;
83 m_ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
86 int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
88 int result = InlineFlowBox::placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
90 result = ltr ? blockEdge - ellipsisWidth : blockEdge;
94 void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo& i, int _tx, int _ty) const
96 if (m_ellipsisBox && object()->shouldPaintWithinRoot(i) && object()->style()->visibility() == VISIBLE &&
97 i.phase == PaintPhaseForeground)
98 m_ellipsisBox->paint(i, _tx, _ty);
101 void RootInlineBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
103 InlineFlowBox::paint(i, tx, ty);
104 paintEllipsisBox(i, tx, ty);
107 bool RootInlineBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty)
109 if (m_ellipsisBox && object()->style()->visibility() == VISIBLE) {
110 if (m_ellipsisBox->nodeAtPoint(i, x, y, tx, ty)) {
111 object()->setInnerNode(i);
115 return InlineFlowBox::nodeAtPoint(i, x, y, tx, ty);
118 void RootInlineBox::adjustPosition(int dx, int dy)
120 InlineFlowBox::adjustPosition(dx, dy);
122 m_bottomOverflow += dy;
124 m_selectionTop += dy;
125 m_selectionBottom += dy;
128 void RootInlineBox::childRemoved(InlineBox* box)
130 if (box->object() == m_lineBreakObj)
131 setLineBreakInfo(0, 0, 0, 0);
133 RootInlineBox* prev = prevRootBox();
134 if (prev && prev->lineBreakObj() == box->object()) {
135 prev->setLineBreakInfo(0, 0, 0, 0);
140 GapRects RootInlineBox::fillLineSelectionGap(int selTop, int selHeight, RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
141 const RenderObject::PaintInfo* i)
144 RenderObject::SelectionState lineState = selectionState();
146 bool leftGap, rightGap;
147 block()->getHorizontalSelectionGapInfo(lineState, leftGap, rightGap);
149 InlineBox* firstBox = firstSelectedBox();
150 InlineBox* lastBox = lastSelectedBox();
152 result.uniteLeft(block()->fillLeftSelectionGap(firstBox->parent()->object(),
153 firstBox->xPos(), selTop, selHeight,
154 rootBlock, blockX, blockY, tx, ty, i));
156 result.uniteRight(block()->fillRightSelectionGap(lastBox->parent()->object(),
157 lastBox->xPos() + lastBox->width(), selTop, selHeight,
158 rootBlock, blockX, blockY, tx, ty, i));
160 if (firstBox && firstBox != lastBox) {
161 // Now fill in any gaps on the line that occurred between two selected elements.
162 int lastX = firstBox->xPos() + firstBox->width();
163 for (InlineBox* box = firstBox->nextLeafChild(); box; box = box->nextLeafChild()) {
164 if (box->selectionState() != RenderObject::SelectionNone) {
165 result.uniteCenter(block()->fillHorizontalSelectionGap(box->parent()->object(),
166 lastX + tx, selTop + ty,
167 box->xPos() - lastX, selHeight, i));
168 lastX = box->xPos() + box->width();
178 void RootInlineBox::setHasSelectedChildren(bool b)
180 if (m_hasSelectedChildren == b)
182 m_hasSelectedChildren = b;
185 RenderObject::SelectionState RootInlineBox::selectionState()
187 // Walk over all of the selected boxes.
188 RenderObject::SelectionState state = RenderObject::SelectionNone;
189 for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) {
190 RenderObject::SelectionState boxState = box->selectionState();
191 if ((boxState == RenderObject::SelectionStart && state == RenderObject::SelectionEnd) ||
192 (boxState == RenderObject::SelectionEnd && state == RenderObject::SelectionStart))
193 state = RenderObject::SelectionBoth;
194 else if (state == RenderObject::SelectionNone ||
195 ((boxState == RenderObject::SelectionStart || boxState == RenderObject::SelectionEnd) &&
196 (state == RenderObject::SelectionNone || state == RenderObject::SelectionInside)))
198 if (state == RenderObject::SelectionBoth)
205 InlineBox* RootInlineBox::firstSelectedBox()
207 for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild())
208 if (box->selectionState() != RenderObject::SelectionNone)
213 InlineBox* RootInlineBox::lastSelectedBox()
215 for (InlineBox* box = lastLeafChild(); box; box = box->prevLeafChild())
216 if (box->selectionState() != RenderObject::SelectionNone)
221 int RootInlineBox::selectionTop()
224 return m_selectionTop;
226 int prevBottom = prevRootBox()->selectionBottom();
227 if (prevBottom < m_selectionTop && block()->containsFloats()) {
228 // This line has actually been moved further down, probably from a large line-height, but possibly because the
229 // line was forced to clear floats. If so, let's check the offsets, and only be willing to use the previous
230 // line's bottom overflow if the offsets are greater on both sides.
231 int prevLeft = block()->leftOffset(prevBottom);
232 int prevRight = block()->rightOffset(prevBottom);
233 int newLeft = block()->leftOffset(m_selectionTop);
234 int newRight = block()->rightOffset(m_selectionTop);
235 if (prevLeft > newLeft || prevRight < newRight)
236 return m_selectionTop;
242 RenderBlock* RootInlineBox::block() const
244 return static_cast<RenderBlock*>(m_object);
247 InlineBox* RootInlineBox::closestLeafChildForXPos(int _x, int _tx)
249 InlineBox *firstLeaf = firstLeafChildAfterBox();
250 InlineBox *lastLeaf = lastLeafChildBeforeBox();
251 if (firstLeaf == lastLeaf)
254 // Avoid returning a list marker when possible.
255 if (_x <= _tx + firstLeaf->m_x && !firstLeaf->object()->isListMarker())
256 // The x coordinate is less or equal to left edge of the firstLeaf.
260 if (_x >= _tx + lastLeaf->m_x + lastLeaf->m_width && !lastLeaf->object()->isListMarker())
261 // The x coordinate is greater or equal to right edge of the lastLeaf.
265 for (InlineBox *leaf = firstLeaf; leaf && leaf != lastLeaf; leaf = leaf->nextLeafChild()) {
266 if (!leaf->object()->isListMarker()) {
267 int leafX = _tx + leaf->m_x;
268 if (_x < leafX + leaf->m_width)
269 // The x coordinate is less than the right edge of the box.
278 void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, BidiStatus* status, BidiContext* context)
280 m_lineBreakObj = obj;
281 m_lineBreakPos = breakPos;
282 m_lineBreakContext = context;
284 m_lineBreakBidiStatus = *status;