#include "dom/dom_exception.h"
#include "css/cssstyleselector.h"
#include "xml/dom2_eventsimpl.h"
#include "xml/dom_textimpl.h"
#include "xml/dom_docimpl.h"
#include "misc/htmlhashes.h"
#include "rendering/render_text.h"
#include <kdebug.h>
using namespace DOM;
using namespace khtml;
CharacterDataImpl::CharacterDataImpl(DocumentImpl *doc)
: NodeImpl(doc)
{
str = 0;
}
CharacterDataImpl::CharacterDataImpl(DocumentImpl *doc, const DOMString &_text)
: NodeImpl(doc)
{
str = _text.impl ? _text.impl : new DOMStringImpl((QChar*)0, 0);
str->ref();
}
CharacterDataImpl::~CharacterDataImpl()
{
if(str) str->deref();
}
DOMString CharacterDataImpl::data() const
{
return str;
}
void CharacterDataImpl::setData( const DOMString &_data, int &exceptioncode )
{
if (isReadOnly()) {
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return;
}
if(str == _data.impl) return; DOMStringImpl *oldStr = str;
str = _data.impl;
if(str) str->ref();
if (m_render)
(static_cast<RenderText*>(m_render))->setText(str);
dispatchModifiedEvent(oldStr);
if(oldStr) oldStr->deref();
getDocument()->removeAllMarkers(this);
}
unsigned long CharacterDataImpl::length() const
{
return str->l;
}
DOMString CharacterDataImpl::substringData( const unsigned long offset, const unsigned long count, int &exceptioncode )
{
exceptioncode = 0;
checkCharDataOperation(offset, exceptioncode);
if (exceptioncode)
return DOMString();
return str->substring(offset,count);
}
void CharacterDataImpl::appendData( const DOMString &arg, int &exceptioncode )
{
exceptioncode = 0;
if (isReadOnly()) {
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return;
}
DOMStringImpl *oldStr = str;
str = str->copy();
str->ref();
str->append(arg.impl);
if (m_render)
(static_cast<RenderText*>(m_render))->setTextWithOffset(str, oldStr->l, 0);
dispatchModifiedEvent(oldStr);
oldStr->deref();
}
void CharacterDataImpl::insertData( const unsigned long offset, const DOMString &arg, int &exceptioncode )
{
exceptioncode = 0;
checkCharDataOperation(offset, exceptioncode);
if (exceptioncode)
return;
DOMStringImpl *oldStr = str;
str = str->copy();
str->ref();
str->insert(arg.impl, offset);
if (m_render)
(static_cast<RenderText*>(m_render))->setTextWithOffset(str, offset, 0);
dispatchModifiedEvent(oldStr);
oldStr->deref();
uint length = arg.length();
getDocument()->shiftMarkers(this, offset, length);
}
void CharacterDataImpl::deleteData( const unsigned long offset, const unsigned long count, int &exceptioncode )
{
exceptioncode = 0;
checkCharDataOperation(offset, exceptioncode);
if (exceptioncode)
return;
DOMStringImpl *oldStr = str;
str = str->copy();
str->ref();
str->remove(offset,count);
if (m_render)
(static_cast<RenderText*>(m_render))->setTextWithOffset(str, offset, count);
dispatchModifiedEvent(oldStr);
oldStr->deref();
getDocument()->removeAllMarkers(this, offset, count);
getDocument()->shiftMarkers(this, offset + count, -count);
}
void CharacterDataImpl::replaceData( const unsigned long offset, const unsigned long count, const DOMString &arg, int &exceptioncode )
{
exceptioncode = 0;
checkCharDataOperation(offset, exceptioncode);
if (exceptioncode)
return;
unsigned long realCount;
if (offset + count > str->l)
realCount = str->l-offset;
else
realCount = count;
DOMStringImpl *oldStr = str;
str = str->copy();
str->ref();
str->remove(offset,realCount);
str->insert(arg.impl, offset);
if (m_render)
(static_cast<RenderText*>(m_render))->setTextWithOffset(str, offset, count);
dispatchModifiedEvent(oldStr);
oldStr->deref();
int diff = arg.length() - count;
getDocument()->removeAllMarkers(this, offset, count);
getDocument()->shiftMarkers(this, offset + count, diff);
}
DOMString CharacterDataImpl::nodeValue() const
{
return str;
}
bool CharacterDataImpl::containsOnlyWhitespace(unsigned int from, unsigned int len) const
{
if (str)
return str->containsOnlyWhitespace(from, len);
return true;
}
bool CharacterDataImpl::containsOnlyWhitespace() const
{
if (str)
return str->containsOnlyWhitespace();
return true;
}
void CharacterDataImpl::setNodeValue( const DOMString &_nodeValue, int &exceptioncode )
{
setData(_nodeValue, exceptioncode);
}
void CharacterDataImpl::dispatchModifiedEvent(DOMStringImpl *prevValue)
{
if (parentNode())
parentNode()->childrenChanged();
if (!getDocument()->hasListenerType(DocumentImpl::DOMCHARACTERDATAMODIFIED_LISTENER))
return;
DOMStringImpl *newValue = str->copy();
newValue->ref();
int exceptioncode = 0;
dispatchEvent(new MutationEventImpl(EventImpl::DOMCHARACTERDATAMODIFIED_EVENT,
true,false,0,prevValue,newValue,DOMString(),0),exceptioncode);
newValue->deref();
dispatchSubtreeModifiedEvent();
}
void CharacterDataImpl::checkCharDataOperation( const unsigned long offset, int &exceptioncode )
{
exceptioncode = 0;
if (offset > str->l) {
exceptioncode = DOMException::INDEX_SIZE_ERR;
return;
}
if (isReadOnly()) {
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return;
}
}
long CharacterDataImpl::maxOffset() const
{
return (long)length();
}
long CharacterDataImpl::caretMinOffset() const
{
RenderText *r = static_cast<RenderText *>(renderer());
return r && r->isText() ? r->caretMinOffset() : 0;
}
long CharacterDataImpl::caretMaxOffset() const
{
RenderText *r = static_cast<RenderText *>(renderer());
return r && r->isText() ? r->caretMaxOffset() : (long)length();
}
unsigned long CharacterDataImpl::caretMaxRenderedOffset() const
{
RenderText *r = static_cast<RenderText *>(renderer());
return r ? r->caretMaxRenderedOffset() : length();
}
bool CharacterDataImpl::rendererIsNeeded(RenderStyle *style)
{
if (!str || str->l == 0)
return false;
return NodeImpl::rendererIsNeeded(style);
}
#ifndef NDEBUG
void CharacterDataImpl::dump(QTextStream *stream, QString ind) const
{
*stream << " str=\"" << DOMString(str).string().ascii() << "\"";
NodeImpl::dump(stream,ind);
}
#endif
CommentImpl::CommentImpl(DocumentImpl *doc, const DOMString &_text)
: CharacterDataImpl(doc, _text)
{
}
CommentImpl::CommentImpl(DocumentImpl *doc)
: CharacterDataImpl(doc)
{
}
CommentImpl::~CommentImpl()
{
}
DOMString CommentImpl::nodeName() const
{
return "#comment";
}
unsigned short CommentImpl::nodeType() const
{
return Node::COMMENT_NODE;
}
NodeImpl *CommentImpl::cloneNode(bool )
{
return getDocument()->createComment( str );
}
NodeImpl::Id CommentImpl::id() const
{
return ID_COMMENT;
}
bool CommentImpl::childTypeAllowed( unsigned short )
{
return false;
}
DOMString CommentImpl::toString() const
{
return DOMString("<!--") + nodeValue() + "-->";
}
TextImpl::TextImpl(DocumentImpl *doc, const DOMString &_text)
: CharacterDataImpl(doc, _text)
{
}
TextImpl::TextImpl(DocumentImpl *doc)
: CharacterDataImpl(doc)
{
}
TextImpl::~TextImpl()
{
}
TextImpl *TextImpl::splitText( const unsigned long offset, int &exceptioncode )
{
exceptioncode = 0;
if (offset > str->l || (long)offset < 0) {
exceptioncode = DOMException::INDEX_SIZE_ERR;
return 0;
}
if (isReadOnly()) {
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return 0;
}
DOMStringImpl *oldStr = str;
TextImpl *newText = createNew(str->substring(offset,str->l-offset));
str = str->copy();
str->ref();
str->remove(offset,str->l-offset);
dispatchModifiedEvent(oldStr);
oldStr->deref();
if (parentNode())
parentNode()->insertBefore(newText,nextSibling(), exceptioncode );
if ( exceptioncode )
return 0;
if (m_render)
(static_cast<RenderText*>(m_render))->setText(str);
return newText;
}
DOMString TextImpl::nodeName() const
{
return "#text";
}
unsigned short TextImpl::nodeType() const
{
return Node::TEXT_NODE;
}
NodeImpl *TextImpl::cloneNode(bool )
{
return getDocument()->createTextNode(str);
}
bool TextImpl::rendererIsNeeded(RenderStyle *style)
{
if (!CharacterDataImpl::rendererIsNeeded(style))
return false;
bool onlyWS = containsOnlyWhitespace();
if (!onlyWS)
return true;
RenderObject *par = parentNode()->renderer();
if (par->isTable() || par->isTableRow() || par->isTableSection() || par->isTableCol())
return false;
if (style->whiteSpace() == PRE)
return true;
RenderObject *prev = previousRenderer();
if (prev && prev->isBR()) return false;
if (par->isInline()) {
if (prev && prev->isRenderBlock())
return false;
} else {
if (par->isRenderBlock() && !par->childrenInline() && (!prev || !prev->isInline()))
return false;
RenderObject *first = par->firstChild();
while (first && first->isFloatingOrPositioned())
first = first->nextSibling();
RenderObject *next = nextRenderer();
if (!first || next == first)
return false;
}
return true;
}
RenderObject *TextImpl::createRenderer(RenderArena *arena, RenderStyle *style)
{
return new (arena) RenderText(this, str);
}
void TextImpl::attach()
{
createRendererIfNeeded();
CharacterDataImpl::attach();
}
NodeImpl::Id TextImpl::id() const
{
return ID_TEXT;
}
void TextImpl::recalcStyle( StyleChange change )
{
if (change != NoChange && parentNode()) {
if(m_render)
m_render->setStyle(parentNode()->renderer()->style());
}
if ( changed() && m_render && m_render->isText() )
static_cast<RenderText*>(m_render)->setText(str);
setChanged( false );
}
bool TextImpl::childTypeAllowed( unsigned short )
{
return false;
}
TextImpl *TextImpl::createNew(DOMStringImpl *_str)
{
return new TextImpl(getDocument(),_str);
}
DOMString TextImpl::toString() const
{
return nodeValue();
}
#ifndef NDEBUG
void TextImpl::formatForDebugger(char *buffer, unsigned length) const
{
DOMString result;
DOMString s;
s = nodeName();
if (s.length() > 0) {
result += s;
}
s = nodeValue();
if (s.length() > 0) {
if (result.length() > 0)
result += "; ";
result += "value=";
result += s;
}
strncpy(buffer, result.string().latin1(), length - 1);
}
#endif
CDATASectionImpl::CDATASectionImpl(DocumentImpl *impl, const DOMString &_text) : TextImpl(impl,_text)
{
}
CDATASectionImpl::CDATASectionImpl(DocumentImpl *impl) : TextImpl(impl)
{
}
CDATASectionImpl::~CDATASectionImpl()
{
}
DOMString CDATASectionImpl::nodeName() const
{
return "#cdata-section";
}
unsigned short CDATASectionImpl::nodeType() const
{
return Node::CDATA_SECTION_NODE;
}
NodeImpl *CDATASectionImpl::cloneNode(bool )
{
return getDocument()->createCDATASection(str);
}
bool CDATASectionImpl::childTypeAllowed( unsigned short )
{
return false;
}
TextImpl *CDATASectionImpl::createNew(DOMStringImpl *_str)
{
return new CDATASectionImpl(getDocument(),_str);
}
DOMString CDATASectionImpl::toString() const
{
return DOMString("<![CDATA[") + nodeValue() + "]]>";
}
EditingTextImpl::EditingTextImpl(DocumentImpl *impl, const DOMString &text)
: TextImpl(impl, text)
{
}
EditingTextImpl::EditingTextImpl(DocumentImpl *impl)
: TextImpl(impl)
{
}
EditingTextImpl::~EditingTextImpl()
{
}
bool EditingTextImpl::rendererIsNeeded(RenderStyle *style)
{
return true;
}