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