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