?? render_container.cpp
字號:
/**
* This file is part of the html renderer for KDE.
*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
* Copyright (C) 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
//#define DEBUG_LAYOUT
#include "render_container.h"
#include "render_table.h"
#include "render_text.h"
#include "render_image.h"
#include "render_canvas.h"
#include "xml/dom_docimpl.h"
#include "xml/dom_position.h"
#include <kdebug.h>
#include <assert.h>
#if APPLE_CHANGES
// For accessibility
#include "KWQAccObjectCache.h"
#endif
using DOM::Position;
using namespace khtml;
RenderContainer::RenderContainer(DOM::NodeImpl* node)
: RenderBox(node)
{
m_first = 0;
m_last = 0;
}
RenderContainer::~RenderContainer()
{
}
void RenderContainer::detach()
{
if (continuation())
continuation()->detach();
while (m_first) {
if (m_first->isListMarker())
m_first->remove();
else
m_first->detach();
}
RenderBox::detach();
}
bool RenderContainer::canHaveChildren() const
{
return true;
}
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
bool needsTable = false;
if(!newChild->isText() && !newChild->isReplaced()) {
switch(newChild->style()->display()) {
case INLINE:
case BLOCK:
case INLINE_BLOCK:
case LIST_ITEM:
case RUN_IN:
case COMPACT:
case BOX:
case INLINE_BOX:
case TABLE:
case INLINE_TABLE:
case TABLE_COLUMN:
break;
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;
#if APPLE_CHANGES
// 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.
// See Radar 2925291.
if ( isTableCell() && !firstChild() && !newChild->isTableCell() )
needsTable = false;
#endif
break;
case NONE:
kdDebug( 6000 ) << "error in RenderObject::addChild()!!!!" << endl;
break;
}
}
if ( needsTable ) {
RenderTable *table;
if( !beforeChild )
beforeChild = lastChild();
if( beforeChild && beforeChild->isAnonymous() && beforeChild->isTable() )
table = static_cast<RenderTable *>(beforeChild);
else {
//kdDebug( 6040 ) << "creating anonymous table" << endl;
table = new (renderArena()) RenderTable(document() /* is anonymous */);
RenderStyle *newStyle = new (renderArena()) RenderStyle();
newStyle->inheritFrom(style());
newStyle->setDisplay(TABLE);
table->setStyle(newStyle);
addChild(table, beforeChild);
}
table->addChild(newChild);
} else {
// just add it...
insertChildNode(newChild, beforeChild);
}
}
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 (!documentBeingDestroyed()) {
oldChild->setNeedsLayoutAndMinMaxRecalc();
oldChild->repaint();
// Keep our layer hierarchy updated.
oldChild->removeLayers(enclosingLayer());
// 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())
canvas()->clearSelection();
}
// remove the child
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);
#if APPLE_CHANGES
if (KWQAccObjectCache::accessibilityEnabled())
document()->getAccObjectCache()->childrenChanged(this);
#endif
return oldChild;
}
void RenderContainer::removeChild(RenderObject *oldChild)
{
removeChildNode(oldChild);
}
void RenderContainer::updatePseudoChild(RenderStyle::PseudoId type, RenderObject* child)
{
// In CSS2, before/after pseudo-content cannot nest. Check this first.
if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER)
return;
RenderStyle* pseudo = getPseudoStyle(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;
// For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
// :after content and not :before content.
if (type == RenderStyle::BEFORE && isInlineContinuation())
newContentWanted = false;
// Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
// then we don't generate the :after content.
if (type == RenderStyle::AFTER && isRenderInline() && continuation())
newContentWanted = false;
// 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 (!newContentWanted ||
(oldContentPresent && !child->style()->contentDataEquivalent(pseudo))) {
// Nuke the child.
if (child && child->style()->styleType() == type) {
oldContentPresent = false;
removeChild(child);
child = (type == RenderStyle::BEFORE) ? firstChild() : lastChild();
}
}
// If we have no pseudo-style or if the pseudo's display type is NONE, then we
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -