File indexing completed on 2024-05-05 16:10:10
0001 /** 0002 * This file is part of the DOM implementation for KDE. 0003 * 0004 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 0005 * (C) 1999 Antti Koivisto (koivisto@kde.org) 0006 * (C) 2003 Dirk Mueller (mueller@kde.org) 0007 * Copyright (C) 2002 Apple Computer, Inc. 0008 * 0009 * This library is free software; you can redistribute it and/or 0010 * modify it under the terms of the GNU Library General Public 0011 * License as published by the Free Software Foundation; either 0012 * version 2 of the License, or (at your option) any later version. 0013 * 0014 * This library is distributed in the hope that it will be useful, 0015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 * Library General Public License for more details. 0018 * 0019 * You should have received a copy of the GNU Library General Public License 0020 * along with this library; see the file COPYING.LIB. If not, write to 0021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0022 * Boston, MA 02110-1301, USA. 0023 * 0024 */ 0025 // ------------------------------------------------------------------------- 0026 //#define DEBUG 0027 //#define DEBUG_LAYOUT 0028 //#define PAR_DEBUG 0029 //#define EVENT_DEBUG 0030 //#define UNSUPPORTED_ATTR 0031 0032 #include "html_elementimpl.h" 0033 #include "dtd.h" 0034 #include "html_documentimpl.h" 0035 #include "htmltokenizer.h" 0036 0037 #include <khtmlview.h> 0038 #include <khtml_part.h> 0039 0040 #include <rendering/render_object.h> 0041 #include <rendering/render_replaced.h> 0042 #include <css/css_valueimpl.h> 0043 #include <css/css_stylesheetimpl.h> 0044 #include <css/cssproperties.h> 0045 #include <css/cssvalues.h> 0046 #include <xml/dom_textimpl.h> 0047 #include <xml/dom2_eventsimpl.h> 0048 #include <dom/dom_doc.h> 0049 0050 #include "khtml_debug.h" 0051 0052 #undef FOCUS_EVENT // for win32, MinGW 0053 0054 using namespace DOM; 0055 using namespace khtml; 0056 0057 HTMLElementImpl::HTMLElementImpl(DocumentImpl *doc) 0058 : ElementImpl(doc) 0059 { 0060 m_htmlCompat = doc && doc->htmlMode() != DocumentImpl::XHtml; 0061 } 0062 0063 HTMLElementImpl::~HTMLElementImpl() 0064 { 0065 } 0066 0067 bool HTMLElementImpl::isInline() const 0068 { 0069 if (renderer()) { 0070 return ElementImpl::isInline(); 0071 } 0072 0073 switch (id()) { 0074 case ID_A: 0075 case ID_FONT: 0076 case ID_TT: 0077 case ID_U: 0078 case ID_B: 0079 case ID_I: 0080 case ID_S: 0081 case ID_STRIKE: 0082 case ID_BIG: 0083 case ID_SMALL: 0084 0085 // %phrase 0086 case ID_EM: 0087 case ID_STRONG: 0088 case ID_DFN: 0089 case ID_CODE: 0090 case ID_SAMP: 0091 case ID_KBD: 0092 case ID_VAR: 0093 case ID_CITE: 0094 case ID_ABBR: 0095 case ID_ACRONYM: 0096 0097 // %special 0098 case ID_SUB: 0099 case ID_SUP: 0100 case ID_SPAN: 0101 case ID_NOBR: 0102 case ID_WBR: 0103 return true; 0104 0105 default: 0106 return ElementImpl::isInline(); 0107 } 0108 } 0109 0110 DOMString HTMLElementImpl::namespaceURI() const 0111 { 0112 return DOMString(XHTML_NAMESPACE); 0113 } 0114 0115 void HTMLElementImpl::parseAttribute(AttributeImpl *attr) 0116 { 0117 DOMString indexstring; 0118 switch (attr->id()) { 0119 case ATTR_ALIGN: 0120 if (attr->val()) { 0121 if (strcasecmp(attr->value(), "middle") == 0) { 0122 addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL_CENTER); 0123 } else { 0124 addCSSProperty(CSS_PROP_TEXT_ALIGN, attr->value().lower()); 0125 } 0126 } else { 0127 removeCSSProperty(CSS_PROP_TEXT_ALIGN); 0128 } 0129 break; 0130 // the core attributes... 0131 case ATTR_ID: 0132 // unique id 0133 setHasID(); 0134 document()->incDOMTreeVersion(DocumentImpl::TV_IDNameHref); 0135 break; 0136 case ATTR_CLASS: 0137 if (attr->val()) { 0138 DOMString v = attr->value(); 0139 const QChar *characters = v.unicode(); 0140 unsigned length = v.length(); 0141 unsigned i; 0142 for (i = 0; i < length && characters[i].isSpace(); ++i) { } 0143 setHasClass(i < length); 0144 attributes()->setClass(v); 0145 } else { 0146 setHasClass(false); 0147 } 0148 document()->incDOMTreeVersion(DocumentImpl::TV_Class); 0149 break; 0150 case ATTR_NAME: 0151 document()->incDOMTreeVersion(DocumentImpl::TV_IDNameHref); 0152 break; 0153 case ATTR_CONTENTEDITABLE: 0154 setContentEditable(attr); 0155 break; 0156 case ATTR_STYLE: 0157 getInlineStyleDecls()->updateFromAttribute(attr->value()); 0158 setChanged(); 0159 break; 0160 case ATTR_TABINDEX: 0161 indexstring = getAttribute(ATTR_TABINDEX); 0162 if (attr->val()) { 0163 setTabIndex(attr->value().toInt()); 0164 } else { 0165 setNoTabIndex(); 0166 } 0167 break; 0168 // i18n attributes 0169 case ATTR_LANG: 0170 break; 0171 case ATTR_DIR: 0172 addCSSProperty(CSS_PROP_DIRECTION, attr->value().lower()); 0173 break; 0174 // standard events 0175 case ATTR_ONCLICK: 0176 setHTMLEventListener(EventImpl::KHTML_ECMA_CLICK_EVENT, 0177 document()->createHTMLEventListener(attr->value().string(), "onclick", this)); 0178 break; 0179 case ATTR_ONDBLCLICK: 0180 setHTMLEventListener(EventImpl::KHTML_ECMA_DBLCLICK_EVENT, 0181 document()->createHTMLEventListener(attr->value().string(), "ondblclick", this)); 0182 break; 0183 case ATTR_ONMOUSEDOWN: 0184 setHTMLEventListener(EventImpl::MOUSEDOWN_EVENT, 0185 document()->createHTMLEventListener(attr->value().string(), "onmousedown", this)); 0186 break; 0187 case ATTR_ONMOUSEMOVE: 0188 setHTMLEventListener(EventImpl::MOUSEMOVE_EVENT, 0189 document()->createHTMLEventListener(attr->value().string(), "onmousemove", this)); 0190 break; 0191 case ATTR_ONMOUSEOUT: 0192 setHTMLEventListener(EventImpl::MOUSEOUT_EVENT, 0193 document()->createHTMLEventListener(attr->value().string(), "onmouseout", this)); 0194 break; 0195 case ATTR_ONMOUSEOVER: 0196 setHTMLEventListener(EventImpl::MOUSEOVER_EVENT, 0197 document()->createHTMLEventListener(attr->value().string(), "onmouseover", this)); 0198 break; 0199 case ATTR_ONMOUSEUP: 0200 setHTMLEventListener(EventImpl::MOUSEUP_EVENT, 0201 document()->createHTMLEventListener(attr->value().string(), "onmouseup", this)); 0202 break; 0203 case ATTR_ONKEYDOWN: 0204 setHTMLEventListener(EventImpl::KEYDOWN_EVENT, 0205 document()->createHTMLEventListener(attr->value().string(), "onkeydown", this)); 0206 break; 0207 case ATTR_ONKEYPRESS: 0208 setHTMLEventListener(EventImpl::KEYPRESS_EVENT, 0209 document()->createHTMLEventListener(attr->value().string(), "onkeypress", this)); 0210 break; 0211 case ATTR_ONKEYUP: 0212 setHTMLEventListener(EventImpl::KEYUP_EVENT, 0213 document()->createHTMLEventListener(attr->value().string(), "onkeyup", this)); 0214 break; 0215 case ATTR_ONFOCUS: 0216 setHTMLEventListener(EventImpl::FOCUS_EVENT, 0217 document()->createHTMLEventListener(attr->value().string(), "onfocus", this)); 0218 break; 0219 case ATTR_ONBLUR: 0220 setHTMLEventListener(EventImpl::BLUR_EVENT, 0221 document()->createHTMLEventListener(attr->value().string(), "onblur", this)); 0222 break; 0223 case ATTR_ONSCROLL: 0224 setHTMLEventListener(EventImpl::SCROLL_EVENT, 0225 document()->createHTMLEventListener(attr->value().string(), "onscroll", this)); 0226 break; 0227 // other misc attributes 0228 default: 0229 #ifdef UNSUPPORTED_ATTR 0230 qCDebug(KHTML_LOG) << "UATTR: <" << this->nodeName().string() << "> [" 0231 << attr->name().string() << "]=[" << attr->value().string() << "]"; 0232 #endif 0233 break; 0234 } 0235 } 0236 0237 void HTMLElementImpl::recalcStyle(StyleChange ch) 0238 { 0239 ElementImpl::recalcStyle(ch); 0240 0241 if (m_render /*&& changed*/) { 0242 m_render->updateFromElement(); 0243 } 0244 } 0245 0246 void HTMLElementImpl::addCSSProperty(int id, const DOMString &value) 0247 { 0248 if (!m_hasCombinedStyle) { 0249 createNonCSSDecl(); 0250 } 0251 nonCSSStyleDecls()->setProperty(id, value, false); 0252 setChanged(); 0253 } 0254 0255 void HTMLElementImpl::addCSSProperty(int id, int value) 0256 { 0257 if (!m_hasCombinedStyle) { 0258 createNonCSSDecl(); 0259 } 0260 nonCSSStyleDecls()->setProperty(id, value, false); 0261 setChanged(); 0262 } 0263 0264 void HTMLElementImpl::addCSSLength(int id, const DOMString &value, bool numOnly, bool multiLength) 0265 { 0266 if (!m_hasCombinedStyle) { 0267 createNonCSSDecl(); 0268 } 0269 0270 // strip attribute garbage to avoid CSS parsing errors 0271 // ### create specialized hook that avoids parsing every 0272 // value twice! 0273 if (value.implementation()) { 0274 // match \s*[+-]?\d*(\.\d*)?[%\*]? 0275 unsigned i = 0, j = 0; 0276 QChar *s = value.implementation()->s; 0277 unsigned l = value.implementation()->l; 0278 0279 while (i < l && s[i].isSpace()) { 0280 ++i; 0281 } 0282 if (i < l && (s[i] == '+' || s[i] == '-')) { 0283 ++i; 0284 } 0285 while (i < l && s[i].isDigit()) { 0286 ++i, ++j; 0287 } 0288 0289 // no digits! 0290 if (j == 0) { 0291 return; 0292 } 0293 0294 int v = qBound(-8192, QString::fromRawData(s, i).toInt(), 8191); 0295 const char *suffix = "px"; 0296 if (!numOnly || multiLength) { 0297 // look if we find a % or * 0298 while (i < l) { 0299 if (multiLength && s[i] == '*') { 0300 suffix = ""; 0301 break; 0302 } 0303 if (s[i] == '%') { 0304 suffix = "%"; 0305 break; 0306 } 0307 ++i; 0308 } 0309 } 0310 if (numOnly) { 0311 suffix = ""; 0312 } 0313 0314 QString ns = QString::number(v) + suffix; 0315 nonCSSStyleDecls()->setLengthProperty(id, DOMString(ns), false, multiLength); 0316 setChanged(); 0317 return; 0318 } 0319 0320 nonCSSStyleDecls()->setLengthProperty(id, value, false, multiLength); 0321 setChanged(); 0322 } 0323 0324 static inline bool isHexDigit(const QChar &c) 0325 { 0326 return (c >= '0' && c <= '9') || 0327 (c >= 'a' && c <= 'f') || 0328 (c >= 'A' && c <= 'F'); 0329 } 0330 0331 static inline int toHex(const QChar &c) 0332 { 0333 return ((c >= '0' && c <= '9') 0334 ? (c.unicode() - '0') 0335 : ((c >= 'a' && c <= 'f') 0336 ? (c.unicode() - 'a' + 10) 0337 : ((c >= 'A' && c <= 'F') 0338 ? (c.unicode() - 'A' + 10) 0339 : -1))); 0340 } 0341 0342 /* color parsing that tries to match as close as possible IE 6. */ 0343 void HTMLElementImpl::addHTMLColor(int id, const DOMString &c) 0344 { 0345 if (!m_hasCombinedStyle) { 0346 createNonCSSDecl(); 0347 } 0348 0349 // this is the only case no color gets applied in IE. 0350 if (!c.length()) { 0351 removeCSSProperty(id); 0352 return; 0353 } 0354 0355 if (nonCSSStyleDecls()->setProperty(id, c, false)) { 0356 return; 0357 } 0358 0359 QString color = c.string(); 0360 // not something that fits the specs. 0361 0362 // we're emulating IEs color parser here. It maps transparent to black, otherwise it tries to build a rgb value 0363 // out of everyhting you put in. The algorithm is experimentally determined, but seems to work for all test cases I have. 0364 0365 // the length of the color value is rounded up to the next 0366 // multiple of 3. each part of the rgb triple then gets one third 0367 // of the length. 0368 // 0369 // Each triplet is parsed byte by byte, mapping 0370 // each number to a hex value (0-9a-fA-F to their values 0371 // everything else to 0). 0372 // 0373 // The highest non zero digit in all triplets is remembered, and 0374 // used as a normalization point to normalize to values between 0 0375 // and 255. 0376 0377 if (color.toLower() != "transparent") { 0378 if (color[0] == '#') { 0379 color.remove(0, 1); 0380 } 0381 int basicLength = (color.length() + 2) / 3; 0382 if (basicLength > 1) { 0383 // IE ignores colors with three digits or less 0384 // qDebug("trying to fix up color '%s'. basicLength=%d, length=%d", 0385 // color.toLatin1().constData(), basicLength, color.length() ); 0386 int colors[3] = { 0, 0, 0 }; 0387 int component = 0; 0388 int pos = 0; 0389 int maxDigit = basicLength - 1; 0390 while (component < 3) { 0391 // search forward for digits in the string 0392 int numDigits = 0; 0393 while (pos < (int)color.length() && numDigits < basicLength) { 0394 int hex = toHex(color[pos]); 0395 colors[component] = (colors[component] << 4); 0396 if (hex > 0) { 0397 colors[component] += hex; 0398 maxDigit = qMin(maxDigit, numDigits); 0399 } 0400 numDigits++; 0401 pos++; 0402 } 0403 while (numDigits++ < basicLength) { 0404 colors[component] <<= 4; 0405 } 0406 component++; 0407 } 0408 maxDigit = basicLength - maxDigit; 0409 // qDebug("color is %x %x %x, maxDigit=%d", colors[0], colors[1], colors[2], maxDigit ); 0410 0411 // normalize to 00-ff. The highest filled digit counts, minimum is 2 digits 0412 maxDigit -= 2; 0413 colors[0] >>= 4 * maxDigit; 0414 colors[1] >>= 4 * maxDigit; 0415 colors[2] >>= 4 * maxDigit; 0416 // qDebug("normalized color is %x %x %x", colors[0], colors[1], colors[2] ); 0417 // assert( colors[0] < 0x100 && colors[1] < 0x100 && colors[2] < 0x100 ); 0418 0419 color.sprintf("#%02x%02x%02x", colors[0], colors[1], colors[2]); 0420 // qDebug( "trying to add fixed color string '%s'", color.toLatin1().constData() ); 0421 if (nonCSSStyleDecls()->setProperty(id, DOMString(color), false)) { 0422 return; 0423 } 0424 } 0425 } 0426 nonCSSStyleDecls()->setProperty(id, CSS_VAL_BLACK, false); 0427 } 0428 0429 void HTMLElementImpl::removeCSSProperty(int id) 0430 { 0431 if (!m_hasCombinedStyle) { 0432 return; 0433 } 0434 nonCSSStyleDecls()->setParent(document()->elementSheet()); 0435 nonCSSStyleDecls()->removeProperty(id); 0436 setChanged(); 0437 } 0438 0439 DOMString HTMLElementImpl::innerHTML() const 0440 { 0441 QString result = ""; //Use QString to accumulate since DOMString is poor for appends 0442 for (NodeImpl *child = firstChild(); child != nullptr; child = child->nextSibling()) { 0443 DOMString kid = child->toString(); 0444 result += QString::fromRawData(kid.unicode(), kid.length()); 0445 } 0446 return result; 0447 } 0448 0449 DOMString HTMLElementImpl::innerText() const 0450 { 0451 QString text = ""; 0452 if (!firstChild()) { 0453 return text; 0454 } 0455 0456 const NodeImpl *n = this; 0457 // find the next text/image after the anchor, to get a position 0458 while (n) { 0459 if (n->firstChild()) { 0460 n = n->firstChild(); 0461 } else if (n->nextSibling()) { 0462 n = n->nextSibling(); 0463 } else { 0464 NodeImpl *next = nullptr; 0465 while (!next) { 0466 n = n->parentNode(); 0467 if (!n || n == (NodeImpl *)this) { 0468 goto end; 0469 } 0470 next = n->nextSibling(); 0471 } 0472 n = next; 0473 } 0474 if (n->isTextNode()) { 0475 DOMStringImpl *data = static_cast<const TextImpl *>(n)->string(); 0476 text += QString::fromRawData(data->s, data->l); 0477 } 0478 } 0479 end: 0480 return text; 0481 } 0482 0483 DocumentFragment HTMLElementImpl::createContextualFragment(const DOMString &html) 0484 { 0485 // IE originally restricted innerHTML to a small subset of elements; 0486 // and we largely matched that. Mozilla's embrace of innerHTML, however, extended 0487 // it to pretty much everything, and so the web (and HTML5) requires it now. 0488 // For now, we accept everything, but do not do context-based recovery in the parser. 0489 if (!document()->isHTMLDocument()) { 0490 return DocumentFragment(); 0491 } 0492 0493 DocumentFragmentImpl *fragment = new DocumentFragmentImpl(docPtr()); 0494 DocumentFragment f(fragment); 0495 { 0496 HTMLTokenizer tok(docPtr(), fragment); 0497 tok.begin(); 0498 tok.write(html.string(), true); 0499 tok.end(); 0500 } 0501 0502 // Exceptions are ignored because none ought to happen here. 0503 int ignoredExceptionCode; 0504 0505 // we need to pop <html> and <body> elements and remove <head> to 0506 // accomadate folks passing complete HTML documents to make the 0507 // child of an element. 0508 for (NodeImpl *node = fragment->firstChild(); node;) { 0509 if (node->id() == ID_HTML || node->id() == ID_BODY) { 0510 NodeImpl *firstChild = node->firstChild(); 0511 NodeImpl *child = firstChild; 0512 while (child) { 0513 NodeImpl *nextChild = child->nextSibling(); 0514 fragment->insertBefore(child, node, ignoredExceptionCode); 0515 child = nextChild; 0516 } 0517 if (!firstChild) { 0518 NodeImpl *nextNode = node->nextSibling(); 0519 fragment->removeChild(node, ignoredExceptionCode); 0520 node = nextNode; 0521 } else { 0522 fragment->removeChild(node, ignoredExceptionCode); 0523 node = firstChild; 0524 } 0525 } else if (node->id() == ID_HEAD) { 0526 NodeImpl *nextNode = node->nextSibling(); 0527 fragment->removeChild(node, ignoredExceptionCode); 0528 node = nextNode; 0529 } else { 0530 node = node->nextSibling(); 0531 } 0532 } 0533 0534 return f; 0535 } 0536 0537 void HTMLElementImpl::setInnerHTML(const DOMString &html, int &exceptioncode) 0538 { 0539 if (id() == ID_SCRIPT || id() == ID_STYLE) { 0540 // Script and CSS source shouldn't be parsed as HTML. 0541 removeChildren(); 0542 appendChild(document()->createTextNode(html), exceptioncode); 0543 return; 0544 } 0545 0546 DocumentFragment fragment = createContextualFragment(html); 0547 if (fragment.isNull()) { 0548 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; 0549 return; 0550 } 0551 0552 // Make sure adding the new child is ok, before removing all children (#96187) 0553 checkAddChild(fragment.handle(), exceptioncode); 0554 if (exceptioncode) { 0555 return; 0556 } 0557 0558 removeChildren(); 0559 appendChild(fragment.handle(), exceptioncode); 0560 } 0561 0562 void HTMLElementImpl::setInnerText(const DOMString &text, int &exceptioncode) 0563 { 0564 // following the IE specs. 0565 if (endTagRequirement(id()) == FORBIDDEN) { 0566 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; 0567 return; 0568 } 0569 // IE disallows innerHTML on inline elements. I don't see why we should have this restriction, as our 0570 // dhtml engine can cope with it. Lars 0571 //if ( isInline() ) return false; 0572 switch (id()) { 0573 case ID_COL: 0574 case ID_COLGROUP: 0575 case ID_FRAMESET: 0576 case ID_HEAD: 0577 case ID_HTML: 0578 case ID_TABLE: 0579 case ID_TBODY: 0580 case ID_TFOOT: 0581 case ID_THEAD: 0582 case ID_TR: 0583 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; 0584 return; 0585 default: 0586 break; 0587 } 0588 0589 removeChildren(); 0590 0591 TextImpl *t = new TextImpl(docPtr(), text.implementation()); 0592 appendChild(t, exceptioncode); 0593 } 0594 0595 void HTMLElementImpl::addHTMLAlignment(DOMString alignment) 0596 { 0597 //qDebug("alignment is %s", alignment.string().toLatin1().constData() ); 0598 // vertical alignment with respect to the current baseline of the text 0599 // right or left means floating images 0600 int propfloat = -1; 0601 int propvalign = -1; 0602 if (strcasecmp(alignment, "absmiddle") == 0) { 0603 propvalign = CSS_VAL_MIDDLE; 0604 } else if (strcasecmp(alignment, "absbottom") == 0) { 0605 propvalign = CSS_VAL_BOTTOM; 0606 } else if (strcasecmp(alignment, "left") == 0) { 0607 propfloat = CSS_VAL_LEFT; 0608 propvalign = CSS_VAL_TOP; 0609 } else if (strcasecmp(alignment, "right") == 0) { 0610 propfloat = CSS_VAL_RIGHT; 0611 propvalign = CSS_VAL_TOP; 0612 } else if (strcasecmp(alignment, "top") == 0) { 0613 propvalign = CSS_VAL_TOP; 0614 } else if (strcasecmp(alignment, "middle") == 0) { 0615 propvalign = CSS_VAL__KHTML_BASELINE_MIDDLE; 0616 } else if (strcasecmp(alignment, "center") == 0) { 0617 propvalign = CSS_VAL_MIDDLE; 0618 } else if (strcasecmp(alignment, "bottom") == 0) { 0619 propvalign = CSS_VAL_BASELINE; 0620 } else if (strcasecmp(alignment, "texttop") == 0) { 0621 propvalign = CSS_VAL_TEXT_TOP; 0622 } 0623 0624 if (propfloat != -1) { 0625 addCSSProperty(CSS_PROP_FLOAT, propfloat); 0626 } 0627 if (propvalign != -1) { 0628 addCSSProperty(CSS_PROP_VERTICAL_ALIGN, propvalign); 0629 } 0630 } 0631 0632 DOMString HTMLElementImpl::contentEditable() const 0633 { 0634 document()->updateRendering(); 0635 0636 if (!renderer()) { 0637 return "false"; 0638 } 0639 0640 switch (renderer()->style()->userInput()) { 0641 case UI_ENABLED: 0642 return "true"; 0643 case UI_DISABLED: 0644 case UI_NONE: 0645 return "false"; 0646 default:; 0647 } 0648 return "inherit"; 0649 } 0650 0651 void HTMLElementImpl::setContentEditable(AttributeImpl *attr) 0652 { 0653 const DOMString &enabled = attr->value(); 0654 if (enabled.isEmpty() || strcasecmp(enabled, "true") == 0) { 0655 addCSSProperty(CSS_PROP__KHTML_USER_INPUT, CSS_VAL_ENABLED); 0656 } else if (strcasecmp(enabled, "false") == 0) { 0657 addCSSProperty(CSS_PROP__KHTML_USER_INPUT, CSS_VAL_NONE); 0658 } else if (strcasecmp(enabled, "inherit") == 0) { 0659 addCSSProperty(CSS_PROP__KHTML_USER_INPUT, CSS_VAL_INHERIT); 0660 } 0661 } 0662 0663 void HTMLElementImpl::setContentEditable(const DOMString &enabled) 0664 { 0665 if (enabled == "inherit") { 0666 int exceptionCode; 0667 removeAttribute(ATTR_CONTENTEDITABLE, exceptionCode); 0668 } else { 0669 setAttribute(ATTR_CONTENTEDITABLE, enabled.isEmpty() ? "true" : enabled); 0670 } 0671 } 0672 0673 DOMString HTMLElementImpl::toString() const 0674 { 0675 if (!hasChildNodes()) { 0676 DOMString result = openTagStartToString(); 0677 result += ">"; 0678 0679 if (endTagRequirement(id()) == REQUIRED) { 0680 result += "</"; 0681 result += nonCaseFoldedTagName(); 0682 result += ">"; 0683 } 0684 0685 return result; 0686 } 0687 0688 return ElementImpl::toString(); 0689 } 0690 0691 // ------------------------------------------------------------------------- 0692 HTMLGenericElementImpl::HTMLGenericElementImpl(DocumentImpl *doc, ushort i) 0693 : HTMLElementImpl(doc) 0694 { 0695 m_localName = LocalName::fromId(i); 0696 } 0697 0698 HTMLGenericElementImpl::HTMLGenericElementImpl(DocumentImpl *doc, LocalName l) 0699 : HTMLElementImpl(doc), 0700 m_localName(l) 0701 {} 0702 0703 HTMLGenericElementImpl::~HTMLGenericElementImpl() 0704 { 0705 }