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 "ExceptionCode.h"
26 #include "RenderCombineText.h"
27 #include "RenderText.h"
28
29 #if ENABLE(SVG)
30 #include "RenderSVGInlineText.h"
31 #include "SVGNames.h"
32 #endif
33
34 using namespace std;
35
36 namespace WebCore {
37
create(Document * document,const String & data)38 PassRefPtr<Text> Text::create(Document* document, const String& data)
39 {
40 return adoptRef(new Text(document, data));
41 }
42
splitText(unsigned offset,ExceptionCode & ec)43 PassRefPtr<Text> Text::splitText(unsigned offset, ExceptionCode& ec)
44 {
45 ec = 0;
46
47 // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than
48 // the number of 16-bit units in data.
49 if (offset > length()) {
50 ec = INDEX_SIZE_ERR;
51 return 0;
52 }
53
54 RefPtr<StringImpl> oldStr = dataImpl();
55 RefPtr<Text> newText = virtualCreate(oldStr->substring(offset));
56 setDataImpl(oldStr->substring(0, offset));
57
58 dispatchModifiedEvent(oldStr.get());
59
60 if (parentNode())
61 parentNode()->insertBefore(newText.get(), nextSibling(), ec);
62 if (ec)
63 return 0;
64
65 if (parentNode())
66 document()->textNodeSplit(this);
67
68 if (renderer())
69 toRenderText(renderer())->setTextWithOffset(dataImpl(), 0, oldStr->length());
70
71 return newText.release();
72 }
73
earliestLogicallyAdjacentTextNode(const Text * t)74 static const Text* earliestLogicallyAdjacentTextNode(const Text* t)
75 {
76 const Node* n = t;
77 while ((n = n->previousSibling())) {
78 Node::NodeType type = n->nodeType();
79 if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
80 t = static_cast<const Text*>(n);
81 continue;
82 }
83
84 // We would need to visit EntityReference child text nodes if they existed
85 ASSERT(type != Node::ENTITY_REFERENCE_NODE || !n->hasChildNodes());
86 break;
87 }
88 return t;
89 }
90
latestLogicallyAdjacentTextNode(const Text * t)91 static const Text* latestLogicallyAdjacentTextNode(const Text* t)
92 {
93 const Node* n = t;
94 while ((n = n->nextSibling())) {
95 Node::NodeType type = n->nodeType();
96 if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
97 t = static_cast<const Text*>(n);
98 continue;
99 }
100
101 // We would need to visit EntityReference child text nodes if they existed
102 ASSERT(type != Node::ENTITY_REFERENCE_NODE || !n->hasChildNodes());
103 break;
104 }
105 return t;
106 }
107
wholeText() const108 String Text::wholeText() const
109 {
110 const Text* startText = earliestLogicallyAdjacentTextNode(this);
111 const Text* endText = latestLogicallyAdjacentTextNode(this);
112
113 Node* onePastEndText = endText->nextSibling();
114 unsigned resultLength = 0;
115 for (const Node* n = startText; n != onePastEndText; n = n->nextSibling()) {
116 if (!n->isTextNode())
117 continue;
118 const Text* t = static_cast<const Text*>(n);
119 const String& data = t->data();
120 if (std::numeric_limits<unsigned>::max() - data.length() < resultLength)
121 CRASH();
122 resultLength += data.length();
123 }
124 UChar* resultData;
125 String result = String::createUninitialized(resultLength, resultData);
126 UChar* p = resultData;
127 for (const Node* n = startText; n != onePastEndText; n = n->nextSibling()) {
128 if (!n->isTextNode())
129 continue;
130 const Text* t = static_cast<const Text*>(n);
131 const String& data = t->data();
132 unsigned dataLength = data.length();
133 memcpy(p, data.characters(), dataLength * sizeof(UChar));
134 p += dataLength;
135 }
136 ASSERT(p == resultData + resultLength);
137
138 return result;
139 }
140
replaceWholeText(const String & newText,ExceptionCode &)141 PassRefPtr<Text> Text::replaceWholeText(const String& newText, ExceptionCode&)
142 {
143 // Remove all adjacent text nodes, and replace the contents of this one.
144
145 // Protect startText and endText against mutation event handlers removing the last ref
146 RefPtr<Text> startText = const_cast<Text*>(earliestLogicallyAdjacentTextNode(this));
147 RefPtr<Text> endText = const_cast<Text*>(latestLogicallyAdjacentTextNode(this));
148
149 RefPtr<Text> protectedThis(this); // Mutation event handlers could cause our last ref to go away
150 ContainerNode* parent = parentNode(); // Protect against mutation handlers moving this node during traversal
151 ExceptionCode ignored = 0;
152 for (RefPtr<Node> n = startText; n && n != this && n->isTextNode() && n->parentNode() == parent;) {
153 RefPtr<Node> nodeToRemove(n.release());
154 n = nodeToRemove->nextSibling();
155 parent->removeChild(nodeToRemove.get(), ignored);
156 }
157
158 if (this != endText) {
159 Node* onePastEndText = endText->nextSibling();
160 for (RefPtr<Node> n = nextSibling(); n && n != onePastEndText && n->isTextNode() && n->parentNode() == parent;) {
161 RefPtr<Node> nodeToRemove(n.release());
162 n = nodeToRemove->nextSibling();
163 parent->removeChild(nodeToRemove.get(), ignored);
164 }
165 }
166
167 if (newText.isEmpty()) {
168 if (parent && parentNode() == parent)
169 parent->removeChild(this, ignored);
170 return 0;
171 }
172
173 setData(newText, ignored);
174 return protectedThis.release();
175 }
176
nodeName() const177 String Text::nodeName() const
178 {
179 return textAtom.string();
180 }
181
nodeType() const182 Node::NodeType Text::nodeType() const
183 {
184 return TEXT_NODE;
185 }
186
cloneNode(bool)187 PassRefPtr<Node> Text::cloneNode(bool /*deep*/)
188 {
189 return create(document(), data());
190 }
191
rendererIsNeeded(RenderStyle * style)192 bool Text::rendererIsNeeded(RenderStyle *style)
193 {
194 if (!CharacterData::rendererIsNeeded(style))
195 return false;
196
197 bool onlyWS = containsOnlyWhitespace();
198 if (!onlyWS)
199 return true;
200
201 RenderObject *par = parentNode()->renderer();
202
203 if (par->isTable() || par->isTableRow() || par->isTableSection() || par->isTableCol() || par->isFrameSet())
204 return false;
205
206 if (style->preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
207 return true;
208
209 RenderObject *prev = previousRenderer();
210 if (prev && prev->isBR()) // <span><br/> <br/></span>
211 return false;
212
213 if (par->isRenderInline()) {
214 // <span><div/> <div/></span>
215 if (prev && !prev->isInline())
216 return false;
217 } else {
218 if (par->isRenderBlock() && !par->childrenInline() && (!prev || !prev->isInline()))
219 return false;
220
221 RenderObject *first = par->firstChild();
222 while (first && first->isFloatingOrPositioned())
223 first = first->nextSibling();
224 RenderObject *next = nextRenderer();
225 if (!first || next == first)
226 // Whitespace at the start of a block just goes away. Don't even
227 // make a render object for this text.
228 return false;
229 }
230
231 return true;
232 }
233
createRenderer(RenderArena * arena,RenderStyle * style)234 RenderObject* Text::createRenderer(RenderArena* arena, RenderStyle* style)
235 {
236 #if ENABLE(SVG)
237 Node* parentOrHost = parentOrHostNode();
238 if (parentOrHost->isSVGElement()
239 #if ENABLE(SVG_FOREIGN_OBJECT)
240 && !parentOrHost->hasTagName(SVGNames::foreignObjectTag)
241 #endif
242 )
243 return new (arena) RenderSVGInlineText(this, dataImpl());
244 #endif
245
246 if (style->hasTextCombine())
247 return new (arena) RenderCombineText(this, dataImpl());
248
249 return new (arena) RenderText(this, dataImpl());
250 }
251
attach()252 void Text::attach()
253 {
254 createRendererIfNeeded();
255 CharacterData::attach();
256 }
257
recalcStyle(StyleChange change)258 void Text::recalcStyle(StyleChange change)
259 {
260 if (change != NoChange && parentNode()) {
261 if (renderer())
262 renderer()->setStyle(parentNode()->renderer()->style());
263 }
264 if (needsStyleRecalc()) {
265 if (renderer()) {
266 if (renderer()->isText())
267 toRenderText(renderer())->setText(dataImpl());
268 } else {
269 if (attached())
270 detach();
271 attach();
272 }
273 }
274 clearNeedsStyleRecalc();
275 }
276
childTypeAllowed(NodeType) const277 bool Text::childTypeAllowed(NodeType) const
278 {
279 return false;
280 }
281
virtualCreate(const String & data)282 PassRefPtr<Text> Text::virtualCreate(const String& data)
283 {
284 return create(document(), data);
285 }
286
createWithLengthLimit(Document * document,const String & data,unsigned start,unsigned maxChars)287 PassRefPtr<Text> Text::createWithLengthLimit(Document* document, const String& data, unsigned start, unsigned maxChars)
288 {
289 unsigned dataLength = data.length();
290
291 if (!start && dataLength <= maxChars)
292 return create(document, data);
293
294 RefPtr<Text> result = Text::create(document, String());
295 result->parserAppendData(data.characters() + start, dataLength - start, maxChars);
296
297 return result;
298 }
299
300 #ifndef NDEBUG
formatForDebugger(char * buffer,unsigned length) const301 void Text::formatForDebugger(char *buffer, unsigned length) const
302 {
303 String result;
304 String s;
305
306 s = nodeName();
307 if (s.length() > 0) {
308 result += s;
309 }
310
311 s = data();
312 if (s.length() > 0) {
313 if (result.length() > 0)
314 result += "; ";
315 result += "value=";
316 result += s;
317 }
318
319 strncpy(buffer, result.utf8().data(), length - 1);
320 }
321 #endif
322
323 } // namespace WebCore
324