File indexing completed on 2024-04-28 15:23:59
0001 /** 0002 * This file is part of the html renderer for KDE. 0003 * 0004 * Copyright (C) 2001-2003 Lars Knoll (knoll@kde.org) 0005 * (C) 2001 Antti Koivisto (koivisto@kde.org) 0006 * (C) 2000-2003 Dirk Mueller (mueller@kde.org) 0007 * (C) 2002-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 //#define DEBUG_LAYOUT 0028 0029 #include "rendering/render_container.h" 0030 #include "rendering/render_table.h" 0031 #include "rendering/render_text.h" 0032 #include "rendering/render_image.h" 0033 #include "rendering/render_canvas.h" 0034 #include "rendering/render_generated.h" 0035 #include "rendering/render_inline.h" 0036 #include "rendering/render_layer.h" 0037 #include "rendering/render_position.h" 0038 #include "xml/dom_docimpl.h" 0039 #include "xml/dom_position.h" 0040 #include "css/css_valueimpl.h" 0041 0042 #include "khtml_debug.h" 0043 #include <assert.h> 0044 #include <limits.h> 0045 0046 using DOM::Position; 0047 using namespace khtml; 0048 0049 RenderContainer::RenderContainer(DOM::NodeImpl *node) 0050 : RenderObject(node) 0051 { 0052 m_first = nullptr; 0053 m_last = nullptr; 0054 } 0055 0056 void RenderContainer::addChild(RenderObject *newChild, RenderObject *beforeChild) 0057 { 0058 #ifdef DEBUG_LAYOUT 0059 // qCDebug(KHTML_LOG) << this << ": " << renderName() << "(RenderObject)::addChild( " << newChild << ": " << 0060 // newChild->renderName() << ", " << (beforeChild ? beforeChild->renderName() : "0") << " )"; 0061 #endif 0062 // protect ourselves from deletion 0063 setDoNotDelete(true); 0064 0065 bool needsTable = false; 0066 0067 if (!newChild->isText() && !newChild->isReplaced()) { 0068 switch (newChild->style()->display()) { 0069 case INLINE: 0070 case BLOCK: 0071 case LIST_ITEM: 0072 case RUN_IN: 0073 case COMPACT: 0074 case INLINE_BLOCK: 0075 case TABLE: 0076 case INLINE_TABLE: 0077 break; 0078 case TABLE_COLUMN: 0079 if (isTableCol()) { 0080 break; 0081 } 0082 // nobreak 0083 case TABLE_COLUMN_GROUP: 0084 case TABLE_CAPTION: 0085 case TABLE_ROW_GROUP: 0086 case TABLE_HEADER_GROUP: 0087 case TABLE_FOOTER_GROUP: 0088 0089 //qCDebug(KHTML_LOG) << "adding section"; 0090 if (!isTable()) { 0091 needsTable = true; 0092 } 0093 break; 0094 case TABLE_ROW: 0095 //qCDebug(KHTML_LOG) << "adding row"; 0096 if (!isTableSection()) { 0097 needsTable = true; 0098 } 0099 break; 0100 case TABLE_CELL: 0101 //qCDebug(KHTML_LOG) << "adding cell"; 0102 if (!isTableRow()) { 0103 needsTable = true; 0104 } 0105 // I'm not 100% sure this is the best way to fix this, but without this 0106 // change we recurse infinitely when trying to render the CSS2 test page: 0107 // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html. 0108 if (isTableCell() && !firstChild() && !newChild->isTableCell()) { 0109 needsTable = false; 0110 } 0111 0112 break; 0113 case NONE: 0114 // RenderHtml and some others can have display:none 0115 // KHTMLAssert(false); 0116 break; 0117 } 0118 } 0119 0120 if (needsTable) { 0121 RenderTable *table; 0122 RenderObject *last = beforeChild ? beforeChild->previousSibling() : lastChild(); 0123 if (last && last->isTable() && last->isAnonymous()) { 0124 table = static_cast<RenderTable *>(last); 0125 } else { 0126 //qCDebug(KHTML_LOG) << "creating anonymous table, before=" << beforeChild; 0127 table = new(renderArena()) RenderTable(document() /* is anonymous */); 0128 RenderStyle *newStyle = new RenderStyle(); 0129 newStyle->inheritFrom(style()); 0130 newStyle->setDisplay(TABLE); 0131 newStyle->setFlowAroundFloats(true); 0132 table->setParent(this); // so it finds the arena 0133 table->setStyle(newStyle); 0134 table->setParent(nullptr); 0135 addChild(table, beforeChild); 0136 } 0137 table->addChild(newChild); 0138 } else { 0139 // just add it... 0140 insertChildNode(newChild, beforeChild); 0141 } 0142 0143 if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { 0144 DOM::DOMStringImpl *textToTransform = static_cast<RenderText *>(newChild)->originalString(); 0145 if (textToTransform) { 0146 static_cast<RenderText *>(newChild)->setText(textToTransform, true); 0147 } 0148 } 0149 newChild->attach(); 0150 0151 setDoNotDelete(false); 0152 } 0153 0154 RenderObject *RenderContainer::removeChildNode(RenderObject *oldChild) 0155 { 0156 KHTMLAssert(oldChild->parent() == this); 0157 bool inCleanup = documentBeingDestroyed(); 0158 0159 if (!inCleanup) { 0160 oldChild->setNeedsLayoutAndMinMaxRecalc(); // Dirty the containing block chain 0161 oldChild->setNeedsLayout(false); // The child itself does not need to layout - it's going away. 0162 0163 // Repaint, so that the area exposed when the child 0164 // disappears gets repainted properly. 0165 if (oldChild->height() && oldChild->width()) { 0166 oldChild->repaint(); 0167 } 0168 } 0169 0170 // detach the place holder box 0171 if (oldChild->isBox()) { 0172 RenderBox *rb = static_cast<RenderBox *>(oldChild); 0173 InlineBox *ph = rb->placeHolderBox(); 0174 if (ph) { 0175 ph->detach(rb->renderArena(), inCleanup /*NoRemove*/); 0176 rb->setPlaceHolderBox(nullptr); 0177 } 0178 } 0179 0180 if (!inCleanup) { 0181 // if we remove visible child from an invisible parent, we don't know the layer visibility any more 0182 RenderLayer *layer = nullptr; 0183 if (m_style->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->layer()) { 0184 layer = enclosingLayer(); 0185 if (layer) { 0186 layer->dirtyVisibleContentStatus(); 0187 } 0188 } 0189 0190 // Keep our layer hierarchy updated. 0191 if (oldChild->firstChild() || oldChild->layer()) { 0192 if (!layer) { 0193 layer = enclosingLayer(); 0194 } 0195 oldChild->removeLayers(layer); 0196 } 0197 // remove the child from any special layout lists 0198 oldChild->removeFromObjectLists(); 0199 0200 // keep our fixed object lists updated. 0201 if (oldChild->style()->hasFixedBackgroundImage() || oldChild->style()->position() == PFIXED) { 0202 if (oldChild->style()->hasFixedBackgroundImage()) { 0203 canvas()->removeStaticObject(oldChild); 0204 } 0205 if (oldChild->style()->position() == PFIXED) { 0206 canvas()->removeStaticObject(oldChild, true); 0207 } 0208 } 0209 0210 if (oldChild->isPosWithStaticDim() && childrenInline()) { 0211 dirtyLinesFromChangedChild(oldChild); 0212 } 0213 0214 // We are about to take out node from the rendering tree and therefore 0215 // it's possible that we're modifying the line box tree too. 0216 // In order to properly recalculate it later we need 0217 // to delete all the boxes from the current flow of the removed child. (vtokarev) 0218 // In particular that's relevant when we're merging split inline flow. (continuations) 0219 // We're taking the render objects from one block and insert into another 0220 // so we have to force line box tree recalculation 0221 if (oldChild->isInline()) { 0222 if (oldChild->isText()) { 0223 InlineTextBox *box = static_cast<RenderText *>(oldChild)->firstTextBox(); 0224 InlineTextBox *nextTextBox; 0225 assert(!box || box->parent()); 0226 // delete all the text boxes 0227 for (; box; box = nextTextBox) { 0228 nextTextBox = box->nextTextBox(); 0229 box->remove(); 0230 box->deleteLine(renderArena()); 0231 } 0232 } else if (oldChild->isInlineFlow()) { 0233 InlineFlowBox *box = static_cast<RenderFlow *>(oldChild)->firstLineBox(); 0234 InlineFlowBox *nextFlowBox; 0235 assert(!box || box->parent()); 0236 // delete all the flow 0237 for (; box; box = nextFlowBox) { 0238 nextFlowBox = box->nextFlowBox(); 0239 box->remove(); 0240 box->deleteLine(renderArena()); 0241 } 0242 } 0243 } 0244 0245 // if oldChild is the start or end of the selection, then clear 0246 // the selection to avoid problems of invalid pointers 0247 0248 // ### This is not the "proper" solution... ideally the selection 0249 // ### should be maintained based on DOM Nodes and a Range, which 0250 // ### gets adjusted appropriately when nodes are deleted/inserted 0251 // ### near etc. But this at least prevents crashes caused when 0252 // ### the start or end of the selection is deleted and then 0253 // ### accessed when the user next selects something. 0254 0255 if (oldChild->isSelectionBorder()) { 0256 canvas()->clearSelection(); 0257 } 0258 } 0259 0260 // remove the child from the render-tree 0261 if (oldChild->previousSibling()) { 0262 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); 0263 } 0264 if (oldChild->nextSibling()) { 0265 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); 0266 } 0267 0268 if (m_first == oldChild) { 0269 m_first = oldChild->nextSibling(); 0270 } 0271 if (m_last == oldChild) { 0272 m_last = oldChild->previousSibling(); 0273 } 0274 0275 oldChild->setPreviousSibling(nullptr); 0276 oldChild->setNextSibling(nullptr); 0277 oldChild->setParent(nullptr); 0278 0279 return oldChild; 0280 } 0281 0282 void RenderContainer::setStyle(RenderStyle *_style) 0283 { 0284 RenderObject::setStyle(_style); 0285 0286 // If we are a pseudo-container we need to restyle the children 0287 if (style()->isGenerated()) { 0288 // ### we could save this call when the change only affected 0289 // non inherited properties 0290 RenderStyle *pseudoStyle = new RenderStyle(); 0291 pseudoStyle->inheritFrom(style()); 0292 pseudoStyle->ref(); 0293 RenderObject *child = firstChild(); 0294 while (child != nullptr) { 0295 child->setStyle(pseudoStyle); 0296 child = child->nextSibling(); 0297 } 0298 pseudoStyle->deref(); 0299 } 0300 } 0301 0302 static bool inUpdatePseudoChildren = false; 0303 0304 void RenderContainer::updatePseudoChildren() 0305 { 0306 if (inUpdatePseudoChildren) { 0307 return; 0308 } 0309 inUpdatePseudoChildren = true; 0310 0311 // In CSS2, before/after pseudo-content cannot nest. Check this first. 0312 // Remove when CSS 3 Generated Content becomes Candidate Recommendation 0313 if (style()->styleType() == RenderStyle::BEFORE 0314 || style()->styleType() == RenderStyle::AFTER) { 0315 return; 0316 } 0317 0318 updatePseudoChild(RenderStyle::BEFORE); 0319 updatePseudoChild(RenderStyle::AFTER); 0320 // updatePseudoChild(RenderStyle::MARKER, marker()); 0321 0322 inUpdatePseudoChildren = false; 0323 } 0324 0325 void RenderContainer::updatePseudoChild(RenderStyle::PseudoId type) 0326 { 0327 // The head manages generated content for its continuations 0328 if (isInlineContinuation()) { 0329 return; 0330 } 0331 0332 RenderStyle *pseudo = style()->getPseudoStyle(type); 0333 0334 RenderObject *child = pseudoContainer(type); 0335 0336 // Whether or not we currently have generated content attached. 0337 bool oldContentPresent = child && (child->style()->styleType() == type); 0338 0339 // Whether or not we now want generated content. 0340 bool newContentWanted = pseudo && pseudo->display() != NONE; 0341 0342 // No generated content 0343 if (!oldContentPresent && !newContentWanted) { 0344 return; 0345 } 0346 0347 bool movedContent = (type == RenderStyle::AFTER && isRenderInline() && continuation()); 0348 0349 // Whether or not we want the same old content. 0350 bool sameOldContent = oldContentPresent && newContentWanted && !movedContent 0351 && (child->style()->contentDataEquivalent(pseudo)); 0352 0353 // No change in content, update style 0354 if (sameOldContent) { 0355 child->setStyle(pseudo); 0356 return; 0357 } 0358 0359 // If we don't want generated content any longer, or if we have generated content, 0360 // but it's no longer identical to the new content data we want to build 0361 // render objects for, then we nuke all of the old generated content. 0362 if (oldContentPresent && (!newContentWanted || !sameOldContent)) { 0363 // The child needs to be removed. 0364 oldContentPresent = false; 0365 child->detach(); 0366 child = nullptr; 0367 } 0368 0369 // If we have no pseudo-style or if the pseudo's display type is NONE, then we 0370 // have no generated content and can now return. 0371 if (!newContentWanted) { 0372 return; 0373 } 0374 0375 // Generated content consists of a single container that houses multiple children (specified 0376 // by the content property). This pseudo container gets the pseudo style set on it. 0377 RenderContainer *pseudoContainer = nullptr; 0378 pseudoContainer = RenderFlow::createFlow(element(), pseudo, renderArena()); 0379 pseudoContainer->setIsAnonymous(true); 0380 pseudoContainer->createGeneratedContent(); 0381 0382 // Only add the container if it had content 0383 if (pseudoContainer->firstChild()) { 0384 addPseudoContainer(pseudoContainer); 0385 pseudoContainer->close(); 0386 } 0387 } 0388 0389 void RenderContainer::createGeneratedContent() 0390 { 0391 RenderStyle *pseudo = style(); 0392 RenderStyle *style = new RenderStyle(); 0393 style->ref(); 0394 style->inheritFrom(pseudo); 0395 0396 // Now walk our list of generated content and create render objects for every type 0397 // we encounter. 0398 for (ContentData *contentData = pseudo->contentData(); 0399 contentData; contentData = contentData->_nextContent) { 0400 if (contentData->_contentType == CONTENT_TEXT) { 0401 RenderText *t = new(renderArena()) RenderText(node(), nullptr); 0402 t->setIsAnonymous(true); 0403 t->setStyle(style); 0404 t->setText(contentData->contentText()); 0405 addChild(t); 0406 } else if (contentData->_contentType == CONTENT_OBJECT) { 0407 RenderImage *img = new(renderArena()) RenderImage(node()); 0408 img->setIsAnonymous(true); 0409 img->setStyle(style); 0410 img->setContentObject(contentData->contentObject()); 0411 addChild(img); 0412 } else if (contentData->_contentType == CONTENT_COUNTER) { 0413 // really a counter or just a glyph? 0414 EListStyleType type = (EListStyleType)contentData->contentCounter()->listStyle(); 0415 RenderObject *t = nullptr; 0416 if (isListStyleCounted(type)) { 0417 t = new(renderArena()) RenderCounter(node(), contentData->contentCounter()); 0418 } else { 0419 t = new(renderArena()) RenderGlyph(node(), type); 0420 } 0421 t->setIsAnonymous(true); 0422 t->setStyle(style); 0423 addChild(t); 0424 } else if (contentData->_contentType == CONTENT_QUOTE) { 0425 RenderQuote *t = new(renderArena()) RenderQuote(node(), contentData->contentQuote()); 0426 t->setIsAnonymous(true); 0427 t->setStyle(style); 0428 addChild(t); 0429 } 0430 } 0431 style->deref(); 0432 } 0433 0434 RenderContainer *RenderContainer::pseudoContainer(RenderStyle::PseudoId type) const 0435 { 0436 RenderObject *child = nullptr; 0437 switch (type) { 0438 case RenderStyle::AFTER: 0439 child = lastChild(); 0440 break; 0441 case RenderStyle::BEFORE: 0442 child = firstChild(); 0443 break; 0444 case RenderStyle::REPLACED: 0445 child = lastChild(); 0446 if (child && child->style()->styleType() == RenderStyle::AFTER) { 0447 child = child->previousSibling(); 0448 } 0449 break; 0450 default: 0451 child = nullptr; 0452 } 0453 0454 if (child && child->style()->styleType() == type) { 0455 assert(child->isRenderBlock() || child->isRenderInline()); 0456 return static_cast<RenderContainer *>(child); 0457 } 0458 if (type == RenderStyle::AFTER) { 0459 // check continuations 0460 if (continuation()) { 0461 return continuation()->pseudoContainer(type); 0462 } 0463 } 0464 if (child && child->isAnonymousBlock()) { 0465 return static_cast<RenderBlock *>(child)->pseudoContainer(type); 0466 } 0467 return nullptr; 0468 } 0469 0470 void RenderContainer::addPseudoContainer(RenderObject *child) 0471 { 0472 RenderStyle::PseudoId type = child->style()->styleType(); 0473 switch (type) { 0474 case RenderStyle::AFTER: { 0475 RenderObject *o = this; 0476 while (o->continuation()) { 0477 o = o->continuation(); 0478 } 0479 0480 // Coalesce inlines 0481 if (child->style()->display() == INLINE && o->lastChild() && o->lastChild()->isAnonymousBlock()) { 0482 o->lastChild()->addChild(child, nullptr); 0483 } else { 0484 o->addChild(child, nullptr); 0485 } 0486 break; 0487 } 0488 case RenderStyle::BEFORE: 0489 // Coalesce inlines 0490 if (child->style()->display() == INLINE && firstChild() && firstChild()->isAnonymousBlock()) { 0491 firstChild()->addChild(child, firstChild()->firstChild()); 0492 } else { 0493 addChild(child, firstChild()); 0494 } 0495 break; 0496 case RenderStyle::REPLACED: 0497 addChild(child, pseudoContainer(RenderStyle::AFTER)); 0498 break; 0499 default: 0500 break; 0501 } 0502 } 0503 0504 void RenderContainer::updateReplacedContent() 0505 { 0506 // Only for normal elements 0507 if (!style() || style()->styleType() != RenderStyle::NOPSEUDO) { 0508 return; 0509 } 0510 0511 // delete old generated content 0512 RenderContainer *container = pseudoContainer(RenderStyle::REPLACED); 0513 if (container) { 0514 container->detach(); 0515 } 0516 0517 if (style()->useNormalContent()) { 0518 return; 0519 } 0520 0521 // create generated content 0522 RenderStyle *pseudo = style()->getPseudoStyle(RenderStyle::REPLACED); 0523 if (!pseudo) { 0524 pseudo = new RenderStyle(); 0525 pseudo->inheritFrom(style()); 0526 pseudo->setStyleType(RenderStyle::REPLACED); 0527 } 0528 if (pseudo->useNormalContent()) { 0529 pseudo->setContentData(style()->contentData()); 0530 } 0531 0532 container = RenderFlow::createFlow(node(), pseudo, renderArena()); 0533 container->setIsAnonymous(true); 0534 container->createGeneratedContent(); 0535 0536 addChild(container, pseudoContainer(RenderStyle::AFTER)); 0537 } 0538 0539 void RenderContainer::appendChildNode(RenderObject *newChild) 0540 { 0541 KHTMLAssert(newChild->parent() == nullptr); 0542 0543 newChild->setParent(this); 0544 RenderObject *lChild = lastChild(); 0545 0546 if (lChild) { 0547 newChild->setPreviousSibling(lChild); 0548 lChild->setNextSibling(newChild); 0549 } else { 0550 setFirstChild(newChild); 0551 } 0552 0553 setLastChild(newChild); 0554 0555 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children 0556 // and don't have a layer attached to ourselves. 0557 RenderLayer *layer = nullptr; 0558 if (newChild->firstChild() || newChild->layer()) { 0559 layer = enclosingLayer(); 0560 newChild->addLayers(layer, newChild); 0561 // keep our fixed object lists updated. 0562 if (newChild->style() && (newChild->style()->hasFixedBackgroundImage() || newChild->style()->position() == PFIXED)) { 0563 if (newChild->style()->hasFixedBackgroundImage()) { 0564 canvas()->addStaticObject(newChild); 0565 } 0566 if (newChild->style()->position() == PFIXED) { 0567 canvas()->addStaticObject(newChild, true); 0568 } 0569 } 0570 } 0571 0572 // if the new child is visible but this object was not, tell the layer it has some visible content 0573 // that needs to be drawn and layer visibility optimization can't be used 0574 if (style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->layer()) { 0575 if (!layer) { 0576 layer = enclosingLayer(); 0577 } 0578 if (layer) { 0579 layer->setHasVisibleContent(true); 0580 } 0581 } 0582 0583 if (!newChild->isFloatingOrPositioned() && childrenInline()) { 0584 dirtyLinesFromChangedChild(newChild); 0585 } 0586 0587 newChild->setNeedsLayoutAndMinMaxRecalc(); // Goes up the containing block hierarchy. 0588 0589 if (!normalChildNeedsLayout()) { 0590 // We may supply the static position for an absolute positioned child. 0591 if (newChild->firstChild() || newChild->isPosWithStaticDim() || !newChild->isPositioned()) { 0592 setChildNeedsLayout(true); 0593 } else { 0594 assert(!newChild->inPosObjectList()); 0595 newChild->containingBlock()->insertPositionedObject(newChild); 0596 } 0597 } 0598 } 0599 0600 void RenderContainer::insertChildNode(RenderObject *child, RenderObject *beforeChild) 0601 { 0602 if (!beforeChild) { 0603 appendChildNode(child); 0604 return; 0605 } 0606 0607 KHTMLAssert(!child->parent()); 0608 while (beforeChild->parent() != this && beforeChild->parent()->isAnonymous()) { 0609 beforeChild = beforeChild->parent(); 0610 } 0611 KHTMLAssert(beforeChild->parent() == this); 0612 0613 if (beforeChild == firstChild()) { 0614 setFirstChild(child); 0615 } 0616 0617 RenderObject *prev = beforeChild->previousSibling(); 0618 child->setNextSibling(beforeChild); 0619 beforeChild->setPreviousSibling(child); 0620 if (prev) { 0621 prev->setNextSibling(child); 0622 } 0623 child->setPreviousSibling(prev); 0624 child->setParent(this); 0625 0626 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children 0627 // and don't have a layer attached to ourselves. 0628 RenderLayer *layer = nullptr; 0629 if (child->firstChild() || child->layer()) { 0630 layer = enclosingLayer(); 0631 child->addLayers(layer, child); 0632 // keep our fixed object lists updated. 0633 if (child->style() && (child->style()->hasFixedBackgroundImage() || child->style()->position() == PFIXED)) { 0634 if (child->style()->hasFixedBackgroundImage()) { 0635 canvas()->addStaticObject(child); 0636 } 0637 if (child->style()->position() == PFIXED) { 0638 canvas()->addStaticObject(child, true); 0639 } 0640 } 0641 0642 } 0643 0644 // if the new child is visible but this object was not, tell the layer it has some visible content 0645 // that needs to be drawn and layer visibility optimization can't be used 0646 if (style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->layer()) { 0647 if (!layer) { 0648 layer = enclosingLayer(); 0649 } 0650 if (layer) { 0651 layer->setHasVisibleContent(true); 0652 } 0653 } 0654 0655 if (!child->isFloating() && childrenInline()) { 0656 dirtyLinesFromChangedChild(child); 0657 } 0658 0659 child->setNeedsLayoutAndMinMaxRecalc(); 0660 0661 if (!normalChildNeedsLayout()) { 0662 // We may supply the static position for an absolute positioned child. 0663 if (child->firstChild() || child->isPosWithStaticDim() || !child->isPositioned()) { 0664 setChildNeedsLayout(true); 0665 } else { 0666 assert(!child->inPosObjectList()); 0667 child->containingBlock()->insertPositionedObject(child); 0668 } 0669 } 0670 } 0671 0672 void RenderContainer::layout() 0673 { 0674 KHTMLAssert(needsLayout()); 0675 KHTMLAssert(minMaxKnown()); 0676 const bool pagedMode = canvas()->pagedMode(); 0677 RenderObject *child = firstChild(); 0678 while (child) { 0679 if (pagedMode) { 0680 child->setNeedsLayout(true); 0681 } 0682 child->layoutIfNeeded(); 0683 if (child->containsPageBreak()) { 0684 setContainsPageBreak(true); 0685 } 0686 if (child->needsPageClear()) { 0687 setNeedsPageClear(true); 0688 } 0689 child = child->nextSibling(); 0690 } 0691 setNeedsLayout(false); 0692 } 0693 0694 void RenderContainer::removeSuperfluousAnonymousBlockChild(RenderObject *child) 0695 { 0696 KHTMLAssert(child->parent() == this && child->isAnonymousBlock()); 0697 0698 if (child->doNotDelete() || child->continuation()) { 0699 return; 0700 } 0701 0702 RenderObject *childSFirstChild = child->firstChild(); 0703 RenderObject *childSLastChild = child->lastChild(); 0704 0705 if (childSFirstChild) { 0706 RenderObject *o = childSFirstChild; 0707 while (o) { 0708 o->setParent(this); 0709 o = o->nextSibling(); 0710 } 0711 childSFirstChild->setPreviousSibling(child->previousSibling()); 0712 childSLastChild->setNextSibling(child->nextSibling()); 0713 if (child->previousSibling()) { 0714 child->previousSibling()->setNextSibling(childSFirstChild); 0715 } 0716 if (child->nextSibling()) { 0717 child->nextSibling()->setPreviousSibling(childSLastChild); 0718 } 0719 if (child == firstChild()) { 0720 m_first = childSFirstChild; 0721 } 0722 if (child == lastChild()) { 0723 m_last = childSLastChild; 0724 } 0725 } else { 0726 if (child->previousSibling()) { 0727 child->previousSibling()->setNextSibling(child->nextSibling()); 0728 } 0729 if (child->nextSibling()) { 0730 child->nextSibling()->setPreviousSibling(child->previousSibling()); 0731 } 0732 if (child == firstChild()) { 0733 m_first = child->nextSibling(); 0734 } 0735 if (child == lastChild()) { 0736 m_last = child->previousSibling(); 0737 } 0738 } 0739 child->setParent(nullptr); 0740 child->setPreviousSibling(nullptr); 0741 child->setNextSibling(nullptr); 0742 if (!child->isText()) { 0743 RenderContainer *c = static_cast<RenderContainer *>(child); 0744 c->m_first = nullptr; 0745 c->m_next = nullptr; 0746 } 0747 child->detach(); 0748 } 0749 0750 RenderPosition RenderContainer::positionForCoordinates(int _x, int _y) 0751 { 0752 // no children...return this render object's element, if there is one, and offset 0 0753 if (!firstChild()) { 0754 return RenderPosition(element(), 0); 0755 } 0756 0757 // look for the geometrically-closest child and pass off to that child 0758 int min = INT_MAX; 0759 RenderObject *closestRenderer = firstChild(); 0760 for (RenderObject *renderer = firstChild(); renderer; renderer = renderer->nextSibling()) { 0761 int absx, absy; 0762 renderer->absolutePosition(absx, absy); 0763 0764 int top = absy + borderTop() + paddingTop(); 0765 int bottom = top + renderer->contentHeight(); 0766 int left = absx + borderLeft() + paddingLeft(); 0767 int right = left + renderer->contentWidth(); 0768 0769 int cmp; 0770 cmp = abs(_y - top); if (cmp < min) { 0771 closestRenderer = renderer; 0772 min = cmp; 0773 } 0774 cmp = abs(_y - bottom); if (cmp < min) { 0775 closestRenderer = renderer; 0776 min = cmp; 0777 } 0778 cmp = abs(_x - left); if (cmp < min) { 0779 closestRenderer = renderer; 0780 min = cmp; 0781 } 0782 cmp = abs(_x - right); if (cmp < min) { 0783 closestRenderer = renderer; 0784 min = cmp; 0785 } 0786 } 0787 0788 return closestRenderer->positionForCoordinates(_x, _y); 0789 } 0790 0791 #undef DEBUG_LAYOUT