Commit 74afab63 authored by antti@apple.com's avatar antti@apple.com
Browse files

Don't use NodeRenderingContext when attaching text renderers

https://bugs.webkit.org/show_bug.cgi?id=120402

Reviewed by Andreas Kling.

This patch moves various functions for creating text renderers from NodeRenderingContext and Text to StyleResolveTree.
It also tightens the logic and combines some functions.

* dom/CharacterData.cpp:
(WebCore::CharacterData::parserAppendData):
(WebCore::CharacterData::setDataAndUpdate):
* dom/ContainerNode.cpp:
(WebCore::attachChild):
(WebCore::detachChild):
* dom/NodeRenderingContext.cpp:
* dom/NodeRenderingContext.h:
* dom/Text.cpp:
(WebCore::Text::~Text):
* dom/Text.h:
* html/HTMLViewSourceDocument.cpp:
(WebCore::HTMLViewSourceDocument::addText):
* html/parser/HTMLConstructionSite.cpp:
(WebCore::executeTask):
* html/shadow/InsertionPoint.cpp:
(WebCore::InsertionPoint::willAttachRenderers):
(WebCore::InsertionPoint::willDetachRenderers):
* style/StyleResolveTree.cpp:
(WebCore::Style::isRendererReparented):
(WebCore::Style::previousSiblingRenderer):
(WebCore::Style::nextSiblingRenderer):
        
    From NodeRenderingContext::next/previousRenderer

(WebCore::Style::createTextRenderersForSiblingsAfterAttachIfNeeded):
        
    From Text::createTextRenderersForSiblingsAfterAttachIfNeeded()

(WebCore::Style::textRendererIsNeeded):
        
    From Text::textRendererIsNeeded

(WebCore::Style::createTextRendererIfNeeded):
        
    Combines code from Text::createTextRendererIfNeeded, NodeRenderingContext::createRendererForTextIfNeeded,
    NodeRenderingContext constructor and text node relevant code NodeRenderingContext::shouldCreateRenderer.

(WebCore::Style::attachTextRenderer):
(WebCore::Style::detachTextRenderer):
        
    New functions of attaching text renderers. From Text::attach/detachText()

(WebCore::Style::updateTextRendererAfterContentChange):
        
    From Text::updateTextRenderer.

(WebCore::Style::attachShadowRoot):
(WebCore::Style::attachChildren):
(WebCore::Style::attachRenderTree):
(WebCore::Style::detachShadowRoot):
(WebCore::Style::detachChildren):
(WebCore::Style::updateTextStyle):
* style/StyleResolveTree.h:
* xml/parser/XMLDocumentParser.cpp:
(WebCore::XMLDocumentParser::exitText):
* xml/parser/XMLDocumentParserLibxml2.cpp:
(WebCore::XMLDocumentParser::cdataBlock):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@154738 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 5ffa75e0
2013-08-28 Antti Koivisto <antti@apple.com>
Don't use NodeRenderingContext when attaching text renderers
https://bugs.webkit.org/show_bug.cgi?id=120402
Reviewed by Andreas Kling.
This patch moves various functions for creating text renderers from NodeRenderingContext and Text to StyleResolveTree.
It also tightens the logic and combines some functions.
* dom/CharacterData.cpp:
(WebCore::CharacterData::parserAppendData):
(WebCore::CharacterData::setDataAndUpdate):
* dom/ContainerNode.cpp:
(WebCore::attachChild):
(WebCore::detachChild):
* dom/NodeRenderingContext.cpp:
* dom/NodeRenderingContext.h:
* dom/Text.cpp:
(WebCore::Text::~Text):
* dom/Text.h:
* html/HTMLViewSourceDocument.cpp:
(WebCore::HTMLViewSourceDocument::addText):
* html/parser/HTMLConstructionSite.cpp:
(WebCore::executeTask):
* html/shadow/InsertionPoint.cpp:
(WebCore::InsertionPoint::willAttachRenderers):
(WebCore::InsertionPoint::willDetachRenderers):
* style/StyleResolveTree.cpp:
(WebCore::Style::isRendererReparented):
(WebCore::Style::previousSiblingRenderer):
(WebCore::Style::nextSiblingRenderer):
From NodeRenderingContext::next/previousRenderer
(WebCore::Style::createTextRenderersForSiblingsAfterAttachIfNeeded):
From Text::createTextRenderersForSiblingsAfterAttachIfNeeded()
(WebCore::Style::textRendererIsNeeded):
From Text::textRendererIsNeeded
(WebCore::Style::createTextRendererIfNeeded):
Combines code from Text::createTextRendererIfNeeded, NodeRenderingContext::createRendererForTextIfNeeded,
NodeRenderingContext constructor and text node relevant code NodeRenderingContext::shouldCreateRenderer.
(WebCore::Style::attachTextRenderer):
(WebCore::Style::detachTextRenderer):
New functions of attaching text renderers. From Text::attach/detachText()
(WebCore::Style::updateTextRendererAfterContentChange):
From Text::updateTextRenderer.
(WebCore::Style::attachShadowRoot):
(WebCore::Style::attachChildren):
(WebCore::Style::attachRenderTree):
(WebCore::Style::detachShadowRoot):
(WebCore::Style::detachChildren):
(WebCore::Style::updateTextStyle):
* style/StyleResolveTree.h:
* xml/parser/XMLDocumentParser.cpp:
(WebCore::XMLDocumentParser::exitText):
* xml/parser/XMLDocumentParserLibxml2.cpp:
(WebCore::XMLDocumentParser::cdataBlock):
2013-08-28 Antti Koivisto <antti@apple.com>
 
Make descendant iterators always require ContainerNode root
......@@ -91,7 +91,7 @@ unsigned CharacterData::parserAppendData(const String& string, unsigned offset,
ASSERT(!renderer() || isTextNode());
if (isTextNode())
toText(this)->updateTextRenderer(oldLength, 0);
Style::updateTextRendererAfterContentChange(*toText(this), oldLength, 0);
document()->incDOMTreeVersion();
// We don't call dispatchModifiedEvent here because we don't want the
......@@ -191,7 +191,7 @@ void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfRep
ASSERT(!renderer() || isTextNode());
if (isTextNode())
toText(this)->updateTextRenderer(offsetOfReplacedData, oldLength);
Style::updateTextRendererAfterContentChange(*toText(this), offsetOfReplacedData, oldLength);
if (document()->frame())
document()->frame()->selection().textWasReplaced(this, offsetOfReplacedData, oldLength, newLength);
......
......@@ -110,7 +110,7 @@ static inline void attachChild(Node* child)
if (child->isElementNode())
Style::attachRenderTree(toElement(child));
else if (child->isTextNode())
toText(child)->attachText();
Style::attachTextRenderer(*toText(child));
}
static inline void detachChild(Node* child)
......@@ -118,7 +118,7 @@ static inline void detachChild(Node* child)
if (child->isElementNode())
Style::detachRenderTree(toElement(child));
else if (child->isTextNode())
toText(child)->detachText();
Style::detachTextRenderer(*toText(child));
}
void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent)
......
......@@ -285,45 +285,6 @@ void NodeRenderingContext::createRendererForElementIfNeeded()
parentRenderer->addChild(newRenderer, nextRenderer);
}
void NodeRenderingContext::createRendererForTextIfNeeded()
{
ASSERT(!m_node->renderer());
Text* textNode = toText(m_node);
if (!shouldCreateRenderer())
return;
RenderObject* parentRenderer = this->parentRenderer();
ASSERT(parentRenderer);
Document* document = textNode->document();
if (resetStyleInheritance())
m_style = document->ensureStyleResolver().defaultStyleForElement();
else
m_style = parentRenderer->style();
if (!textNode->textRendererIsNeeded(*this))
return;
RenderText* newRenderer = textNode->createTextRenderer(document->renderArena(), m_style.get());
if (!newRenderer)
return;
if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) {
newRenderer->destroy();
return;
}
// Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
// for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
RenderObject* nextRenderer = this->nextRenderer();
textNode->setRenderer(newRenderer);
// Parent takes care of the animations, no need to call setAnimatableStyle.
newRenderer->setStyle(m_style.release());
parentRenderer->addChild(newRenderer, nextRenderer);
}
bool NodeRenderingContext::resetStyleInheritance() const
{
ContainerNode* parent = m_node->parentNode();
......
......@@ -50,7 +50,6 @@ public:
NodeRenderingContext(Node*, const Style::AttachContext&);
~NodeRenderingContext();
void createRendererForTextIfNeeded();
void createRendererForElementIfNeeded();
Node* node() const;
......
......@@ -58,8 +58,7 @@ PassRefPtr<Text> Text::createEditingText(Document* document, const String& data)
Text::~Text()
{
if (renderer())
detachText();
ASSERT(!renderer());
}
PassRefPtr<Text> Text::splitText(unsigned offset, ExceptionCode& ec)
......@@ -178,52 +177,6 @@ PassRefPtr<Node> Text::cloneNode(bool /*deep*/)
return create(document(), data());
}
bool Text::textRendererIsNeeded(const NodeRenderingContext& context)
{
if (isEditingText())
return true;
if (!length())
return false;
if (context.style()->display() == NONE)
return false;
bool onlyWS = containsOnlyWhitespace();
if (!onlyWS)
return true;
RenderObject* parent = context.parentRenderer();
if (parent->isTable() || parent->isTableRow() || parent->isTableSection() || parent->isRenderTableCol() || parent->isFrameSet())
return false;
if (context.style()->preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
return true;
RenderObject* prev = context.previousRenderer();
if (prev && prev->isBR()) // <span><br/> <br/></span>
return false;
if (parent->isRenderInline()) {
// <span><div/> <div/></span>
if (prev && !prev->isInline())
return false;
} else {
if (parent->isRenderBlock() && !parent->childrenInline() && (!prev || !prev->isInline()))
return false;
RenderObject* first = parent->firstChild();
while (first && first->isFloatingOrOutOfFlowPositioned())
first = first->nextSibling();
if (!first || context.nextRenderer() == first) {
// Whitespace at the start of a block just goes away. Don't even
// make a render object for this text.
return false;
}
}
return true;
}
#if ENABLE(SVG)
static bool isSVGShadowText(Text* text)
......@@ -239,11 +192,6 @@ static bool isSVGText(Text* text)
}
#endif
void Text::createTextRendererIfNeeded()
{
NodeRenderingContext(this).createRendererForTextIfNeeded();
}
RenderText* Text::createTextRenderer(RenderArena* arena, RenderStyle* style)
{
#if ENABLE(SVG)
......@@ -256,70 +204,6 @@ RenderText* Text::createTextRenderer(RenderArena* arena, RenderStyle* style)
return new (arena) RenderText(this, dataImpl());
}
void Text::createTextRenderersForSiblingsAfterAttachIfNeeded(Node* sibling)
{
ASSERT(sibling->previousSibling());
ASSERT(sibling->previousSibling()->renderer());
ASSERT(!sibling->renderer());
ASSERT(sibling->attached());
// If this node got a renderer it may be the previousRenderer() of sibling text nodes and thus affect the
// result of Text::textRendererIsNeeded() for those nodes.
for (; sibling; sibling = sibling->nextSibling()) {
if (sibling->renderer())
break;
if (!sibling->attached())
break; // Assume this means none of the following siblings are attached.
if (!sibling->isTextNode())
continue;
ASSERT(!sibling->renderer());
toText(sibling)->createTextRendererIfNeeded();
// If we again decided not to create a renderer for next, we can bail out the loop,
// because it won't affect the result of Text::textRendererIsNeeded() for the rest
// of sibling nodes.
if (!sibling->renderer())
break;
}
}
void Text::attachText()
{
createTextRendererIfNeeded();
Node* sibling = nextSibling();
if (renderer() && sibling && !sibling->renderer() && sibling->attached())
createTextRenderersForSiblingsAfterAttachIfNeeded(sibling);
setAttached(true);
clearNeedsStyleRecalc();
}
void Text::detachText()
{
if (renderer())
renderer()->destroyAndCleanupAnonymousWrappers();
setRenderer(0);
setAttached(false);
}
void Text::updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
{
if (!attached())
return;
RenderText* textRenderer = toRenderText(renderer());
if (!textRenderer) {
attachText();
return;
}
NodeRenderingContext renderingContext(this, textRenderer->style());
if (!textRendererIsNeeded(renderingContext)) {
if (attached())
detachText();
attachText();
return;
}
textRenderer->setTextWithOffset(dataImpl(), offsetOfReplacedData, lengthOfReplacedData);
}
bool Text::childTypeAllowed(NodeType) const
{
return false;
......
......@@ -48,15 +48,7 @@ public:
String wholeText() const;
PassRefPtr<Text> replaceWholeText(const String&, ExceptionCode&);
void createTextRendererIfNeeded();
bool textRendererIsNeeded(const NodeRenderingContext&);
RenderText* createTextRenderer(RenderArena*, RenderStyle*);
void updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData);
void attachText();
void detachText();
static void createTextRenderersForSiblingsAfterAttachIfNeeded(Node*);
virtual bool canContainRangeEndPoint() const OVERRIDE FINAL { return true; }
......
......@@ -253,7 +253,7 @@ void HTMLViewSourceDocument::addText(const String& text, const AtomicString& cla
}
RefPtr<Text> text = Text::create(this, substring);
m_current->parserAppendChild(text);
text->attachText();
Style::attachTextRenderer(*text);
if (i < size - 1)
finishLine();
}
......
......@@ -103,7 +103,7 @@ static inline void executeTask(HTMLConstructionSiteTask& task)
if (task.child->isElementNode())
Style::attachRenderTree(toElement(task.child.get()));
else if (task.child->isTextNode())
toText(task.child.get())->attachText();
Style::attachTextRenderer(*toText(task.child.get()));
}
task.child->beginParsingChildren();
......
......@@ -60,7 +60,7 @@ void InsertionPoint::willAttachRenderers()
if (current->attached())
continue;
if (current->isTextNode()) {
toText(current)->attachText();
Style::attachTextRenderer(*toText(current));
continue;
}
if (current->isElementNode())
......@@ -75,7 +75,7 @@ void InsertionPoint::willDetachRenderers()
for (Node* current = firstDistributed(); current; current = nextDistributedTo(current)) {
if (current->isTextNode()) {
toText(current)->detachText();
Style::detachTextRenderer(*toText(current));
continue;
}
if (current->isElementNode())
......
......@@ -109,6 +109,185 @@ static void createRendererIfNeeded(Element* element, const AttachContext& contex
NodeRenderingContext(element, context).createRendererForElementIfNeeded();
}
static bool isRendererReparented(const RenderObject* renderer)
{
if (!renderer->node()->isElementNode())
return false;
if (renderer->style() && !renderer->style()->flowThread().isEmpty())
return true;
return false;
}
static RenderObject* previousSiblingRenderer(const Text& textNode)
{
if (textNode.renderer())
return textNode.renderer()->previousSibling();
for (Node* sibling = NodeRenderingTraversal::previousSibling(&textNode); sibling; sibling = NodeRenderingTraversal::previousSibling(sibling)) {
RenderObject* renderer = sibling->renderer();
if (renderer && !isRendererReparented(renderer))
return renderer;
}
return 0;
}
static RenderObject* nextSiblingRenderer(const Text& textNode)
{
if (textNode.renderer())
return textNode.renderer()->nextSibling();
for (Node* sibling = NodeRenderingTraversal::nextSibling(&textNode); sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) {
RenderObject* renderer = sibling->renderer();
if (renderer && !isRendererReparented(renderer))
return renderer;
}
return 0;
}
static void createTextRenderersForSiblingsAfterAttachIfNeeded(Node* sibling)
{
ASSERT(sibling->previousSibling());
ASSERT(sibling->previousSibling()->renderer());
ASSERT(!sibling->renderer());
ASSERT(sibling->attached());
// If this node got a renderer it may be the previousRenderer() of sibling text nodes and thus affect the
// result of Text::textRendererIsNeeded() for those nodes.
for (; sibling; sibling = sibling->nextSibling()) {
if (sibling->renderer())
break;
if (!sibling->attached())
break; // Assume this means none of the following siblings are attached.
if (!sibling->isTextNode())
continue;
ASSERT(!sibling->renderer());
attachTextRenderer(*toText(sibling));
// If we again decided not to create a renderer for next, we can bail out the loop,
// because it won't affect the result of Text::textRendererIsNeeded() for the rest
// of sibling nodes.
if (!sibling->renderer())
break;
}
}
static bool textRendererIsNeeded(const Text& textNode, const RenderObject& parentRenderer, const RenderStyle& style)
{
if (textNode.isEditingText())
return true;
if (!textNode.length())
return false;
if (style.display() == NONE)
return false;
if (!textNode.containsOnlyWhitespace())
return true;
// This text node has nothing but white space. We may still need a renderer in some cases.
if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
return false;
if (style.preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
return true;
RenderObject* previousRenderer = previousSiblingRenderer(textNode);
if (previousRenderer && previousRenderer->isBR()) // <span><br/> <br/></span>
return false;
if (parentRenderer.isRenderInline()) {
// <span><div/> <div/></span>
if (previousRenderer && !previousRenderer->isInline())
return false;
} else {
if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
return false;
RenderObject* first = parentRenderer.firstChild();
while (first && first->isFloatingOrOutOfFlowPositioned())
first = first->nextSibling();
RenderObject* nextRenderer = nextSiblingRenderer(textNode);
if (!first || nextRenderer == first) {
// Whitespace at the start of a block just goes away. Don't even make a render object for this text.
return false;
}
}
return true;
}
static void createTextRendererIfNeeded(Text& textNode)
{
ASSERT(!textNode.renderer());
ContainerNode* renderingParentNode = NodeRenderingTraversal::parent(&textNode);
if (!renderingParentNode)
return;
RenderObject* parentRenderer = renderingParentNode->renderer();
if (!parentRenderer || !parentRenderer->canHaveChildren())
return;
if (!renderingParentNode->childShouldCreateRenderer(&textNode))
return;
Document* document = textNode.document();
RefPtr<RenderStyle> style;
bool resetStyleInheritance = renderingParentNode->isShadowRoot() && toShadowRoot(renderingParentNode)->resetStyleInheritance();
if (resetStyleInheritance)
style = document->ensureStyleResolver().defaultStyleForElement();
else
style = parentRenderer->style();
if (!textRendererIsNeeded(textNode, *parentRenderer, *style))
return;
RenderText* newRenderer = textNode.createTextRenderer(document->renderArena(), style.get());
if (!newRenderer)
return;
if (!parentRenderer->isChildAllowed(newRenderer, style.get())) {
newRenderer->destroy();
return;
}
// Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
// for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
RenderObject* nextRenderer = nextSiblingRenderer(textNode);
textNode.setRenderer(newRenderer);
// Parent takes care of the animations, no need to call setAnimatableStyle.
newRenderer->setStyle(style.release());
parentRenderer->addChild(newRenderer, nextRenderer);
Node* sibling = textNode.nextSibling();
if (sibling && !sibling->renderer() && sibling->attached())
createTextRenderersForSiblingsAfterAttachIfNeeded(sibling);
}
void attachTextRenderer(Text& textNode)
{
createTextRendererIfNeeded(textNode);
textNode.setAttached(true);
textNode.clearNeedsStyleRecalc();
}
void detachTextRenderer(Text& textNode)
{
if (textNode.renderer())
textNode.renderer()->destroyAndCleanupAnonymousWrappers();
textNode.setRenderer(0);
textNode.setAttached(false);
}
void updateTextRendererAfterContentChange(Text& textNode, unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
{
if (!textNode.attached())
return;
RenderText* textRenderer = toRenderText(textNode.renderer());
if (!textRenderer) {
attachTextRenderer(textNode);
return;
}
RenderObject* parentRenderer = NodeRenderingTraversal::parent(&textNode)->renderer();
if (!textRendererIsNeeded(textNode, *parentRenderer, *textRenderer->style())) {
detachTextRenderer(textNode);
attachTextRenderer(textNode);
return;
}
textRenderer->setTextWithOffset(textNode.dataImpl(), offsetOfReplacedData, lengthOfReplacedData);
}
static void attachShadowRoot(ShadowRoot* shadowRoot, const AttachContext& context)
{
if (shadowRoot->attached())
......@@ -120,7 +299,7 @@ static void attachShadowRoot(ShadowRoot* shadowRoot, const AttachContext& contex
childrenContext.resolvedStyle = 0;
for (Node* child = shadowRoot->firstChild(); child; child = child->nextSibling()) {
if (child->isTextNode()) {
toText(child)->attachText();
attachTextRenderer(*toText(child));
continue;
}
if (child->isElementNode())
......@@ -155,7 +334,7 @@ static void attachChildren(Element* current, const AttachContext& context)
if (child->attached())
continue;
if (child->isTextNode()) {
toText(child)->attachText();
attachTextRenderer(*toText(child));
continue;
}
if (child->isElementNode())
......@@ -191,7 +370,7 @@ void attachRenderTree(Element* current, const AttachContext& context)
Node* sibling = current->nextSibling();
if (current->renderer() && sibling && !sibling->renderer() && sibling->attached())
Text::createTextRenderersForSiblingsAfterAttachIfNeeded(sibling);
createTextRenderersForSiblingsAfterAttachIfNeeded(sibling);
current->setAttached(true);
current->clearNeedsStyleRecalc();
......@@ -217,7 +396,7 @@ static void detachShadowRoot(ShadowRoot* shadowRoot, const AttachContext& contex
childrenContext.resolvedStyle = 0;
for (Node* child = shadowRoot->firstChild(); child; child = child->nextSibling()) {
if (child->isTextNode()) {
toText(child)->detachText();
Style::detachTextRenderer(*toText(child));
continue;
}
if (child->isElementNode())
......@@ -234,7 +413,7 @@ static void detachChildren(Element* current, const AttachContext& context)
for (Node* child = current->firstChild(); child; child = child->nextSibling()) {
if (child->isTextNode()) {
toText(child)->detachText();
Style::detachTextRenderer(*toText(child));
continue;
}
if (child->isElementNode())
......@@ -373,7 +552,7 @@ static void updateTextStyle(Text* text, RenderStyle* parentElementStyle, Style::
if (renderer)
renderer->setText(text->dataImpl());
else
text->attachText();