1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) 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 25 #include "bindings/v8/ExceptionState.h" 26 #include "core/dom/Document.h" 27 #include "core/dom/ExceptionCode.h" 28 #include "core/dom/MutationObserverInterestGroup.h" 29 #include "core/dom/MutationRecord.h" 30 #include "core/dom/ProcessingInstruction.h" 31 #include "core/dom/Text.h" 32 #include "core/editing/FrameSelection.h" 33 #include "core/events/MutationEvent.h" 34 #include "core/events/ThreadLocalEventNames.h" 35 #include "core/inspector/InspectorInstrumentation.h" 36 37 using namespace std; 38 39 namespace WebCore { 40 41 void CharacterData::atomize() 42 { 43 m_data = AtomicString(m_data); 44 } 45 46 void CharacterData::setData(const String& data) 47 { 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().didRemoveText(this, 0, oldLength); 58 } 59 60 String CharacterData::substringData(unsigned offset, unsigned count, ExceptionState& exceptionState) 61 { 62 if (offset > length()) { 63 exceptionState.throwDOMException(IndexSizeError, "The offset " + String::number(offset) + " is greater than the node's length (" + String::number(length()) + ")."); 64 return String(); 65 } 66 67 return m_data.substring(offset, count); 68 } 69 70 void CharacterData::parserAppendData(const String& string) 71 { 72 unsigned oldLength = m_data.length(); 73 m_data.append(string); 74 75 ASSERT(!renderer() || isTextNode()); 76 if (isTextNode()) 77 toText(this)->updateTextRenderer(oldLength, 0); 78 79 document().incDOMTreeVersion(); 80 81 if (parentNode()) 82 parentNode()->childrenChanged(); 83 } 84 85 void CharacterData::appendData(const String& data) 86 { 87 String newStr = m_data + data; 88 89 setDataAndUpdate(newStr, m_data.length(), 0, data.length()); 90 91 // FIXME: Should we call textInserted here? 92 } 93 94 void CharacterData::insertData(unsigned offset, const String& data, ExceptionState& exceptionState, RecalcStyleBehavior recalcStyleBehavior) 95 { 96 if (offset > length()) { 97 exceptionState.throwDOMException(IndexSizeError, "The offset " + String::number(offset) + " is greater than the node's length (" + String::number(length()) + ")."); 98 return; 99 } 100 101 String newStr = m_data; 102 newStr.insert(data, offset); 103 104 setDataAndUpdate(newStr, offset, 0, data.length(), recalcStyleBehavior); 105 106 document().didInsertText(this, offset, data.length()); 107 } 108 109 void CharacterData::deleteData(unsigned offset, unsigned count, ExceptionState& exceptionState, RecalcStyleBehavior recalcStyleBehavior) 110 { 111 if (offset > length()) { 112 exceptionState.throwDOMException(IndexSizeError, "The offset " + String::number(offset) + " is greater than the node's length (" + String::number(length()) + ")."); 113 return; 114 } 115 116 unsigned realCount; 117 if (offset + count > length()) 118 realCount = length() - offset; 119 else 120 realCount = count; 121 122 String newStr = m_data; 123 newStr.remove(offset, realCount); 124 125 setDataAndUpdate(newStr, offset, count, 0, recalcStyleBehavior); 126 127 document().didRemoveText(this, offset, realCount); 128 } 129 130 void CharacterData::replaceData(unsigned offset, unsigned count, const String& data, ExceptionState& exceptionState) 131 { 132 if (offset > length()) { 133 exceptionState.throwDOMException(IndexSizeError, "The offset " + String::number(offset) + " is greater than the node's length (" + String::number(length()) + ")."); 134 return; 135 } 136 137 unsigned realCount; 138 if (offset + count > length()) 139 realCount = length() - offset; 140 else 141 realCount = count; 142 143 String newStr = m_data; 144 newStr.remove(offset, realCount); 145 newStr.insert(data, offset); 146 147 setDataAndUpdate(newStr, offset, count, data.length()); 148 149 // update the markers for spell checking and grammar checking 150 document().didRemoveText(this, offset, realCount); 151 document().didInsertText(this, offset, data.length()); 152 } 153 154 String CharacterData::nodeValue() const 155 { 156 return m_data; 157 } 158 159 bool CharacterData::containsOnlyWhitespace() const 160 { 161 return m_data.containsOnlyWhitespace(); 162 } 163 164 void CharacterData::setNodeValue(const String& nodeValue) 165 { 166 setData(nodeValue); 167 } 168 169 void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, RecalcStyleBehavior recalcStyleBehavior) 170 { 171 String oldData = m_data; 172 m_data = newData; 173 174 ASSERT(!renderer() || isTextNode()); 175 if (isTextNode()) 176 toText(this)->updateTextRenderer(offsetOfReplacedData, oldLength, recalcStyleBehavior); 177 178 if (nodeType() == PROCESSING_INSTRUCTION_NODE) 179 toProcessingInstruction(this)->checkStyleSheet(); 180 181 if (document().frame()) 182 document().frame()->selection().didUpdateCharacterData(this, offsetOfReplacedData, oldLength, newLength); 183 184 document().incDOMTreeVersion(); 185 didModifyData(oldData); 186 } 187 188 void CharacterData::didModifyData(const String& oldData) 189 { 190 if (OwnPtr<MutationObserverInterestGroup> mutationRecipients = MutationObserverInterestGroup::createForCharacterDataMutation(*this)) 191 mutationRecipients->enqueueMutationRecord(MutationRecord::createCharacterData(this, oldData)); 192 193 if (parentNode()) 194 parentNode()->childrenChanged(); 195 196 if (!isInShadowTree()) { 197 if (document().hasListenerType(Document::DOMCHARACTERDATAMODIFIED_LISTENER)) 198 dispatchScopedEvent(MutationEvent::create(EventTypeNames::DOMCharacterDataModified, true, 0, oldData, m_data)); 199 dispatchSubtreeModifiedEvent(); 200 } 201 InspectorInstrumentation::characterDataModified(this); 202 } 203 204 int CharacterData::maxCharacterOffset() const 205 { 206 return static_cast<int>(length()); 207 } 208 209 bool CharacterData::offsetInCharacters() const 210 { 211 return true; 212 } 213 214 } // namespace WebCore 215