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 Apple Inc. All rights reserved.
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.
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.
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.
27 #include "ExceptionCode.h"
28 #include "RenderText.h"
29 #include "TextBreakIterator.h"
32 #include "RenderSVGInlineText.h"
39 Text::Text(Document
* document
, const String
& text
)
40 : CharacterData(document
, text
)
44 Text::Text(Document
* document
)
45 : CharacterData(document
)
53 PassRefPtr
<Text
> Text::splitText(unsigned offset
, ExceptionCode
& ec
)
57 // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than
58 // the number of 16-bit units in data.
59 if (offset
> m_data
->length()) {
64 RefPtr
<StringImpl
> oldStr
= m_data
;
65 RefPtr
<Text
> newText
= createNew(oldStr
->substring(offset
));
66 m_data
= oldStr
->substring(0, offset
);
68 dispatchModifiedEvent(oldStr
.get());
71 parentNode()->insertBefore(newText
.get(), nextSibling(), ec
);
76 document()->textNodeSplit(this);
79 static_cast<RenderText
*>(renderer())->setText(m_data
);
81 return newText
.release();
84 static const Text
* earliestLogicallyAdjacentTextNode(const Text
* 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
);
94 // We would need to visit EntityReference child text nodes if they existed
95 ASSERT(type
!= Node::ENTITY_REFERENCE_NODE
|| !n
->hasChildNodes());
101 static const Text
* latestLogicallyAdjacentTextNode(const Text
* t
)
104 while ((n
= n
->nextSibling())) {
105 Node::NodeType type
= n
->nodeType();
106 if (type
== Node::TEXT_NODE
|| type
== Node::CDATA_SECTION_NODE
) {
107 t
= static_cast<const Text
*>(n
);
111 // We would need to visit EntityReference child text nodes if they existed
112 ASSERT(type
!= Node::ENTITY_REFERENCE_NODE
|| !n
->hasChildNodes());
118 String
Text::wholeText() const
120 const Text
* startText
= earliestLogicallyAdjacentTextNode(this);
121 const Text
* endText
= latestLogicallyAdjacentTextNode(this);
123 Vector
<UChar
> result
;
124 Node
* onePastEndText
= endText
->nextSibling();
125 for (const Node
* n
= startText
; n
!= onePastEndText
; n
= n
->nextSibling()) {
126 if (!n
->isTextNode())
128 const Text
* t
= static_cast<const Text
*>(n
);
129 const String
& data
= t
->data();
130 result
.append(data
.characters(), data
.length());
133 return String::adopt(result
);
136 PassRefPtr
<Text
> Text::replaceWholeText(const String
& newText
, ExceptionCode
&)
138 // Remove all adjacent text nodes, and replace the contents of this one.
140 // Protect startText and endText against mutation event handlers removing the last ref
141 RefPtr
<Text
> startText
= const_cast<Text
*>(earliestLogicallyAdjacentTextNode(this));
142 RefPtr
<Text
> endText
= const_cast<Text
*>(latestLogicallyAdjacentTextNode(this));
144 RefPtr
<Text
> protectedThis(this); // Mutation event handlers could cause our last ref to go away
145 Node
* parent
= parentNode(); // Protect against mutation handlers moving this node during traversal
146 ExceptionCode ignored
= 0;
147 for (RefPtr
<Node
> n
= startText
; n
&& n
!= this && n
->isTextNode() && n
->parentNode() == parent
;) {
148 RefPtr
<Node
> nodeToRemove(n
.release());
149 n
= nodeToRemove
->nextSibling();
150 parent
->removeChild(nodeToRemove
.get(), ignored
);
153 if (this != endText
) {
154 Node
* onePastEndText
= endText
->nextSibling();
155 for (RefPtr
<Node
> n
= nextSibling(); n
&& n
!= onePastEndText
&& n
->isTextNode() && n
->parentNode() == parent
;) {
156 RefPtr
<Node
> nodeToRemove(n
.release());
157 n
= nodeToRemove
->nextSibling();
158 parent
->removeChild(nodeToRemove
.get(), ignored
);
162 if (newText
.isEmpty()) {
163 if (parent
&& parentNode() == parent
)
164 parent
->removeChild(this, ignored
);
168 setData(newText
, ignored
);
169 return protectedThis
.release();
172 String
Text::nodeName() const
174 return textAtom
.string();
177 Node::NodeType
Text::nodeType() const
182 PassRefPtr
<Node
> Text::cloneNode(bool /*deep*/)
184 return document()->createTextNode(m_data
);
187 bool Text::rendererIsNeeded(RenderStyle
*style
)
189 if (!CharacterData::rendererIsNeeded(style
))
192 bool onlyWS
= containsOnlyWhitespace();
196 RenderObject
*par
= parentNode()->renderer();
198 if (par
->isTable() || par
->isTableRow() || par
->isTableSection() || par
->isTableCol() || par
->isFrameSet())
201 if (style
->preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
204 RenderObject
*prev
= previousRenderer();
205 if (prev
&& prev
->isBR()) // <span><br/> <br/></span>
208 if (par
->isInlineFlow()) {
209 // <span><div/> <div/></span>
210 if (prev
&& !prev
->isInline())
213 if (par
->isRenderBlock() && !par
->childrenInline() && (!prev
|| !prev
->isInline()))
216 RenderObject
*first
= par
->firstChild();
217 while (first
&& first
->isFloatingOrPositioned())
218 first
= first
->nextSibling();
219 RenderObject
*next
= nextRenderer();
220 if (!first
|| next
== first
)
221 // Whitespace at the start of a block just goes away. Don't even
222 // make a render object for this text.
229 RenderObject
*Text::createRenderer(RenderArena
*arena
, RenderStyle
*style
)
232 if (parentNode()->isSVGElement())
233 return new (arena
) RenderSVGInlineText(this, m_data
);
234 #endif // ENABLE(SVG)
236 return new (arena
) RenderText(this, m_data
);
241 createRendererIfNeeded();
242 CharacterData::attach();
245 void Text::recalcStyle(StyleChange change
)
247 if (change
!= NoChange
&& parentNode()) {
249 renderer()->setStyle(parentNode()->renderer()->style());
253 if (renderer()->isText())
254 static_cast<RenderText
*>(renderer())->setText(m_data
);
261 setChanged(NoStyleChange
);
265 bool Text::childTypeAllowed(NodeType
)
270 PassRefPtr
<Text
> Text::createNew(PassRefPtr
<StringImpl
> string
)
272 return new Text(document(), string
);
275 PassRefPtr
<Text
> Text::createWithLengthLimit(Document
* doc
, const String
& text
, unsigned& charsLeft
, unsigned maxChars
)
277 if (charsLeft
== text
.length() && charsLeft
<= maxChars
) {
279 return new Text(doc
, text
);
282 unsigned start
= text
.length() - charsLeft
;
283 unsigned end
= start
+ std::min(charsLeft
, maxChars
);
285 // check we are not on an unbreakable boundary
286 TextBreakIterator
* it
= characterBreakIterator(text
.characters(), text
.length());
287 if (end
< text
.length() && !isTextBreak(it
, end
))
288 end
= textBreakPreceding(it
, end
);
290 // maxChars of unbreakable characters could lead to infinite loop
294 String nodeText
= text
.substring(start
, end
- start
);
295 charsLeft
= text
.length() - end
;
297 return new Text(doc
, nodeText
);
301 void Text::formatForDebugger(char *buffer
, unsigned length
) const
307 if (s
.length() > 0) {
312 if (s
.length() > 0) {
313 if (result
.length() > 0)
319 strncpy(buffer
, result
.utf8().data(), length
- 1);
323 } // namespace WebCore