blob: 7221496f8eb32eacd44106b045a96c7898da9108 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
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 "core/dom/CharacterData.h"
24
Ben Murdochdf957042013-08-06 11:01:27 +010025#include "bindings/v8/ExceptionState.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010026#include "core/dom/Document.h"
27#include "core/dom/EventNames.h"
28#include "core/dom/ExceptionCode.h"
29#include "core/dom/MutationEvent.h"
30#include "core/dom/MutationObserverInterestGroup.h"
31#include "core/dom/MutationRecord.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010032#include "core/dom/Text.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010033#include "core/editing/FrameSelection.h"
34#include "core/inspector/InspectorInstrumentation.h"
35#include "core/platform/text/TextBreakIterator.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010036
37using namespace std;
38
39namespace WebCore {
40
Torne (Richard Coles)5267f702013-06-11 10:57:24 +010041void CharacterData::atomize()
42{
43 m_data = AtomicString(m_data);
44}
45
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +010046void CharacterData::setData(const String& data)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010047{
48 const String& nonNullData = !data.isNull() ? data : emptyString();
49 if (m_data == nonNullData)
50 return;
51
52 RefPtr<CharacterData> protect = this;
53
54 unsigned oldLength = length();
55
56 setDataAndUpdate(nonNullData, 0, oldLength, nonNullData.length());
57 document()->textRemoved(this, 0, oldLength);
58}
59
Ben Murdochdf957042013-08-06 11:01:27 +010060String CharacterData::substringData(unsigned offset, unsigned count, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010061{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +010062 if (offset > length()) {
Ben Murdochdf957042013-08-06 11:01:27 +010063 es.throwDOMException(IndexSizeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010064 return String();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +010065 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010066
67 return m_data.substring(offset, count);
68}
69
70unsigned CharacterData::parserAppendData(const String& string, unsigned offset, unsigned lengthLimit)
71{
72 unsigned oldLength = m_data.length();
73
74 ASSERT(lengthLimit >= oldLength);
75
76 unsigned characterLength = string.length() - offset;
77 unsigned characterLengthLimit = min(characterLength, lengthLimit - oldLength);
78
79 // Check that we are not on an unbreakable boundary.
80 // Some text break iterator implementations work best if the passed buffer is as small as possible,
81 // see <https://bugs.webkit.org/show_bug.cgi?id=29092>.
82 // We need at least two characters look-ahead to account for UTF-16 surrogates.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010083 ASSERT(!string.is8Bit() || string.containsOnlyLatin1()); // Latin-1 doesn't have unbreakable boundaries.
84 if (characterLengthLimit < characterLength && !string.is8Bit()) {
85 NonSharedCharacterBreakIterator it(string.characters16() + offset, (characterLengthLimit + 2 > characterLength) ? characterLength : characterLengthLimit + 2);
Ben Murdoche69819b2013-07-17 14:56:49 +010086 if (!it.isBreak(characterLengthLimit))
87 characterLengthLimit = it.preceding(characterLengthLimit);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010088 }
89
90 if (!characterLengthLimit)
91 return 0;
92
93 if (string.is8Bit())
94 m_data.append(string.characters8() + offset, characterLengthLimit);
95 else
96 m_data.append(string.characters16() + offset, characterLengthLimit);
97
98 ASSERT(!renderer() || isTextNode());
99 if (isTextNode())
100 toText(this)->updateTextRenderer(oldLength, 0);
101
102 document()->incDOMTreeVersion();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100103
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100104 if (parentNode())
105 parentNode()->childrenChanged();
106
107 return characterLengthLimit;
108}
109
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100110void CharacterData::appendData(const String& data)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100111{
Ben Murdoch1fad5ca2013-08-07 11:05:11 +0100112 String newStr = m_data + data;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100113
114 setDataAndUpdate(newStr, m_data.length(), 0, data.length());
115
116 // FIXME: Should we call textInserted here?
117}
118
Ben Murdochdf957042013-08-06 11:01:27 +0100119void CharacterData::insertData(unsigned offset, const String& data, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100120{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100121 if (offset > length()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100122 es.throwDOMException(IndexSizeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100123 return;
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100124 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100125
126 String newStr = m_data;
127 newStr.insert(data, offset);
128
129 setDataAndUpdate(newStr, offset, 0, data.length());
130
131 document()->textInserted(this, offset, data.length());
132}
133
Ben Murdochdf957042013-08-06 11:01:27 +0100134void CharacterData::deleteData(unsigned offset, unsigned count, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100135{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100136 if (offset > length()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100137 es.throwDOMException(IndexSizeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100138 return;
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100139 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100140
141 unsigned realCount;
142 if (offset + count > length())
143 realCount = length() - offset;
144 else
145 realCount = count;
146
147 String newStr = m_data;
148 newStr.remove(offset, realCount);
149
150 setDataAndUpdate(newStr, offset, count, 0);
151
152 document()->textRemoved(this, offset, realCount);
153}
154
Ben Murdochdf957042013-08-06 11:01:27 +0100155void CharacterData::replaceData(unsigned offset, unsigned count, const String& data, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100156{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100157 if (offset > length()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100158 es.throwDOMException(IndexSizeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100159 return;
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100160 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100161
162 unsigned realCount;
163 if (offset + count > length())
164 realCount = length() - offset;
165 else
166 realCount = count;
167
168 String newStr = m_data;
169 newStr.remove(offset, realCount);
170 newStr.insert(data, offset);
171
172 setDataAndUpdate(newStr, offset, count, data.length());
173
174 // update the markers for spell checking and grammar checking
175 document()->textRemoved(this, offset, realCount);
176 document()->textInserted(this, offset, data.length());
177}
178
179String CharacterData::nodeValue() const
180{
181 return m_data;
182}
183
184bool CharacterData::containsOnlyWhitespace() const
185{
186 return m_data.containsOnlyWhitespace();
187}
188
Ben Murdoche69819b2013-07-17 14:56:49 +0100189void CharacterData::setNodeValue(const String& nodeValue)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100190{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100191 setData(nodeValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100192}
193
194void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength)
195{
196 String oldData = m_data;
197 m_data = newData;
198
199 ASSERT(!renderer() || isTextNode());
200 if (isTextNode())
201 toText(this)->updateTextRenderer(offsetOfReplacedData, oldLength);
202
203 if (document()->frame())
204 document()->frame()->selection()->textWasReplaced(this, offsetOfReplacedData, oldLength, newLength);
205
206 document()->incDOMTreeVersion();
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100207 didModifyData(oldData);
208}
209
210void CharacterData::didModifyData(const String& oldData)
211{
212 if (OwnPtr<MutationObserverInterestGroup> mutationRecipients = MutationObserverInterestGroup::createForCharacterDataMutation(this))
213 mutationRecipients->enqueueMutationRecord(MutationRecord::createCharacterData(this, oldData));
214
215 if (parentNode())
216 parentNode()->childrenChanged();
217
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100218 if (!isInShadowTree()) {
219 if (document()->hasListenerType(Document::DOMCHARACTERDATAMODIFIED_LISTENER))
220 dispatchScopedEvent(MutationEvent::create(eventNames().DOMCharacterDataModifiedEvent, true, 0, oldData, m_data));
221 dispatchSubtreeModifiedEvent();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100222 }
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100223 InspectorInstrumentation::characterDataModified(document(), this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100224}
225
226int CharacterData::maxCharacterOffset() const
227{
228 return static_cast<int>(length());
229}
230
231bool CharacterData::offsetInCharacters() const
232{
233 return true;
234}
235
236} // namespace WebCore