File indexing completed on 2024-12-01 12:34:05
0001 /** 0002 * This file is part of the html renderer for KDE. 0003 * 0004 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) 0005 * (C) 1999-2003 Antti Koivisto (koivisto@kde.org) 0006 * (C) 2002-2003 Dirk Mueller (mueller@kde.org) 0007 * (C) 2003-2007 Apple Computer, Inc. 0008 * (C) 2007 Germain Garand (germain@ebooksfrance.org) 0009 * 0010 * This library is free software; you can redistribute it and/or 0011 * modify it under the terms of the GNU Library General Public 0012 * License as published by the Free Software Foundation; either 0013 * version 2 of the License, or (at your option) any later version. 0014 * 0015 * This library is distributed in the hope that it will be useful, 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0018 * Library General Public License for more details. 0019 * 0020 * You should have received a copy of the GNU Library General Public License 0021 * along with this library; see the file COPYING.LIB. If not, write to 0022 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0023 * Boston, MA 02110-1301, USA. 0024 */ 0025 // ------------------------------------------------------------------------- 0026 0027 #include "render_flow.h" 0028 0029 #include "khtml_debug.h" 0030 #include <assert.h> 0031 #include <QPainter> 0032 0033 #include "render_text.h" 0034 #include "render_table.h" 0035 #include "render_canvas.h" 0036 #include "render_inline.h" 0037 #include "render_block.h" 0038 #include "render_arena.h" 0039 #include <xml/dom_nodeimpl.h> 0040 #include <xml/dom_docimpl.h> 0041 #include <html/html_formimpl.h> 0042 0043 #include <khtmlview.h> 0044 0045 using namespace DOM; 0046 using namespace khtml; 0047 0048 RenderFlow *RenderFlow::createFlow(DOM::NodeImpl *node, RenderStyle *style, RenderArena *arena) 0049 { 0050 RenderFlow *result; 0051 if (style->display() == INLINE) { 0052 result = new(arena) RenderInline(node); 0053 } else { 0054 result = new(arena) RenderBlock(node); 0055 } 0056 result->setStyle(style); 0057 return result; 0058 } 0059 0060 RenderFlow *RenderFlow::continuationBefore(const RenderObject *beforeChild) 0061 { 0062 if (beforeChild && beforeChild->parent() == this) { 0063 return this; 0064 } 0065 0066 RenderFlow *curr = continuation(); 0067 RenderFlow *nextToLast = this; 0068 RenderFlow *last = this; 0069 while (curr) { 0070 if (beforeChild && beforeChild->parent() == curr) { 0071 if (curr->firstChild() == beforeChild) { 0072 return last; 0073 } 0074 return curr; 0075 } 0076 0077 nextToLast = last; 0078 last = curr; 0079 curr = curr->continuation(); 0080 } 0081 0082 if (!beforeChild && !last->firstChild()) { 0083 return nextToLast; 0084 } 0085 return last; 0086 } 0087 0088 void RenderFlow::addChildWithContinuation(RenderObject *newChild, RenderObject *beforeChild) 0089 { 0090 RenderFlow *flow = continuationBefore(beforeChild); 0091 0092 RenderObject *bc = beforeChild; 0093 while (bc && bc->parent() != flow && !bc->parent()->isAnonymousBlock()) { 0094 // skip implicit containers around beforeChild 0095 bc = bc->parent(); 0096 } 0097 0098 RenderFlow *beforeChildParent = bc ? static_cast<RenderFlow *>(bc->parent()) : 0099 (flow->continuation() ? flow->continuation() : flow); 0100 0101 if (newChild->isFloatingOrPositioned()) { 0102 return beforeChildParent->addChildToFlow(newChild, beforeChild); 0103 } 0104 0105 // A continuation always consists of two potential candidates: an inline or an anonymous 0106 // block box holding block children. 0107 bool childInline = newChild->isInline(); 0108 bool bcpInline = beforeChildParent->isInline(); 0109 bool flowInline = flow->isInline(); 0110 0111 if (flow == beforeChildParent) { 0112 return flow->addChildToFlow(newChild, beforeChild); 0113 } else { 0114 // The goal here is to match up if we can, so that we can coalesce and create the 0115 // minimal # of continuations needed for the inline. 0116 if (childInline == bcpInline) { 0117 return beforeChildParent->addChildToFlow(newChild, beforeChild); 0118 } else if (flowInline == childInline) { 0119 return flow->addChildToFlow(newChild, nullptr); // Just treat like an append. 0120 } else { 0121 return beforeChildParent->addChildToFlow(newChild, beforeChild); 0122 } 0123 } 0124 } 0125 0126 void RenderFlow::addChild(RenderObject *newChild, RenderObject *beforeChild) 0127 { 0128 #ifdef DEBUG_LAYOUT 0129 // qCDebug(KHTML_LOG) << renderName() << "(RenderFlow)::addChild( " << newChild->renderName() << 0130 // ", " << (beforeChild ? beforeChild->renderName() : "0") << " )"; 0131 // qCDebug(KHTML_LOG) << "current height = " << m_height; 0132 #endif 0133 0134 if (continuation()) { 0135 return addChildWithContinuation(newChild, beforeChild); 0136 } 0137 return addChildToFlow(newChild, beforeChild); 0138 } 0139 0140 void RenderFlow::extractLineBox(InlineFlowBox *box) 0141 { 0142 m_lastLineBox = box->prevFlowBox(); 0143 if (box == m_firstLineBox) { 0144 m_firstLineBox = nullptr; 0145 } 0146 if (box->prevLineBox()) { 0147 box->prevLineBox()->setNextLineBox(nullptr); 0148 } 0149 box->setPreviousLineBox(nullptr); 0150 for (InlineRunBox *curr = box; curr; curr = curr->nextLineBox()) { 0151 curr->setExtracted(); 0152 } 0153 } 0154 0155 void RenderFlow::attachLineBox(InlineFlowBox *box) 0156 { 0157 if (m_lastLineBox) { 0158 m_lastLineBox->setNextLineBox(box); 0159 box->setPreviousLineBox(m_lastLineBox); 0160 } else { 0161 m_firstLineBox = box; 0162 } 0163 InlineFlowBox *last = box; 0164 for (InlineFlowBox *curr = box; curr; curr = curr->nextFlowBox()) { 0165 curr->setExtracted(false); 0166 last = curr; 0167 } 0168 m_lastLineBox = last; 0169 } 0170 0171 void RenderFlow::removeInlineBox(InlineBox *_box) 0172 { 0173 if (_box->isInlineFlowBox()) { 0174 InlineFlowBox *box = static_cast<InlineFlowBox *>(_box); 0175 if (box == m_firstLineBox) { 0176 m_firstLineBox = box->nextFlowBox(); 0177 } 0178 if (box == m_lastLineBox) { 0179 m_lastLineBox = box->prevFlowBox(); 0180 } 0181 if (box->nextLineBox()) { 0182 box->nextLineBox()->setPreviousLineBox(box->prevLineBox()); 0183 } 0184 if (box->prevLineBox()) { 0185 box->prevLineBox()->setNextLineBox(box->nextLineBox()); 0186 } 0187 } 0188 RenderBox::removeInlineBox(_box); 0189 } 0190 0191 void RenderFlow::deleteInlineBoxes(RenderArena *arena) 0192 { 0193 if (m_firstLineBox) { 0194 if (!arena) { 0195 arena = renderArena(); 0196 } 0197 InlineRunBox *curr = m_firstLineBox, *next = nullptr; 0198 while (curr) { 0199 next = curr->nextLineBox(); 0200 if (!curr->isPlaceHolderBox()) { 0201 curr->detach(arena, true /*noRemove*/); 0202 } 0203 curr = next; 0204 } 0205 m_firstLineBox = nullptr; 0206 m_lastLineBox = nullptr; 0207 } 0208 } 0209 0210 void RenderFlow::dirtyInlineBoxes(bool fullLayout, bool isRootLineBox) 0211 { 0212 if (!isRootLineBox && (isReplaced() || isPositioned())) { 0213 return RenderBox::dirtyInlineBoxes(fullLayout, isRootLineBox); 0214 } 0215 0216 if (fullLayout) { 0217 deleteInlineBoxes(); 0218 } else { 0219 for (InlineRunBox *curr = firstLineBox(); curr; curr = curr->nextLineBox()) { 0220 curr->dirtyInlineBoxes(); 0221 } 0222 } 0223 } 0224 0225 void RenderFlow::deleteLastLineBox(RenderArena *arena) 0226 { 0227 if (m_lastLineBox) { 0228 if (!arena) { 0229 arena = renderArena(); 0230 } 0231 InlineRunBox *curr = m_lastLineBox, *prev = m_lastLineBox; 0232 if (m_firstLineBox == m_lastLineBox) { 0233 m_firstLineBox = m_lastLineBox = nullptr; 0234 } else { 0235 prev = curr->prevLineBox(); 0236 while (!prev->isInlineFlowBox()) { 0237 prev = prev->prevLineBox(); 0238 prev->detach(arena); 0239 } 0240 m_lastLineBox = static_cast<InlineFlowBox *>(prev); 0241 prev->setNextLineBox(nullptr); 0242 } 0243 if (curr->parent()) { 0244 curr->parent()->removeFromLine(curr); 0245 } 0246 curr->detach(arena); 0247 } 0248 } 0249 0250 InlineBox *RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox) 0251 { 0252 if (!isRootLineBox && 0253 (isReplaced() || makePlaceHolderBox)) { // Inline tables and inline blocks 0254 return RenderBox::createInlineBox(false, false); // (or positioned element placeholders). 0255 } 0256 0257 InlineFlowBox *flowBox = nullptr; 0258 if (isInlineFlow()) { 0259 flowBox = new(renderArena()) InlineFlowBox(this); 0260 } else { 0261 flowBox = new(renderArena()) RootInlineBox(this); 0262 } 0263 0264 if (!m_firstLineBox) { 0265 m_firstLineBox = m_lastLineBox = flowBox; 0266 } else { 0267 m_lastLineBox->setNextLineBox(flowBox); 0268 flowBox->setPreviousLineBox(m_lastLineBox); 0269 m_lastLineBox = flowBox; 0270 } 0271 0272 return flowBox; 0273 } 0274 0275 void RenderFlow::dirtyLinesFromChangedChild(RenderObject *child) 0276 { 0277 if (!parent() || (selfNeedsLayout() && !isInlineFlow()) || isTable()) { 0278 return; 0279 } 0280 0281 // If we have no first line box, then just bail early. 0282 if (!firstLineBox()) { 0283 // For an empty inline, propagate the check up to our parent, unless the parent 0284 // is already dirty. 0285 if (isInline() && !parent()->selfNeedsLayout() && parent()->isInlineFlow()) { 0286 static_cast<RenderFlow *>(parent())->dirtyLinesFromChangedChild(this); 0287 } 0288 return; 0289 } 0290 0291 // Try to figure out which line box we belong in. First try to find a previous 0292 // line box by examining our siblings. If we didn't find a line box, then use our 0293 // parent's first line box. 0294 RootInlineBox *box = nullptr; 0295 RenderObject *curr = nullptr; 0296 for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) { 0297 if (curr->isFloatingOrPositioned()) { 0298 continue; 0299 } 0300 0301 if (curr->isReplaced() && curr->isBox()) { 0302 InlineBox *placeHolderBox = static_cast<RenderBox *>(curr)->placeHolderBox(); 0303 if (placeHolderBox) { 0304 box = placeHolderBox->root(); 0305 } 0306 } else if (curr->isText()) { 0307 InlineTextBox *textBox = static_cast<RenderText *>(curr)->lastTextBox(); 0308 if (textBox) { 0309 box = textBox->root(); 0310 } 0311 } else if (curr->isInlineFlow()) { 0312 InlineRunBox *runBox = static_cast<RenderFlow *>(curr)->lastLineBox(); 0313 if (runBox) { 0314 box = runBox->root(); 0315 } 0316 } 0317 0318 if (box) { 0319 break; 0320 } 0321 } 0322 if (!box) { 0323 box = firstLineBox()->root(); 0324 } 0325 0326 // If we found a line box, then dirty it. 0327 if (box) { 0328 RootInlineBox *adjacentBox; 0329 box->markDirty(); 0330 0331 // dirty the adjacent lines that might be affected 0332 // NOTE: we dirty the previous line because RootInlineBox objects cache 0333 // the address of the first object on the next line after a BR, which we may be 0334 // invalidating here. For more info, see how RenderBlock::layoutInlineChildren 0335 // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak, 0336 // despite the name, actually returns the first RenderObject after the BR. 0337 0338 adjacentBox = box->prevRootBox(); 0339 if (adjacentBox) { 0340 adjacentBox->markDirty(); 0341 } 0342 if (child->isBR() || (curr && curr->isBR())) { 0343 adjacentBox = box->nextRootBox(); 0344 if (adjacentBox) { 0345 adjacentBox->markDirty(); 0346 } 0347 } 0348 } 0349 } 0350 0351 QList< QRectF > RenderFlow::getClientRects() 0352 { 0353 if (isRenderInline() && isInlineFlow()) { 0354 QList<QRectF> list; 0355 0356 InlineFlowBox *child = firstLineBox(); 0357 if (child) { 0358 int x = 0, y = 0; 0359 absolutePosition(x,y); 0360 do { 0361 QRectF rect(x + child->xPos(), y + child->yPos(), child->width(), child->height()); 0362 list.append(clientRectToViewport(rect)); 0363 child = child->nextFlowBox(); 0364 } while (child); 0365 } 0366 0367 // In case our flow is splitted by blocks 0368 for (RenderObject *cont = continuation(); cont; cont = cont->continuation()) { 0369 list.append(cont->getClientRects()); 0370 } 0371 0372 // Empty Flow, return the Flow itself 0373 if (list.isEmpty()) { 0374 return RenderObject::getClientRects(); 0375 } 0376 0377 return list; 0378 } else { 0379 return RenderObject::getClientRects(); 0380 } 0381 } 0382 0383 void RenderFlow::detach() 0384 { 0385 if (continuation()) { 0386 continuation()->detach(); 0387 } 0388 m_continuation = nullptr; 0389 0390 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will 0391 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. 0392 detachRemainingChildren(); 0393 0394 if (!documentBeingDestroyed()) { 0395 if (m_firstLineBox) { 0396 // We can't wait for RenderContainer::destroy to clear the selection, 0397 // because by then we will have nuked the line boxes. 0398 if (isSelectionBorder()) { 0399 canvas()->clearSelection(); 0400 } 0401 0402 // If line boxes are contained inside a root, that means we're an inline. 0403 // In that case, we need to remove all the line boxes so that the parent 0404 // lines aren't pointing to deleted children. If the first line box does 0405 // not have a parent that means they are either already disconnected or 0406 // root lines that can just be destroyed without disconnecting. 0407 if (m_firstLineBox->parent()) { 0408 for (InlineRunBox *box = m_firstLineBox; box; box = box->nextLineBox()) { 0409 box->remove(); 0410 } 0411 } 0412 0413 // If we are an anonymous block, then our line boxes might have children 0414 // that will outlast this block. In the non-anonymous block case those 0415 // children will be destroyed by the time we return from this function. 0416 if (isAnonymousBlock()) { 0417 for (InlineFlowBox *box = m_firstLineBox; box; box = box->nextFlowBox()) { 0418 while (InlineBox *childBox = box->firstChild()) { 0419 childBox->remove(); 0420 } 0421 } 0422 } 0423 } else if (isInline() && parent()) 0424 // empty inlines propagate linebox dirtying to the parent 0425 { 0426 parent()->dirtyLinesFromChangedChild(this); 0427 } 0428 } 0429 0430 deleteInlineBoxes(); 0431 0432 RenderBox::detach(); 0433 } 0434 0435 void RenderFlow::paintLines(PaintInfo &i, int _tx, int _ty) 0436 { 0437 // Only paint during the foreground/selection phases. 0438 if (i.phase != PaintActionForeground && i.phase != PaintActionSelection && i.phase != PaintActionOutline) { 0439 return; 0440 } 0441 0442 if (!firstLineBox()) { 0443 return; 0444 } 0445 0446 // We can check the first box and last box and avoid painting if we don't 0447 // intersect. This is a quick short-circuit that we can take to avoid walking any lines. 0448 // FIXME: This check is flawed in two extremely obscure ways. 0449 // (1) If some line in the middle has a huge overflow, it might actually extend below the last line. 0450 // (2) The overflow from an inline block on a line is not reported to the line. 0451 int maxOutlineSize = maximalOutlineSize(i.phase); 0452 int yPos = firstLineBox()->root()->topOverflow() - maxOutlineSize; 0453 int h = maxOutlineSize + lastLineBox()->root()->bottomOverflow() - yPos; 0454 yPos += _ty; 0455 if ((yPos >= i.r.y() + i.r.height()) || (yPos + h <= i.r.y())) { 0456 return; 0457 } 0458 for (InlineFlowBox *curr = firstLineBox(); curr; curr = curr->nextFlowBox()) { 0459 yPos = curr->root()->topOverflow() - maxOutlineSize; 0460 h = curr->root()->bottomOverflow() + maxOutlineSize - yPos; 0461 yPos += _ty; 0462 if ((yPos < i.r.y() + i.r.height()) && (yPos + h > i.r.y())) { 0463 curr->paint(i, _tx, _ty); 0464 } 0465 } 0466 0467 if (i.phase == PaintActionOutline && i.outlineObjects) { 0468 foreach (RenderFlow *oo, *i.outlineObjects) 0469 if (oo->isRenderInline()) { 0470 static_cast<RenderInline *>(oo)->paintOutlines(i.p, _tx, _ty); 0471 } 0472 i.outlineObjects->clear(); 0473 } 0474 } 0475 0476 bool RenderFlow::hitTestLines(NodeInfo &i, int x, int y, int tx, int ty, HitTestAction hitTestAction) 0477 { 0478 (void) hitTestAction; 0479 /* 0480 if (hitTestAction != HitTestForeground) // ### port hitTest 0481 return false; 0482 */ 0483 0484 if (!firstLineBox()) { 0485 return false; 0486 } 0487 0488 // We can check the first box and last box and avoid hit testing if we don't 0489 // contain the point. This is a quick short-circuit that we can take to avoid walking any lines. 0490 // FIXME: This check is flawed in two extremely obscure ways. 0491 // (1) If some line in the middle has a huge overflow, it might actually extend below the last line. 0492 // (2) The overflow from an inline block on a line is not reported to the line. 0493 if ((y >= ty + lastLineBox()->root()->bottomOverflow()) || (y < ty + firstLineBox()->root()->topOverflow())) { 0494 return false; 0495 } 0496 0497 // See if our root lines contain the point. If so, then we hit test 0498 // them further. Note that boxes can easily overlap, so we can't make any assumptions 0499 // based off positions of our first line box or our last line box. 0500 for (InlineFlowBox *curr = lastLineBox(); curr; curr = curr->prevFlowBox()) { 0501 if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) { 0502 bool inside = curr->nodeAtPoint(i, x, y, tx, ty); 0503 if (inside) { 0504 setInnerNode(i); 0505 return true; 0506 } 0507 } 0508 } 0509 0510 return false; 0511 } 0512 0513 void RenderFlow::repaint(Priority prior) 0514 { 0515 if (isInlineFlow()) { 0516 // Find our leftmost position. 0517 int left = 0; 0518 // root inline box not reliably availabe during relayout 0519 int top = firstLineBox() ? ( 0520 needsLayout() ? firstLineBox()->xPos() : firstLineBox()->root()->topOverflow() 0521 ) : 0; 0522 for (InlineRunBox *curr = firstLineBox(); curr; curr = curr->nextLineBox()) 0523 if (curr == firstLineBox() || curr->xPos() < left) { 0524 left = curr->xPos(); 0525 } 0526 0527 // Now invalidate a rectangle. 0528 int ow = style() ? style()->outlineSize() : 0; 0529 0530 // We need to add in the relative position offsets of any inlines (including us) up to our 0531 // containing block. 0532 RenderBlock *cb = containingBlock(); 0533 for (RenderObject *inlineFlow = this; inlineFlow && inlineFlow->isInlineFlow() && inlineFlow != cb; 0534 inlineFlow = inlineFlow->parent()) { 0535 if (inlineFlow->style() && inlineFlow->style()->position() == PRELATIVE && inlineFlow->layer()) { 0536 KHTMLAssert(inlineFlow->isBox()); 0537 static_cast<RenderBox *>(inlineFlow)->relativePositionOffset(left, top); 0538 } 0539 } 0540 0541 RootInlineBox *lastRoot = lastLineBox() && !needsLayout() ? lastLineBox()->root() : nullptr; 0542 containingBlock()->repaintRectangle(-ow + left, -ow + top, 0543 width() + ow * 2, 0544 (lastRoot ? lastRoot->bottomOverflow() - top : height()) + ow * 2, prior); 0545 } else { 0546 if (firstLineBox() && firstLineBox()->topOverflow() < 0) { 0547 int ow = style() ? style()->outlineSize() : 0; 0548 repaintRectangle(-ow, -ow + firstLineBox()->topOverflow(), 0549 effectiveWidth() + ow * 2, effectiveHeight() + ow * 2, prior); 0550 } else { 0551 return RenderBox::repaint(prior); 0552 } 0553 } 0554 } 0555 0556 int 0557 RenderFlow::lowestPosition(bool includeOverflowInterior, bool includeSelf) const 0558 { 0559 int bottom = includeSelf && m_width > 0 ? m_height : 0; 0560 if (!includeOverflowInterior && hasOverflowClip()) { 0561 return bottom; 0562 } 0563 0564 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 0565 // For now, we have to descend into all the children, since we may have a huge abs div inside 0566 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 0567 // the abs div. 0568 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { 0569 if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) { 0570 int lp = c->yPos() + c->lowestPosition(false); 0571 bottom = qMax(bottom, lp); 0572 } 0573 } 0574 0575 if (includeSelf && isRelPositioned()) { 0576 int x = 0; 0577 relativePositionOffset(x, bottom); 0578 } 0579 0580 return bottom; 0581 } 0582 0583 int RenderFlow::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const 0584 { 0585 int right = includeSelf && m_height > 0 ? m_width : 0; 0586 if (!includeOverflowInterior && hasOverflowClip()) { 0587 return right; 0588 } 0589 0590 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 0591 // For now, we have to descend into all the children, since we may have a huge abs div inside 0592 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 0593 // the abs div. 0594 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { 0595 if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) { 0596 int rp = c->xPos() + c->rightmostPosition(false); 0597 right = qMax(right, rp); 0598 } 0599 } 0600 0601 if (includeSelf && isRelPositioned()) { 0602 int y = 0; 0603 relativePositionOffset(right, y); 0604 } 0605 0606 return right; 0607 } 0608 0609 int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const 0610 { 0611 int left = includeSelf && m_height > 0 ? 0 : m_width; 0612 if (!includeOverflowInterior && hasOverflowClip()) { 0613 return left; 0614 } 0615 0616 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 0617 // For now, we have to descend into all the children, since we may have a huge abs div inside 0618 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 0619 // the abs div. 0620 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { 0621 if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) { 0622 int lp = c->xPos() + c->leftmostPosition(false); 0623 left = qMin(left, lp); 0624 } 0625 } 0626 0627 if (includeSelf && isRelPositioned()) { 0628 int y = 0; 0629 relativePositionOffset(left, y); 0630 } 0631 0632 return left; 0633 } 0634 0635 int RenderFlow::highestPosition(bool includeOverflowInterior, bool includeSelf) const 0636 { 0637 int top = RenderBox::highestPosition(includeOverflowInterior, includeSelf); 0638 if (!includeOverflowInterior && hasOverflowClip()) { 0639 return top; 0640 } 0641 0642 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 0643 // For now, we have to descend into all the children, since we may have a huge abs div inside 0644 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 0645 // the abs div. 0646 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { 0647 if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) { 0648 int hp = c->yPos() + c->highestPosition(false); 0649 top = qMin(top, hp); 0650 } 0651 } 0652 0653 if (includeSelf && isRelPositioned()) { 0654 int x = 0; 0655 relativePositionOffset(x, top); 0656 } 0657 0658 return top; 0659 }