RenderObjectChildList.cpp [plain text]
#include "config.h"
#include "RenderObjectChildList.h"
#include "AXObjectCache.h"
#include "ContentData.h"
#include "RenderBlock.h"
#include "RenderCounter.h"
#include "RenderImage.h"
#include "RenderImageResourceStyleImage.h"
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderListItem.h"
#include "RenderQuote.h"
#include "RenderStyle.h"
#include "RenderTextFragment.h"
#include "RenderView.h"
namespace WebCore {
void RenderObjectChildList::destroyLeftoverChildren()
{
while (firstChild()) {
if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText()))
firstChild()->remove(); else if (firstChild()->isRunIn() && firstChild()->node()) {
firstChild()->node()->setRenderer(0);
firstChild()->node()->setNeedsStyleRecalc();
firstChild()->destroy();
} else {
if (firstChild()->node())
firstChild()->node()->setRenderer(0);
firstChild()->destroy();
}
}
}
RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
{
ASSERT(oldChild->parent() == owner);
if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) {
oldChild->setNeedsLayoutAndPrefWidthsRecalc();
if (oldChild->isBody())
owner->view()->repaint();
else
oldChild->repaint();
}
if (oldChild->isBox())
toRenderBox(oldChild)->deleteLineBoxWrapper();
if (!owner->documentBeingDestroyed() && fullRemove) {
RenderLayer* layer = 0;
if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
layer = owner->enclosingLayer();
layer->dirtyVisibleContentStatus();
}
if (oldChild->firstChild() || oldChild->hasLayer()) {
if (!layer)
layer = owner->enclosingLayer();
oldChild->removeLayers(layer);
}
if (oldChild->isListItem())
toRenderListItem(oldChild)->updateListMarkerNumbers();
if (oldChild->isPositioned() && owner->childrenInline())
owner->dirtyLinesFromChangedChild(oldChild);
#if ENABLE(SVG)
owner->setNeedsBoundariesUpdate();
#endif
}
if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder())
owner->view()->clearSelection();
if (oldChild->previousSibling())
oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
if (oldChild->nextSibling())
oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
if (firstChild() == oldChild)
setFirstChild(oldChild->nextSibling());
if (lastChild() == oldChild)
setLastChild(oldChild->previousSibling());
oldChild->setPreviousSibling(0);
oldChild->setNextSibling(0);
oldChild->setParent(0);
RenderCounter::rendererRemovedFromTree(oldChild);
RenderQuote::rendererRemovedFromTree(oldChild);
if (AXObjectCache::accessibilityEnabled())
owner->document()->axObjectCache()->childrenChanged(owner);
return oldChild;
}
void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
{
ASSERT(newChild->parent() == 0);
ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
newChild->setParent(owner);
RenderObject* lChild = lastChild();
if (lChild) {
newChild->setPreviousSibling(lChild);
lChild->setNextSibling(newChild);
} else
setFirstChild(newChild);
setLastChild(newChild);
if (fullAppend) {
RenderLayer* layer = 0;
if (newChild->firstChild() || newChild->hasLayer()) {
layer = owner->enclosingLayer();
newChild->addLayers(layer, newChild);
}
if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
if (!layer)
layer = owner->enclosingLayer();
if (layer)
layer->setHasVisibleContent(true);
}
if (newChild->isListItem())
toRenderListItem(newChild)->updateListMarkerNumbers();
if (!newChild->isFloatingOrPositioned() && owner->childrenInline())
owner->dirtyLinesFromChangedChild(newChild);
}
RenderCounter::rendererSubtreeAttached(newChild);
RenderQuote::rendererSubtreeAttached(newChild);
newChild->setNeedsLayoutAndPrefWidthsRecalc(); if (!owner->normalChildNeedsLayout())
owner->setChildNeedsLayout(true);
if (AXObjectCache::accessibilityEnabled())
owner->document()->axObjectCache()->childrenChanged(owner);
}
void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
{
if (!beforeChild) {
appendChildNode(owner, child, fullInsert);
return;
}
ASSERT(!child->parent());
while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
beforeChild = beforeChild->parent();
ASSERT(beforeChild->parent() == owner);
ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
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(owner);
if (fullInsert) {
RenderLayer* layer = 0;
if (child->firstChild() || child->hasLayer()) {
layer = owner->enclosingLayer();
child->addLayers(layer, child);
}
if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
if (!layer)
layer = owner->enclosingLayer();
if (layer)
layer->setHasVisibleContent(true);
}
if (child->isListItem())
toRenderListItem(child)->updateListMarkerNumbers();
if (!child->isFloating() && owner->childrenInline())
owner->dirtyLinesFromChangedChild(child);
}
RenderCounter::rendererSubtreeAttached(child);
RenderQuote::rendererSubtreeAttached(child);
child->setNeedsLayoutAndPrefWidthsRecalc();
if (!owner->normalChildNeedsLayout())
owner->setChildNeedsLayout(true);
if (AXObjectCache::accessibilityEnabled())
owner->document()->axObjectCache()->childrenChanged(owner);
}
static RenderObject* findBeforeAfterParent(RenderObject* object)
{
if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
return object;
RenderObject* beforeAfterParent = object;
while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage())
&& (beforeAfterParent->style()->styleType() != FIRST_LETTER))
beforeAfterParent = beforeAfterParent->firstChild();
return beforeAfterParent ? beforeAfterParent->parent() : 0;
}
RenderObject* RenderObjectChildList::beforePseudoElementRenderer(const RenderObject* owner) const
{
RenderObject* first = const_cast<RenderObject*>(owner);
do {
first = first->firstChild();
while (first && (first->isListMarker() || (first->isRenderInline() && first->isRunIn())))
first = first->nextInPreOrderAfterChildren(owner);
} while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO);
if (!first)
return 0;
if (first->isBeforeContent())
return first;
first = owner->firstChild();
if (!first->isRenderBlock())
return 0;
first = first->firstChild();
while (first && first->isListMarker())
first = first->nextSibling();
if (first && first->isBeforeContent() && first->isRenderInline() && first->isRunIn())
return first;
return 0;
}
RenderObject* RenderObjectChildList::afterPseudoElementRenderer(const RenderObject* owner) const
{
RenderObject* last = const_cast<RenderObject*>(owner);
do {
last = last->lastChild();
} while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
if (last && !last->isAfterContent())
return 0;
return last;
}
void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject)
{
ASSERT(owner->document()->usesBeforeAfterRules());
if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
return;
if (!styledObject)
styledObject = owner;
RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
RenderObject* child;
switch (type) {
case BEFORE:
child = beforePseudoElementRenderer(owner);
break;
case AFTER:
child = afterPseudoElementRenderer(owner);
break;
default:
ASSERT_NOT_REACHED();
return;
}
bool oldContentPresent = child;
bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
if (newContentWanted && type == BEFORE && owner->isElementContinuation())
newContentWanted = false;
if (newContentWanted && type == AFTER && owner->virtualContinuation())
newContentWanted = false;
if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
if (child->style()->styleType() == type) {
oldContentPresent = false;
child->destroy();
child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
}
}
if (!newContentWanted)
return;
if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
!(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
pseudoElementStyle->setDisplay(INLINE);
if (oldContentPresent) {
if (child && child->style()->styleType() == type) {
child->setStyle(pseudoElementStyle);
RenderObject* beforeAfterParent = findBeforeAfterParent(child);
if (!beforeAfterParent)
return;
if (beforeAfterParent != child) {
RenderObject* curr = beforeAfterParent;
while (curr && curr != child) {
ASSERT(curr->isAnonymous());
RefPtr<RenderStyle> newStyle = RenderStyle::create();
newStyle->inheritFrom(pseudoElementStyle);
newStyle->setDisplay(curr->style()->display());
newStyle->setStyleType(curr->style()->styleType());
curr->setStyle(newStyle);
curr = curr->parent();
}
}
for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
if (genChild->isText())
genChild->setStyle(pseudoElementStyle);
else if (genChild->isImage()) {
RefPtr<RenderStyle> style = RenderStyle::create();
style->inheritFrom(pseudoElementStyle);
genChild->setStyle(style.release());
} else {
ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
}
}
}
return; }
RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
RenderObject* generatedContentContainer = 0;
for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
RenderObject* renderer = 0;
switch (content->type()) {
case CONTENT_NONE:
break;
case CONTENT_TEXT:
renderer = new (owner->renderArena()) RenderTextFragment(owner->document() , content->text());
renderer->setStyle(pseudoElementStyle);
break;
case CONTENT_OBJECT: {
RenderImage* image = new (owner->renderArena()) RenderImage(owner->document()); RefPtr<RenderStyle> style = RenderStyle::create();
style->inheritFrom(pseudoElementStyle);
image->setStyle(style.release());
if (StyleImage* styleImage = content->image())
image->setImageResource(RenderImageResourceStyleImage::create(styleImage));
else
image->setImageResource(RenderImageResource::create());
renderer = image;
break;
}
case CONTENT_COUNTER:
renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
renderer->setStyle(pseudoElementStyle);
break;
case CONTENT_QUOTE:
renderer = new (owner->renderArena()) RenderQuote(owner->document(), content->quote());
renderer->setStyle(pseudoElementStyle);
break;
}
if (renderer) {
if (!generatedContentContainer) {
generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
ASSERT(styledObject->node()); generatedContentContainer->setNode(styledObject->node()); generatedContentContainer->setStyle(pseudoElementStyle);
if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) {
generatedContentContainer->destroy();
renderer->destroy();
return;
}
owner->addChild(generatedContentContainer, insertBefore);
}
if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
generatedContentContainer->addChild(renderer);
else
renderer->destroy();
}
}
}
}