1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@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 "Text.h"
24
25#include "CString.h"
26#include "ExceptionCode.h"
27#include "RenderText.h"
28#include "TextBreakIterator.h"
29
30#if ENABLE(SVG)
31#include "RenderSVGInlineText.h"
32#include "SVGNames.h"
33#endif
34
35#if ENABLE(WML)
36#include "WMLDocument.h"
37#include "WMLVariables.h"
38#endif
39
40using namespace std;
41
42namespace WebCore {
43
44Text::Text(Document* document, const String& data)
45    : CharacterData(document, data, CreateText)
46{
47}
48
49PassRefPtr<Text> Text::create(Document* document, const String& data)
50{
51    return adoptRef(new Text(document, data));
52}
53
54PassRefPtr<Text> Text::splitText(unsigned offset, ExceptionCode& ec)
55{
56    ec = 0;
57
58    // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than
59    // the number of 16-bit units in data.
60    if (offset > length()) {
61        ec = INDEX_SIZE_ERR;
62        return 0;
63    }
64
65    RefPtr<StringImpl> oldStr = dataImpl();
66    RefPtr<Text> newText = virtualCreate(oldStr->substring(offset));
67    setDataImpl(oldStr->substring(0, offset));
68
69    dispatchModifiedEvent(oldStr.get());
70
71    if (parentNode())
72        parentNode()->insertBefore(newText.get(), nextSibling(), ec);
73    if (ec)
74        return 0;
75
76    if (parentNode())
77        document()->textNodeSplit(this);
78
79    if (renderer())
80        toRenderText(renderer())->setText(dataImpl());
81
82    return newText.release();
83}
84
85static const Text* earliestLogicallyAdjacentTextNode(const Text* t)
86{
87    const Node* n = t;
88    while ((n = n->previousSibling())) {
89        Node::NodeType type = n->nodeType();
90        if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
91            t = static_cast<const Text*>(n);
92            continue;
93        }
94
95        // We would need to visit EntityReference child text nodes if they existed
96        ASSERT(type != Node::ENTITY_REFERENCE_NODE || !n->hasChildNodes());
97        break;
98    }
99    return t;
100}
101
102static const Text* latestLogicallyAdjacentTextNode(const Text* t)
103{
104    const Node* n = t;
105    while ((n = n->nextSibling())) {
106        Node::NodeType type = n->nodeType();
107        if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
108            t = static_cast<const Text*>(n);
109            continue;
110        }
111
112        // We would need to visit EntityReference child text nodes if they existed
113        ASSERT(type != Node::ENTITY_REFERENCE_NODE || !n->hasChildNodes());
114        break;
115    }
116    return t;
117}
118
119String Text::wholeText() const
120{
121    const Text* startText = earliestLogicallyAdjacentTextNode(this);
122    const Text* endText = latestLogicallyAdjacentTextNode(this);
123
124    Node* onePastEndText = endText->nextSibling();
125    unsigned resultLength = 0;
126    for (const Node* n = startText; n != onePastEndText; n = n->nextSibling()) {
127        if (!n->isTextNode())
128            continue;
129        const Text* t = static_cast<const Text*>(n);
130        const String& data = t->data();
131        resultLength += data.length();
132    }
133    UChar* resultData;
134    String result = String::createUninitialized(resultLength, resultData);
135    UChar* p = resultData;
136    for (const Node* n = startText; n != onePastEndText; n = n->nextSibling()) {
137        if (!n->isTextNode())
138            continue;
139        const Text* t = static_cast<const Text*>(n);
140        const String& data = t->data();
141        unsigned dataLength = data.length();
142        memcpy(p, data.characters(), dataLength * sizeof(UChar));
143        p += dataLength;
144    }
145    ASSERT(p == resultData + resultLength);
146
147    return result;
148}
149
150PassRefPtr<Text> Text::replaceWholeText(const String& newText, ExceptionCode&)
151{
152    // Remove all adjacent text nodes, and replace the contents of this one.
153
154    // Protect startText and endText against mutation event handlers removing the last ref
155    RefPtr<Text> startText = const_cast<Text*>(earliestLogicallyAdjacentTextNode(this));
156    RefPtr<Text> endText = const_cast<Text*>(latestLogicallyAdjacentTextNode(this));
157
158    RefPtr<Text> protectedThis(this); // Mutation event handlers could cause our last ref to go away
159    Node* parent = parentNode(); // Protect against mutation handlers moving this node during traversal
160    ExceptionCode ignored = 0;
161    for (RefPtr<Node> n = startText; n && n != this && n->isTextNode() && n->parentNode() == parent;) {
162        RefPtr<Node> nodeToRemove(n.release());
163        n = nodeToRemove->nextSibling();
164        parent->removeChild(nodeToRemove.get(), ignored);
165    }
166
167    if (this != endText) {
168        Node* onePastEndText = endText->nextSibling();
169        for (RefPtr<Node> n = nextSibling(); n && n != onePastEndText && n->isTextNode() && n->parentNode() == parent;) {
170            RefPtr<Node> nodeToRemove(n.release());
171            n = nodeToRemove->nextSibling();
172            parent->removeChild(nodeToRemove.get(), ignored);
173        }
174    }
175
176    if (newText.isEmpty()) {
177        if (parent && parentNode() == parent)
178            parent->removeChild(this, ignored);
179        return 0;
180    }
181
182    setData(newText, ignored);
183    return protectedThis.release();
184}
185
186String Text::nodeName() const
187{
188    return textAtom.string();
189}
190
191Node::NodeType Text::nodeType() const
192{
193    return TEXT_NODE;
194}
195
196PassRefPtr<Node> Text::cloneNode(bool /*deep*/)
197{
198    return create(document(), data());
199}
200
201bool Text::rendererIsNeeded(RenderStyle *style)
202{
203    if (!CharacterData::rendererIsNeeded(style))
204        return false;
205
206    bool onlyWS = containsOnlyWhitespace();
207    if (!onlyWS)
208        return true;
209
210    RenderObject *par = parentNode()->renderer();
211
212    if (par->isTable() || par->isTableRow() || par->isTableSection() || par->isTableCol() || par->isFrameSet())
213        return false;
214
215    if (style->preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
216        return true;
217
218    RenderObject *prev = previousRenderer();
219    if (prev && prev->isBR()) // <span><br/> <br/></span>
220        return false;
221
222    if (par->isRenderInline()) {
223        // <span><div/> <div/></span>
224        if (prev && !prev->isInline())
225            return false;
226    } else {
227        if (par->isRenderBlock() && !par->childrenInline() && (!prev || !prev->isInline()))
228            return false;
229
230        RenderObject *first = par->firstChild();
231        while (first && first->isFloatingOrPositioned())
232            first = first->nextSibling();
233        RenderObject *next = nextRenderer();
234        if (!first || next == first)
235            // Whitespace at the start of a block just goes away.  Don't even
236            // make a render object for this text.
237            return false;
238    }
239
240    return true;
241}
242
243RenderObject* Text::createRenderer(RenderArena* arena, RenderStyle*)
244{
245#if ENABLE(SVG)
246    if (parentNode()->isSVGElement()
247#if ENABLE(SVG_FOREIGN_OBJECT)
248        && !parentNode()->hasTagName(SVGNames::foreignObjectTag)
249#endif
250    )
251        return new (arena) RenderSVGInlineText(this, dataImpl());
252#endif
253
254    return new (arena) RenderText(this, dataImpl());
255}
256
257void Text::attach()
258{
259#if ENABLE(WML)
260    if (document()->isWMLDocument() && !containsOnlyWhitespace()) {
261        String text = data();
262        ASSERT(!text.isEmpty());
263
264        text = substituteVariableReferences(text, document());
265
266        ExceptionCode code = 0;
267        setData(text, code);
268        ASSERT(!code);
269    }
270#endif
271
272    createRendererIfNeeded();
273    CharacterData::attach();
274}
275
276void Text::recalcStyle(StyleChange change)
277{
278    if (change != NoChange && parentNode()) {
279        if (renderer())
280            renderer()->setStyle(parentNode()->renderer()->style());
281    }
282    if (needsStyleRecalc()) {
283        if (renderer()) {
284            if (renderer()->isText())
285                toRenderText(renderer())->setText(dataImpl());
286        } else {
287            if (attached())
288                detach();
289            attach();
290        }
291    }
292    setNeedsStyleRecalc(NoStyleChange);
293}
294
295bool Text::childTypeAllowed(NodeType)
296{
297    return false;
298}
299
300PassRefPtr<Text> Text::virtualCreate(const String& data)
301{
302    return create(document(), data);
303}
304
305PassRefPtr<Text> Text::createWithLengthLimit(Document* document, const String& data, unsigned& charsLeft, unsigned maxChars)
306{
307    unsigned dataLength = data.length();
308
309    if (charsLeft == dataLength && charsLeft <= maxChars) {
310        charsLeft = 0;
311        return create(document, data);
312    }
313
314    unsigned start = dataLength - charsLeft;
315    unsigned end = start + min(charsLeft, maxChars);
316
317    // Check we are not on an unbreakable boundary.
318    // Some text break iterator implementations work best if the passed buffer is as small as possible,
319    // see <https://bugs.webkit.org/show_bug.cgi?id=29092>.
320    // We need at least two characters look-ahead to account for UTF-16 surrogates.
321    if (end < dataLength) {
322        TextBreakIterator* it = characterBreakIterator(data.characters() + start, (end + 2 > dataLength) ? dataLength - start : end - start + 2);
323        if (!isTextBreak(it, end - start))
324            end = textBreakPreceding(it, end - start) + start;
325    }
326
327    // If we have maxChars of unbreakable characters the above could lead to
328    // an infinite loop.
329    // FIXME: It would be better to just have the old value of end before calling
330    // textBreakPreceding rather than this, because this exceeds the length limit.
331    if (end <= start)
332        end = dataLength;
333
334    charsLeft = dataLength - end;
335    return create(document, data.substring(start, end - start));
336}
337
338#ifndef NDEBUG
339void Text::formatForDebugger(char *buffer, unsigned length) const
340{
341    String result;
342    String s;
343
344    s = nodeName();
345    if (s.length() > 0) {
346        result += s;
347    }
348
349    s = data();
350    if (s.length() > 0) {
351        if (result.length() > 0)
352            result += "; ";
353        result += "value=";
354        result += s;
355    }
356
357    strncpy(buffer, result.utf8().data(), length - 1);
358}
359#endif
360
361} // namespace WebCore
362