Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  * Copyright (C) 2004-2008, 2013, 2014 Apple Inc. All rights reserved.
      5  * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      6  * Copyright (C) 2011 Motorola Mobility. All rights reserved.
      7  *
      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.
     12  *
     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.
     17  *
     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., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  *
     23  */
     24 
     25 #include "config.h"
     26 #include "core/html/HTMLElement.h"
     27 
     28 #include "bindings/core/v8/ExceptionState.h"
     29 #include "bindings/core/v8/ScriptEventListener.h"
     30 #include "core/CSSPropertyNames.h"
     31 #include "core/CSSValueKeywords.h"
     32 #include "core/HTMLNames.h"
     33 #include "core/XMLNames.h"
     34 #include "core/css/CSSMarkup.h"
     35 #include "core/css/CSSValuePool.h"
     36 #include "core/css/StylePropertySet.h"
     37 #include "core/dom/DocumentFragment.h"
     38 #include "core/dom/ElementTraversal.h"
     39 #include "core/dom/ExceptionCode.h"
     40 #include "core/dom/NodeTraversal.h"
     41 #include "core/dom/Text.h"
     42 #include "core/dom/shadow/ElementShadow.h"
     43 #include "core/dom/shadow/ShadowRoot.h"
     44 #include "core/editing/markup.h"
     45 #include "core/events/EventListener.h"
     46 #include "core/events/KeyboardEvent.h"
     47 #include "core/frame/Settings.h"
     48 #include "core/html/HTMLBRElement.h"
     49 #include "core/html/HTMLFormElement.h"
     50 #include "core/html/HTMLInputElement.h"
     51 #include "core/html/HTMLMenuElement.h"
     52 #include "core/html/HTMLTemplateElement.h"
     53 #include "core/html/HTMLTextFormControlElement.h"
     54 #include "core/html/parser/HTMLParserIdioms.h"
     55 #include "core/rendering/RenderObject.h"
     56 #include "platform/text/BidiResolver.h"
     57 #include "platform/text/BidiTextRun.h"
     58 #include "platform/text/TextRunIterator.h"
     59 #include "wtf/StdLibExtras.h"
     60 #include "wtf/text/CString.h"
     61 
     62 namespace blink {
     63 
     64 using namespace HTMLNames;
     65 using namespace WTF;
     66 
     67 using std::min;
     68 using std::max;
     69 
     70 DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLElement);
     71 
     72 String HTMLElement::nodeName() const
     73 {
     74     // FIXME: Would be nice to have an atomicstring lookup based off uppercase
     75     // chars that does not have to copy the string on a hit in the hash.
     76     // FIXME: We should have a way to detect XHTML elements and replace the hasPrefix() check with it.
     77     if (document().isHTMLDocument()) {
     78         if (!tagQName().hasPrefix())
     79             return tagQName().localNameUpper();
     80         return Element::nodeName().upper();
     81     }
     82     return Element::nodeName();
     83 }
     84 
     85 bool HTMLElement::ieForbidsInsertHTML() const
     86 {
     87     // FIXME: Supposedly IE disallows settting innerHTML, outerHTML
     88     // and createContextualFragment on these tags.  We have no tests to
     89     // verify this however, so this list could be totally wrong.
     90     // This list was moved from the previous endTagRequirement() implementation.
     91     // This is also called from editing and assumed to be the list of tags
     92     // for which no end tag should be serialized. It's unclear if the list for
     93     // IE compat and the list for serialization sanity are the same.
     94     if (hasTagName(areaTag)
     95         || hasTagName(baseTag)
     96         || hasTagName(basefontTag)
     97         || hasTagName(brTag)
     98         || hasTagName(colTag)
     99         || hasTagName(embedTag)
    100         || hasTagName(frameTag)
    101         || hasTagName(hrTag)
    102         || hasTagName(imageTag)
    103         || hasTagName(imgTag)
    104         || hasTagName(inputTag)
    105         || hasTagName(linkTag)
    106         || (RuntimeEnabledFeatures::contextMenuEnabled() && hasTagName(menuitemTag))
    107         || hasTagName(metaTag)
    108         || hasTagName(paramTag)
    109         || hasTagName(sourceTag)
    110         || hasTagName(wbrTag))
    111         return true;
    112     return false;
    113 }
    114 
    115 static inline CSSValueID unicodeBidiAttributeForDirAuto(HTMLElement* element)
    116 {
    117     if (element->hasTagName(preTag) || element->hasTagName(textareaTag))
    118         return CSSValueWebkitPlaintext;
    119     // FIXME: For bdo element, dir="auto" should result in "bidi-override isolate" but we don't support having multiple values in unicode-bidi yet.
    120     // See https://bugs.webkit.org/show_bug.cgi?id=73164.
    121     return CSSValueWebkitIsolate;
    122 }
    123 
    124 unsigned HTMLElement::parseBorderWidthAttribute(const AtomicString& value) const
    125 {
    126     unsigned borderWidth = 0;
    127     if (value.isEmpty() || !parseHTMLNonNegativeInteger(value, borderWidth))
    128         return hasTagName(tableTag) ? 1 : borderWidth;
    129     return borderWidth;
    130 }
    131 
    132 void HTMLElement::applyBorderAttributeToStyle(const AtomicString& value, MutableStylePropertySet* style)
    133 {
    134     addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderWidth, parseBorderWidthAttribute(value), CSSPrimitiveValue::CSS_PX);
    135     addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderStyle, CSSValueSolid);
    136 }
    137 
    138 void HTMLElement::mapLanguageAttributeToLocale(const AtomicString& value, MutableStylePropertySet* style)
    139 {
    140     if (!value.isEmpty()) {
    141         // Have to quote so the locale id is treated as a string instead of as a CSS keyword.
    142         addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitLocale, quoteCSSString(value));
    143     } else {
    144         // The empty string means the language is explicitly unknown.
    145         addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitLocale, CSSValueAuto);
    146     }
    147 }
    148 
    149 bool HTMLElement::isPresentationAttribute(const QualifiedName& name) const
    150 {
    151     if (name == alignAttr || name == contenteditableAttr || name == hiddenAttr || name == langAttr || name.matches(XMLNames::langAttr) || name == draggableAttr || name == dirAttr)
    152         return true;
    153     return Element::isPresentationAttribute(name);
    154 }
    155 
    156 static inline bool isValidDirAttribute(const AtomicString& value)
    157 {
    158     return equalIgnoringCase(value, "auto") || equalIgnoringCase(value, "ltr") || equalIgnoringCase(value, "rtl");
    159 }
    160 
    161 void HTMLElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
    162 {
    163     if (name == alignAttr) {
    164         if (equalIgnoringCase(value, "middle"))
    165             addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueCenter);
    166         else
    167             addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, value);
    168     } else if (name == contenteditableAttr) {
    169         if (value.isEmpty() || equalIgnoringCase(value, "true")) {
    170             addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserModify, CSSValueReadWrite);
    171             addPropertyToPresentationAttributeStyle(style, CSSPropertyWordWrap, CSSValueBreakWord);
    172             addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitLineBreak, CSSValueAfterWhiteSpace);
    173         } else if (equalIgnoringCase(value, "plaintext-only")) {
    174             addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserModify, CSSValueReadWritePlaintextOnly);
    175             addPropertyToPresentationAttributeStyle(style, CSSPropertyWordWrap, CSSValueBreakWord);
    176             addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitLineBreak, CSSValueAfterWhiteSpace);
    177         } else if (equalIgnoringCase(value, "false"))
    178             addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserModify, CSSValueReadOnly);
    179     } else if (name == hiddenAttr) {
    180         addPropertyToPresentationAttributeStyle(style, CSSPropertyDisplay, CSSValueNone);
    181     } else if (name == draggableAttr) {
    182         if (equalIgnoringCase(value, "true")) {
    183             addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserDrag, CSSValueElement);
    184             addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserSelect, CSSValueNone);
    185         } else if (equalIgnoringCase(value, "false"))
    186             addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserDrag, CSSValueNone);
    187     } else if (name == dirAttr) {
    188         if (equalIgnoringCase(value, "auto"))
    189             addPropertyToPresentationAttributeStyle(style, CSSPropertyUnicodeBidi, unicodeBidiAttributeForDirAuto(this));
    190         else {
    191             if (isValidDirAttribute(value))
    192                 addPropertyToPresentationAttributeStyle(style, CSSPropertyDirection, value);
    193             else
    194                 addPropertyToPresentationAttributeStyle(style, CSSPropertyDirection, "ltr");
    195             if (!hasTagName(bdiTag) && !hasTagName(bdoTag) && !hasTagName(outputTag))
    196                 addPropertyToPresentationAttributeStyle(style, CSSPropertyUnicodeBidi, CSSValueEmbed);
    197         }
    198     } else if (name.matches(XMLNames::langAttr))
    199         mapLanguageAttributeToLocale(value, style);
    200     else if (name == langAttr) {
    201         // xml:lang has a higher priority than lang.
    202         if (!fastHasAttribute(XMLNames::langAttr))
    203             mapLanguageAttributeToLocale(value, style);
    204     } else
    205         Element::collectStyleForPresentationAttribute(name, value, style);
    206 }
    207 
    208 const AtomicString& HTMLElement::eventNameForAttributeName(const QualifiedName& attrName)
    209 {
    210     if (!attrName.namespaceURI().isNull())
    211         return nullAtom;
    212 
    213     if (!attrName.localName().startsWith("on", false))
    214         return nullAtom;
    215 
    216     typedef HashMap<AtomicString, AtomicString> StringToStringMap;
    217     DEFINE_STATIC_LOCAL(StringToStringMap, attributeNameToEventNameMap, ());
    218     if (!attributeNameToEventNameMap.size()) {
    219         attributeNameToEventNameMap.set(onabortAttr.localName(), EventTypeNames::abort);
    220         attributeNameToEventNameMap.set(onanimationendAttr.localName(), EventTypeNames::animationend);
    221         attributeNameToEventNameMap.set(onanimationiterationAttr.localName(), EventTypeNames::animationiteration);
    222         attributeNameToEventNameMap.set(onanimationstartAttr.localName(), EventTypeNames::animationstart);
    223         attributeNameToEventNameMap.set(onautocompleteAttr.localName(), EventTypeNames::autocomplete);
    224         attributeNameToEventNameMap.set(onautocompleteerrorAttr.localName(), EventTypeNames::autocompleteerror);
    225         attributeNameToEventNameMap.set(onbeforecopyAttr.localName(), EventTypeNames::beforecopy);
    226         attributeNameToEventNameMap.set(onbeforecutAttr.localName(), EventTypeNames::beforecut);
    227         attributeNameToEventNameMap.set(onbeforepasteAttr.localName(), EventTypeNames::beforepaste);
    228         attributeNameToEventNameMap.set(onblurAttr.localName(), EventTypeNames::blur);
    229         attributeNameToEventNameMap.set(oncancelAttr.localName(), EventTypeNames::cancel);
    230         attributeNameToEventNameMap.set(oncanplayAttr.localName(), EventTypeNames::canplay);
    231         attributeNameToEventNameMap.set(oncanplaythroughAttr.localName(), EventTypeNames::canplaythrough);
    232         attributeNameToEventNameMap.set(onchangeAttr.localName(), EventTypeNames::change);
    233         attributeNameToEventNameMap.set(onclickAttr.localName(), EventTypeNames::click);
    234         attributeNameToEventNameMap.set(oncloseAttr.localName(), EventTypeNames::close);
    235         attributeNameToEventNameMap.set(oncontextmenuAttr.localName(), EventTypeNames::contextmenu);
    236         attributeNameToEventNameMap.set(oncopyAttr.localName(), EventTypeNames::copy);
    237         attributeNameToEventNameMap.set(oncuechangeAttr.localName(), EventTypeNames::cuechange);
    238         attributeNameToEventNameMap.set(oncutAttr.localName(), EventTypeNames::cut);
    239         attributeNameToEventNameMap.set(ondblclickAttr.localName(), EventTypeNames::dblclick);
    240         attributeNameToEventNameMap.set(ondragAttr.localName(), EventTypeNames::drag);
    241         attributeNameToEventNameMap.set(ondragendAttr.localName(), EventTypeNames::dragend);
    242         attributeNameToEventNameMap.set(ondragenterAttr.localName(), EventTypeNames::dragenter);
    243         attributeNameToEventNameMap.set(ondragleaveAttr.localName(), EventTypeNames::dragleave);
    244         attributeNameToEventNameMap.set(ondragoverAttr.localName(), EventTypeNames::dragover);
    245         attributeNameToEventNameMap.set(ondragstartAttr.localName(), EventTypeNames::dragstart);
    246         attributeNameToEventNameMap.set(ondropAttr.localName(), EventTypeNames::drop);
    247         attributeNameToEventNameMap.set(ondurationchangeAttr.localName(), EventTypeNames::durationchange);
    248         attributeNameToEventNameMap.set(onemptiedAttr.localName(), EventTypeNames::emptied);
    249         attributeNameToEventNameMap.set(onendedAttr.localName(), EventTypeNames::ended);
    250         attributeNameToEventNameMap.set(onerrorAttr.localName(), EventTypeNames::error);
    251         attributeNameToEventNameMap.set(onfocusAttr.localName(), EventTypeNames::focus);
    252         attributeNameToEventNameMap.set(onfocusinAttr.localName(), EventTypeNames::focusin);
    253         attributeNameToEventNameMap.set(onfocusoutAttr.localName(), EventTypeNames::focusout);
    254         attributeNameToEventNameMap.set(oninputAttr.localName(), EventTypeNames::input);
    255         attributeNameToEventNameMap.set(oninvalidAttr.localName(), EventTypeNames::invalid);
    256         attributeNameToEventNameMap.set(onkeydownAttr.localName(), EventTypeNames::keydown);
    257         attributeNameToEventNameMap.set(onkeypressAttr.localName(), EventTypeNames::keypress);
    258         attributeNameToEventNameMap.set(onkeyupAttr.localName(), EventTypeNames::keyup);
    259         attributeNameToEventNameMap.set(onloadAttr.localName(), EventTypeNames::load);
    260         attributeNameToEventNameMap.set(onloadeddataAttr.localName(), EventTypeNames::loadeddata);
    261         attributeNameToEventNameMap.set(onloadedmetadataAttr.localName(), EventTypeNames::loadedmetadata);
    262         attributeNameToEventNameMap.set(onloadstartAttr.localName(), EventTypeNames::loadstart);
    263         attributeNameToEventNameMap.set(onmousedownAttr.localName(), EventTypeNames::mousedown);
    264         attributeNameToEventNameMap.set(onmouseenterAttr.localName(), EventTypeNames::mouseenter);
    265         attributeNameToEventNameMap.set(onmouseleaveAttr.localName(), EventTypeNames::mouseleave);
    266         attributeNameToEventNameMap.set(onmousemoveAttr.localName(), EventTypeNames::mousemove);
    267         attributeNameToEventNameMap.set(onmouseoutAttr.localName(), EventTypeNames::mouseout);
    268         attributeNameToEventNameMap.set(onmouseoverAttr.localName(), EventTypeNames::mouseover);
    269         attributeNameToEventNameMap.set(onmouseupAttr.localName(), EventTypeNames::mouseup);
    270         attributeNameToEventNameMap.set(onmousewheelAttr.localName(), EventTypeNames::mousewheel);
    271         attributeNameToEventNameMap.set(onpasteAttr.localName(), EventTypeNames::paste);
    272         attributeNameToEventNameMap.set(onpauseAttr.localName(), EventTypeNames::pause);
    273         attributeNameToEventNameMap.set(onplayAttr.localName(), EventTypeNames::play);
    274         attributeNameToEventNameMap.set(onplayingAttr.localName(), EventTypeNames::playing);
    275         attributeNameToEventNameMap.set(onprogressAttr.localName(), EventTypeNames::progress);
    276         attributeNameToEventNameMap.set(onratechangeAttr.localName(), EventTypeNames::ratechange);
    277         attributeNameToEventNameMap.set(onresetAttr.localName(), EventTypeNames::reset);
    278         attributeNameToEventNameMap.set(onresizeAttr.localName(), EventTypeNames::resize);
    279         attributeNameToEventNameMap.set(onscrollAttr.localName(), EventTypeNames::scroll);
    280         attributeNameToEventNameMap.set(onseekedAttr.localName(), EventTypeNames::seeked);
    281         attributeNameToEventNameMap.set(onseekingAttr.localName(), EventTypeNames::seeking);
    282         attributeNameToEventNameMap.set(onselectAttr.localName(), EventTypeNames::select);
    283         attributeNameToEventNameMap.set(onselectstartAttr.localName(), EventTypeNames::selectstart);
    284         attributeNameToEventNameMap.set(onshowAttr.localName(), EventTypeNames::show);
    285         attributeNameToEventNameMap.set(onstalledAttr.localName(), EventTypeNames::stalled);
    286         attributeNameToEventNameMap.set(onsubmitAttr.localName(), EventTypeNames::submit);
    287         attributeNameToEventNameMap.set(onsuspendAttr.localName(), EventTypeNames::suspend);
    288         attributeNameToEventNameMap.set(ontimeupdateAttr.localName(), EventTypeNames::timeupdate);
    289         attributeNameToEventNameMap.set(ontoggleAttr.localName(), EventTypeNames::toggle);
    290         attributeNameToEventNameMap.set(ontouchcancelAttr.localName(), EventTypeNames::touchcancel);
    291         attributeNameToEventNameMap.set(ontouchendAttr.localName(), EventTypeNames::touchend);
    292         attributeNameToEventNameMap.set(ontouchmoveAttr.localName(), EventTypeNames::touchmove);
    293         attributeNameToEventNameMap.set(ontouchstartAttr.localName(), EventTypeNames::touchstart);
    294         attributeNameToEventNameMap.set(ontransitionendAttr.localName(), EventTypeNames::webkitTransitionEnd);
    295         attributeNameToEventNameMap.set(onvolumechangeAttr.localName(), EventTypeNames::volumechange);
    296         attributeNameToEventNameMap.set(onwaitingAttr.localName(), EventTypeNames::waiting);
    297         attributeNameToEventNameMap.set(onwebkitanimationendAttr.localName(), EventTypeNames::webkitAnimationEnd);
    298         attributeNameToEventNameMap.set(onwebkitanimationiterationAttr.localName(), EventTypeNames::webkitAnimationIteration);
    299         attributeNameToEventNameMap.set(onwebkitanimationstartAttr.localName(), EventTypeNames::webkitAnimationStart);
    300         attributeNameToEventNameMap.set(onwebkitfullscreenchangeAttr.localName(), EventTypeNames::webkitfullscreenchange);
    301         attributeNameToEventNameMap.set(onwebkitfullscreenerrorAttr.localName(), EventTypeNames::webkitfullscreenerror);
    302         attributeNameToEventNameMap.set(onwebkittransitionendAttr.localName(), EventTypeNames::webkitTransitionEnd);
    303         attributeNameToEventNameMap.set(onwheelAttr.localName(), EventTypeNames::wheel);
    304     }
    305 
    306     return attributeNameToEventNameMap.get(attrName.localName());
    307 }
    308 
    309 void HTMLElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    310 {
    311     if (name == tabindexAttr)
    312         return Element::parseAttribute(name, value);
    313 
    314     if (name == dirAttr) {
    315         dirAttributeChanged(value);
    316     } else {
    317         const AtomicString& eventName = eventNameForAttributeName(name);
    318         if (!eventName.isNull())
    319             setAttributeEventListener(eventName, createAttributeEventListener(this, name, value, eventParameterName()));
    320     }
    321 }
    322 
    323 PassRefPtrWillBeRawPtr<DocumentFragment> HTMLElement::textToFragment(const String& text, ExceptionState& exceptionState)
    324 {
    325     RefPtrWillBeRawPtr<DocumentFragment> fragment = DocumentFragment::create(document());
    326     unsigned i, length = text.length();
    327     UChar c = 0;
    328     for (unsigned start = 0; start < length; ) {
    329 
    330         // Find next line break.
    331         for (i = start; i < length; i++) {
    332           c = text[i];
    333           if (c == '\r' || c == '\n')
    334               break;
    335         }
    336 
    337         fragment->appendChild(Text::create(document(), text.substring(start, i - start)), exceptionState);
    338         if (exceptionState.hadException())
    339             return nullptr;
    340 
    341         if (c == '\r' || c == '\n') {
    342             fragment->appendChild(HTMLBRElement::create(document()), exceptionState);
    343             if (exceptionState.hadException())
    344                 return nullptr;
    345             // Make sure \r\n doesn't result in two line breaks.
    346             if (c == '\r' && i + 1 < length && text[i + 1] == '\n')
    347                 i++;
    348         }
    349 
    350         start = i + 1; // Character after line break.
    351     }
    352 
    353     return fragment;
    354 }
    355 
    356 static inline bool shouldProhibitSetInnerOuterText(const HTMLElement& element)
    357 {
    358     return element.hasTagName(colTag)
    359         || element.hasTagName(colgroupTag)
    360         || element.hasTagName(framesetTag)
    361         || element.hasTagName(headTag)
    362         || element.hasTagName(htmlTag)
    363         || element.hasTagName(tableTag)
    364         || element.hasTagName(tbodyTag)
    365         || element.hasTagName(tfootTag)
    366         || element.hasTagName(theadTag)
    367         || element.hasTagName(trTag);
    368 }
    369 
    370 void HTMLElement::setInnerText(const String& text, ExceptionState& exceptionState)
    371 {
    372     if (ieForbidsInsertHTML()) {
    373         exceptionState.throwDOMException(NoModificationAllowedError, "The '" + localName() + "' element does not support text insertion.");
    374         return;
    375     }
    376     if (shouldProhibitSetInnerOuterText(*this)) {
    377         exceptionState.throwDOMException(NoModificationAllowedError, "The '" + localName() + "' element does not support text insertion.");
    378         return;
    379     }
    380 
    381     // FIXME: This doesn't take whitespace collapsing into account at all.
    382 
    383     if (!text.contains('\n') && !text.contains('\r')) {
    384         if (text.isEmpty()) {
    385             removeChildren();
    386             return;
    387         }
    388         replaceChildrenWithText(this, text, exceptionState);
    389         return;
    390     }
    391 
    392     // FIXME: Do we need to be able to detect preserveNewline style even when there's no renderer?
    393     // FIXME: Can the renderer be out of date here? Do we need to call updateStyleIfNeeded?
    394     // For example, for the contents of textarea elements that are display:none?
    395     RenderObject* r = renderer();
    396     if (r && r->style()->preserveNewline()) {
    397         if (!text.contains('\r')) {
    398             replaceChildrenWithText(this, text, exceptionState);
    399             return;
    400         }
    401         String textWithConsistentLineBreaks = text;
    402         textWithConsistentLineBreaks.replace("\r\n", "\n");
    403         textWithConsistentLineBreaks.replace('\r', '\n');
    404         replaceChildrenWithText(this, textWithConsistentLineBreaks, exceptionState);
    405         return;
    406     }
    407 
    408     // Add text nodes and <br> elements.
    409     RefPtrWillBeRawPtr<DocumentFragment> fragment = textToFragment(text, exceptionState);
    410     if (!exceptionState.hadException())
    411         replaceChildrenWithFragment(this, fragment.release(), exceptionState);
    412 }
    413 
    414 void HTMLElement::setOuterText(const String& text, ExceptionState& exceptionState)
    415 {
    416     if (ieForbidsInsertHTML()) {
    417         exceptionState.throwDOMException(NoModificationAllowedError, "The '" + localName() + "' element does not support text insertion.");
    418         return;
    419     }
    420     if (shouldProhibitSetInnerOuterText(*this)) {
    421         exceptionState.throwDOMException(NoModificationAllowedError, "The '" + localName() + "' element does not support text insertion.");
    422         return;
    423     }
    424 
    425     ContainerNode* parent = parentNode();
    426     if (!parent) {
    427         exceptionState.throwDOMException(NoModificationAllowedError, "The element has no parent.");
    428         return;
    429     }
    430 
    431     RefPtrWillBeRawPtr<Node> prev = previousSibling();
    432     RefPtrWillBeRawPtr<Node> next = nextSibling();
    433     RefPtrWillBeRawPtr<Node> newChild = nullptr;
    434 
    435     // Convert text to fragment with <br> tags instead of linebreaks if needed.
    436     if (text.contains('\r') || text.contains('\n'))
    437         newChild = textToFragment(text, exceptionState);
    438     else
    439         newChild = Text::create(document(), text);
    440 
    441     // textToFragment might cause mutation events.
    442     if (!parentNode())
    443         exceptionState.throwDOMException(HierarchyRequestError, "The element has no parent.");
    444 
    445     if (exceptionState.hadException())
    446         return;
    447 
    448     parent->replaceChild(newChild.release(), this, exceptionState);
    449 
    450     RefPtrWillBeRawPtr<Node> node = next ? next->previousSibling() : nullptr;
    451     if (!exceptionState.hadException() && node && node->isTextNode())
    452         mergeWithNextTextNode(toText(node.get()), exceptionState);
    453 
    454     if (!exceptionState.hadException() && prev && prev->isTextNode())
    455         mergeWithNextTextNode(toText(prev.get()), exceptionState);
    456 }
    457 
    458 void HTMLElement::applyAlignmentAttributeToStyle(const AtomicString& alignment, MutableStylePropertySet* style)
    459 {
    460     // Vertical alignment with respect to the current baseline of the text
    461     // right or left means floating images.
    462     CSSValueID floatValue = CSSValueInvalid;
    463     CSSValueID verticalAlignValue = CSSValueInvalid;
    464 
    465     if (equalIgnoringCase(alignment, "absmiddle"))
    466         verticalAlignValue = CSSValueMiddle;
    467     else if (equalIgnoringCase(alignment, "absbottom"))
    468         verticalAlignValue = CSSValueBottom;
    469     else if (equalIgnoringCase(alignment, "left")) {
    470         floatValue = CSSValueLeft;
    471         verticalAlignValue = CSSValueTop;
    472     } else if (equalIgnoringCase(alignment, "right")) {
    473         floatValue = CSSValueRight;
    474         verticalAlignValue = CSSValueTop;
    475     } else if (equalIgnoringCase(alignment, "top"))
    476         verticalAlignValue = CSSValueTop;
    477     else if (equalIgnoringCase(alignment, "middle"))
    478         verticalAlignValue = CSSValueWebkitBaselineMiddle;
    479     else if (equalIgnoringCase(alignment, "center"))
    480         verticalAlignValue = CSSValueMiddle;
    481     else if (equalIgnoringCase(alignment, "bottom"))
    482         verticalAlignValue = CSSValueBaseline;
    483     else if (equalIgnoringCase(alignment, "texttop"))
    484         verticalAlignValue = CSSValueTextTop;
    485 
    486     if (floatValue != CSSValueInvalid)
    487         addPropertyToPresentationAttributeStyle(style, CSSPropertyFloat, floatValue);
    488 
    489     if (verticalAlignValue != CSSValueInvalid)
    490         addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, verticalAlignValue);
    491 }
    492 
    493 bool HTMLElement::hasCustomFocusLogic() const
    494 {
    495     return false;
    496 }
    497 
    498 String HTMLElement::contentEditable() const
    499 {
    500     const AtomicString& value = fastGetAttribute(contenteditableAttr);
    501 
    502     if (value.isNull())
    503         return "inherit";
    504     if (value.isEmpty() || equalIgnoringCase(value, "true"))
    505         return "true";
    506     if (equalIgnoringCase(value, "false"))
    507          return "false";
    508     if (equalIgnoringCase(value, "plaintext-only"))
    509         return "plaintext-only";
    510 
    511     return "inherit";
    512 }
    513 
    514 void HTMLElement::setContentEditable(const String& enabled, ExceptionState& exceptionState)
    515 {
    516     if (equalIgnoringCase(enabled, "true"))
    517         setAttribute(contenteditableAttr, "true");
    518     else if (equalIgnoringCase(enabled, "false"))
    519         setAttribute(contenteditableAttr, "false");
    520     else if (equalIgnoringCase(enabled, "plaintext-only"))
    521         setAttribute(contenteditableAttr, "plaintext-only");
    522     else if (equalIgnoringCase(enabled, "inherit"))
    523         removeAttribute(contenteditableAttr);
    524     else
    525         exceptionState.throwDOMException(SyntaxError, "The value provided ('" + enabled + "') is not one of 'true', 'false', 'plaintext-only', or 'inherit'.");
    526 }
    527 
    528 bool HTMLElement::draggable() const
    529 {
    530     return equalIgnoringCase(getAttribute(draggableAttr), "true");
    531 }
    532 
    533 void HTMLElement::setDraggable(bool value)
    534 {
    535     setAttribute(draggableAttr, value ? "true" : "false");
    536 }
    537 
    538 bool HTMLElement::spellcheck() const
    539 {
    540     return isSpellCheckingEnabled();
    541 }
    542 
    543 void HTMLElement::setSpellcheck(bool enable)
    544 {
    545     setAttribute(spellcheckAttr, enable ? "true" : "false");
    546 }
    547 
    548 
    549 void HTMLElement::click()
    550 {
    551     dispatchSimulatedClick(0, SendNoEvents);
    552 }
    553 
    554 void HTMLElement::accessKeyAction(bool sendMouseEvents)
    555 {
    556     dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
    557 }
    558 
    559 String HTMLElement::title() const
    560 {
    561     return fastGetAttribute(titleAttr);
    562 }
    563 
    564 short HTMLElement::tabIndex() const
    565 {
    566     if (supportsFocus())
    567         return Element::tabIndex();
    568     return -1;
    569 }
    570 
    571 TranslateAttributeMode HTMLElement::translateAttributeMode() const
    572 {
    573     const AtomicString& value = getAttribute(translateAttr);
    574 
    575     if (value == nullAtom)
    576         return TranslateAttributeInherit;
    577     if (equalIgnoringCase(value, "yes") || equalIgnoringCase(value, ""))
    578         return TranslateAttributeYes;
    579     if (equalIgnoringCase(value, "no"))
    580         return TranslateAttributeNo;
    581 
    582     return TranslateAttributeInherit;
    583 }
    584 
    585 bool HTMLElement::translate() const
    586 {
    587     for (const HTMLElement* element = this; element; element = Traversal<HTMLElement>::firstAncestor(*element)) {
    588         TranslateAttributeMode mode = element->translateAttributeMode();
    589         if (mode != TranslateAttributeInherit) {
    590             ASSERT(mode == TranslateAttributeYes || mode == TranslateAttributeNo);
    591             return mode == TranslateAttributeYes;
    592         }
    593     }
    594 
    595     // Default on the root element is translate=yes.
    596     return true;
    597 }
    598 
    599 void HTMLElement::setTranslate(bool enable)
    600 {
    601     setAttribute(translateAttr, enable ? "yes" : "no");
    602 }
    603 
    604 // Returns the conforming 'dir' value associated with the state the attribute is in (in its canonical case), if any,
    605 // or the empty string if the attribute is in a state that has no associated keyword value or if the attribute is
    606 // not in a defined state (e.g. the attribute is missing and there is no missing value default).
    607 // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#limited-to-only-known-values
    608 static inline const AtomicString& toValidDirValue(const AtomicString& value)
    609 {
    610     DEFINE_STATIC_LOCAL(const AtomicString, ltrValue, ("ltr", AtomicString::ConstructFromLiteral));
    611     DEFINE_STATIC_LOCAL(const AtomicString, rtlValue, ("rtl", AtomicString::ConstructFromLiteral));
    612     DEFINE_STATIC_LOCAL(const AtomicString, autoValue, ("auto", AtomicString::ConstructFromLiteral));
    613 
    614     if (equalIgnoringCase(value, ltrValue))
    615         return ltrValue;
    616     if (equalIgnoringCase(value, rtlValue))
    617         return rtlValue;
    618     if (equalIgnoringCase(value, autoValue))
    619         return autoValue;
    620     return nullAtom;
    621 }
    622 
    623 const AtomicString& HTMLElement::dir()
    624 {
    625     return toValidDirValue(fastGetAttribute(dirAttr));
    626 }
    627 
    628 void HTMLElement::setDir(const AtomicString& value)
    629 {
    630     setAttribute(dirAttr, value);
    631 }
    632 
    633 HTMLFormElement* HTMLElement::findFormAncestor() const
    634 {
    635     return Traversal<HTMLFormElement>::firstAncestor(*this);
    636 }
    637 
    638 static inline bool elementAffectsDirectionality(const Node* node)
    639 {
    640     return node->isHTMLElement() && (isHTMLBDIElement(toHTMLElement(*node)) || toHTMLElement(*node).hasAttribute(dirAttr));
    641 }
    642 
    643 static void setHasDirAutoFlagRecursively(Node* firstNode, bool flag, Node* lastNode = 0)
    644 {
    645     firstNode->setSelfOrAncestorHasDirAutoAttribute(flag);
    646 
    647     Node* node = firstNode->firstChild();
    648 
    649     while (node) {
    650         if (elementAffectsDirectionality(node)) {
    651             if (node == lastNode)
    652                 return;
    653             node = NodeTraversal::nextSkippingChildren(*node, firstNode);
    654             continue;
    655         }
    656         node->setSelfOrAncestorHasDirAutoAttribute(flag);
    657         if (node == lastNode)
    658             return;
    659         node = NodeTraversal::next(*node, firstNode);
    660     }
    661 }
    662 
    663 void HTMLElement::childrenChanged(const ChildrenChange& change)
    664 {
    665     Element::childrenChanged(change);
    666     adjustDirectionalityIfNeededAfterChildrenChanged(change);
    667 }
    668 
    669 bool HTMLElement::hasDirectionAuto() const
    670 {
    671     const AtomicString& direction = fastGetAttribute(dirAttr);
    672     return (isHTMLBDIElement(*this) && direction == nullAtom) || equalIgnoringCase(direction, "auto");
    673 }
    674 
    675 TextDirection HTMLElement::directionalityIfhasDirAutoAttribute(bool& isAuto) const
    676 {
    677     if (!(selfOrAncestorHasDirAutoAttribute() && hasDirectionAuto())) {
    678         isAuto = false;
    679         return LTR;
    680     }
    681 
    682     isAuto = true;
    683     return directionality();
    684 }
    685 
    686 TextDirection HTMLElement::directionality(Node** strongDirectionalityTextNode) const
    687 {
    688     if (isHTMLInputElement(*this)) {
    689         HTMLInputElement* inputElement = toHTMLInputElement(const_cast<HTMLElement*>(this));
    690         bool hasStrongDirectionality;
    691         TextDirection textDirection = determineDirectionality(inputElement->value(), hasStrongDirectionality);
    692         if (strongDirectionalityTextNode)
    693             *strongDirectionalityTextNode = hasStrongDirectionality ? inputElement : 0;
    694         return textDirection;
    695     }
    696 
    697     Node* node = firstChild();
    698     while (node) {
    699         // Skip bdi, script, style and text form controls.
    700         if (equalIgnoringCase(node->nodeName(), "bdi") || isHTMLScriptElement(*node) || isHTMLStyleElement(*node)
    701             || (node->isElementNode() && toElement(node)->isTextFormControl())) {
    702             node = NodeTraversal::nextSkippingChildren(*node, this);
    703             continue;
    704         }
    705 
    706         // Skip elements with valid dir attribute
    707         if (node->isElementNode()) {
    708             AtomicString dirAttributeValue = toElement(node)->fastGetAttribute(dirAttr);
    709             if (isValidDirAttribute(dirAttributeValue)) {
    710                 node = NodeTraversal::nextSkippingChildren(*node, this);
    711                 continue;
    712             }
    713         }
    714 
    715         if (node->isTextNode()) {
    716             bool hasStrongDirectionality;
    717             TextDirection textDirection = determineDirectionality(node->textContent(true), hasStrongDirectionality);
    718             if (hasStrongDirectionality) {
    719                 if (strongDirectionalityTextNode)
    720                     *strongDirectionalityTextNode = node;
    721                 return textDirection;
    722             }
    723         }
    724         node = NodeTraversal::next(*node, this);
    725     }
    726     if (strongDirectionalityTextNode)
    727         *strongDirectionalityTextNode = 0;
    728     return LTR;
    729 }
    730 
    731 void HTMLElement::dirAttributeChanged(const AtomicString& value)
    732 {
    733     Element* parent = parentElement();
    734 
    735     if (parent && parent->isHTMLElement() && parent->selfOrAncestorHasDirAutoAttribute())
    736         toHTMLElement(parent)->adjustDirectionalityIfNeededAfterChildAttributeChanged(this);
    737 
    738     if (equalIgnoringCase(value, "auto"))
    739         calculateAndAdjustDirectionality();
    740 }
    741 
    742 void HTMLElement::adjustDirectionalityIfNeededAfterChildAttributeChanged(Element* child)
    743 {
    744     ASSERT(selfOrAncestorHasDirAutoAttribute());
    745     Node* strongDirectionalityTextNode;
    746     TextDirection textDirection = directionality(&strongDirectionalityTextNode);
    747     setHasDirAutoFlagRecursively(child, false);
    748     if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection) {
    749         Element* elementToAdjust = this;
    750         for (; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) {
    751             if (elementAffectsDirectionality(elementToAdjust)) {
    752                 elementToAdjust->setNeedsStyleRecalc(SubtreeStyleChange);
    753                 return;
    754             }
    755         }
    756     }
    757 }
    758 
    759 void HTMLElement::calculateAndAdjustDirectionality()
    760 {
    761     Node* strongDirectionalityTextNode;
    762     TextDirection textDirection = directionality(&strongDirectionalityTextNode);
    763     setHasDirAutoFlagRecursively(this, hasDirectionAuto(), strongDirectionalityTextNode);
    764     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
    765         setHasDirAutoFlagRecursively(root, hasDirectionAuto());
    766     if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection)
    767         setNeedsStyleRecalc(SubtreeStyleChange);
    768 }
    769 
    770 void HTMLElement::adjustDirectionalityIfNeededAfterChildrenChanged(const ChildrenChange& change)
    771 {
    772     if (!selfOrAncestorHasDirAutoAttribute())
    773         return;
    774 
    775     Node* oldMarkedNode = change.siblingBeforeChange ? NodeTraversal::nextSkippingChildren(*change.siblingBeforeChange) : 0;
    776     while (oldMarkedNode && elementAffectsDirectionality(oldMarkedNode))
    777         oldMarkedNode = NodeTraversal::nextSkippingChildren(*oldMarkedNode, this);
    778     if (oldMarkedNode)
    779         setHasDirAutoFlagRecursively(oldMarkedNode, false);
    780 
    781     for (Element* elementToAdjust = this; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) {
    782         if (elementAffectsDirectionality(elementToAdjust)) {
    783             toHTMLElement(elementToAdjust)->calculateAndAdjustDirectionality();
    784             return;
    785         }
    786     }
    787 }
    788 
    789 void HTMLElement::addHTMLLengthToStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
    790 {
    791     // FIXME: This function should not spin up the CSS parser, but should instead just figure out the correct
    792     // length unit and make the appropriate parsed value.
    793 
    794     // strip attribute garbage..
    795     StringImpl* v = value.impl();
    796     if (v) {
    797         unsigned length = 0;
    798 
    799         while (length < v->length() && (*v)[length] <= ' ')
    800             length++;
    801 
    802         for (; length < v->length(); length++) {
    803             UChar cc = (*v)[length];
    804             if (cc > '9')
    805                 break;
    806             if (cc < '0') {
    807                 if (cc == '%' || cc == '*')
    808                     length++;
    809                 if (cc != '.')
    810                     break;
    811             }
    812         }
    813 
    814         if (length != v->length()) {
    815             addPropertyToPresentationAttributeStyle(style, propertyID, v->substring(0, length));
    816             return;
    817         }
    818     }
    819 
    820     addPropertyToPresentationAttributeStyle(style, propertyID, value);
    821 }
    822 
    823 static RGBA32 parseColorStringWithCrazyLegacyRules(const String& colorString)
    824 {
    825     // Per spec, only look at the first 128 digits of the string.
    826     const size_t maxColorLength = 128;
    827     // We'll pad the buffer with two extra 0s later, so reserve two more than the max.
    828     Vector<char, maxColorLength+2> digitBuffer;
    829 
    830     size_t i = 0;
    831     // Skip a leading #.
    832     if (colorString[0] == '#')
    833         i = 1;
    834 
    835     // Grab the first 128 characters, replacing non-hex characters with 0.
    836     // Non-BMP characters are replaced with "00" due to them appearing as two "characters" in the String.
    837     for (; i < colorString.length() && digitBuffer.size() < maxColorLength; i++) {
    838         if (!isASCIIHexDigit(colorString[i]))
    839             digitBuffer.append('0');
    840         else
    841             digitBuffer.append(colorString[i]);
    842     }
    843 
    844     if (!digitBuffer.size())
    845         return Color::black;
    846 
    847     // Pad the buffer out to at least the next multiple of three in size.
    848     digitBuffer.append('0');
    849     digitBuffer.append('0');
    850 
    851     if (digitBuffer.size() < 6)
    852         return makeRGB(toASCIIHexValue(digitBuffer[0]), toASCIIHexValue(digitBuffer[1]), toASCIIHexValue(digitBuffer[2]));
    853 
    854     // Split the digits into three components, then search the last 8 digits of each component.
    855     ASSERT(digitBuffer.size() >= 6);
    856     size_t componentLength = digitBuffer.size() / 3;
    857     size_t componentSearchWindowLength = min<size_t>(componentLength, 8);
    858     size_t redIndex = componentLength - componentSearchWindowLength;
    859     size_t greenIndex = componentLength * 2 - componentSearchWindowLength;
    860     size_t blueIndex = componentLength * 3 - componentSearchWindowLength;
    861     // Skip digits until one of them is non-zero, or we've only got two digits left in the component.
    862     while (digitBuffer[redIndex] == '0' && digitBuffer[greenIndex] == '0' && digitBuffer[blueIndex] == '0' && (componentLength - redIndex) > 2) {
    863         redIndex++;
    864         greenIndex++;
    865         blueIndex++;
    866     }
    867     ASSERT(redIndex + 1 < componentLength);
    868     ASSERT(greenIndex >= componentLength);
    869     ASSERT(greenIndex + 1 < componentLength * 2);
    870     ASSERT(blueIndex >= componentLength * 2);
    871     ASSERT_WITH_SECURITY_IMPLICATION(blueIndex + 1 < digitBuffer.size());
    872 
    873     int redValue = toASCIIHexValue(digitBuffer[redIndex], digitBuffer[redIndex + 1]);
    874     int greenValue = toASCIIHexValue(digitBuffer[greenIndex], digitBuffer[greenIndex + 1]);
    875     int blueValue = toASCIIHexValue(digitBuffer[blueIndex], digitBuffer[blueIndex + 1]);
    876     return makeRGB(redValue, greenValue, blueValue);
    877 }
    878 
    879 // Color parsing that matches HTML's "rules for parsing a legacy color value"
    880 void HTMLElement::addHTMLColorToStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& attributeValue)
    881 {
    882     // An empty string doesn't apply a color. (One containing only whitespace does, which is why this check occurs before stripping.)
    883     if (attributeValue.isEmpty())
    884         return;
    885 
    886     String colorString = attributeValue.stripWhiteSpace();
    887 
    888     // "transparent" doesn't apply a color either.
    889     if (equalIgnoringCase(colorString, "transparent"))
    890         return;
    891 
    892     // If the string is a named CSS color or a 3/6-digit hex color, use that.
    893     Color parsedColor;
    894     if (!parsedColor.setFromString(colorString))
    895         parsedColor.setRGB(parseColorStringWithCrazyLegacyRules(colorString));
    896 
    897     style->setProperty(propertyID, cssValuePool().createColorValue(parsedColor.rgb()));
    898 }
    899 
    900 bool HTMLElement::isInteractiveContent() const
    901 {
    902     return false;
    903 }
    904 
    905 
    906 HTMLMenuElement* HTMLElement::contextMenu() const
    907 {
    908     const AtomicString& contextMenuId(fastGetAttribute(contextmenuAttr));
    909     if (contextMenuId.isNull())
    910         return nullptr;
    911 
    912     Element* element = treeScope().getElementById(contextMenuId);
    913     // Not checking if the menu element is of type "popup".
    914     // Ignoring menu element type attribute is intentional according to the standard.
    915     return isHTMLMenuElement(element) ? toHTMLMenuElement(element) : nullptr;
    916 }
    917 
    918 void HTMLElement::setContextMenu(HTMLMenuElement* contextMenu)
    919 {
    920     if (!contextMenu) {
    921         setAttribute(contextmenuAttr, "");
    922         return;
    923     }
    924 
    925     // http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#reflecting-content-attributes-in-idl-attributes
    926     // On setting, if the given element has an id attribute, and has the same home
    927     // subtree as the element of the attribute being set, and the given element is the
    928     // first element in that home subtree whose ID is the value of that id attribute,
    929     // then the content attribute must be set to the value of that id attribute.
    930     // Otherwise, the content attribute must be set to the empty string.
    931     const AtomicString& contextMenuId(contextMenu->fastGetAttribute(idAttr));
    932 
    933     if (!contextMenuId.isNull() && contextMenu == treeScope().getElementById(contextMenuId))
    934         setAttribute(contextmenuAttr, contextMenuId);
    935     else
    936         setAttribute(contextmenuAttr, "");
    937 }
    938 
    939 void HTMLElement::defaultEventHandler(Event* event)
    940 {
    941     if (event->type() == EventTypeNames::keypress && event->isKeyboardEvent()) {
    942         handleKeypressEvent(toKeyboardEvent(event));
    943         if (event->defaultHandled())
    944             return;
    945     }
    946 
    947     Element::defaultEventHandler(event);
    948 }
    949 
    950 bool HTMLElement::matchesReadOnlyPseudoClass() const
    951 {
    952     return !matchesReadWritePseudoClass();
    953 }
    954 
    955 bool HTMLElement::matchesReadWritePseudoClass() const
    956 {
    957     if (fastHasAttribute(contenteditableAttr)) {
    958         const AtomicString& value = fastGetAttribute(contenteditableAttr);
    959 
    960         if (value.isEmpty() || equalIgnoringCase(value, "true") || equalIgnoringCase(value, "plaintext-only"))
    961             return true;
    962         if (equalIgnoringCase(value, "false"))
    963             return false;
    964         // All other values should be treated as "inherit".
    965     }
    966 
    967     return parentElement() && parentElement()->hasEditableStyle();
    968 }
    969 
    970 void HTMLElement::handleKeypressEvent(KeyboardEvent* event)
    971 {
    972     if (!document().settings() || !document().settings()->spatialNavigationEnabled() || !supportsFocus())
    973         return;
    974     // if the element is a text form control (like <input type=text> or <textarea>)
    975     // or has contentEditable attribute on, we should enter a space or newline
    976     // even in spatial navigation mode instead of handling it as a "click" action.
    977     if (isTextFormControl() || isContentEditable())
    978         return;
    979     int charCode = event->charCode();
    980     if (charCode == '\r' || charCode == ' ') {
    981         dispatchSimulatedClick(event);
    982         event->setDefaultHandled();
    983     }
    984 }
    985 
    986 const AtomicString& HTMLElement::eventParameterName()
    987 {
    988     DEFINE_STATIC_LOCAL(const AtomicString, eventString, ("event", AtomicString::ConstructFromLiteral));
    989     return eventString;
    990 }
    991 
    992 } // namespace blink
    993 
    994 #ifndef NDEBUG
    995 
    996 // For use in the debugger
    997 void dumpInnerHTML(blink::HTMLElement*);
    998 
    999 void dumpInnerHTML(blink::HTMLElement* element)
   1000 {
   1001     printf("%s\n", element->innerHTML().ascii().data());
   1002 }
   1003 #endif
   1004