Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Library General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Library General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Library General Public License
     17  * along with this library; see the file COPYING.LIB.  If not, write to
     18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19  * Boston, MA 02110-1301, USA.
     20  */
     21 
     22 #include "config.h"
     23 #include "core/dom/Text.h"
     24 
     25 #include "SVGNames.h"
     26 #include "bindings/v8/ExceptionState.h"
     27 #include "bindings/v8/ExceptionStatePlaceholder.h"
     28 #include "core/css/resolver/StyleResolver.h"
     29 #include "core/dom/ExceptionCode.h"
     30 #include "core/dom/NodeRenderStyle.h"
     31 #include "core/dom/NodeRenderingContext.h"
     32 #include "core/dom/ScopedEventQueue.h"
     33 #include "core/dom/shadow/ShadowRoot.h"
     34 #include "core/rendering/RenderCombineText.h"
     35 #include "core/rendering/RenderText.h"
     36 #include "core/rendering/svg/RenderSVGInlineText.h"
     37 #include "wtf/text/CString.h"
     38 #include "wtf/text/StringBuilder.h"
     39 
     40 using namespace std;
     41 
     42 namespace WebCore {
     43 
     44 PassRefPtr<Text> Text::create(Document* document, const String& data)
     45 {
     46     return adoptRef(new Text(document, data, CreateText));
     47 }
     48 
     49 PassRefPtr<Text> Text::createEditingText(Document* document, const String& data)
     50 {
     51     return adoptRef(new Text(document, data, CreateEditingText));
     52 }
     53 
     54 PassRefPtr<Text> Text::splitText(unsigned offset, ExceptionState& es)
     55 {
     56     // IndexSizeError: Raised if the specified offset is negative or greater than
     57     // the number of 16-bit units in data.
     58     if (offset > length()) {
     59         es.throwDOMException(IndexSizeError);
     60         return 0;
     61     }
     62 
     63     EventQueueScope scope;
     64     String oldStr = data();
     65     RefPtr<Text> newText = cloneWithData(oldStr.substring(offset));
     66     setDataWithoutUpdate(oldStr.substring(0, offset));
     67 
     68     didModifyData(oldStr);
     69 
     70     if (parentNode())
     71         parentNode()->insertBefore(newText.get(), nextSibling(), es);
     72     if (es.hadException())
     73         return 0;
     74 
     75     if (parentNode())
     76         document()->textNodeSplit(this);
     77 
     78     if (renderer())
     79         toRenderText(renderer())->setTextWithOffset(dataImpl(), 0, oldStr.length());
     80 
     81     return newText.release();
     82 }
     83 
     84 static const Text* earliestLogicallyAdjacentTextNode(const Text* t)
     85 {
     86     const Node* n = t;
     87     while ((n = n->previousSibling())) {
     88         Node::NodeType type = n->nodeType();
     89         if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
     90             t = static_cast<const Text*>(n);
     91             continue;
     92         }
     93 
     94         break;
     95     }
     96     return t;
     97 }
     98 
     99 static const Text* latestLogicallyAdjacentTextNode(const Text* t)
    100 {
    101     const Node* n = t;
    102     while ((n = n->nextSibling())) {
    103         Node::NodeType type = n->nodeType();
    104         if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
    105             t = static_cast<const Text*>(n);
    106             continue;
    107         }
    108 
    109         break;
    110     }
    111     return t;
    112 }
    113 
    114 String Text::wholeText() const
    115 {
    116     const Text* startText = earliestLogicallyAdjacentTextNode(this);
    117     const Text* endText = latestLogicallyAdjacentTextNode(this);
    118 
    119     Node* onePastEndText = endText->nextSibling();
    120     unsigned resultLength = 0;
    121     for (const Node* n = startText; n != onePastEndText; n = n->nextSibling()) {
    122         if (!n->isTextNode())
    123             continue;
    124         const Text* t = static_cast<const Text*>(n);
    125         const String& data = t->data();
    126         if (std::numeric_limits<unsigned>::max() - data.length() < resultLength)
    127             CRASH();
    128         resultLength += data.length();
    129     }
    130     StringBuilder result;
    131     result.reserveCapacity(resultLength);
    132     for (const Node* n = startText; n != onePastEndText; n = n->nextSibling()) {
    133         if (!n->isTextNode())
    134             continue;
    135         const Text* t = static_cast<const Text*>(n);
    136         result.append(t->data());
    137     }
    138     ASSERT(result.length() == resultLength);
    139 
    140     return result.toString();
    141 }
    142 
    143 PassRefPtr<Text> Text::replaceWholeText(const String& newText)
    144 {
    145     // Remove all adjacent text nodes, and replace the contents of this one.
    146 
    147     // Protect startText and endText against mutation event handlers removing the last ref
    148     RefPtr<Text> startText = const_cast<Text*>(earliestLogicallyAdjacentTextNode(this));
    149     RefPtr<Text> endText = const_cast<Text*>(latestLogicallyAdjacentTextNode(this));
    150 
    151     RefPtr<Text> protectedThis(this); // Mutation event handlers could cause our last ref to go away
    152     RefPtr<ContainerNode> parent = parentNode(); // Protect against mutation handlers moving this node during traversal
    153     for (RefPtr<Node> n = startText; n && n != this && n->isTextNode() && n->parentNode() == parent;) {
    154         RefPtr<Node> nodeToRemove(n.release());
    155         n = nodeToRemove->nextSibling();
    156         parent->removeChild(nodeToRemove.get(), IGNORE_EXCEPTION);
    157     }
    158 
    159     if (this != endText) {
    160         Node* onePastEndText = endText->nextSibling();
    161         for (RefPtr<Node> n = nextSibling(); n && n != onePastEndText && n->isTextNode() && n->parentNode() == parent;) {
    162             RefPtr<Node> nodeToRemove(n.release());
    163             n = nodeToRemove->nextSibling();
    164             parent->removeChild(nodeToRemove.get(), IGNORE_EXCEPTION);
    165         }
    166     }
    167 
    168     if (newText.isEmpty()) {
    169         if (parent && parentNode() == parent)
    170             parent->removeChild(this, IGNORE_EXCEPTION);
    171         return 0;
    172     }
    173 
    174     setData(newText);
    175     return protectedThis.release();
    176 }
    177 
    178 String Text::nodeName() const
    179 {
    180     return textAtom.string();
    181 }
    182 
    183 Node::NodeType Text::nodeType() const
    184 {
    185     return TEXT_NODE;
    186 }
    187 
    188 PassRefPtr<Node> Text::cloneNode(bool /*deep*/)
    189 {
    190     return cloneWithData(data());
    191 }
    192 
    193 bool Text::textRendererIsNeeded(const NodeRenderingContext& context)
    194 {
    195     if (isEditingText())
    196         return true;
    197 
    198     if (!length())
    199         return false;
    200 
    201     if (context.style()->display() == NONE)
    202         return false;
    203 
    204     if (!containsOnlyWhitespace())
    205         return true;
    206 
    207     RenderObject* parent = context.parentRenderer();
    208     if (!parent->canHaveWhitespaceChildren())
    209         return false;
    210 
    211     if (context.style()->preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
    212         return true;
    213 
    214     RenderObject* prev = context.previousRenderer();
    215     if (prev && prev->isBR()) // <span><br/> <br/></span>
    216         return false;
    217 
    218     if (parent->isRenderInline()) {
    219         // <span><div/> <div/></span>
    220         if (prev && !prev->isInline())
    221             return false;
    222     } else {
    223         if (parent->isRenderBlock() && !parent->childrenInline() && (!prev || !prev->isInline()))
    224             return false;
    225 
    226         // Avoiding creation of a Renderer for the text node is a non-essential memory optimization.
    227         // So to avoid blowing up on very wide DOMs, we limit the number of siblings to visit.
    228         unsigned maxSiblingsToVisit = 50;
    229 
    230         RenderObject* first = parent->firstChild();
    231         while (first && first->isFloatingOrOutOfFlowPositioned() && maxSiblingsToVisit--)
    232             first = first->nextSibling();
    233         if (!first || context.nextRenderer() == first)
    234             // Whitespace at the start of a block just goes away.  Don't even
    235             // make a render object for this text.
    236             return false;
    237     }
    238     return true;
    239 }
    240 
    241 static bool isSVGShadowText(Text* text)
    242 {
    243     Node* parentNode = text->parentNode();
    244     return parentNode->isShadowRoot() && toShadowRoot(parentNode)->host()->hasTagName(SVGNames::trefTag);
    245 }
    246 
    247 static bool isSVGText(Text* text)
    248 {
    249     Node* parentOrShadowHostNode = text->parentOrShadowHostNode();
    250     return parentOrShadowHostNode->isSVGElement() && !parentOrShadowHostNode->hasTagName(SVGNames::foreignObjectTag);
    251 }
    252 
    253 RenderText* Text::createTextRenderer(RenderStyle* style)
    254 {
    255     if (isSVGText(this) || isSVGShadowText(this))
    256         return new RenderSVGInlineText(this, dataImpl());
    257 
    258     if (style->hasTextCombine())
    259         return new RenderCombineText(this, dataImpl());
    260 
    261     return new RenderText(this, dataImpl());
    262 }
    263 
    264 void Text::attach(const AttachContext& context)
    265 {
    266     NodeRenderingContext(this, context.resolvedStyle).createRendererForTextIfNeeded();
    267     CharacterData::attach(context);
    268 }
    269 
    270 bool Text::recalcTextStyle(StyleChange change)
    271 {
    272     if (RenderText* renderer = toRenderText(this->renderer())) {
    273         if (change != NoChange || needsStyleRecalc())
    274             renderer->setStyle(document()->styleResolver()->styleForText(this));
    275         if (needsStyleRecalc())
    276             renderer->setText(dataImpl());
    277         clearNeedsStyleRecalc();
    278     } else if (needsStyleRecalc() || needsWhitespaceRenderer()) {
    279         reattach();
    280         return true;
    281     }
    282     return false;
    283 }
    284 
    285 // If a whitespace node had no renderer and goes through a recalcStyle it may
    286 // need to create one if the parent style now has white-space: pre.
    287 bool Text::needsWhitespaceRenderer()
    288 {
    289     ASSERT(!renderer());
    290     if (RenderStyle* style = parentRenderStyle())
    291         return style->preserveNewline();
    292     return false;
    293 }
    294 
    295 void Text::updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
    296 {
    297     if (!attached())
    298         return;
    299     RenderText* textRenderer = toRenderText(renderer());
    300     if (!textRenderer || !textRendererIsNeeded(NodeRenderingContext(this, textRenderer->style()))) {
    301         reattach();
    302         return;
    303     }
    304     textRenderer->setTextWithOffset(dataImpl(), offsetOfReplacedData, lengthOfReplacedData);
    305 }
    306 
    307 bool Text::childTypeAllowed(NodeType) const
    308 {
    309     return false;
    310 }
    311 
    312 PassRefPtr<Text> Text::cloneWithData(const String& data)
    313 {
    314     return create(document(), data);
    315 }
    316 
    317 PassRefPtr<Text> Text::createWithLengthLimit(Document* document, const String& data, unsigned start, unsigned lengthLimit)
    318 {
    319     unsigned dataLength = data.length();
    320 
    321     if (!start && dataLength <= lengthLimit)
    322         return create(document, data);
    323 
    324     RefPtr<Text> result = Text::create(document, String());
    325     result->parserAppendData(data, start, lengthLimit);
    326 
    327     return result;
    328 }
    329 
    330 #ifndef NDEBUG
    331 void Text::formatForDebugger(char *buffer, unsigned length) const
    332 {
    333     StringBuilder result;
    334     String s;
    335 
    336     result.append(nodeName());
    337 
    338     s = data();
    339     if (s.length() > 0) {
    340         if (result.length())
    341             result.appendLiteral("; ");
    342         result.appendLiteral("value=");
    343         result.append(s);
    344     }
    345 
    346     strncpy(buffer, result.toString().utf8().data(), length - 1);
    347 }
    348 #endif
    349 
    350 } // namespace WebCore
    351