2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * Copyright (C) 2003 Apple Computer, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 #include "dom/dom_exception.h"
25 #include "css/cssstyleselector.h"
26 #include "xml/dom2_eventsimpl.h"
27 #include "xml/dom_textimpl.h"
28 #include "xml/dom_docimpl.h"
30 #include "misc/htmlhashes.h"
31 #include "rendering/render_text.h"
36 using namespace khtml;
39 CharacterDataImpl::CharacterDataImpl(DocumentPtr *doc)
45 CharacterDataImpl::CharacterDataImpl(DocumentPtr *doc, const DOMString &_text)
48 str = _text.impl ? _text.impl : new DOMStringImpl((QChar*)0, 0);
52 CharacterDataImpl::~CharacterDataImpl()
57 DOMString CharacterDataImpl::data() const
62 void CharacterDataImpl::setData( const DOMString &_data, int &exceptioncode )
64 // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
66 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
70 if(str == _data.impl) return; // ### fire DOMCharacterDataModified if modified?
71 DOMStringImpl *oldStr = str;
75 (static_cast<RenderText*>(m_render))->setText(str);
77 dispatchModifiedEvent(oldStr);
78 if(oldStr) oldStr->deref();
80 getDocument()->removeAllMarkers(this);
83 unsigned long CharacterDataImpl::length() const
88 DOMString CharacterDataImpl::substringData( const unsigned long offset, const unsigned long count, int &exceptioncode )
91 checkCharDataOperation(offset, exceptioncode);
95 return str->substring(offset,count);
98 void CharacterDataImpl::appendData( const DOMString &arg, int &exceptioncode )
102 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly
104 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
108 DOMStringImpl *oldStr = str;
111 str->append(arg.impl);
113 (static_cast<RenderText*>(m_render))->setTextWithOffset(str, oldStr->l, 0);
115 dispatchModifiedEvent(oldStr);
119 void CharacterDataImpl::insertData( const unsigned long offset, const DOMString &arg, int &exceptioncode )
122 checkCharDataOperation(offset, exceptioncode);
126 DOMStringImpl *oldStr = str;
129 str->insert(arg.impl, offset);
131 (static_cast<RenderText*>(m_render))->setTextWithOffset(str, offset, 0);
133 dispatchModifiedEvent(oldStr);
136 // update the markers for spell checking and grammar checking
137 uint length = arg.length();
138 getDocument()->shiftMarkers(this, offset, length);
141 void CharacterDataImpl::deleteData( const unsigned long offset, const unsigned long count, int &exceptioncode )
144 checkCharDataOperation(offset, exceptioncode);
148 DOMStringImpl *oldStr = str;
151 str->remove(offset,count);
153 (static_cast<RenderText*>(m_render))->setTextWithOffset(str, offset, count);
155 dispatchModifiedEvent(oldStr);
158 // update the markers for spell checking and grammar checking
159 getDocument()->removeAllMarkers(this, offset, count);
160 getDocument()->shiftMarkers(this, offset + count, -count);
163 void CharacterDataImpl::replaceData( const unsigned long offset, const unsigned long count, const DOMString &arg, int &exceptioncode )
166 checkCharDataOperation(offset, exceptioncode);
170 unsigned long realCount;
171 if (offset + count > str->l)
172 realCount = str->l-offset;
176 DOMStringImpl *oldStr = str;
179 str->remove(offset,realCount);
180 str->insert(arg.impl, offset);
182 (static_cast<RenderText*>(m_render))->setTextWithOffset(str, offset, count);
184 dispatchModifiedEvent(oldStr);
187 // update the markers for spell checking and grammar checking
188 int diff = arg.length() - count;
189 getDocument()->removeAllMarkers(this, offset, count);
190 getDocument()->shiftMarkers(this, offset + count, diff);
193 DOMString CharacterDataImpl::nodeValue() const
198 bool CharacterDataImpl::containsOnlyWhitespace(unsigned int from, unsigned int len) const
201 return str->containsOnlyWhitespace(from, len);
205 bool CharacterDataImpl::containsOnlyWhitespace() const
208 return str->containsOnlyWhitespace();
212 void CharacterDataImpl::setNodeValue( const DOMString &_nodeValue, int &exceptioncode )
214 // NO_MODIFICATION_ALLOWED_ERR: taken care of by setData()
215 setData(_nodeValue, exceptioncode);
218 void CharacterDataImpl::dispatchModifiedEvent(DOMStringImpl *prevValue)
221 parentNode()->childrenChanged();
222 if (!getDocument()->hasListenerType(DocumentImpl::DOMCHARACTERDATAMODIFIED_LISTENER))
225 DOMStringImpl *newValue = str->copy();
227 int exceptioncode = 0;
228 dispatchEvent(new MutationEventImpl(EventImpl::DOMCHARACTERDATAMODIFIED_EVENT,
229 true,false,0,prevValue,newValue,DOMString(),0),exceptioncode);
231 dispatchSubtreeModifiedEvent();
234 void CharacterDataImpl::checkCharDataOperation( const unsigned long offset, int &exceptioncode )
238 // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than the number of 16-bit
240 if (offset > str->l) {
241 exceptioncode = DOMException::INDEX_SIZE_ERR;
245 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly
247 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
252 long CharacterDataImpl::maxOffset() const
254 return (long)length();
257 long CharacterDataImpl::caretMinOffset() const
259 RenderText *r = static_cast<RenderText *>(renderer());
260 return r && r->isText() ? r->caretMinOffset() : 0;
263 long CharacterDataImpl::caretMaxOffset() const
265 RenderText *r = static_cast<RenderText *>(renderer());
266 return r && r->isText() ? r->caretMaxOffset() : (long)length();
269 unsigned long CharacterDataImpl::caretMaxRenderedOffset() const
271 RenderText *r = static_cast<RenderText *>(renderer());
272 return r ? r->caretMaxRenderedOffset() : length();
276 void CharacterDataImpl::dump(QTextStream *stream, QString ind) const
278 *stream << " str=\"" << DOMString(str).string().ascii() << "\"";
280 NodeImpl::dump(stream,ind);
284 // ---------------------------------------------------------------------------
286 CommentImpl::CommentImpl(DocumentPtr *doc, const DOMString &_text)
287 : CharacterDataImpl(doc, _text)
291 CommentImpl::CommentImpl(DocumentPtr *doc)
292 : CharacterDataImpl(doc)
296 CommentImpl::~CommentImpl()
300 DOMString CommentImpl::nodeName() const
305 unsigned short CommentImpl::nodeType() const
307 return Node::COMMENT_NODE;
310 NodeImpl *CommentImpl::cloneNode(bool /*deep*/)
312 return getDocument()->createComment( str );
315 NodeImpl::Id CommentImpl::id() const
321 bool CommentImpl::childTypeAllowed( unsigned short /*type*/ )
326 DOMString CommentImpl::toString() const
328 // FIXME: substitute entity references as needed!
329 return DOMString("<!--") + nodeValue() + "-->";
332 // ---------------------------------------------------------------------------
334 // ### allow having children in text nodes for entities, comments etc.
336 TextImpl::TextImpl(DocumentPtr *doc, const DOMString &_text)
337 : CharacterDataImpl(doc, _text)
341 TextImpl::TextImpl(DocumentPtr *doc)
342 : CharacterDataImpl(doc)
346 TextImpl::~TextImpl()
350 TextImpl *TextImpl::splitText( const unsigned long offset, int &exceptioncode )
354 // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than
355 // the number of 16-bit units in data.
357 // ### we explicitly check for a negative long that has been cast to an unsigned long
358 // ... this can happen if JS code passes in -1 - we need to catch this earlier! (in the
360 if (offset > str->l || (long)offset < 0) {
361 exceptioncode = DOMException::INDEX_SIZE_ERR;
365 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
367 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
371 DOMStringImpl *oldStr = str;
372 TextImpl *newText = createNew(str->substring(offset,str->l-offset));
375 str->remove(offset,str->l-offset);
377 dispatchModifiedEvent(oldStr);
381 parentNode()->insertBefore(newText,nextSibling(), exceptioncode );
386 (static_cast<RenderText*>(m_render))->setText(str);
390 DOMString TextImpl::nodeName() const
395 unsigned short TextImpl::nodeType() const
397 return Node::TEXT_NODE;
400 NodeImpl *TextImpl::cloneNode(bool /*deep*/)
402 return getDocument()->createTextNode(str);
405 bool TextImpl::rendererIsNeeded(RenderStyle *style)
407 if (!CharacterDataImpl::rendererIsNeeded(style)) {
410 bool onlyWS = containsOnlyWhitespace();
415 RenderObject *par = parentNode()->renderer();
417 if (par->isTable() || par->isTableRow() || par->isTableSection() || par->isTableCol()) {
421 if (style->whiteSpace() == PRE) {
425 if (par->isInline()) {
426 // <span><div/> <div/></span>
427 RenderObject *prev = previousRenderer();
428 if (prev && prev->isRenderBlock()) {
432 RenderObject *prev = previousRenderer();
433 if (par->isRenderBlock() && !par->childrenInline() && (!prev || !prev->isInline())) {
437 RenderObject *first = par->firstChild();
438 RenderObject *next = nextRenderer();
439 if (!first || next == first) {
440 // Whitespace at the start of a block just goes away. Don't even
441 // make a render object for this text.
449 RenderObject *TextImpl::createRenderer(RenderArena *arena, RenderStyle *style)
451 return new (arena) RenderText(this, str);
454 void TextImpl::attach()
456 createRendererIfNeeded();
457 CharacterDataImpl::attach();
460 NodeImpl::Id TextImpl::id() const
465 void TextImpl::recalcStyle( StyleChange change )
467 // qDebug("textImpl::recalcStyle");
468 if (change != NoChange && parentNode()) {
469 // qDebug("DomText::recalcStyle");
471 m_render->setStyle(parentNode()->renderer()->style());
473 if ( changed() && m_render && m_render->isText() )
474 static_cast<RenderText*>(m_render)->setText(str);
479 bool TextImpl::childTypeAllowed( unsigned short /*type*/ )
484 TextImpl *TextImpl::createNew(DOMStringImpl *_str)
486 return new TextImpl(docPtr(),_str);
489 DOMString TextImpl::toString() const
491 // FIXME: substitute entity references as needed!
496 void TextImpl::formatForDebugger(char *buffer, unsigned length) const
502 if (s.length() > 0) {
507 if (s.length() > 0) {
508 if (result.length() > 0)
514 strncpy(buffer, result.string().latin1(), length - 1);
518 // ---------------------------------------------------------------------------
520 CDATASectionImpl::CDATASectionImpl(DocumentPtr *impl, const DOMString &_text) : TextImpl(impl,_text)
524 CDATASectionImpl::CDATASectionImpl(DocumentPtr *impl) : TextImpl(impl)
528 CDATASectionImpl::~CDATASectionImpl()
532 DOMString CDATASectionImpl::nodeName() const
534 return "#cdata-section";
537 unsigned short CDATASectionImpl::nodeType() const
539 return Node::CDATA_SECTION_NODE;
542 NodeImpl *CDATASectionImpl::cloneNode(bool /*deep*/)
544 return getDocument()->createCDATASection(str);
548 bool CDATASectionImpl::childTypeAllowed( unsigned short /*type*/ )
553 TextImpl *CDATASectionImpl::createNew(DOMStringImpl *_str)
555 return new CDATASectionImpl(docPtr(),_str);
558 DOMString CDATASectionImpl::toString() const
560 // FIXME: substitute entity references as needed!
561 return DOMString("<![CDATA[") + nodeValue() + "]]>";
564 // ---------------------------------------------------------------------------
566 EditingTextImpl::EditingTextImpl(DocumentPtr *impl, const DOMString &text)
567 : TextImpl(impl, text)
571 EditingTextImpl::EditingTextImpl(DocumentPtr *impl)
576 EditingTextImpl::~EditingTextImpl()
580 bool EditingTextImpl::rendererIsNeeded(RenderStyle *style)