html_elementimpl.cpp [plain text]
#include "html/dtd.h"
#include "html/html_elementimpl.h"
#include "html/html_documentimpl.h"
#include "html/htmltokenizer.h"
#include "misc/htmlhashes.h"
#include "khtmlview.h"
#include "khtml_part.h"
#include "rendering/render_object.h"
#include "rendering/render_replaced.h"
#include "css/css_valueimpl.h"
#include "css/css_stylesheetimpl.h"
#include "css/cssproperties.h"
#include "css/cssvalues.h"
#include "xml/dom_textimpl.h"
#include "xml/dom2_eventsimpl.h"
#include <kdebug.h>
using namespace DOM;
using namespace khtml;
HTMLElementImpl::HTMLElementImpl(DocumentPtr *doc)
: ElementImpl(doc),
m_contentEditable(FlagNone)
{
}
HTMLElementImpl::~HTMLElementImpl()
{
}
bool HTMLElementImpl::isInline() const
{
if (renderer())
return ElementImpl::isInline();
switch(id()) {
case ID_A:
case ID_FONT:
case ID_TT:
case ID_U:
case ID_B:
case ID_I:
case ID_S:
case ID_STRIKE:
case ID_BIG:
case ID_SMALL:
case ID_EM:
case ID_STRONG:
case ID_DFN:
case ID_CODE:
case ID_SAMP:
case ID_KBD:
case ID_VAR:
case ID_CITE:
case ID_ABBR:
case ID_ACRONYM:
case ID_SUB:
case ID_SUP:
case ID_SPAN:
case ID_NOBR:
case ID_WBR:
return true;
default:
return ElementImpl::isInline();
}
}
void HTMLElementImpl::parseAttribute(AttributeImpl *attr)
{
DOMString indexstring;
switch( attr->id() )
{
case ATTR_ALIGN:
if (attr->val()) {
if ( strcasecmp(attr->value(), "middle" ) == 0 )
addCSSProperty( CSS_PROP_TEXT_ALIGN, "center" );
else
addCSSProperty(CSS_PROP_TEXT_ALIGN, attr->value());
}
else
removeCSSProperty(CSS_PROP_TEXT_ALIGN);
break;
case ATTR_ID:
setHasID(attr->val());
setChanged();
break;
case ATTR_CLASS:
setHasClass(attr->val());
setChanged();
break;
case ATTR_CONTENTEDITABLE:
{
setContentEditable(attr->value());
setChanged();
break;
}
case ATTR_STYLE:
setHasStyle();
if(!m_styleDecls) createDecl();
m_styleDecls->setProperty(attr->value());
setChanged();
break;
case ATTR_TABINDEX:
indexstring=getAttribute(ATTR_TABINDEX);
if (indexstring.length())
setTabIndex(indexstring.toInt());
break;
case ATTR_LANG:
break;
case ATTR_DIR:
addCSSProperty(CSS_PROP_DIRECTION, attr->value());
addCSSProperty(CSS_PROP_UNICODE_BIDI, CSS_VAL_EMBED);
break;
case ATTR_ONCLICK:
setHTMLEventListener(EventImpl::KHTML_CLICK_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONCONTEXTMENU:
setHTMLEventListener(EventImpl::CONTEXTMENU_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONDBLCLICK:
setHTMLEventListener(EventImpl::KHTML_DBLCLICK_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONMOUSEDOWN:
setHTMLEventListener(EventImpl::MOUSEDOWN_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONMOUSEMOVE:
setHTMLEventListener(EventImpl::MOUSEMOVE_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONMOUSEOUT:
setHTMLEventListener(EventImpl::MOUSEOUT_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONMOUSEOVER:
setHTMLEventListener(EventImpl::MOUSEOVER_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONMOUSEUP:
setHTMLEventListener(EventImpl::MOUSEUP_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONFOCUS:
setHTMLEventListener(EventImpl::DOMFOCUSIN_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONKEYDOWN:
setHTMLEventListener(EventImpl::KEYDOWN_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONKEYPRESS:
setHTMLEventListener(EventImpl::KEYPRESS_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONKEYUP:
setHTMLEventListener(EventImpl::KEYUP_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONSCROLL:
setHTMLEventListener(EventImpl::SCROLL_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
default:
#ifdef UNSUPPORTED_ATTR
kdDebug(6030) << "UATTR: <" << this->nodeName().string() << "> ["
<< attr->name().string() << "]=[" << attr->value().string() << "]" << endl;
#endif
break;
}
}
void HTMLElementImpl::addCSSProperty(int id, const DOMString &value)
{
if(!m_styleDecls) createDecl();
m_styleDecls->setProperty(id, value, false, true);
setChanged();
}
void HTMLElementImpl::addCSSProperty(int id, int value)
{
if(!m_styleDecls) createDecl();
m_styleDecls->setProperty(id, value, false, true);
setChanged();
}
void HTMLElementImpl::addCSSLength(int id, const DOMString &value)
{
if(!m_styleDecls) createDecl();
DOMStringImpl* v = value.implementation();
if ( v ) {
unsigned int l = 0;
while ( l < v->l && v->s[l].unicode() <= ' ') l++;
for ( ;l < v->l; l++ ) {
char cc = v->s[l].latin1();
if ( cc > '9' || ( cc < '0' && cc != '*' && cc != '%' && cc != '.') )
break;
}
if ( l != v->l ) {
m_styleDecls->setLengthProperty( id, DOMString( v->s, l ), false, true );
setChanged();
return;
}
}
m_styleDecls->setLengthProperty(id, value, false, true);
setChanged();
}
static inline bool isHexDigit( const QChar &c ) {
return ( c >= '0' && c <= '9' ) ||
( c >= 'a' && c <= 'f' ) ||
( c >= 'A' && c <= 'F' );
}
static inline int toHex( const QChar &c ) {
return ( (c >= '0' && c <= '9')
? (c.unicode() - '0')
: ( ( c >= 'a' && c <= 'f' )
? (c.unicode() - 'a' + 10)
: ( ( c >= 'A' && c <= 'F' )
? (c.unicode() - 'A' + 10)
: -1 ) ) );
}
void HTMLElementImpl::addHTMLColor( int id, const DOMString &c )
{
if(!m_styleDecls) createDecl();
if ( !c.length() )
return;
if ( m_styleDecls->setProperty(id, c, false, true) )
return;
QString color = c.string();
if ( color.lower() != "transparent" ) {
if ( color[0] == '#' )
color.remove( 0, 1 );
int basicLength = (color.length() + 2) / 3;
if ( basicLength > 1 ) {
int colors[3] = { 0, 0, 0 };
int component = 0;
int pos = 0;
int maxDigit = basicLength-1;
while ( component < 3 ) {
int numDigits = 0;
while ( pos < (int)color.length() && numDigits < basicLength ) {
int hex = toHex( color[pos] );
colors[component] = (colors[component] << 4);
if ( hex > 0 ) {
colors[component] += hex;
maxDigit = QMIN( maxDigit, numDigits );
}
numDigits++;
pos++;
}
while ( numDigits++ < basicLength )
colors[component] <<= 4;
component++;
}
maxDigit = basicLength - maxDigit;
maxDigit -= 2;
colors[0] >>= 4*maxDigit;
colors[1] >>= 4*maxDigit;
colors[2] >>= 4*maxDigit;
color.sprintf("#%02x%02x%02x", colors[0], colors[1], colors[2] );
if ( m_styleDecls->setProperty(id, DOMString(color), false, true) )
return;
}
}
m_styleDecls->setProperty(id, CSS_VAL_BLACK, false, true);
}
void HTMLElementImpl::removeCSSProperty(int id)
{
if(!m_styleDecls)
return;
m_styleDecls->parent()->deref();
m_styleDecls->setParent(getDocument()->elementSheet());
m_styleDecls->parent()->ref();
m_styleDecls->removeProperty(id);
setChanged();
}
DOMString HTMLElementImpl::innerHTML() const
{
return toHTML();
}
DOMString HTMLElementImpl::innerText() const
{
DOMString text;
const NodeImpl *n = firstChild();
while(n) {
if(n->isTextNode() ) {
text += static_cast<const TextImpl *>(n)->data();
}
if(n->firstChild())
n = n->firstChild();
else if(n->nextSibling())
n = n->nextSibling();
else {
NodeImpl *next = 0;
while(!next) {
n = n->parentNode();
if(!n || n == (NodeImpl *)this ) goto end;
next = n->nextSibling();
}
n = next;
}
}
end:
return text;
}
DocumentFragmentImpl *HTMLElementImpl::createContextualFragment( const DOMString &html )
{
if( endTag[id()] == FORBIDDEN )
return NULL;
switch( id() ) {
case ID_COL:
case ID_COLGROUP:
case ID_FRAMESET:
case ID_HEAD:
case ID_STYLE:
case ID_TABLE:
case ID_TBODY:
case ID_TFOOT:
case ID_THEAD:
case ID_TITLE:
return NULL;
default:
break;
}
if ( !getDocument()->isHTMLDocument() )
return NULL;
DocumentFragmentImpl *fragment = new DocumentFragmentImpl( docPtr() );
fragment->ref();
{
HTMLTokenizer tok( docPtr(), fragment );
tok.begin();
tok.write( html.string(), true );
tok.end();
}
int ignoredExceptionCode;
NodeImpl *node = fragment->firstChild();
while (node != NULL) {
if (node->id() == ID_HTML || node->id() == ID_BODY) {
NodeImpl *firstChild = node->firstChild();
NodeImpl *child = firstChild;
while (child != NULL) {
NodeImpl *nextChild = child->nextSibling();
fragment->insertBefore(child, node, ignoredExceptionCode);
child = nextChild;
}
if (firstChild == NULL) {
NodeImpl *nextNode = node->nextSibling();
fragment->removeChild(node, ignoredExceptionCode);
node = nextNode;
} else {
fragment->removeChild(node, ignoredExceptionCode);
node = firstChild;
}
} else if (node->id() == ID_HEAD) {
NodeImpl *nextNode = node->nextSibling();
fragment->removeChild(node, ignoredExceptionCode);
node = nextNode;
} else {
node = node->nextSibling();
}
}
fragment->setParent(this);
fragment->deref();
fragment->setParent(0);
return fragment;
}
bool HTMLElementImpl::setInnerHTML( const DOMString &html )
{
DocumentFragmentImpl *fragment = createContextualFragment( html );
if (fragment == NULL) {
return false;
}
removeChildren();
int ec = 0;
appendChild( fragment, ec );
delete fragment;
return !ec;
}
bool HTMLElementImpl::setInnerText( const DOMString &text )
{
if( endTag[id()] == FORBIDDEN )
return false;
switch( id() ) {
case ID_COL:
case ID_COLGROUP:
case ID_FRAMESET:
case ID_HEAD:
case ID_HTML:
case ID_TABLE:
case ID_TBODY:
case ID_TFOOT:
case ID_THEAD:
case ID_TR:
return false;
default:
break;
}
removeChildren();
TextImpl *t = new TextImpl( docPtr(), text );
int ec = 0;
appendChild( t, ec );
if ( !ec )
return true;
return false;
}
DOMString HTMLElementImpl::namespaceURI() const
{
if (getDocument()->isHTMLDocument())
return DOMString();
else
return XHTML_NAMESPACE;
}
void HTMLElementImpl::addHTMLAlignment( DOMString alignment )
{
int propfloat = -1;
int propvalign = -1;
if ( strcasecmp( alignment, "absmiddle" ) == 0 ) {
propvalign = CSS_VAL_MIDDLE;
} else if ( strcasecmp( alignment, "absbottom" ) == 0 ) {
propvalign = CSS_VAL_BOTTOM;
} else if ( strcasecmp( alignment, "left" ) == 0 ) {
propfloat = CSS_VAL_LEFT;
propvalign = CSS_VAL_TOP;
} else if ( strcasecmp( alignment, "right" ) == 0 ) {
propfloat = CSS_VAL_RIGHT;
propvalign = CSS_VAL_TOP;
} else if ( strcasecmp( alignment, "top" ) == 0 ) {
propvalign = CSS_VAL_TOP;
} else if ( strcasecmp( alignment, "middle" ) == 0 ) {
propvalign = CSS_VAL__KHTML_BASELINE_MIDDLE;
} else if ( strcasecmp( alignment, "center" ) == 0 ) {
propvalign = CSS_VAL_MIDDLE;
} else if ( strcasecmp( alignment, "bottom" ) == 0 ) {
propvalign = CSS_VAL_BASELINE;
} else if ( strcasecmp ( alignment, "texttop") == 0 ) {
propvalign = CSS_VAL_TEXT_TOP;
}
if ( propfloat != -1 )
addCSSProperty( CSS_PROP_FLOAT, propfloat );
if ( propvalign != -1 )
addCSSProperty( CSS_PROP_VERTICAL_ALIGN, propvalign );
}
bool HTMLElementImpl::isContentEditable() const {
if (m_contentEditable == FlagEnabled)
return true;
if (m_contentEditable == FlagDisabled)
return false;
NodeImpl *node = parentNode();
while (node && node->isHTMLElement()) {
HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
if (element->m_contentEditable == FlagEnabled)
return true;
if (element->m_contentEditable == FlagDisabled)
return false;
node = node->parentNode();
}
return false;
}
DOMString HTMLElementImpl::contentEditable() const {
if (m_contentEditable == FlagEnabled)
return "true";
if (m_contentEditable == FlagDisabled)
return "false";
return "inherit";
}
void HTMLElementImpl::setContentEditable(const DOMString &enabled) {
if ( strcasecmp ( enabled, "true" ) == 0 )
m_contentEditable = FlagEnabled;
else if ( enabled.isEmpty() ) setAttribute(ATTR_CONTENTEDITABLE, "true");
else if ( strcasecmp ( enabled, "false" ) == 0 )
m_contentEditable = FlagDisabled;
else if ( strcasecmp ( enabled, "inherit" ) == 0 ) {
m_contentEditable = FlagNone;
}
}
void HTMLElementImpl::click()
{
int x = 0;
int y = 0;
if (renderer()) {
renderer()->absolutePosition(x,y);
x += renderer()->width() / 2;
y += renderer()->height() / 2;
}
QMouseEvent evt(QEvent::MouseButtonRelease, QPoint(x,y), Qt::LeftButton, 0);
dispatchMouseEvent(&evt, EventImpl::KHTML_CLICK_EVENT);
}
DOMString HTMLElementImpl::toString() const
{
if (!hasChildNodes()) {
DOMString result = openTagStartToString();
result += ">";
if (endTag[id()] == REQUIRED) {
result += "</";
result += tagName();
result += ">";
}
return result;
}
return ElementImpl::toString();
}
HTMLGenericElementImpl::HTMLGenericElementImpl(DocumentPtr *doc, ushort i)
: HTMLElementImpl(doc)
{
_id = i;
}
HTMLGenericElementImpl::~HTMLGenericElementImpl()
{
}