diff options
Diffstat (limited to 'khtml/rendering/render_container.cpp')
-rw-r--r-- | khtml/rendering/render_container.cpp | 597 |
1 files changed, 0 insertions, 597 deletions
diff --git a/khtml/rendering/render_container.cpp b/khtml/rendering/render_container.cpp deleted file mode 100644 index 69f987477..000000000 --- a/khtml/rendering/render_container.cpp +++ /dev/null @@ -1,597 +0,0 @@ -/** - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2001-2003 Lars Knoll (knoll@kde.org) - * (C) 2001 Antti Koivisto (koivisto@kde.org) - * (C) 2000-2003 Dirk Mueller (mueller@kde.org) - * (C) 2002-2003 Apple Computer, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -//#define DEBUG_LAYOUT - -#include "rendering/render_container.h" -#include "rendering/render_table.h" -#include "rendering/render_text.h" -#include "rendering/render_image.h" -#include "rendering/render_canvas.h" -#include "rendering/render_generated.h" -#include "rendering/render_inline.h" -#include "xml/dom_docimpl.h" -#include "css/css_valueimpl.h" - -#include <kdebug.h> -#include <assert.h> - -using namespace khtml; - -RenderContainer::RenderContainer(DOM::NodeImpl* node) - : RenderObject(node) -{ - m_first = 0; - m_last = 0; -} - -void RenderContainer::detach() -{ - if (continuation()) - continuation()->detach(); - - // We simulate removeNode calls for all our children - // and set parent to 0 to avoid removeNode from being called. - // First call removeLayers and removeFromObjectLists since they assume - // a valid render-tree - for(RenderObject* n = m_first; n; n = n->nextSibling() ) { - n->removeLayers(enclosingLayer()); - n->removeFromObjectLists(); - } - - RenderObject* next; - for(RenderObject* n = m_first; n; n = next ) { - n->setParent(0); - next = n->nextSibling(); - n->detach(); - } - m_first = 0; - m_last = 0; - - RenderObject::detach(); -} - -void RenderContainer::addChild(RenderObject *newChild, RenderObject *beforeChild) -{ -#ifdef DEBUG_LAYOUT - kdDebug( 6040 ) << this << ": " << renderName() << "(RenderObject)::addChild( " << newChild << ": " << - newChild->renderName() << ", " << (beforeChild ? beforeChild->renderName() : "0") << " )" << endl; -#endif - // protect ourselves from deletion - setDoNotDelete(true); - - bool needsTable = false; - - if(!newChild->isText() && !newChild->isReplaced()) { - switch(newChild->style()->display()) { - case INLINE: - case BLOCK: - case LIST_ITEM: - case RUN_IN: - case COMPACT: - case INLINE_BLOCK: - case TABLE: - case INLINE_TABLE: - break; - case TABLE_COLUMN: - if ( isTableCol() ) - break; - // nobreak - case TABLE_COLUMN_GROUP: - case TABLE_CAPTION: - case TABLE_ROW_GROUP: - case TABLE_HEADER_GROUP: - case TABLE_FOOTER_GROUP: - - //kdDebug( 6040 ) << "adding section" << endl; - if ( !isTable() ) - needsTable = true; - break; - case TABLE_ROW: - //kdDebug( 6040 ) << "adding row" << endl; - if ( !isTableSection() ) - needsTable = true; - break; - case TABLE_CELL: - //kdDebug( 6040 ) << "adding cell" << endl; - if ( !isTableRow() ) - needsTable = true; - // I'm not 100% sure this is the best way to fix this, but without this - // change we recurse infinitely when trying to render the CSS2 test page: - // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html. - if ( isTableCell() && !firstChild() && !newChild->isTableCell() ) - needsTable = false; - - break; - case NONE: - // RenderHtml and some others can have display:none - // KHTMLAssert(false); - break; - } - } - - if ( needsTable ) { - RenderTable *table; - RenderObject *last = beforeChild ? beforeChild->previousSibling() : lastChild(); - if ( last && last->isTable() && last->isAnonymous() ) { - table = static_cast<RenderTable *>(last); - } else { - //kdDebug( 6040 ) << "creating anonymous table, before=" << beforeChild << endl; - table = new (renderArena()) RenderTable(document() /* is anonymous */); - RenderStyle *newStyle = new RenderStyle(); - newStyle->inheritFrom(style()); - newStyle->setDisplay( TABLE ); - newStyle->setFlowAroundFloats( true ); - table->setParent( this ); // so it finds the arena - table->setStyle(newStyle); - table->setParent( 0 ); - addChild(table, beforeChild); - } - table->addChild(newChild); - } else { - // just add it... - insertChildNode(newChild, beforeChild); - } - - if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { - DOM::DOMStringImpl* textToTransform = static_cast<RenderText*>(newChild)->originalString(); - if (textToTransform) - static_cast<RenderText*>(newChild)->setText(textToTransform, true); - } - newChild->attach(); - - setDoNotDelete(false); -} - -RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild) -{ - KHTMLAssert(oldChild->parent() == this); - - // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or - // that a positioned child got yanked). We also repaint, so that the area exposed when the child - // disappears gets repainted properly. - if ( document()->renderer() ) { - oldChild->setNeedsLayoutAndMinMaxRecalc(); - oldChild->repaint(); - - // Keep our layer hierarchy updated. - oldChild->removeLayers(enclosingLayer()); - // remove the child from any special layout lists - oldChild->removeFromObjectLists(); - - // if oldChild is the start or end of the selection, then clear - // the selection to avoid problems of invalid pointers - - // ### This is not the "proper" solution... ideally the selection - // ### should be maintained based on DOM Nodes and a Range, which - // ### gets adjusted appropriately when nodes are deleted/inserted - // ### near etc. But this at least prevents crashes caused when - // ### the start or end of the selection is deleted and then - // ### accessed when the user next selects something. - - if (oldChild->isSelectionBorder()) { - RenderObject *root = oldChild; - while (root->parent()) - root = root->parent(); - if (root->isCanvas()) { - static_cast<RenderCanvas*>(root)->clearSelection(); - } - } - } - - // remove the child from the render-tree - if (oldChild->previousSibling()) - oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); - if (oldChild->nextSibling()) - oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); - - if (m_first == oldChild) - m_first = oldChild->nextSibling(); - if (m_last == oldChild) - m_last = oldChild->previousSibling(); - - oldChild->setPreviousSibling(0); - oldChild->setNextSibling(0); - oldChild->setParent(0); - - return oldChild; -} - -void RenderContainer::setStyle(RenderStyle* _style) -{ - RenderObject::setStyle(_style); - - // If we are a pseudo-container we need to restyle the children - if (style()->isGenerated()) - { - // ### we could save this call when the change only affected - // non inherited properties - RenderStyle *pseudoStyle = new RenderStyle(); - pseudoStyle->inheritFrom(style()); - pseudoStyle->ref(); - RenderObject *child = firstChild(); - while (child != 0) - { - child->setStyle(pseudoStyle); - child = child->nextSibling(); - } - pseudoStyle->deref(); - } -} - -void RenderContainer::updatePseudoChildren() -{ - // In CSS2, before/after pseudo-content cannot nest. Check this first. - // Remove when CSS 3 Generated Content becomes Candidate Recommendation - if (style()->styleType() == RenderStyle::BEFORE - || style()->styleType() == RenderStyle::AFTER) - return; - - updatePseudoChild(RenderStyle::BEFORE); - updatePseudoChild(RenderStyle::AFTER); - // updatePseudoChild(RenderStyle::MARKER, marker()); -} - -void RenderContainer::updatePseudoChild(RenderStyle::PseudoId type) -{ - // The head manages generated content for its continuations - if (isInlineContinuation()) return; - - RenderStyle* pseudo = style()->getPseudoStyle(type); - - RenderObject* child = pseudoContainer(type); - - // Whether or not we currently have generated content attached. - bool oldContentPresent = child && (child->style()->styleType() == type); - - // Whether or not we now want generated content. - bool newContentWanted = pseudo && pseudo->display() != NONE; - - // No generated content - if (!oldContentPresent && !newContentWanted) - return; - - bool movedContent = (type == RenderStyle::AFTER && isRenderInline() && continuation()); - - // Whether or not we want the same old content. - bool sameOldContent = oldContentPresent && newContentWanted && !movedContent - && (child->style()->contentDataEquivalent(pseudo)); - - // No change in content, update style - if( sameOldContent ) { - child->setStyle(pseudo); - return; - } - - // If we don't want generated content any longer, or if we have generated content, - // but it's no longer identical to the new content data we want to build - // render objects for, then we nuke all of the old generated content. - if (oldContentPresent && (!newContentWanted || !sameOldContent)) - { - // The child needs to be removed. - oldContentPresent = false; - child->detach(); - child = 0; - } - - // If we have no pseudo-style or if the pseudo's display type is NONE, then we - // have no generated content and can now return. - if (!newContentWanted) - return; - - // Generated content consists of a single container that houses multiple children (specified - // by the content property). This pseudo container gets the pseudo style set on it. - RenderContainer* pseudoContainer = 0; - pseudoContainer = RenderFlow::createFlow(element(), pseudo, renderArena()); - pseudoContainer->setIsAnonymous( true ); - pseudoContainer->createGeneratedContent(); - - // Only add the container if it had content - if (pseudoContainer->firstChild()) { - addPseudoContainer(pseudoContainer); - pseudoContainer->close(); - } -} - -void RenderContainer::createGeneratedContent() -{ - RenderStyle* pseudo = style(); - RenderStyle* style = new RenderStyle(); - style->ref(); - style->inheritFrom(pseudo); - - // Now walk our list of generated content and create render objects for every type - // we encounter. - for (ContentData* contentData = pseudo->contentData(); - contentData; contentData = contentData->_nextContent) - { - if (contentData->_contentType == CONTENT_TEXT) - { - RenderText* t = new (renderArena()) RenderText( node(), 0); - t->setIsAnonymous( true ); - t->setStyle(style); - t->setText(contentData->contentText()); - addChild(t); - } - else if (contentData->_contentType == CONTENT_OBJECT) - { - RenderImage* img = new (renderArena()) RenderImage(node()); - img->setIsAnonymous( true ); - img->setStyle(style); - img->setContentObject(contentData->contentObject()); - addChild(img); - } - else if (contentData->_contentType == CONTENT_COUNTER) - { - // really a counter or just a glyph? - EListStyleType type = (EListStyleType)contentData->contentCounter()->listStyle(); - RenderObject *t = 0; - if (isListStyleCounted(type)) { - t = new (renderArena()) RenderCounter( node(), contentData->contentCounter() ); - } - else { - t = new (renderArena()) RenderGlyph( node(), type ); - } - t->setIsAnonymous( true ); - t->setStyle(style); - addChild(t); - } - else if (contentData->_contentType == CONTENT_QUOTE) - { - RenderQuote* t = new (renderArena()) RenderQuote( node(), contentData->contentQuote() ); - t->setIsAnonymous( true ); - t->setStyle(style); - addChild(t); - } - } - style->deref(); -} - -RenderContainer* RenderContainer::pseudoContainer(RenderStyle::PseudoId type) const -{ - RenderObject *child = 0; - switch (type) { - case RenderStyle::AFTER: - child = lastChild(); - break; - case RenderStyle::BEFORE: - child = firstChild(); - break; - case RenderStyle::REPLACED: - child = lastChild(); - if (child && child->style()->styleType() == RenderStyle::AFTER) - child = child->previousSibling(); - break; - default: - child = 0; - } - - if (child && child->style()->styleType() == type) { - assert(child->isRenderBlock() || child->isRenderInline()); - return static_cast<RenderContainer*>(child); - } - if (type == RenderStyle::AFTER) { - // check continuations - if (continuation()) - return continuation()->pseudoContainer(type); - } - if (child && child->isAnonymousBlock()) - return static_cast<RenderBlock*>(child)->pseudoContainer(type); - return 0; -} - -void RenderContainer::addPseudoContainer(RenderObject* child) -{ - RenderStyle::PseudoId type = child->style()->styleType(); - switch (type) { - case RenderStyle::AFTER: { - RenderObject *o = this; - while (o->continuation()) o = o->continuation(); - - // Coalesce inlines - if (child->style()->display() == INLINE && o->lastChild() && o->lastChild()->isAnonymousBlock()) { - o->lastChild()->addChild(child, 0); - } else - o->addChild(child, 0); - break; - } - case RenderStyle::BEFORE: - // Coalesce inlines - if (child->style()->display() == INLINE && firstChild() && firstChild()->isAnonymousBlock()) { - firstChild()->addChild(child, firstChild()->firstChild()); - } else - addChild(child, firstChild()); - break; - case RenderStyle::REPLACED: - addChild(child, pseudoContainer(RenderStyle::AFTER)); - break; - default: - break; - } -} - -void RenderContainer::updateReplacedContent() -{ - // Only for normal elements - if (!style() || style()->styleType() != RenderStyle::NOPSEUDO) - return; - - // delete old generated content - RenderContainer *container = pseudoContainer(RenderStyle::REPLACED); - if (container) { - container->detach(); - } - - if (style()->useNormalContent()) return; - - // create generated content - RenderStyle* pseudo = style()->getPseudoStyle(RenderStyle::REPLACED); - if (!pseudo) { - pseudo = new RenderStyle(); - pseudo->inheritFrom(style()); - pseudo->setStyleType(RenderStyle::REPLACED); - } - if (pseudo->useNormalContent()) - pseudo->setContentData(style()->contentData()); - - container = RenderFlow::createFlow(node(), pseudo, renderArena()); - container->setIsAnonymous( true ); - container->createGeneratedContent(); - - addChild(container, pseudoContainer(RenderStyle::AFTER)); -} - -void RenderContainer::appendChildNode(RenderObject* newChild) -{ - KHTMLAssert(newChild->parent() == 0); - - newChild->setParent(this); - RenderObject* lChild = lastChild(); - - if(lChild) - { - newChild->setPreviousSibling(lChild); - lChild->setNextSibling(newChild); - } - else - setFirstChild(newChild); - - setLastChild(newChild); - - // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children - // and don't have a layer attached to ourselves. - if (newChild->firstChild() || newChild->layer()) { - RenderLayer* layer = enclosingLayer(); - newChild->addLayers(layer, newChild); - } - - newChild->setNeedsLayoutAndMinMaxRecalc(); // Goes up the containing block hierarchy. - if (!normalChildNeedsLayout()) - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. -} - -void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild) -{ - if(!beforeChild) { - appendChildNode(child); - return; - } - - KHTMLAssert(!child->parent()); - while ( beforeChild->parent() != this && beforeChild->parent()->isAnonymousBlock() ) - beforeChild = beforeChild->parent(); - KHTMLAssert(beforeChild->parent() == this); - - if(beforeChild == firstChild()) - setFirstChild(child); - - RenderObject* prev = beforeChild->previousSibling(); - child->setNextSibling(beforeChild); - beforeChild->setPreviousSibling(child); - if(prev) prev->setNextSibling(child); - child->setPreviousSibling(prev); - child->setParent(this); - - // Keep our layer hierarchy updated. - RenderLayer* layer = enclosingLayer(); - child->addLayers(layer, child); - - child->setNeedsLayoutAndMinMaxRecalc(); - if (!normalChildNeedsLayout()) - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. -} - - -void RenderContainer::layout() -{ - KHTMLAssert( needsLayout() ); - KHTMLAssert( minMaxKnown() ); - const bool pagedMode = canvas()->pagedMode(); - RenderObject *child = firstChild(); - while( child ) { - if (pagedMode) child->setNeedsLayout(true); - child->layoutIfNeeded(); - if (child->containsPageBreak()) setContainsPageBreak(true); - if (child->needsPageClear()) setNeedsPageClear(true); - child = child->nextSibling(); - } - setNeedsLayout(false); -} - -void RenderContainer::removeLeftoverAnonymousBoxes() -{ - // we have to go over all child nodes and remove anonymous boxes, that do _not_ - // have inline children to keep the tree flat - RenderObject *child = firstChild(); - while( child ) { - RenderObject *next = child->nextSibling(); - - if ( child->isRenderBlock() && child->isAnonymousBlock() && !child->continuation() && - !child->childrenInline() && !child->isTableCell() && !child->doNotDelete()) { - RenderObject *firstAnChild = child->firstChild(); - RenderObject *lastAnChild = child->lastChild(); - if ( firstAnChild ) { - RenderObject *o = firstAnChild; - while( o ) { - o->setParent( this ); - o = o->nextSibling(); - } - firstAnChild->setPreviousSibling( child->previousSibling() ); - lastAnChild->setNextSibling( child->nextSibling() ); - if ( child->previousSibling() ) - child->previousSibling()->setNextSibling( firstAnChild ); - if ( child->nextSibling() ) - child->nextSibling()->setPreviousSibling( lastAnChild ); - if ( child == firstChild() ) - m_first = firstAnChild; - if ( child == lastChild() ) - m_last = lastAnChild; - } else { - if ( child->previousSibling() ) - child->previousSibling()->setNextSibling( child->nextSibling() ); - if ( child->nextSibling() ) - child->nextSibling()->setPreviousSibling( child->previousSibling() ); - if ( child == firstChild() ) - m_first = child->nextSibling(); - if ( child == lastChild() ) - m_last = child->previousSibling(); - } - child->setParent( 0 ); - child->setPreviousSibling( 0 ); - child->setNextSibling( 0 ); - if ( !child->isText() ) { - RenderContainer *c = static_cast<RenderContainer *>(child); - c->m_first = 0; - c->m_next = 0; - } - child->detach(); - } - child = next; - } - if ( parent() ) - parent()->removeLeftoverAnonymousBoxes(); -} - -#undef DEBUG_LAYOUT |