diff options
author | Steve Block <steveblock@google.com> | 2010-09-29 17:32:26 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-09-29 17:35:08 +0100 |
commit | 68513a70bcd92384395513322f1b801e7bf9c729 (patch) | |
tree | 161b50f75a5921d61731bb25e730005994fcec85 /WebCore/html | |
parent | fd5c6425ce58eb75211be7718d5dee960842a37e (diff) | |
download | external_webkit-68513a70bcd92384395513322f1b801e7bf9c729.zip external_webkit-68513a70bcd92384395513322f1b801e7bf9c729.tar.gz external_webkit-68513a70bcd92384395513322f1b801e7bf9c729.tar.bz2 |
Merge WebKit at r67908: Initial merge by Git
Change-Id: I43a553e7b3299b28cb6ee8aa035ed70fe342b972
Diffstat (limited to 'WebCore/html')
44 files changed, 967 insertions, 764 deletions
diff --git a/WebCore/html/HTMLAnchorElement.cpp b/WebCore/html/HTMLAnchorElement.cpp index e1ee86a..995552e 100644 --- a/WebCore/html/HTMLAnchorElement.cpp +++ b/WebCore/html/HTMLAnchorElement.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Simon Hausmann <hausmann@kde.org> - * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * (C) 2006 Graham Dennis (graham.dennis@gmail.com) * * This library is free software; you can redistribute it and/or @@ -105,117 +105,67 @@ bool HTMLAnchorElement::isKeyboardFocusable(KeyboardEvent* event) const return hasNonEmptyBoundingBox(); } -void HTMLAnchorElement::defaultEventHandler(Event* evt) +static void appendServerMapMousePosition(String& url, Event* event) { - // React on clicks and on keypresses. - // Don't make this KEYUP_EVENT again, it makes khtml follow links it shouldn't, - // when pressing Enter in the combo. - if (isLink() && (evt->type() == eventNames().clickEvent || (evt->type() == eventNames().keydownEvent && focused()))) { - MouseEvent* e = 0; - if (evt->type() == eventNames().clickEvent && evt->isMouseEvent()) - e = static_cast<MouseEvent*>(evt); + if (!event->isMouseEvent()) + return; - KeyboardEvent* k = 0; - if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) - k = static_cast<KeyboardEvent*>(evt); + ASSERT(event->target()); + Node* target = event->target()->toNode(); + ASSERT(target); + if (!target->hasTagName(imgTag)) + return; - if (e && e->button() == RightButton) { - HTMLElement::defaultEventHandler(evt); - return; - } + HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(event->target()->toNode()); + if (!imageElement || !imageElement->isServerMap()) + return; - // If the link is editable, then we need to check the settings to see whether or not to follow the link - if (isContentEditable()) { - EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; - if (Settings* settings = document()->settings()) - editableLinkBehavior = settings->editableLinkBehavior(); - - switch (editableLinkBehavior) { - // Always follow the link (Safari 2.0 behavior) - default: - case EditableLinkDefaultBehavior: - case EditableLinkAlwaysLive: - break; - - case EditableLinkNeverLive: - HTMLElement::defaultEventHandler(evt); - return; + RenderImage* renderer = toRenderImage(imageElement->renderer()); + if (!renderer) + return; - // If the selection prior to clicking on this link resided in the same editable block as this link, - // and the shift key isn't pressed, we don't want to follow the link - case EditableLinkLiveWhenNotFocused: - if (e && !e->shiftKey() && m_rootEditableElementForSelectionOnMouseDown == rootEditableElement()) { - HTMLElement::defaultEventHandler(evt); - return; - } - break; - - // Only follow the link if the shift key is down (WinIE/Firefox behavior) - case EditableLinkOnlyLiveWithShiftKey: - if (e && !e->shiftKey()) { - HTMLElement::defaultEventHandler(evt); - return; - } - break; - } - } + // FIXME: This should probably pass true for useTransforms. + FloatPoint absolutePosition = renderer->absoluteToLocal(FloatPoint(static_cast<MouseEvent*>(event)->pageX(), static_cast<MouseEvent*>(event)->pageY())); + int x = absolutePosition.x(); + int y = absolutePosition.y(); + url += "?"; + url += String::number(x); + url += ","; + url += String::number(y); +} - if (k) { - if (k->keyIdentifier() != "Enter") { - HTMLElement::defaultEventHandler(evt); - return; - } - evt->setDefaultHandled(); - dispatchSimulatedClick(evt); +void HTMLAnchorElement::defaultEventHandler(Event* event) +{ + if (isLink()) { + if (focused() && isEnterKeyKeydownEvent(event) && treatLinkAsLiveForEventType(NonMouseEvent)) { + event->setDefaultHandled(); + dispatchSimulatedClick(event); return; } - String url = deprecatedParseURL(getAttribute(hrefAttr)); - - ASSERT(evt->target()); - ASSERT(evt->target()->toNode()); - if (evt->target()->toNode()->hasTagName(imgTag)) { - HTMLImageElement* img = static_cast<HTMLImageElement*>(evt->target()->toNode()); - if (img && img->isServerMap()) { - RenderImage* r = toRenderImage(img->renderer()); - if (r && e) { - // FIXME: broken with transforms - FloatPoint absPos = r->localToAbsolute(); - int x = e->pageX() - absPos.x(); - int y = e->pageY() - absPos.y(); - url += "?"; - url += String::number(x); - url += ","; - url += String::number(y); - } else { - evt->setDefaultHandled(); - HTMLElement::defaultEventHandler(evt); - return; - } - } + if (isLinkClick(event) && treatLinkAsLiveForEventType(eventType(event))) { + String url = deprecatedParseURL(getAttribute(hrefAttr)); + appendServerMapMousePosition(url, event); + handleLinkClick(event, document(), url, getAttribute(targetAttr), hasRel(RelationNoReferrer)); + return; } - if (!evt->defaultPrevented() && document()->frame()) - document()->frame()->loader()->urlSelected(document()->completeURL(url), getAttribute(targetAttr), evt, false, false, true, hasRel(RelationNoReferrer) ? NoReferrer : SendReferrer); - - evt->setDefaultHandled(); - } else if (isLink() && isContentEditable()) { - // This keeps track of the editable block that the selection was in (if it was in one) just before the link was clicked - // for the LiveWhenNotFocused editable link behavior - if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() != RightButton && document()->frame() && document()->frame()->selection()) { - MouseEvent* e = static_cast<MouseEvent*>(evt); - - m_rootEditableElementForSelectionOnMouseDown = document()->frame()->selection()->rootEditableElement(); - m_wasShiftKeyDownOnMouseDown = e && e->shiftKey(); - } else if (evt->type() == eventNames().mouseoverEvent) { - // These are cleared on mouseover and not mouseout because their values are needed for drag events, but these happen - // after mouse out events. - m_rootEditableElementForSelectionOnMouseDown = 0; - m_wasShiftKeyDownOnMouseDown = false; + if (isContentEditable()) { + // This keeps track of the editable block that the selection was in (if it was in one) just before the link was clicked + // for the LiveWhenNotFocused editable link behavior + if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() != RightButton && document()->frame() && document()->frame()->selection()) { + m_rootEditableElementForSelectionOnMouseDown = document()->frame()->selection()->rootEditableElement(); + m_wasShiftKeyDownOnMouseDown = static_cast<MouseEvent*>(event)->shiftKey(); + } else if (event->type() == eventNames().mouseoverEvent) { + // These are cleared on mouseover and not mouseout because their values are needed for drag events, + // but drag events happen after mouse out events. + m_rootEditableElementForSelectionOnMouseDown = 0; + m_wasShiftKeyDownOnMouseDown = false; + } } } - HTMLElement::defaultEventHandler(evt); + HTMLElement::defaultEventHandler(event); } void HTMLAnchorElement::setActive(bool down, bool pause) @@ -512,32 +462,69 @@ String HTMLAnchorElement::toString() const bool HTMLAnchorElement::isLiveLink() const { - if (!isLink()) - return false; + return isLink() && treatLinkAsLiveForEventType(m_wasShiftKeyDownOnMouseDown ? MouseEventWithShiftKey : MouseEventWithoutShiftKey); +} + +HTMLAnchorElement::EventType HTMLAnchorElement::eventType(Event* event) +{ + if (!event->isMouseEvent()) + return NonMouseEvent; + return static_cast<MouseEvent*>(event)->shiftKey() ? MouseEventWithShiftKey : MouseEventWithoutShiftKey; +} + +bool HTMLAnchorElement::treatLinkAsLiveForEventType(EventType eventType) const +{ if (!isContentEditable()) return true; - - EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; - if (Settings* settings = document()->settings()) - editableLinkBehavior = settings->editableLinkBehavior(); - - switch (editableLinkBehavior) { - default: - case EditableLinkDefaultBehavior: - case EditableLinkAlwaysLive: - return true; - - case EditableLinkNeverLive: - return false; - - // Don't set the link to be live if the current selection is in the same editable block as - // this link or if the shift key is down - case EditableLinkLiveWhenNotFocused: - return m_wasShiftKeyDownOnMouseDown || m_rootEditableElementForSelectionOnMouseDown != rootEditableElement(); - - case EditableLinkOnlyLiveWithShiftKey: - return m_wasShiftKeyDownOnMouseDown; + + Settings* settings = document()->settings(); + if (!settings) + return true; + + switch (settings->editableLinkBehavior()) { + case EditableLinkDefaultBehavior: + case EditableLinkAlwaysLive: + return true; + + case EditableLinkNeverLive: + return false; + + // If the selection prior to clicking on this link resided in the same editable block as this link, + // and the shift key isn't pressed, we don't want to follow the link. + case EditableLinkLiveWhenNotFocused: + return eventType == MouseEventWithShiftKey || (eventType == MouseEventWithoutShiftKey && m_rootEditableElementForSelectionOnMouseDown != rootEditableElement()); + + case EditableLinkOnlyLiveWithShiftKey: + return eventType == MouseEventWithShiftKey; } + + ASSERT_NOT_REACHED(); + return false; +} + +bool isEnterKeyKeydownEvent(Event* event) +{ + return event->type() == eventNames().keydownEvent && event->isKeyboardEvent() && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "Enter"; +} + +bool isMiddleMouseButtonEvent(Event* event) +{ + return event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == MiddleButton; +} + +bool isLinkClick(Event* event) +{ + return event->type() == eventNames().clickEvent || (event->type() == eventNames().mouseupEvent && isMiddleMouseButtonEvent(event)); +} + +void handleLinkClick(Event* event, Document* document, const String& url, const String& target, bool hideReferrer) +{ + event->setDefaultHandled(); + + Frame* frame = document->frame(); + if (!frame) + return; + frame->loader()->urlSelected(document->completeURL(url), target, event, false, false, true, hideReferrer ? NoReferrer : SendReferrer); } } diff --git a/WebCore/html/HTMLAnchorElement.h b/WebCore/html/HTMLAnchorElement.h index a5ef167..16baff1 100644 --- a/WebCore/html/HTMLAnchorElement.h +++ b/WebCore/html/HTMLAnchorElement.h @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Simon Hausmann <hausmann@kde.org> - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -109,11 +109,26 @@ private: virtual short tabIndex() const; virtual bool draggable() const; + enum EventType { + MouseEventWithoutShiftKey, + MouseEventWithShiftKey, + NonMouseEvent, + }; + static EventType eventType(Event*); + bool treatLinkAsLiveForEventType(EventType) const; + RefPtr<Element> m_rootEditableElementForSelectionOnMouseDown; bool m_wasShiftKeyDownOnMouseDown; uint32_t m_linkRelations; }; +// Functions shared with the other anchor elements (SVG and WML). + +bool isEnterKeyKeydownEvent(Event*); +bool isMiddleMouseButtonEvent(Event*); +bool isLinkClick(Event*); +void handleLinkClick(Event*, Document*, const String& url, const String& target, bool hideReferrer = false); + } // namespace WebCore #endif // HTMLAnchorElement_h diff --git a/WebCore/html/HTMLBodyElement.cpp b/WebCore/html/HTMLBodyElement.cpp index 98e0d6f..05c13ac 100644 --- a/WebCore/html/HTMLBodyElement.cpp +++ b/WebCore/html/HTMLBodyElement.cpp @@ -275,9 +275,9 @@ void HTMLBodyElement::setVLink(const String& value) setAttribute(vlinkAttr, value); } -static int adjustForZoom(int value, FrameView* frameView) +static int adjustForZoom(int value, Document* document) { - float zoomFactor = frameView->zoomFactor(); + float zoomFactor = document->frame()->pageZoomFactor(); if (zoomFactor == 1) return value; // Needed because of truncation (rather than rounding) when scaling up. @@ -289,57 +289,63 @@ static int adjustForZoom(int value, FrameView* frameView) int HTMLBodyElement::scrollLeft() const { // Update the document's layout. - Document* doc = document(); - doc->updateLayoutIgnorePendingStylesheets(); - FrameView* view = doc->view(); - return view ? adjustForZoom(view->scrollX(), view) : 0; + Document* document = this->document(); + document->updateLayoutIgnorePendingStylesheets(); + FrameView* view = document->view(); + return view ? adjustForZoom(view->scrollX(), document) : 0; } void HTMLBodyElement::setScrollLeft(int scrollLeft) { Document* document = this->document(); document->updateLayoutIgnorePendingStylesheets(); - FrameView* view = document->view(); + Frame* frame = document->frame(); + if (!frame) + return; + FrameView* view = frame->view(); if (!view) return; - view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * view->zoomFactor()), view->scrollY())); + view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor()), view->scrollY())); } int HTMLBodyElement::scrollTop() const { // Update the document's layout. - Document* doc = document(); - doc->updateLayoutIgnorePendingStylesheets(); - FrameView* view = doc->view(); - return view ? adjustForZoom(view->scrollY(), view) : 0; + Document* document = this->document(); + document->updateLayoutIgnorePendingStylesheets(); + FrameView* view = document->view(); + return view ? adjustForZoom(view->scrollY(), document) : 0; } void HTMLBodyElement::setScrollTop(int scrollTop) { Document* document = this->document(); document->updateLayoutIgnorePendingStylesheets(); - FrameView* view = document->view(); + Frame* frame = document->frame(); + if (!frame) + return; + FrameView* view = frame->view(); if (!view) return; - view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * view->zoomFactor()))); + view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor()))); } int HTMLBodyElement::scrollHeight() const { // Update the document's layout. - Document* doc = document(); - doc->updateLayoutIgnorePendingStylesheets(); - FrameView* view = doc->view(); - return view ? adjustForZoom(view->contentsHeight(), view) : 0; + Document* document = this->document(); + document->updateLayoutIgnorePendingStylesheets(); + FrameView* view = document->view(); + return view ? adjustForZoom(view->contentsHeight(), document) : 0; } int HTMLBodyElement::scrollWidth() const { // Update the document's layout. - Document* doc = document(); - doc->updateLayoutIgnorePendingStylesheets(); - FrameView* view = doc->view(); - return view ? adjustForZoom(view->contentsWidth(), view) : 0; + Document* document = this->document(); + document->updateLayoutIgnorePendingStylesheets(); + FrameView* view = document->view(); + return view ? adjustForZoom(view->contentsWidth(), document) : 0; } void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const diff --git a/WebCore/html/HTMLCanvasElement.cpp b/WebCore/html/HTMLCanvasElement.cpp index 3838f14..6f46ab4 100644 --- a/WebCore/html/HTMLCanvasElement.cpp +++ b/WebCore/html/HTMLCanvasElement.cpp @@ -193,7 +193,7 @@ void HTMLCanvasElement::didDraw(const FloatRect& rect) FloatRect destRect = ro->contentBoxRect(); FloatRect r = mapRect(rect, FloatRect(0, 0, size().width(), size().height()), destRect); r.intersect(destRect); - if (m_dirtyRect.contains(r)) + if (r.isEmpty() || m_dirtyRect.contains(r)) return; m_dirtyRect.unite(r); diff --git a/WebCore/html/HTMLDocument.cpp b/WebCore/html/HTMLDocument.cpp index 26e8314..f9efc4f 100644 --- a/WebCore/html/HTMLDocument.cpp +++ b/WebCore/html/HTMLDocument.cpp @@ -80,8 +80,8 @@ namespace WebCore { using namespace HTMLNames; -HTMLDocument::HTMLDocument(Frame* frame, const KURL& url) - : Document(frame, url, false, true) +HTMLDocument::HTMLDocument(Frame* frame, const KURL& url, const KURL& baseURL) + : Document(frame, url, false, true, baseURL) { clearXMLVersion(); } @@ -136,11 +136,6 @@ void HTMLDocument::setDesignMode(const String& value) Document::setDesignMode(mode); } -String HTMLDocument::compatMode() const -{ - return inQuirksMode() ? "BackCompat" : "CSS1Compat"; -} - Element* HTMLDocument::activeElement() { if (Node* node = focusedNode()) diff --git a/WebCore/html/HTMLDocument.h b/WebCore/html/HTMLDocument.h index ae65d42..37edd87 100644 --- a/WebCore/html/HTMLDocument.h +++ b/WebCore/html/HTMLDocument.h @@ -35,9 +35,9 @@ class HTMLElement; class HTMLDocument : public Document, public CachedResourceClient { public: - static PassRefPtr<HTMLDocument> create(Frame* frame, const KURL& url) + static PassRefPtr<HTMLDocument> create(Frame* frame, const KURL& url, const KURL& baseURL = KURL()) { - return adoptRef(new HTMLDocument(frame, url)); + return adoptRef(new HTMLDocument(frame, url, baseURL)); } virtual ~HTMLDocument(); @@ -50,7 +50,6 @@ public: String designMode() const; void setDesignMode(const String&); - String compatMode() const; virtual void setCompatibilityModeFromDoctype(); Element* activeElement(); @@ -81,7 +80,7 @@ public: bool hasExtraNamedItem(AtomicStringImpl* name); protected: - HTMLDocument(Frame*, const KURL&); + HTMLDocument(Frame* frame, const KURL& url, const KURL& baseURL = KURL()); #ifdef ANDROID_INSTRUMENT // Overridden to resolve the ambiguous diff --git a/WebCore/html/HTMLElement.cpp b/WebCore/html/HTMLElement.cpp index 0862130..a56efdc 100644 --- a/WebCore/html/HTMLElement.cpp +++ b/WebCore/html/HTMLElement.cpp @@ -39,6 +39,7 @@ #include "HTMLElementFactory.h" #include "HTMLFormElement.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "RenderWordBreak.h" #include "ScriptEventListener.h" #include "Settings.h" @@ -46,6 +47,7 @@ #include "TextIterator.h" #include "markup.h" #include <wtf/StdLibExtras.h> +#include <wtf/text/CString.h> namespace WebCore { @@ -142,12 +144,10 @@ void HTMLElement::parseMappedAttribute(Attribute* attr) setContentEditable(attr); } else if (attr->name() == tabindexAttr) { indexstring = getAttribute(tabindexAttr); - if (indexstring.length()) { - bool parsedOK; - int tabindex = indexstring.toIntStrict(&parsedOK); - if (parsedOK) - // Clamp tabindex to the range of 'short' to match Firefox's behavior. - setTabIndexExplicitly(max(static_cast<int>(std::numeric_limits<short>::min()), min(tabindex, static_cast<int>(std::numeric_limits<short>::max())))); + int tabindex = 0; + if (parseHTMLInteger(indexstring, tabindex)) { + // Clamp tabindex to the range of 'short' to match Firefox's behavior. + setTabIndexExplicitly(max(static_cast<int>(std::numeric_limits<short>::min()), min(tabindex, static_cast<int>(std::numeric_limits<short>::max())))); } } else if (attr->name() == langAttr) { // FIXME: Implement @@ -266,11 +266,6 @@ String HTMLElement::outerHTML() const return createMarkup(this); } -static bool useLegacyTreeBuilder(Document*) -{ - return false; -} - // FIXME: This logic should move into Range::createContextualFragment PassRefPtr<DocumentFragment> HTMLElement::deprecatedCreateContextualFragment(const String& markup, FragmentScriptingPermission scriptingPermission) { @@ -341,13 +336,6 @@ static PassRefPtr<DocumentFragment> createFragmentFromSource(const String& marku Document* document = contextElement->document(); RefPtr<DocumentFragment> fragment; - if (useLegacyTreeBuilder(document)) { - fragment = contextElement->deprecatedCreateContextualFragment(markup); - if (!fragment) - ec = NO_MODIFICATION_ALLOWED_ERR; - return fragment; - } - fragment = DocumentFragment::create(document); if (document->isHTMLDocument()) { fragment->parseHTML(markup, contextElement); @@ -364,14 +352,6 @@ static PassRefPtr<DocumentFragment> createFragmentFromSource(const String& marku void HTMLElement::setInnerHTML(const String& html, ExceptionCode& ec) { - // FIXME: This code can be removed, it's handled by the HTMLDocumentParser correctly. - if (useLegacyTreeBuilder(document()) && (hasLocalName(scriptTag) || hasLocalName(styleTag))) { - // Script and CSS source shouldn't be parsed as HTML. - removeChildren(); - appendChild(document()->createTextNode(html), ec); - return; - } - RefPtr<DocumentFragment> fragment = createFragmentFromSource(html, this, ec); if (fragment) replaceChildrenWithFragment(this, fragment.release(), ec); diff --git a/WebCore/html/HTMLFontElement.cpp b/WebCore/html/HTMLFontElement.cpp index 81ae415..5239834 100644 --- a/WebCore/html/HTMLFontElement.cpp +++ b/WebCore/html/HTMLFontElement.cpp @@ -27,6 +27,7 @@ #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" using namespace WTF; @@ -45,49 +46,78 @@ PassRefPtr<HTMLFontElement> HTMLFontElement::create(const QualifiedName& tagName return adoptRef(new HTMLFontElement(tagName, document)); } -// Allows leading spaces. -// Allows trailing nonnumeric characters. -// Returns 10 for any size greater than 9. -static bool parseFontSizeNumber(const String& s, int& size) +// http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#fonts-and-colors +static bool parseFontSize(const String& input, int& size) { - unsigned pos = 0; - - // Skip leading spaces. - while (isSpaceOrNewline(s[pos])) - ++pos; - - // Skip a plus or minus. - bool sawPlus = false; - bool sawMinus = false; - if (s[pos] == '+') { - ++pos; - sawPlus = true; - } else if (s[pos] == '-') { - ++pos; - sawMinus = true; + + // Step 1 + // Step 2 + const UChar* position = input.characters(); + const UChar* end = position + input.length(); + + // Step 3 + while (position < end) { + if (!isHTMLSpace(*position)) + break; + ++position; } - - // Parse a single digit. - if (!isASCIIDigit(s[pos])) + + // Step 4 + if (position == end) return false; - int num = s[pos++] - '0'; - - // Check for an additional digit. - if (isASCIIDigit(s[pos])) - num = 10; - - if (sawPlus) { - size = num + 3; - return true; + ASSERT(position < end); + + // Step 5 + enum { + RelativePlus, + RelativeMinus, + Absolute + } mode; + + switch (*position) { + case '+': + mode = RelativePlus; + ++position; + break; + case '-': + mode = RelativeMinus; + ++position; + break; + default: + mode = Absolute; + break; } - - // Don't return 0 (which means 3) or a negative number (which means the same as 1). - if (sawMinus) { - size = num == 1 ? 2 : 1; - return true; + + // Step 6 + Vector<UChar, 16> digits; + while (position < end) { + if (!isASCIIDigit(*position)) + break; + digits.append(*position++); } - - size = num; + + // Step 7 + if (digits.isEmpty()) + return false; + + // Step 8 + int value = charactersToIntStrict(digits.data(), digits.size()); + + // Step 9 + if (mode == RelativePlus) + value += 3; + else if (mode == RelativeMinus) + value = 3 - value; + + // Step 10 + if (value > 7) + value = 7; + + // Step 11 + if (value < 1) + value = 1; + + size = value; return true; } @@ -105,32 +135,35 @@ bool HTMLFontElement::mapToEntry(const QualifiedName& attrName, MappedAttributeE bool HTMLFontElement::cssValueFromFontSizeNumber(const String& s, int& size) { - int num; - if (!parseFontSizeNumber(s, num)) + int num = 0; + if (!parseFontSize(s, num)) return false; - + switch (num) { - case 2: - size = CSSValueSmall; - break; - case 0: // treat 0 the same as 3, because people expect it to be between -1 and +1 - case 3: - size = CSSValueMedium; - break; - case 4: - size = CSSValueLarge; - break; - case 5: - size = CSSValueXLarge; - break; - case 6: - size = CSSValueXxLarge; - break; - default: - if (num > 6) - size = CSSValueWebkitXxxLarge; - else - size = CSSValueXSmall; + case 1: + // FIXME: The spec says that we're supposed to use CSSValueXxSmall here. + size = CSSValueXSmall; + break; + case 2: + size = CSSValueSmall; + break; + case 3: + size = CSSValueMedium; + break; + case 4: + size = CSSValueLarge; + break; + case 5: + size = CSSValueXLarge; + break; + case 6: + size = CSSValueXxLarge; + break; + case 7: + size = CSSValueWebkitXxxLarge; + break; + default: + ASSERT_NOT_REACHED(); } return true; } @@ -138,7 +171,7 @@ bool HTMLFontElement::cssValueFromFontSizeNumber(const String& s, int& size) void HTMLFontElement::parseMappedAttribute(Attribute* attr) { if (attr->name() == sizeAttr) { - int size; + int size = 0; if (cssValueFromFontSizeNumber(attr->value(), size)) addCSSProperty(attr, CSSPropertyFontSize, size); } else if (attr->name() == colorAttr) { diff --git a/WebCore/html/HTMLFormElement.cpp b/WebCore/html/HTMLFormElement.cpp index 56ffd0f..db5da66 100644 --- a/WebCore/html/HTMLFormElement.cpp +++ b/WebCore/html/HTMLFormElement.cpp @@ -65,7 +65,7 @@ using namespace HTMLNames; HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* document) : HTMLElement(tagName, document) - , m_submissionTrigger(NotSubmittedByJavaScript) + , m_wasUserSubmitted(false) , m_autocomplete(true) , m_insubmit(false) , m_doingsubmit(false) @@ -106,13 +106,13 @@ bool HTMLFormElement::rendererIsNeeded(RenderStyle* style) { if (!isDemoted()) return HTMLElement::rendererIsNeeded(style); - + Node* node = parentNode(); RenderObject* parentRenderer = node->renderer(); bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag)) || (parentRenderer->isTableRow() && node->hasTagName(trTag)) || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag)) - || (parentRenderer->isTableCol() && node->hasTagName(colTag)) + || (parentRenderer->isTableCol() && node->hasTagName(colTag)) || (parentRenderer->isTableCell() && node->hasTagName(trTag)); if (!parentIsTableElementPart) @@ -139,7 +139,7 @@ void HTMLFormElement::removedFromDocument() { if (document()->isHTMLDocument()) static_cast<HTMLDocument*>(document())->removeNamedItem(m_name); - + HTMLElement::removedFromDocument(); } @@ -263,7 +263,7 @@ bool HTMLFormElement::prepareSubmit(Event* event) m_insubmit = false; if (m_doingsubmit) - submit(event, true, false, NotSubmittedByJavaScript); + submit(event, true, true, NotSubmittedByJavaScript); return m_doingsubmit; } @@ -271,12 +271,12 @@ bool HTMLFormElement::prepareSubmit(Event* event) void HTMLFormElement::submit(Frame* javaScriptActiveFrame) { if (javaScriptActiveFrame) - submit(0, false, !javaScriptActiveFrame->script()->anyPageIsProcessingUserGesture(), SubmittedByJavaScript); + submit(0, false, javaScriptActiveFrame->script()->anyPageIsProcessingUserGesture(), SubmittedByJavaScript); else - submit(0, false, false, NotSubmittedByJavaScript); + submit(0, false, true, NotSubmittedByJavaScript); } -void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockHistory, FormSubmissionTrigger formSubmissionTrigger) +void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger) { FrameView* view = document()->view(); Frame* frame = document()->frame(); @@ -289,11 +289,11 @@ void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockH } m_insubmit = true; - m_submissionTrigger = formSubmissionTrigger; + m_wasUserSubmitted = processingUserGesture; HTMLFormControlElement* firstSuccessfulSubmitButton = 0; bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button? - + for (unsigned i = 0; i < m_associatedElements.size(); ++i) { HTMLFormControlElement* control = m_associatedElements[i]; if (needButtonActivation) { @@ -307,11 +307,11 @@ void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockH if (needButtonActivation && firstSuccessfulSubmitButton) firstSuccessfulSubmitButton->setActivatedSubmit(true); - frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, lockHistory, formSubmissionTrigger)); + frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, !processingUserGesture, formSubmissionTrigger)); if (needButtonActivation && firstSuccessfulSubmitButton) firstSuccessfulSubmitButton->setActivatedSubmit(false); - + m_doingsubmit = m_insubmit = false; } @@ -355,7 +355,7 @@ void HTMLFormElement::parseMappedAttribute(Attribute* attr) } else if (attr->name() == autocompleteAttr) { m_autocomplete = !equalIgnoringCase(attr->value(), "off"); if (!m_autocomplete) - document()->registerForDocumentActivationCallbacks(this); + document()->registerForDocumentActivationCallbacks(this); else document()->unregisterForDocumentActivationCallbacks(this); } else if (attr->name() == onsubmitAttr) @@ -482,9 +482,9 @@ String HTMLFormElement::target() const return getAttribute(targetAttr); } -FormSubmissionTrigger HTMLFormElement::submissionTrigger() const +bool HTMLFormElement::wasUserSubmitted() const { - return m_submissionTrigger; + return m_wasUserSubmitted; } HTMLFormControlElement* HTMLFormElement::defaultButton() const @@ -556,13 +556,13 @@ void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<N } // name has been accessed, remember it if (namedItems.size() && aliasElem != namedItems.first()) - addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name); + addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name); } void HTMLFormElement::documentDidBecomeActive() { ASSERT(!m_autocomplete); - + for (unsigned i = 0; i < m_associatedElements.size(); ++i) m_associatedElements[i]->reset(); } diff --git a/WebCore/html/HTMLFormElement.h b/WebCore/html/HTMLFormElement.h index 151b2e8..b996d9d 100644 --- a/WebCore/html/HTMLFormElement.h +++ b/WebCore/html/HTMLFormElement.h @@ -42,7 +42,7 @@ class TextEncoding; struct CollectionCache; -class HTMLFormElement : public HTMLElement { +class HTMLFormElement : public HTMLElement { public: static PassRefPtr<HTMLFormElement> create(Document*); static PassRefPtr<HTMLFormElement> create(const QualifiedName&, Document*); @@ -98,7 +98,7 @@ public: virtual String target() const; - FormSubmissionTrigger submissionTrigger() const; + bool wasUserSubmitted() const; HTMLFormControlElement* defaultButton() const; @@ -117,7 +117,7 @@ private: virtual bool rendererIsNeeded(RenderStyle*); virtual void insertedIntoDocument(); virtual void removedFromDocument(); - + virtual void handleLocalEvents(Event*); virtual void parseMappedAttribute(Attribute*); @@ -129,7 +129,7 @@ private: virtual void willMoveToNewOwnerDocument(); virtual void didMoveToNewOwnerDocument(); - void submit(Event*, bool activateSubmitButton, bool lockHistory, FormSubmissionTrigger); + void submit(Event*, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger); unsigned formElementIndex(HTMLFormControlElement*); // Returns true if the submission should be proceeded. @@ -147,11 +147,11 @@ private: OwnPtr<CollectionCache> m_collectionCache; CheckedRadioButtons m_checkedRadioButtons; - + Vector<HTMLFormControlElement*> m_associatedElements; Vector<HTMLImageElement*> m_imageElements; - FormSubmissionTrigger m_submissionTrigger; + bool m_wasUserSubmitted; bool m_autocomplete : 1; bool m_insubmit : 1; diff --git a/WebCore/html/HTMLFrameElementBase.cpp b/WebCore/html/HTMLFrameElementBase.cpp index b967926..8cca465 100644 --- a/WebCore/html/HTMLFrameElementBase.cpp +++ b/WebCore/html/HTMLFrameElementBase.cpp @@ -52,9 +52,8 @@ HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Documen , m_scrolling(ScrollbarAuto) , m_marginWidth(-1) , m_marginHeight(-1) - , m_checkAttachedTimer(this, &HTMLFrameElementBase::checkAttachedTimerFired) + , m_checkInDocumentTimer(this, &HTMLFrameElementBase::checkInDocumentTimerFired) , m_viewSource(false) - , m_shouldOpenURLAfterAttach(false) , m_remainsAliveOnRemovalFromTree(false) { } @@ -183,33 +182,31 @@ void HTMLFrameElementBase::updateOnReparenting() void HTMLFrameElementBase::insertedIntoDocument() { HTMLFrameOwnerElement::insertedIntoDocument(); - - // We delay frame loading until after the render tree is fully constructed. - // Othewise, a synchronous load that executed JavaScript would see incorrect - // (0) values for the frame's renderer-dependent properties, like width. - m_shouldOpenURLAfterAttach = true; - if (m_remainsAliveOnRemovalFromTree) + if (m_remainsAliveOnRemovalFromTree) { updateOnReparenting(); -} - -void HTMLFrameElementBase::removedFromDocument() -{ - m_shouldOpenURLAfterAttach = false; + setRemainsAliveOnRemovalFromTree(false); + return; + } + // DocumentFragments don't kick of any loads. + if (!document()->frame()) + return; - HTMLFrameOwnerElement::removedFromDocument(); + // Loads may cause synchronous javascript execution (e.g. beforeload or + // src=javascript), which could try to access the renderer before the normal + // parser machinery would call lazyAttach() and set us as needing style + // resolve. Any code which expects this to be attached will resolve style + // before using renderer(), so this will make sure we attach in time. + // FIXME: Normally lazyAttach marks the renderer as attached(), but we don't + // want to do that here, as as callers expect to call attach() right after + // this and attach() will ASSERT(!attached()) + ASSERT(!renderer()); // This recalc is unecessary if we already have a renderer. + lazyAttach(DoNotSetAttached); + setNameAndOpenURL(); } void HTMLFrameElementBase::attach() { - if (m_shouldOpenURLAfterAttach) { - m_shouldOpenURLAfterAttach = false; - if (!m_remainsAliveOnRemovalFromTree) - queuePostAttachCallback(&HTMLFrameElementBase::setNameAndOpenURLCallback, this); - } - - setRemainsAliveOnRemovalFromTree(false); - HTMLFrameOwnerElement::attach(); if (RenderPart* part = renderPart()) { @@ -258,19 +255,17 @@ bool HTMLFrameElementBase::isURLAttribute(Attribute *attr) const int HTMLFrameElementBase::width() const { + document()->updateLayoutIgnorePendingStylesheets(); if (!renderBox()) return 0; - - document()->updateLayoutIgnorePendingStylesheets(); return renderBox()->width(); } int HTMLFrameElementBase::height() const { + document()->updateLayoutIgnorePendingStylesheets(); if (!renderBox()) return 0; - - document()->updateLayoutIgnorePendingStylesheets(); return renderBox()->height(); } @@ -281,12 +276,12 @@ void HTMLFrameElementBase::setRemainsAliveOnRemovalFromTree(bool value) // There is a possibility that JS will do document.adoptNode() on this element but will not insert it into the tree. // Start the async timer that is normally stopped by attach(). If it's not stopped and fires, it'll unload the frame. if (value) - m_checkAttachedTimer.startOneShot(0); + m_checkInDocumentTimer.startOneShot(0); else - m_checkAttachedTimer.stop(); + m_checkInDocumentTimer.stop(); } -void HTMLFrameElementBase::checkAttachedTimerFired(Timer<HTMLFrameElementBase>*) +void HTMLFrameElementBase::checkInDocumentTimerFired(Timer<HTMLFrameElementBase>*) { ASSERT(!attached()); ASSERT(m_remainsAliveOnRemovalFromTree); diff --git a/WebCore/html/HTMLFrameElementBase.h b/WebCore/html/HTMLFrameElementBase.h index 1b6e2a3..ae41e75 100644 --- a/WebCore/html/HTMLFrameElementBase.h +++ b/WebCore/html/HTMLFrameElementBase.h @@ -50,15 +50,10 @@ protected: bool isURLAllowed() const; virtual void parseMappedAttribute(Attribute*); - virtual void insertedIntoDocument(); - virtual void removedFromDocument(); - virtual void attach(); private: - virtual bool canLazyAttach() { return false; } - virtual bool supportsFocus() const; virtual void setFocus(bool); @@ -67,7 +62,7 @@ private: virtual void setName(); virtual void willRemove(); - void checkAttachedTimerFired(Timer<HTMLFrameElementBase>*); + void checkInDocumentTimerFired(Timer<HTMLFrameElementBase>*); void updateOnReparenting(); bool viewSourceMode() const { return m_viewSource; } @@ -85,12 +80,19 @@ private: int m_marginWidth; int m_marginHeight; - Timer<HTMLFrameElementBase> m_checkAttachedTimer; + // This is a performance optimization some call "magic iframe" which avoids + // tearing down the frame hierarchy when a web page calls adoptNode on a + // frame owning element but does not immediately insert it into the new + // document before JavaScript yields to WebCore. If the element is not yet + // in a document by the time this timer fires, the frame hierarchy teardown + // will continue. This can also be seen as implementation of: + // "Removing an iframe from a Document does not cause its browsing context + // to be discarded. Indeed, an iframe's browsing context can survive its + // original parent Document if its iframe is moved to another Document." + // From HTML5: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#the-iframe-element + Timer<HTMLFrameElementBase> m_checkInDocumentTimer; bool m_viewSource; - - bool m_shouldOpenURLAfterAttach; - bool m_remainsAliveOnRemovalFromTree; }; diff --git a/WebCore/html/HTMLFrameOwnerElement.cpp b/WebCore/html/HTMLFrameOwnerElement.cpp index 3f946f0..2a7b610 100644 --- a/WebCore/html/HTMLFrameOwnerElement.cpp +++ b/WebCore/html/HTMLFrameOwnerElement.cpp @@ -51,9 +51,12 @@ RenderPart* HTMLFrameOwnerElement::renderPart() const void HTMLFrameOwnerElement::willRemove() { + // FIXME: It is unclear why this can't be moved to removedFromDocument() + // this is the only implementation of willRemove in WebCore! if (Frame* frame = contentFrame()) { - frame->disconnectOwnerElement(); + RefPtr<Frame> protect(frame); frame->loader()->frameDetached(); + frame->disconnectOwnerElement(); } HTMLElement::willRemove(); diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp index 7bc49fc..a44b68c 100644 --- a/WebCore/html/HTMLInputElement.cpp +++ b/WebCore/html/HTMLInputElement.cpp @@ -50,7 +50,7 @@ #include "HTMLImageLoader.h" #include "HTMLNames.h" #include "HTMLOptionElement.h" -#include "HTMLTreeBuilder.h" +#include "HTMLParserIdioms.h" #include "KeyboardEvent.h" #include "LocalizedStrings.h" #include "MouseEvent.h" @@ -154,7 +154,7 @@ HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* docum , m_xPos(0) , m_yPos(0) , m_maxResults(-1) - , m_type(TEXT) + , m_deprecatedTypeNumber(TEXT) , m_checked(false) , m_defaultChecked(false) , m_useDefaultChecked(true) @@ -244,7 +244,7 @@ bool HTMLInputElement::isValidValue(const String& value) const { // Should not call isValidValue() for the following types because // we can't set string values for these types. - if (inputType() == CHECKBOX || inputType() == FILE || inputType() == RADIO) { + if (deprecatedInputType() == CHECKBOX || deprecatedInputType() == FILE || deprecatedInputType() == RADIO) { ASSERT_NOT_REACHED(); return false; } @@ -259,7 +259,7 @@ bool HTMLInputElement::isValidValue(const String& value) const bool HTMLInputElement::typeMismatch(const String& value) const { - switch (inputType()) { + switch (deprecatedInputType()) { case COLOR: return !isValidColorString(value); case NUMBER: @@ -284,7 +284,7 @@ bool HTMLInputElement::typeMismatch(const String& value) const case MONTH: case TIME: case WEEK: - return !parseToDateComponents(inputType(), value, 0); + return !parseToDateComponents(deprecatedInputType(), value, 0); case BUTTON: case CHECKBOX: case FILE: @@ -310,7 +310,7 @@ bool HTMLInputElement::valueMissing(const String& value) const if (!isRequiredFormControl() || readOnly() || disabled()) return false; - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: case DATETIME: case DATETIMELOCAL: @@ -382,7 +382,7 @@ bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) bool HTMLInputElement::rangeUnderflow(const String& value) const { const double nan = numeric_limits<double>::quiet_NaN(); - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: case DATETIME: case DATETIMELOCAL: @@ -419,7 +419,7 @@ bool HTMLInputElement::rangeUnderflow(const String& value) const bool HTMLInputElement::rangeOverflow(const String& value) const { const double nan = numeric_limits<double>::quiet_NaN(); - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: case DATETIME: case DATETIMELOCAL: @@ -455,7 +455,7 @@ bool HTMLInputElement::rangeOverflow(const String& value) const double HTMLInputElement::minimum() const { - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: return parseToDouble(getAttribute(minAttr), DateComponents::minimumDate()); case DATETIME: @@ -495,7 +495,7 @@ double HTMLInputElement::minimum() const double HTMLInputElement::maximum() const { - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: return parseToDouble(getAttribute(maxAttr), DateComponents::maximumDate()); case DATETIME: @@ -542,7 +542,7 @@ double HTMLInputElement::maximum() const double HTMLInputElement::stepBase() const { - switch (inputType()) { + switch (deprecatedInputType()) { case RANGE: return minimum(); case DATE: @@ -581,7 +581,7 @@ bool HTMLInputElement::stepMismatch(const String& value) const double step; if (!getAllowedValueStep(&step)) return false; - switch (inputType()) { + switch (deprecatedInputType()) { case RANGE: // stepMismatch doesn't occur for RANGE. RenderSlider guarantees the // value matches to step on user input, and sanitation takes care @@ -646,7 +646,7 @@ bool HTMLInputElement::getStepParameters(double* defaultStep, double* stepScaleF { ASSERT(defaultStep); ASSERT(stepScaleFactor); - switch (inputType()) { + switch (deprecatedInputType()) { case NUMBER: case RANGE: *defaultStep = numberDefaultStep; @@ -715,11 +715,11 @@ bool HTMLInputElement::getAllowedValueStep(double* step) const return true; } // For DATE, MONTH, WEEK, the parsed value should be an integer. - if (inputType() == DATE || inputType() == MONTH || inputType() == WEEK) + if (deprecatedInputType() == DATE || deprecatedInputType() == MONTH || deprecatedInputType() == WEEK) parsed = max(round(parsed), 1.0); double result = parsed * stepScaleFactor; // For DATETIME, DATETIMELOCAL, TIME, the result should be an integer. - if (inputType() == DATETIME || inputType() == DATETIMELOCAL || inputType() == TIME) + if (deprecatedInputType() == DATETIME || deprecatedInputType() == DATETIMELOCAL || deprecatedInputType() == TIME) result = max(round(result), 1.0); ASSERT(result > 0); *step = result; @@ -777,14 +777,14 @@ bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const if (!HTMLFormControlElementWithState::isKeyboardFocusable(event)) return false; - if (inputType() == RADIO) { + if (deprecatedInputType() == RADIO) { // Never allow keyboard tabbing to leave you in the same radio group. Always // skip any other elements in the group. Node* currentFocusedNode = document()->focusedNode(); if (currentFocusedNode && currentFocusedNode->hasTagName(inputTag)) { HTMLInputElement* focusedInput = static_cast<HTMLInputElement*>(currentFocusedNode); - if (focusedInput->inputType() == RADIO && focusedInput->form() == form() && focusedInput->name() == name()) + if (focusedInput->deprecatedInputType() == RADIO && focusedInput->form() == form() && focusedInput->name() == name()) return false; } @@ -821,7 +821,7 @@ bool HTMLInputElement::shouldUseInputMethod() const // can access the underlying password and display it in clear text -- // e.g. you can use it to access the stored password for any site // with only trivial effort. - return isTextField() && inputType() != PASSWORD; + return isTextField() && deprecatedInputType() != PASSWORD; } void HTMLInputElement::handleFocusEvent() @@ -831,7 +831,7 @@ void HTMLInputElement::handleFocusEvent() void HTMLInputElement::handleBlurEvent() { - if (inputType() == NUMBER) { + if (deprecatedInputType() == NUMBER) { // Reset the renderer value, which might be unmatched with the element value. setFormControlValueMatchesRenderer(false); // We need to reset the renderer value explicitly because an unacceptable @@ -844,6 +844,10 @@ void HTMLInputElement::handleBlurEvent() void HTMLInputElement::setType(const String& t) { + // FIXME: This should just call setAttribute. No reason to handle the empty string specially. + // We should write a test case to show that setting to the empty string does not remove the + // attribute in other browsers and then fix this. Note that setting to null *does* remove + // the attribute and setAttribute implements that. if (t.isEmpty()) { int exccode; removeAttribute(typeAttr, exccode); @@ -851,7 +855,7 @@ void HTMLInputElement::setType(const String& t) setAttribute(typeAttr, t); } -typedef HashMap<String, HTMLInputElement::InputType, CaseFoldingHash> InputTypeMap; +typedef HashMap<String, HTMLInputElement::DeprecatedInputType, CaseFoldingHash> InputTypeMap; static PassOwnPtr<InputTypeMap> createTypeMap() { OwnPtr<InputTypeMap> map = adoptPtr(new InputTypeMap); @@ -882,19 +886,24 @@ static PassOwnPtr<InputTypeMap> createTypeMap() return map.release(); } -void HTMLInputElement::setInputType(const String& t) +void HTMLInputElement::updateType() { static const InputTypeMap* typeMap = createTypeMap().leakPtr(); +<<<<<<< HEAD InputType newType = t.isNull() ? TEXT : typeMap->get(t); #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS if (newType == PASSWORD && document()->focusedNode() == this) android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, true, String()); #endif +======= + const AtomicString& typeString = fastGetAttribute(typeAttr); + DeprecatedInputType newType = typeString.isEmpty() ? TEXT : typeMap->get(typeString); +>>>>>>> webkit.org at r67908 // IMPORTANT: Don't allow the type to be changed to FILE after the first // type change, otherwise a JavaScript programmer would be able to set a text // field's value to something like /etc/passwd and then change it to a file field. - if (inputType() != newType) { + if (deprecatedInputType() != newType) { if (newType == FILE && m_haveType) // Set the attribute back to the old value. // Useful in case we were called from inside parseMappedAttribute. @@ -910,12 +919,12 @@ void HTMLInputElement::setInputType(const String& t) detach(); bool didStoreValue = storesValueSeparateFromAttribute(); - bool wasPasswordField = inputType() == PASSWORD; + bool wasPasswordField = deprecatedInputType() == PASSWORD; bool didRespectHeightAndWidth = respectHeightAndWidthAttrs(); - m_type = newType; + m_deprecatedTypeNumber = newType; setNeedsWillValidateCheck(); bool willStoreValue = storesValueSeparateFromAttribute(); - bool isPasswordField = inputType() == PASSWORD; + bool isPasswordField = deprecatedInputType() == PASSWORD; bool willRespectHeightAndWidth = respectHeightAndWidthAttrs(); if (didStoreValue && !willStoreValue && !m_data.value().isNull()) { @@ -957,13 +966,13 @@ void HTMLInputElement::setInputType(const String& t) } m_haveType = true; - if (inputType() != IMAGE && m_imageLoader) + if (deprecatedInputType() != IMAGE && m_imageLoader) m_imageLoader.clear(); } static const AtomicString* createFormControlTypes() { - AtomicString* types = new AtomicString[HTMLInputElement::numberOfTypes]; + AtomicString* types = new AtomicString[HTMLInputElement::deprecatedNumberOfTypes]; // The values must be lowercased because they will be the return values of // input.type and it must be lowercase according to DOM Level 2. types[HTMLInputElement::BUTTON] = "button"; @@ -996,12 +1005,12 @@ static const AtomicString* createFormControlTypes() const AtomicString& HTMLInputElement::formControlType() const { static const AtomicString* formControlTypes = createFormControlTypes(); - return formControlTypes[inputType()]; + return formControlTypes[deprecatedInputType()]; } bool HTMLInputElement::saveFormControlState(String& result) const { - switch (inputType()) { + switch (deprecatedInputType()) { case BUTTON: case COLOR: case DATE: @@ -1042,8 +1051,8 @@ bool HTMLInputElement::saveFormControlState(String& result) const void HTMLInputElement::restoreFormControlState(const String& state) { - ASSERT(inputType() != PASSWORD); // should never save/restore password fields - switch (inputType()) { + ASSERT(deprecatedInputType() != PASSWORD); // should never save/restore password fields + switch (deprecatedInputType()) { case BUTTON: case COLOR: case DATE: @@ -1090,7 +1099,7 @@ bool HTMLInputElement::canHaveSelection() const void HTMLInputElement::accessKeyAction(bool sendToAnyElement) { - switch (inputType()) { + switch (deprecatedInputType()) { case BUTTON: case CHECKBOX: case FILE: @@ -1137,7 +1146,7 @@ bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttribute } if (attrName == alignAttr) { - if (inputType() == IMAGE) { + if (deprecatedInputType() == IMAGE) { // Share with <img> since the alignment behavior is the same. result = eReplaced; return false; @@ -1170,7 +1179,7 @@ void HTMLInputElement::parseMappedAttribute(Attribute* attr) unregisterForActivationCallbackIfNeeded(); } } else if (attr->name() == typeAttr) { - setInputType(attr->value()); + updateType(); } else if (attr->name() == valueAttr) { // We only need to setChanged if the form is looking at the default value right now. if (m_data.value().isNull()) @@ -1190,10 +1199,10 @@ void HTMLInputElement::parseMappedAttribute(Attribute* attr) } else if (attr->name() == sizeAttr) InputElement::parseSizeAttribute(m_data, this, attr); else if (attr->name() == altAttr) { - if (renderer() && inputType() == IMAGE) + if (renderer() && deprecatedInputType() == IMAGE) toRenderImage(renderer())->updateAltText(); } else if (attr->name() == srcAttr) { - if (renderer() && inputType() == IMAGE) { + if (renderer() && deprecatedInputType() == IMAGE) { if (!m_imageLoader) m_imageLoader = adoptPtr(new HTMLImageLoader(this)); m_imageLoader->updateFromElementIgnoringPreviousError(); @@ -1207,7 +1216,7 @@ void HTMLInputElement::parseMappedAttribute(Attribute* attr) addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); addCSSLength(attr, CSSPropertyMarginRight, attr->value()); } else if (attr->name() == alignAttr) { - if (inputType() == IMAGE) + if (deprecatedInputType() == IMAGE) addHTMLAlignment(attr); } else if (attr->name() == widthAttr) { if (respectHeightAndWidthAttrs()) @@ -1233,7 +1242,7 @@ void HTMLInputElement::parseMappedAttribute(Attribute* attr) setNeedsStyleRecalc(); else if (attr->name() == minAttr || attr->name() == maxAttr) { - if (inputType() == RANGE) { + if (deprecatedInputType() == RANGE) { // Sanitize the value. setValue(value()); setNeedsStyleRecalc(); @@ -1262,14 +1271,14 @@ void HTMLInputElement::parseMappedAttribute(Attribute* attr) bool HTMLInputElement::rendererIsNeeded(RenderStyle *style) { - if (inputType() == HIDDEN) + if (deprecatedInputType() == HIDDEN) return false; return HTMLFormControlElementWithState::rendererIsNeeded(style); } RenderObject* HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle *style) { - switch (inputType()) { + switch (deprecatedInputType()) { case BUTTON: case RESET: case SUBMIT: @@ -1313,13 +1322,13 @@ void HTMLInputElement::attach() { if (!m_inited) { if (!m_haveType) - setInputType(getAttribute(typeAttr)); + updateType(); m_inited = true; } HTMLFormControlElementWithState::attach(); - if (inputType() == IMAGE) { + if (deprecatedInputType() == IMAGE) { if (!m_imageLoader) m_imageLoader = adoptPtr(new HTMLImageLoader(this)); m_imageLoader->updateFromElement(); @@ -1335,7 +1344,7 @@ void HTMLInputElement::attach() } } - if (inputType() == RADIO) + if (deprecatedInputType() == RADIO) updateCheckedRadioButtons(); if (document()->focusedNode() == this) @@ -1368,7 +1377,7 @@ bool HTMLInputElement::isSuccessfulSubmitButton() const { // HTML spec says that buttons must have names to be considered successful. // However, other browsers do not impose this constraint. So we do likewise. - return !disabled() && (inputType() == IMAGE || inputType() == SUBMIT); + return !disabled() && (deprecatedInputType() == IMAGE || deprecatedInputType() == SUBMIT); } bool HTMLInputElement::isActivatedSubmit() const @@ -1384,10 +1393,10 @@ void HTMLInputElement::setActivatedSubmit(bool flag) bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) { // image generates its own names, but for other types there is no form data unless there's a name - if (name().isEmpty() && inputType() != IMAGE) + if (name().isEmpty() && deprecatedInputType() != IMAGE) return false; - switch (inputType()) { + switch (deprecatedInputType()) { case COLOR: case DATE: case DATETIME: @@ -1460,7 +1469,7 @@ bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) // If no filename at all is entered, return successful but empty. // Null would be more logical, but Netscape posts an empty file. Argh. if (!numFiles) { - encoding.appendBlob(name(), File::create(document()->scriptExecutionContext(), "")); + encoding.appendBlob(name(), File::create("")); return true; } @@ -1483,7 +1492,7 @@ void HTMLInputElement::reset() bool HTMLInputElement::isTextField() const { - switch (inputType()) { + switch (deprecatedInputType()) { case COLOR: case DATE: case DATETIME: @@ -1517,7 +1526,7 @@ bool HTMLInputElement::isTextField() const bool HTMLInputElement::isTextType() const { - switch (inputType()) { + switch (deprecatedInputType()) { case EMAIL: case PASSWORD: case SEARCH: @@ -1573,7 +1582,7 @@ void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent) // unchecked to match other browsers. DOM is not a useful standard for this // because it says only to fire change events at "lose focus" time, which is // definitely wrong in practice for these types of elements. - if (sendChangeEvent && inDocument() && (inputType() != RADIO || nowChecked)) + if (sendChangeEvent && inDocument() && (deprecatedInputType() != RADIO || nowChecked)) dispatchFormControlChangeEvent(); } @@ -1611,7 +1620,7 @@ void HTMLInputElement::copyNonAttributeProperties(const Element* source) String HTMLInputElement::value() const { - if (inputType() == FILE) { + if (deprecatedInputType() == FILE) { if (!m_fileList->isEmpty()) { // HTML5 tells us that we're supposed to use this goofy value for // file input controls. Historically, browsers reveals the real @@ -1632,9 +1641,9 @@ String HTMLInputElement::value() const // For Checkbox Types just use "on" or "" based off the checked() state of the control. // For a Range Input use the calculated default value. if (value.isNull()) { - if (inputType() == CHECKBOX || inputType() == RADIO) + if (deprecatedInputType() == CHECKBOX || deprecatedInputType() == RADIO) return checked() ? "on" : ""; - if (inputType() == RANGE) + if (deprecatedInputType() == RANGE) return serializeForNumberType(StepRange(this).defaultValue()); } } @@ -1646,7 +1655,7 @@ String HTMLInputElement::valueWithDefault() const { String v = value(); if (v.isNull()) { - switch (inputType()) { + switch (deprecatedInputType()) { case BUTTON: case CHECKBOX: case COLOR: @@ -1694,7 +1703,7 @@ const String& HTMLInputElement::suggestedValue() const void HTMLInputElement::setSuggestedValue(const String& value) { - if (inputType() != TEXT) + if (deprecatedInputType() != TEXT) return; setFormControlValueMatchesRenderer(false); m_data.setSuggestedValue(sanitizeValue(value)); @@ -1709,12 +1718,12 @@ void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) // For security reasons, we don't allow setting the filename, but we do allow clearing it. // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control // but we don't want to break existing websites, who may be relying on this method to clear things. - if (inputType() == FILE && !value.isEmpty()) + if (deprecatedInputType() == FILE && !value.isEmpty()) return; setFormControlValueMatchesRenderer(false); if (storesValueSeparateFromAttribute()) { - if (inputType() == FILE) + if (deprecatedInputType() == FILE) m_fileList->clear(); else { m_data.setValue(sanitizeValue(value)); @@ -1750,14 +1759,14 @@ void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) double HTMLInputElement::parseToDouble(const String& src, double defaultValue) const { - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: case DATETIME: case DATETIMELOCAL: case TIME: case WEEK: { DateComponents date; - if (!parseToDateComponents(inputType(), src, &date)) + if (!parseToDateComponents(deprecatedInputType(), src, &date)) return defaultValue; double msec = date.millisecondsSinceEpoch(); ASSERT(isfinite(msec)); @@ -1765,7 +1774,7 @@ double HTMLInputElement::parseToDouble(const String& src, double defaultValue) c } case MONTH: { DateComponents date; - if (!parseToDateComponents(inputType(), src, &date)) + if (!parseToDateComponents(deprecatedInputType(), src, &date)) return defaultValue; double months = date.monthsSinceEpoch(); ASSERT(isfinite(months)); @@ -1804,7 +1813,7 @@ double HTMLInputElement::parseToDouble(const String& src, double defaultValue) c double HTMLInputElement::valueAsDate() const { - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: case DATETIME: case TIME: @@ -1812,7 +1821,7 @@ double HTMLInputElement::valueAsDate() const return parseToDouble(value(), DateComponents::invalidMilliseconds()); case MONTH: { DateComponents date; - if (!parseToDateComponents(inputType(), value(), &date)) + if (!parseToDateComponents(deprecatedInputType(), value(), &date)) return DateComponents::invalidMilliseconds(); double msec = date.millisecondsSinceEpoch(); ASSERT(isfinite(msec)); @@ -1846,7 +1855,7 @@ double HTMLInputElement::valueAsDate() const void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec) { - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: case DATETIME: case TIME: @@ -1890,7 +1899,7 @@ void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec) double HTMLInputElement::valueAsNumber() const { const double nan = numeric_limits<double>::quiet_NaN(); - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: case DATETIME: case DATETIMELOCAL: @@ -1929,7 +1938,7 @@ void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec) ec = NOT_SUPPORTED_ERR; return; } - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: case DATETIME: case DATETIMELOCAL: @@ -1967,7 +1976,7 @@ String HTMLInputElement::serializeForDateTimeTypes(double value) const { bool success = false; DateComponents date; - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: success = date.setMillisecondsSinceEpochForDate(value); break; @@ -2024,7 +2033,7 @@ String HTMLInputElement::serialize(double value) const { if (!isfinite(value)) return String(); - switch (inputType()) { + switch (deprecatedInputType()) { case DATE: case DATETIME: case DATETIMELOCAL: @@ -2076,7 +2085,7 @@ bool HTMLInputElement::searchEventsShouldBeDispatched() const void HTMLInputElement::setValueFromRenderer(const String& value) { // File upload controls will always use setFileListFromRenderer. - ASSERT(inputType() != FILE); + ASSERT(deprecatedInputType() != FILE); m_data.setSuggestedValue(String()); updatePlaceholderVisibility(false); InputElement::setValueFromRenderer(m_data, this, this, value); @@ -2107,15 +2116,15 @@ void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) for (int i = 0; i < size; i++) { // Normalize backslashes to slashes before exposing the relative path to script. String relativePath = paths[i].substring(1 + rootPath.length()).replace('\\','/'); - m_fileList->append(File::create(document()->scriptExecutionContext(), relativePath, paths[i])); + m_fileList->append(File::create(relativePath, paths[i])); } } else { for (int i = 0; i < size; i++) - m_fileList->append(File::create(document()->scriptExecutionContext(), paths[i])); + m_fileList->append(File::create(paths[i])); } #else for (int i = 0; i < size; i++) - m_fileList->append(File::create(document()->scriptExecutionContext(), paths[i])); + m_fileList->append(File::create(paths[i])); #endif setFormControlValueMatchesRenderer(true); @@ -2125,7 +2134,7 @@ void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) bool HTMLInputElement::storesValueSeparateFromAttribute() const { - switch (inputType()) { + switch (deprecatedInputType()) { case BUTTON: case CHECKBOX: case HIDDEN: @@ -2166,17 +2175,14 @@ struct EventHandlingState : FastAllocBase { , m_checked(checked) { } }; -void* HTMLInputElement::preDispatchEventHandler(Event *evt) +void* HTMLInputElement::preDispatchEventHandler(Event* evt) { // preventDefault or "return false" are used to reverse the automatic checking/selection we do here. // This result gives us enough info to perform the "undo" in postDispatch of the action we take here. void* result = 0; - if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent() - && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { - + if ((deprecatedInputType() == CHECKBOX || deprecatedInputType() == RADIO) && evt->type() == eventNames().clickEvent) { OwnPtr<EventHandlingState> state = adoptPtr(new EventHandlingState(indeterminate(), checked())); - - if (inputType() == CHECKBOX) { + if (deprecatedInputType() == CHECKBOX) { if (indeterminate()) setIndeterminate(false); else @@ -2203,11 +2209,10 @@ void* HTMLInputElement::preDispatchEventHandler(Event *evt) void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data) { - if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent() - && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { + if ((deprecatedInputType() == CHECKBOX || deprecatedInputType() == RADIO) && evt->type() == eventNames().clickEvent) { if (EventHandlingState* state = reinterpret_cast<EventHandlingState*>(data)) { - if (inputType() == CHECKBOX) { + if (deprecatedInputType() == CHECKBOX) { // Reverse the checking we did in preDispatch. if (evt->defaultPrevented() || evt->defaultHandled()) { setIndeterminate(state->m_indeterminate); @@ -2220,7 +2225,7 @@ void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data) // Make sure it is still a radio button and only do the restoration if it still // belongs to our group. - if (input && input->form() == form() && input->inputType() == RADIO && input->name() == name()) { + if (input && input->form() == form() && input->deprecatedInputType() == RADIO && input->name() == name()) { // Ok, the old radio button is still in our form and in our group and is still a // radio button, so it's safe to restore selection to it. input->setChecked(true); @@ -2246,7 +2251,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) if (isTextField() && evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n") implicitSubmission = true; - if (inputType() == IMAGE && evt->isMouseEvent() && evt->type() == eventNames().clickEvent) { + if (deprecatedInputType() == IMAGE && evt->isMouseEvent() && evt->type() == eventNames().clickEvent) { // record the mouse position for when we get the DOMActivate event MouseEvent* me = static_cast<MouseEvent*>(evt); // FIXME: We could just call offsetX() and offsetY() on the event, @@ -2287,10 +2292,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) return; } - if (inputType() == RADIO - && evt->isMouseEvent() - && evt->type() == eventNames().clickEvent - && static_cast<MouseEvent*>(evt)->button() == LeftButton) { + if (deprecatedInputType() == RADIO && evt->type() == eventNames().clickEvent) { evt->setDefaultHandled(); return; } @@ -2310,10 +2312,10 @@ void HTMLInputElement::defaultEventHandler(Event* evt) // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element // must dispatch a DOMActivate event - a click event will not do the job. if (evt->type() == eventNames().DOMActivateEvent && !disabled()) { - if (inputType() == IMAGE || inputType() == SUBMIT || inputType() == RESET) { + if (deprecatedInputType() == IMAGE || deprecatedInputType() == SUBMIT || deprecatedInputType() == RESET) { if (!form()) return; - if (inputType() == RESET) + if (deprecatedInputType() == RESET) form()->reset(); else { m_activeSubmit = true; @@ -2327,7 +2329,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) } m_activeSubmit = false; } - } else if (inputType() == FILE && renderer()) + } else if (deprecatedInputType() == FILE && renderer()) toRenderFileUploadControl(renderer())->click(); } @@ -2339,7 +2341,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) int charCode = static_cast<KeyboardEvent*>(evt)->charCode(); if (charCode == '\r') { - switch (inputType()) { + switch (deprecatedInputType()) { case CHECKBOX: case COLOR: case DATE: @@ -2372,7 +2374,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) break; } } else if (charCode == ' ') { - switch (inputType()) { + switch (deprecatedInputType()) { case BUTTON: case CHECKBOX: case FILE: @@ -2399,7 +2401,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); if (key == "U+0020") { - switch (inputType()) { + switch (deprecatedInputType()) { case BUTTON: case CHECKBOX: case FILE: @@ -2416,7 +2418,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) } } - if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) { + if (deprecatedInputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) { // Left and up mean "previous radio button". // Right and down mean "next radio button". // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves @@ -2438,7 +2440,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) break; if (n->hasTagName(inputTag)) { HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n); - if (inputElt->inputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) { + if (inputElt->deprecatedInputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) { inputElt->setChecked(true); document()->setFocusedNode(inputElt); inputElt->dispatchSimulatedClick(evt, false, false); @@ -2457,7 +2459,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); if (key == "U+0020") { - switch (inputType()) { + switch (deprecatedInputType()) { case BUTTON: case CHECKBOX: case FILE: @@ -2520,7 +2522,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) RefPtr<HTMLFormElement> formForSubmission = form(); // If there is no form and the element is an <isindex>, then create a temporary form just to be used for submission. - if (!formForSubmission && inputType() == ISINDEX) + if (!formForSubmission && deprecatedInputType() == ISINDEX) formForSubmission = createTemporaryFormForIsIndex(); // Form may never have been present, or may have been destroyed by code responding to the change event. @@ -2551,7 +2553,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent)) toRenderTextControlSingleLine(renderer())->forwardEvent(evt); - if (inputType() == RANGE && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent())) + if (deprecatedInputType() == RANGE && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent())) toRenderSlider(renderer())->forwardEvent(evt); if (!callBaseClassEarly && !evt->defaultHandled()) @@ -2560,7 +2562,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) void HTMLInputElement::handleBeforeTextInsertedEvent(Event* event) { - if (inputType() == NUMBER) { + if (deprecatedInputType() == NUMBER) { BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(event); unsigned length = textEvent->text().length(); bool hasInvalidChar = false; @@ -2679,21 +2681,21 @@ void HTMLInputElement::setAutofilled(bool b) FileList* HTMLInputElement::files() { - if (inputType() != FILE) + if (deprecatedInputType() != FILE) return 0; return m_fileList.get(); } bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const { - if (inputType() != NUMBER) + if (deprecatedInputType() != NUMBER) return true; return proposedValue.isEmpty() || parseToDoubleForNumberType(proposedValue, 0); } String HTMLInputElement::sanitizeValue(const String& proposedValue) const { - if (inputType() == NUMBER) + if (deprecatedInputType() == NUMBER) return parseToDoubleForNumberType(proposedValue, 0) ? proposedValue : String(); if (isTextField()) @@ -2702,7 +2704,7 @@ String HTMLInputElement::sanitizeValue(const String& proposedValue) const // If the proposedValue is null than this is a reset scenario and we // want the range input's value attribute to take priority over the // calculated default (middle) value. - if (inputType() == RANGE && !proposedValue.isNull()) + if (deprecatedInputType() == RANGE && !proposedValue.isNull()) return serializeForNumberType(StepRange(this).clampValue(proposedValue)); return proposedValue; @@ -2710,12 +2712,12 @@ String HTMLInputElement::sanitizeValue(const String& proposedValue) const bool HTMLInputElement::hasUnacceptableValue() const { - return inputType() == NUMBER && renderer() && !isAcceptableValue(toRenderTextControl(renderer())->text()); + return deprecatedInputType() == NUMBER && renderer() && !isAcceptableValue(toRenderTextControl(renderer())->text()); } bool HTMLInputElement::needsActivationCallback() { - return inputType() == PASSWORD || m_autocomplete == Off; + return deprecatedInputType() == PASSWORD || m_autocomplete == Off; } void HTMLInputElement::registerForActivationCallbackIfNeeded() @@ -2735,7 +2737,7 @@ bool HTMLInputElement::isRequiredFormControl() const if (!required()) return false; - switch (inputType()) { + switch (deprecatedInputType()) { case CHECKBOX: case DATE: case DATETIME: @@ -2825,7 +2827,7 @@ void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) cons bool HTMLInputElement::recalcWillValidate() const { - switch (inputType()) { + switch (deprecatedInputType()) { case CHECKBOX: case COLOR: case DATE: @@ -2857,7 +2859,7 @@ bool HTMLInputElement::recalcWillValidate() const return false; } -bool HTMLInputElement::parseToDateComponents(InputType type, const String& formString, DateComponents* out) +bool HTMLInputElement::parseToDateComponents(DeprecatedInputType type, const String& formString, DateComponents* out) { if (formString.isEmpty()) return false; @@ -2899,7 +2901,7 @@ HTMLDataListElement* HTMLInputElement::dataList() const if (!m_hasNonEmptyList) return 0; - switch (inputType()) { + switch (deprecatedInputType()) { case COLOR: case DATE: case DATETIME: @@ -3005,7 +3007,7 @@ void HTMLInputElement::setWapInputFormat(String& mask) #if ENABLE(INPUT_SPEECH) bool HTMLInputElement::isSpeechEnabled() const { - switch (inputType()) { + switch (deprecatedInputType()) { // FIXME: Add support for RANGE, EMAIL, URL, COLOR and DATE/TIME input types. case NUMBER: case PASSWORD: diff --git a/WebCore/html/HTMLInputElement.h b/WebCore/html/HTMLInputElement.h index e023796..7e601ca 100644 --- a/WebCore/html/HTMLInputElement.h +++ b/WebCore/html/HTMLInputElement.h @@ -40,7 +40,7 @@ class VisibleSelection; class HTMLInputElement : public HTMLTextFormControlElement, public InputElement { public: - enum InputType { + enum DeprecatedInputType { TEXT = 0, // TEXT must be 0. PASSWORD, ISINDEX, @@ -65,9 +65,9 @@ public: MONTH, TIME, WEEK, - // If you add new types or change the order of enum values, update numberOfTypes below. + // If you add new types or change the order of enum values, update deprecatedNumberOfTypes below. }; - static const int numberOfTypes = WEEK + 1; + static const int deprecatedNumberOfTypes = WEEK + 1; static PassRefPtr<HTMLInputElement> create(const QualifiedName&, Document*, HTMLFormElement*); virtual ~HTMLInputElement(); @@ -101,17 +101,29 @@ public: // stepUp()/stepDown() for user-interaction. void stepUpFromRenderer(int); - bool isTextButton() const { return m_type == SUBMIT || m_type == RESET || m_type == BUTTON; } - virtual bool isRadioButton() const { return m_type == RADIO; } + bool isTextButton() const { return deprecatedInputType() == SUBMIT || deprecatedInputType() == RESET || deprecatedInputType() == BUTTON; } + + virtual bool isRadioButton() const { return deprecatedInputType() == RADIO; } virtual bool isTextField() const; - virtual bool isSearchField() const { return m_type == SEARCH; } - virtual bool isInputTypeHidden() const { return m_type == HIDDEN; } - virtual bool isPasswordField() const { return m_type == PASSWORD; } - virtual bool isCheckbox() const { return m_type == CHECKBOX; } - bool isTelephoneField() const { return m_type == TELEPHONE; } - bool isNumberField() const { return m_type == NUMBER; } - bool isEmailField() const { return m_type == EMAIL; } - bool isUrlField() const { return m_type == URL; } + virtual bool isSearchField() const { return deprecatedInputType() == SEARCH; } + virtual bool isInputTypeHidden() const { return deprecatedInputType() == HIDDEN; } + virtual bool isPasswordField() const { return deprecatedInputType() == PASSWORD; } + virtual bool isCheckbox() const { return deprecatedInputType() == CHECKBOX; } + + // FIXME: It's highly likely that any call site calling this function should instead + // be using a different one. Many input elements behave like text fields, and in addition + // any unknown input type is treated as text. Consider, for example, isTextField or + // isTextField && !isPasswordField. + bool isText() const { return deprecatedInputType() == TEXT; } + + bool isEmailField() const { return deprecatedInputType() == EMAIL; } + bool isFileUpload() const { return deprecatedInputType() == FILE; } + bool isImageButton() const { return deprecatedInputType() == IMAGE; } + bool isNumberField() const { return deprecatedInputType() == NUMBER; } + bool isSubmitButton() const { return deprecatedInputType() == SUBMIT; } + bool isTelephoneField() const { return deprecatedInputType() == TELEPHONE; } + bool isURLField() const { return deprecatedInputType() == URL; } + #if ENABLE(INPUT_SPEECH) virtual bool isSpeechEnabled() const; #endif @@ -164,8 +176,7 @@ public: virtual bool isActivatedSubmit() const; virtual void setActivatedSubmit(bool flag); - InputType inputType() const { return static_cast<InputType>(m_type); } - void setInputType(const String&); + DeprecatedInputType deprecatedInputType() const { return static_cast<DeprecatedInputType>(m_deprecatedTypeNumber); } String altText() const; @@ -202,10 +213,10 @@ public: void addSearchResult(); void onSearch(); - // Parses the specified string as the InputType, and returns true if it is successfully parsed. + // Parses the specified string as the DeprecatedInputType, and returns true if it is successfully parsed. // An instance pointed by the DateComponents* parameter will have parsed values and be // modified even if the parsing fails. The DateComponents* parameter may be 0. - static bool parseToDateComponents(InputType, const String&, DateComponents*); + static bool parseToDateComponents(DeprecatedInputType, const String&, DateComponents*); #if ENABLE(DATALIST) HTMLElement* list() const; @@ -229,7 +240,7 @@ private: virtual bool isKeyboardFocusable(KeyboardEvent*) const; virtual bool isMouseFocusable() const; - virtual bool isEnumeratable() const { return inputType() != IMAGE; } + virtual bool isEnumeratable() const { return deprecatedInputType() != IMAGE; } virtual void updateFocusAppearance(bool restorePreviousSelection); virtual void aboutToUnload(); virtual bool shouldUseInputMethod() const; @@ -237,15 +248,15 @@ private: virtual const AtomicString& formControlName() const; // isChecked is used by the rendering tree/CSS while checked() is used by JS to determine checked state - virtual bool isChecked() const { return checked() && (inputType() == CHECKBOX || inputType() == RADIO); } + virtual bool isChecked() const { return checked() && (deprecatedInputType() == CHECKBOX || deprecatedInputType() == RADIO); } virtual bool isIndeterminate() const { return indeterminate(); } virtual bool isTextFormControl() const { return isTextField(); } - virtual bool hasSpinButton() const { return m_type == NUMBER || m_type == DATE || m_type == DATETIME || m_type == DATETIMELOCAL || m_type == MONTH || m_type == TIME || m_type == WEEK; } + virtual bool hasSpinButton() const { return deprecatedInputType() == NUMBER || deprecatedInputType() == DATE || deprecatedInputType() == DATETIME || deprecatedInputType() == DATETIMELOCAL || deprecatedInputType() == MONTH || deprecatedInputType() == TIME || deprecatedInputType() == WEEK; } virtual bool canTriggerImplicitSubmission() const { return isTextField(); } - bool allowsIndeterminate() const { return inputType() == CHECKBOX || inputType() == RADIO; } + bool allowsIndeterminate() const { return deprecatedInputType() == CHECKBOX || deprecatedInputType() == RADIO; } virtual const AtomicString& formControlType() const; @@ -270,7 +281,7 @@ private: virtual bool isSuccessfulSubmitButton() const; // Report if this input type uses height & width attributes - bool respectHeightAndWidthAttrs() const { return inputType() == IMAGE || inputType() == HIDDEN; } + bool respectHeightAndWidthAttrs() const { return deprecatedInputType() == IMAGE || deprecatedInputType() == HIDDEN; } virtual void reset(); @@ -298,7 +309,7 @@ private: virtual bool supportsMaxLength() const { return isTextType(); } bool isTextType() const; - virtual bool supportsPlaceholder() const { return isTextType() || inputType() == ISINDEX; } + virtual bool supportsPlaceholder() const { return isTextType() || deprecatedInputType() == ISINDEX; } virtual bool isEmptyValue() const { return value().isEmpty(); } virtual void handleFocusEvent(); virtual void handleBlurEvent(); @@ -309,6 +320,8 @@ private: virtual bool isRequiredFormControl() const; virtual bool recalcWillValidate() const; + void updateType(); + void updateCheckedRadioButtons(); void handleBeforeTextInsertedEvent(Event*); @@ -348,7 +361,7 @@ private: short m_maxResults; OwnPtr<HTMLImageLoader> m_imageLoader; RefPtr<FileList> m_fileList; - unsigned m_type : 5; // InputType + unsigned m_deprecatedTypeNumber : 5; // DeprecatedInputType bool m_checked : 1; bool m_defaultChecked : 1; bool m_useDefaultChecked : 1; diff --git a/WebCore/html/HTMLMarqueeElement.cpp b/WebCore/html/HTMLMarqueeElement.cpp index ada26c1..8128188 100644 --- a/WebCore/html/HTMLMarqueeElement.cpp +++ b/WebCore/html/HTMLMarqueeElement.cpp @@ -132,7 +132,7 @@ bool HTMLMarqueeElement::canSuspend() const return true; } -void HTMLMarqueeElement::suspend() +void HTMLMarqueeElement::suspend(ReasonForSuspension) { if (RenderMarquee* marqueeRenderer = renderMarquee()) marqueeRenderer->suspend(); diff --git a/WebCore/html/HTMLMarqueeElement.h b/WebCore/html/HTMLMarqueeElement.h index 1b3229a..a4825fc 100644 --- a/WebCore/html/HTMLMarqueeElement.h +++ b/WebCore/html/HTMLMarqueeElement.h @@ -49,7 +49,7 @@ private: // ActiveDOMObject virtual bool canSuspend() const; - virtual void suspend(); + virtual void suspend(ReasonForSuspension); virtual void resume(); RenderMarquee* renderMarquee() const; diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp index 827158e..f753183 100644 --- a/WebCore/html/HTMLMediaElement.cpp +++ b/WebCore/html/HTMLMediaElement.cpp @@ -64,6 +64,7 @@ #include <limits> #include <wtf/CurrentTime.h> #include <wtf/MathExtras.h> +#include <wtf/text/CString.h> #if USE(ACCELERATED_COMPOSITING) #include "RenderView.h" @@ -747,19 +748,16 @@ bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction acti if (!url.isValid()) { LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE because url is invalid", urlForLogging(url.string()).utf8().data()); return false; - } - - Frame* frame = document()->frame(); - FrameLoader* loader = frame ? frame->loader() : 0; + } - // don't allow remote to local urls, and check with the frame loader client. - if (!loader || !SecurityOrigin::canDisplay(url, String(), document())) { + Frame* frame = document()->frame(); + if (!frame || !document()->securityOrigin()->canDisplay(url)) { if (actionIfInvalid == Complain) FrameLoader::reportLocalLoadFailed(frame, url.string()); LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE rejected by SecurityOrigin", urlForLogging(url.string()).utf8().data()); return false; } - + return true; } @@ -2029,29 +2027,38 @@ bool HTMLMediaElement::canSuspend() const void HTMLMediaElement::stop() { LOG(Media, "HTMLMediaElement::stop"); - suspend(); -} - -void HTMLMediaElement::suspend() -{ - LOG(Media, "HTMLMediaElement::suspend"); - if (m_isFullscreen) exitFullscreen(); - + m_inActiveDocument = false; userCancelledLoad(); - + // Stop the playback without generating events setPausedInternal(true); - + if (renderer()) renderer()->updateFromElement(); - + stopPeriodicTimers(); cancelPendingEventsAndCallbacks(); } +void HTMLMediaElement::suspend(ReasonForSuspension why) +{ + LOG(Media, "HTMLMediaElement::suspend"); + + switch (why) + { + case DocumentWillBecomeInactive: + stop(); + break; + case JavaScriptDebuggerPaused: + case WillShowDialog: + // Do nothing, we don't pause media playback in these cases. + break; + } +} + void HTMLMediaElement::resume() { LOG(Media, "HTMLMediaElement::resume"); diff --git a/WebCore/html/HTMLMediaElement.h b/WebCore/html/HTMLMediaElement.h index adea0fd..db75a9c 100644 --- a/WebCore/html/HTMLMediaElement.h +++ b/WebCore/html/HTMLMediaElement.h @@ -199,7 +199,7 @@ private: // ActiveDOMObject functions. virtual bool canSuspend() const; - virtual void suspend(); + virtual void suspend(ReasonForSuspension); virtual void resume(); virtual void stop(); virtual bool hasPendingActivity() const; diff --git a/WebCore/html/HTMLMeterElement.cpp b/WebCore/html/HTMLMeterElement.cpp index aaba125..5419a22 100644 --- a/WebCore/html/HTMLMeterElement.cpp +++ b/WebCore/html/HTMLMeterElement.cpp @@ -28,7 +28,7 @@ #include "FormDataList.h" #include "HTMLFormElement.h" #include "HTMLNames.h" -#include "HTMLTreeBuilder.h" +#include "HTMLParserIdioms.h" #include "RenderMeter.h" #include <wtf/StdLibExtras.h> diff --git a/WebCore/html/HTMLObjectElement.cpp b/WebCore/html/HTMLObjectElement.cpp index 56a6095..e9c6f60 100644 --- a/WebCore/html/HTMLObjectElement.cpp +++ b/WebCore/html/HTMLObjectElement.cpp @@ -163,6 +163,7 @@ static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramV void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType) { HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames; + String urlParameter; // Scan the PARAM children and store their name/value pairs. // Get the URL and type from the params if we don't already have them. @@ -180,8 +181,8 @@ void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<S paramValues.append(p->value()); // FIXME: url adjustment does not belong in this function. - if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url"))) - url = deprecatedParseURL(p->value()); + if (url.isEmpty() && urlParameter.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url"))) + urlParameter = deprecatedParseURL(p->value()); // FIXME: serviceType calculation does not belong in this function. if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) { serviceType = p->value(); @@ -217,9 +218,15 @@ void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<S mapDataParamToSrc(¶mNames, ¶mValues); - // If we still don't have a type, try to map from a specific CLASSID to a type. - if (serviceType.isEmpty()) - serviceType = serviceTypeForClassId(classId()); + // HTML5 says that an object resource's URL is specified by the object's data + // attribute, not by a param element. However, for compatibility, allow the + // resource's URL to be given by a param named "src", "movie", "code" or "url" + // if we know that resource points to a plug-in. + if (url.isEmpty() && !urlParameter.isEmpty()) { + SubframeLoader* loader = document()->frame()->loader()->subframeLoader(); + if (loader->resourceWillUsePlugin(urlParameter, serviceType)) + url = urlParameter; + } } @@ -250,7 +257,12 @@ void HTMLObjectElement::updateWidget(bool onlyCreateNonNetscapePlugins) return; String url = this->url(); + + // If the object does not specify a MIME type via a type attribute, but does + // contain a classid attribute, try to map the classid to a MIME type. String serviceType = this->serviceType(); + if (serviceType.isEmpty()) + serviceType = serviceTypeForClassId(classId()); // FIXME: These should be joined into a PluginParameters class. Vector<String> paramNames; diff --git a/WebCore/html/HTMLPlugInImageElement.h b/WebCore/html/HTMLPlugInImageElement.h index 60ad0e6..9616fe8 100644 --- a/WebCore/html/HTMLPlugInImageElement.h +++ b/WebCore/html/HTMLPlugInImageElement.h @@ -59,7 +59,6 @@ protected: bool wouldLoadAsNetscapePlugin(const String& url, const String& serviceType); private: - virtual bool canLazyAttach() { return false; } virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual void recalcStyle(StyleChange); diff --git a/WebCore/html/HTMLProgressElement.cpp b/WebCore/html/HTMLProgressElement.cpp index de65fcb..e707592 100644 --- a/WebCore/html/HTMLProgressElement.cpp +++ b/WebCore/html/HTMLProgressElement.cpp @@ -28,7 +28,7 @@ #include "FormDataList.h" #include "HTMLFormElement.h" #include "HTMLNames.h" -#include "HTMLTreeBuilder.h" +#include "HTMLParserIdioms.h" #include "RenderProgress.h" #include <wtf/StdLibExtras.h> diff --git a/WebCore/html/HTMLTextAreaElement.cpp b/WebCore/html/HTMLTextAreaElement.cpp index 3e34844..ad6c1b3 100644 --- a/WebCore/html/HTMLTextAreaElement.cpp +++ b/WebCore/html/HTMLTextAreaElement.cpp @@ -226,7 +226,7 @@ void HTMLTextAreaElement::updateFocusAppearance(bool restorePreviousSelection) } if (document()->frame()) - document()->frame()->revealSelection(); + document()->frame()->selection()->revealSelection(); } void HTMLTextAreaElement::defaultEventHandler(Event* event) diff --git a/WebCore/html/ImageDocument.cpp b/WebCore/html/ImageDocument.cpp index 6951b7b..db53837 100644 --- a/WebCore/html/ImageDocument.cpp +++ b/WebCore/html/ImageDocument.cpp @@ -117,10 +117,10 @@ inline PassRefPtr<ImageDocumentElement> ImageDocumentElement::create(ImageDocume // -------- -static float pageZoomFactor(Document* document) +static float pageZoomFactor(const Document* document) { - FrameView* view = document->view(); - return view ? view->pageZoomFactor() : 1; + Frame* frame = document->frame(); + return frame ? frame->pageZoomFactor() : 1; } void ImageDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool) @@ -231,7 +231,7 @@ float ImageDocument::scale() const if (!view) return 1; - IntSize imageSize = m_imageElement->cachedImage()->imageSize(view->pageZoomFactor()); + IntSize imageSize = m_imageElement->cachedImage()->imageSize(pageZoomFactor(this)); IntSize windowSize = IntSize(view->width(), view->height()); float widthScale = (float)windowSize.width() / imageSize.width(); @@ -319,8 +319,10 @@ bool ImageDocument::imageFitsInWindow() const return true; FrameView* view = frame()->view(); + if (!view) + return true; - IntSize imageSize = m_imageElement->cachedImage()->imageSize(view->pageZoomFactor()); + IntSize imageSize = m_imageElement->cachedImage()->imageSize(pageZoomFactor(this)); IntSize windowSize = IntSize(view->width(), view->height()); return imageSize.width() <= windowSize.width() && imageSize.height() <= windowSize.height(); diff --git a/WebCore/html/StepRange.cpp b/WebCore/html/StepRange.cpp index aeaf62f..68b0ebd 100644 --- a/WebCore/html/StepRange.cpp +++ b/WebCore/html/StepRange.cpp @@ -23,9 +23,9 @@ #include "HTMLInputElement.h" #include "HTMLNames.h" -#include "HTMLTreeBuilder.h" -#include "PlatformString.h" +#include "HTMLParserIdioms.h" #include <wtf/MathExtras.h> +#include <wtf/text/WTFString.h> using namespace std; diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/WebCore/html/canvas/CanvasRenderingContext2D.cpp index 338960c..0fb7ed5 100755..100644 --- a/WebCore/html/canvas/CanvasRenderingContext2D.cpp +++ b/WebCore/html/canvas/CanvasRenderingContext2D.cpp @@ -659,7 +659,7 @@ void CanvasRenderingContext2D::closePath() FloatRect boundRect = m_path.boundingRect(); if (boundRect.width() || boundRect.height()) - m_path.closeCanvasSubpath(); + m_path.closeSubpath(); } void CanvasRenderingContext2D::moveTo(float x, float y) diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp index bda3569..68a6954 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.cpp +++ b/WebCore/html/canvas/WebGLRenderingContext.cpp @@ -1756,7 +1756,7 @@ WebGLGetInfo WebGLRenderingContext::getVertexAttrib(unsigned long index, unsigne } switch (pname) { case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: - if (!isGLES2Compliant() && !index && m_vertexAttribState[0].bufferBinding == m_vertexAttrib0Buffer + if ((!isGLES2Compliant() && !index && m_vertexAttribState[0].bufferBinding == m_vertexAttrib0Buffer) || index >= m_vertexAttribState.size() || !m_vertexAttribState[index].bufferBinding || !m_vertexAttribState[index].bufferBinding->object()) @@ -1943,8 +1943,8 @@ void WebGLRenderingContext::readPixels(long x, long y, long width, long height, return; } // Validate array type against pixel type. - if (type == GraphicsContext3D::UNSIGNED_BYTE && !pixels->isUnsignedByteArray() - || type != GraphicsContext3D::UNSIGNED_BYTE && !pixels->isUnsignedShortArray()) { + if ((type == GraphicsContext3D::UNSIGNED_BYTE && !pixels->isUnsignedByteArray()) + || (type != GraphicsContext3D::UNSIGNED_BYTE && !pixels->isUnsignedShortArray())) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2221,8 +2221,8 @@ void WebGLRenderingContext::texParameter(unsigned long target, unsigned long pna break; case GraphicsContext3D::TEXTURE_WRAP_S: case GraphicsContext3D::TEXTURE_WRAP_T: - if (isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT - || !isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT) { + if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT) + || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); return; } @@ -3012,8 +3012,8 @@ void WebGLRenderingContext::handleNPOTTextures(bool prepareToDraw) { bool resetActiveUnit = false; for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) { - if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture() - || m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture()) { + if ((m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture()) + || (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())) { if (ii != m_activeTextureUnit) { m_context->activeTexture(ii); resetActiveUnit = true; diff --git a/WebCore/html/parser/HTMLConstructionSite.cpp b/WebCore/html/parser/HTMLConstructionSite.cpp index 0172b3d..6215bba 100644 --- a/WebCore/html/parser/HTMLConstructionSite.cpp +++ b/WebCore/html/parser/HTMLConstructionSite.cpp @@ -114,19 +114,19 @@ PassRefPtr<ChildType> HTMLConstructionSite::attach(ContainerNode* parent, PassRe void HTMLConstructionSite::attachAtSite(const AttachmentSite& site, PassRefPtr<Node> prpChild) { + // FIXME: It's unfortunate that we need to hold a reference to child + // here to call attach(). We should investigate whether we can rely on + // |site.parent| to hold a ref at this point. RefPtr<Node> child = prpChild; - if (site.nextChild) { + if (site.nextChild) site.parent->parserInsertBefore(child, site.nextChild); - if (site.parent->attached() && !child->attached()) - child->attach(); - return; - } - site.parent->parserAddChild(child); - // It's slightly unfortunate that we need to hold a reference to child - // here to call attach(). We should investigate whether we can rely on - // |site.parent| to hold a ref at this point. - if (site.parent->attached() && !child->attached()) + else + site.parent->parserAddChild(child); + + // JavaScript run from beforeload (or DOM Mutation or event handlers) + // might have removed the child, in which case we should not attach it. + if (child->parentNode() && site.parent->attached() && !child->attached()) child->attach(); } diff --git a/WebCore/html/parser/HTMLDocumentParser.cpp b/WebCore/html/parser/HTMLDocumentParser.cpp index a442d54..2da403f 100644 --- a/WebCore/html/parser/HTMLDocumentParser.cpp +++ b/WebCore/html/parser/HTMLDocumentParser.cpp @@ -36,6 +36,8 @@ #include "HTMLScriptRunner.h" #include "HTMLTreeBuilder.h" #include "HTMLDocument.h" +#include "NestingLevelIncrementer.h" +#include "Settings.h" #include "XSSAuditor.h" #include <wtf/CurrentTime.h> @@ -53,23 +55,6 @@ using namespace HTMLNames; namespace { -class NestingLevelIncrementer : public Noncopyable { -public: - explicit NestingLevelIncrementer(int& counter) - : m_counter(&counter) - { - ++(*m_counter); - } - - ~NestingLevelIncrementer() - { - --(*m_counter); - } - -private: - int* m_counter; -}; - // This is a direct transcription of step 4 from: // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElement, bool reportErrors) @@ -99,7 +84,7 @@ HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElement, bo HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors) : ScriptableDocumentParser(document) - , m_tokenizer(HTMLTokenizer::create()) + , m_tokenizer(HTMLTokenizer::create(usePreHTML5ParserQuirks(document))) , m_scriptRunner(HTMLScriptRunner::create(document, this)) , m_treeBuilder(HTMLTreeBuilder::create(m_tokenizer.get(), document, reportErrors)) , m_parserScheduler(HTMLParserScheduler::create(this)) @@ -112,7 +97,7 @@ HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors // minimize code duplication between these constructors. HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission) : ScriptableDocumentParser(fragment->document()) - , m_tokenizer(HTMLTokenizer::create()) + , m_tokenizer(HTMLTokenizer::create(usePreHTML5ParserQuirks(fragment->document()))) , m_treeBuilder(HTMLTreeBuilder::create(m_tokenizer.get(), fragment, contextElement, scriptingPermission)) , m_endWasDelayed(false) , m_writeNestingLevel(0) @@ -547,5 +532,11 @@ void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFra ASSERT(!parser->processingData()); // Make sure we're done. <rdar://problem/3963151> parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction. } + +bool HTMLDocumentParser::usePreHTML5ParserQuirks(Document* document) +{ + ASSERT(document); + return document->settings() && document->settings()->usePreHTML5ParserQuirks(); +} } diff --git a/WebCore/html/parser/HTMLDocumentParser.h b/WebCore/html/parser/HTMLDocumentParser.h index 6d5b6d7..e65a582 100644 --- a/WebCore/html/parser/HTMLDocumentParser.h +++ b/WebCore/html/parser/HTMLDocumentParser.h @@ -66,6 +66,8 @@ public: void resumeParsingAfterYield(); static void parseDocumentFragment(const String&, DocumentFragment*, Element* contextElement, FragmentScriptingPermission = FragmentScriptingAllowed); + + static bool usePreHTML5ParserQuirks(Document*); protected: virtual void insert(const SegmentedString&); @@ -139,7 +141,7 @@ private: OwnPtr<HTMLParserScheduler> m_parserScheduler; bool m_endWasDelayed; - int m_writeNestingLevel; + unsigned m_writeNestingLevel; }; } diff --git a/WebCore/html/parser/HTMLElementStack.cpp b/WebCore/html/parser/HTMLElementStack.cpp index b6f4111..123778d 100644 --- a/WebCore/html/parser/HTMLElementStack.cpp +++ b/WebCore/html/parser/HTMLElementStack.cpp @@ -28,6 +28,8 @@ #include "Element.h" #include "HTMLNames.h" +#include "MathMLNames.h" +#include "SVGNames.h" #include <wtf/PassOwnPtr.h> #if ENABLE(SVG) @@ -92,6 +94,19 @@ inline bool isTableRowScopeMarker(Element* element) || element->hasTagName(htmlTag); } +inline bool isForeignContentScopeMarker(Element* element) +{ + return element->hasTagName(MathMLNames::miTag) + || element->hasTagName(MathMLNames::moTag) + || element->hasTagName(MathMLNames::mnTag) + || element->hasTagName(MathMLNames::msTag) + || element->hasTagName(MathMLNames::mtextTag) + || element->hasTagName(SVGNames::foreignObjectTag) + || element->hasTagName(SVGNames::descTag) + || element->hasTagName(SVGNames::titleTag) + || element->namespaceURI() == HTMLNames::xhtmlNamespaceURI; +} + inline bool isButtonScopeMarker(Element* element) { return isScopeMarker(element) @@ -186,12 +201,6 @@ void HTMLElementStack::pop() popCommon(); } -void HTMLElementStack::popUntilElementWithNamespace(const AtomicString& namespaceURI) -{ - while (top()->namespaceURI() != namespaceURI) - pop(); -} - void HTMLElementStack::popUntil(const AtomicString& tagName) { while (!top()->hasLocalName(tagName)) { @@ -247,6 +256,12 @@ void HTMLElementStack::popUntilTableRowScopeMarker() pop(); } +void HTMLElementStack::popUntilForeignContentScopeMarker() +{ + while (!isForeignContentScopeMarker(top())) + pop(); +} + void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<Element> element) { ASSERT(!m_top); // <html> should always be the bottom of the stack. diff --git a/WebCore/html/parser/HTMLElementStack.h b/WebCore/html/parser/HTMLElementStack.h index 73cfcb1..47fa603 100644 --- a/WebCore/html/parser/HTMLElementStack.h +++ b/WebCore/html/parser/HTMLElementStack.h @@ -90,7 +90,6 @@ public: void pop(); void popUntil(const AtomicString& tagName); - void popUntilElementWithNamespace(const AtomicString& namespaceURI); void popUntil(Element*); void popUntilPopped(const AtomicString& tagName); void popUntilPopped(Element*); @@ -98,6 +97,7 @@ public: void popUntilTableScopeMarker(); // "clear the stack back to a table context" in the spec. void popUntilTableBodyScopeMarker(); // "clear the stack back to a table body context" in the spec. void popUntilTableRowScopeMarker(); // "clear the stack back to a table row context" in the spec. + void popUntilForeignContentScopeMarker(); void popHTMLHeadElement(); void popHTMLBodyElement(); void popAll(); diff --git a/WebCore/html/parser/HTMLParserIdioms.cpp b/WebCore/html/parser/HTMLParserIdioms.cpp new file mode 100644 index 0000000..a558cf5 --- /dev/null +++ b/WebCore/html/parser/HTMLParserIdioms.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "HTMLParserIdioms.h" + +#include <wtf/MathExtras.h> +#include <wtf/dtoa.h> +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +String stripLeadingAndTrailingHTMLSpaces(const String& string) +{ + const UChar* characters = string.characters(); + unsigned length = string.length(); + + unsigned numLeadingSpaces; + for (numLeadingSpaces = 0; numLeadingSpaces < length; ++numLeadingSpaces) { + if (isNotHTMLSpace(characters[numLeadingSpaces])) + break; + } + + if (numLeadingSpaces == length) + return emptyAtom; + + unsigned numTrailingSpaces; + for (numTrailingSpaces = 0; numTrailingSpaces < length; ++numTrailingSpaces) { + if (isNotHTMLSpace(characters[length - numTrailingSpaces - 1])) + break; + } + + ASSERT(numLeadingSpaces + numTrailingSpaces < length); + + return string.substring(numLeadingSpaces, length - numTrailingSpaces); +} + +String serializeForNumberType(double number) +{ + // According to HTML5, "the best representation of the number n as a floating + // point number" is a string produced by applying ToString() to n. + NumberToStringBuffer buffer; + unsigned length = numberToString(number, buffer); + return String(buffer, length); +} + +bool parseToDoubleForNumberType(const String& string, double* result) +{ + // See HTML5 2.4.4.3 `Real numbers.' + + // String::toDouble() accepts leading + and whitespace characters, which are not valid here. + UChar firstCharacter = string[0]; + if (firstCharacter != '-' && !isASCIIDigit(firstCharacter)) + return false; + + bool valid = false; + double value = string.toDouble(&valid); + if (!valid) + return false; + + // NaN and infinity are considered valid by String::toDouble, but not valid here. + if (!isfinite(value)) + return false; + + if (result) { + // The following expression converts -0 to +0. + *result = value ? value : 0; + } + + return true; +} + +// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers +bool parseHTMLInteger(const String& input, int& value) +{ + // Step 1 + // Step 2 + const UChar* position = input.characters(); + const UChar* end = position + input.length(); + + // Step 3 + int sign = 1; + + // Step 4 + while (position < end) { + if (!isHTMLSpace(*position)) + break; + ++position; + } + + // Step 5 + if (position == end) + return false; + ASSERT(position < end); + + // Step 6 + if (*position == '-') { + sign = -1; + ++position; + } else if (*position == '+') + ++position; + if (position == end) + return false; + ASSERT(position < end); + + // Step 7 + if (!isASCIIDigit(*position)) + return false; + + // Step 8 + Vector<UChar, 16> digits; + while (position < end) { + if (!isASCIIDigit(*position)) + break; + digits.append(*position++); + } + + // Step 9 + value = sign * charactersToIntStrict(digits.data(), digits.size()); + return true; +} + +} diff --git a/WebCore/html/parser/HTMLParserIdioms.h b/WebCore/html/parser/HTMLParserIdioms.h new file mode 100644 index 0000000..f4704f7 --- /dev/null +++ b/WebCore/html/parser/HTMLParserIdioms.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HTMLParserIdioms_h +#define HTMLParserIdioms_h + +#include <wtf/Forward.h> +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +// Space characters as defined by the HTML specification. +bool isHTMLSpace(UChar); +bool isNotHTMLSpace(UChar); + +// Strip leading and trailing whitespace as defined by the HTML specification. +String stripLeadingAndTrailingHTMLSpaces(const String&); + +// An implementation of the HTML specification's algorithm to convert a number to a string for number and range types. +String serializeForNumberType(double); + +// Convert the specified string to a double. If the conversion fails, the return value is false. +// Leading or trailing illegal characters cause failure, as does passing an empty string. +// The double* parameter may be 0 to check if the string can be parsed without getting the result. +bool parseToDoubleForNumberType(const String&, double*); + +// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers +bool parseHTMLInteger(const String&, int&); + +// Inline implementations of some of the functions declared above. + +inline bool isHTMLSpace(UChar character) +{ + // FIXME: Consider branch permutations as we did in isASCIISpace. + return character == '\t' || character == '\x0A' || character == '\x0C' || character == '\x0D' || character == ' '; +} + +inline bool isNotHTMLSpace(UChar character) +{ + return !isHTMLSpace(character); +} + +} + +#endif diff --git a/WebCore/html/parser/HTMLPreloadScanner.cpp b/WebCore/html/parser/HTMLPreloadScanner.cpp index 5283fa3..7859dd8 100644 --- a/WebCore/html/parser/HTMLPreloadScanner.cpp +++ b/WebCore/html/parser/HTMLPreloadScanner.cpp @@ -31,8 +31,8 @@ #include "CSSHelper.h" #include "CachedResourceLoader.h" #include "Document.h" +#include "HTMLDocumentParser.h" #include "HTMLTokenizer.h" -#include "HTMLTreeBuilder.h" #include "HTMLLinkElement.h" #include "HTMLNames.h" @@ -121,7 +121,7 @@ private: HTMLPreloadScanner::HTMLPreloadScanner(Document* document) : m_document(document) , m_cssScanner(document) - , m_tokenizer(HTMLTokenizer::create()) + , m_tokenizer(HTMLTokenizer::create(HTMLDocumentParser::usePreHTML5ParserQuirks(document))) , m_bodySeen(false) , m_inStyle(false) { @@ -157,13 +157,7 @@ void HTMLPreloadScanner::processToken() return; PreloadTask task(m_token); - m_tokenizer->setState(HTMLTreeBuilder::adjustedLexerState(m_tokenizer->state(), task.tagName(), m_document->frame())); - if (task.tagName() == scriptTag) { - // The tree builder handles scriptTag separately from the other tokenizer - // state adjustments, so we need to handle it separately too. - ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState); - m_tokenizer->setState(HTMLTokenizer::ScriptDataState); - } + m_tokenizer->updateStateFor(task.tagName(), m_document->frame()); if (task.tagName() == bodyTag) m_bodySeen = true; diff --git a/WebCore/html/parser/HTMLScriptRunner.cpp b/WebCore/html/parser/HTMLScriptRunner.cpp index e1fc120..4f54f42 100644 --- a/WebCore/html/parser/HTMLScriptRunner.cpp +++ b/WebCore/html/parser/HTMLScriptRunner.cpp @@ -35,6 +35,7 @@ #include "HTMLScriptRunnerHost.h" #include "HTMLInputStream.h" #include "HTMLNames.h" +#include "NestingLevelIncrementer.h" #include "NotImplemented.h" #include "ScriptElement.h" #include "ScriptSourceCode.h" @@ -43,24 +44,6 @@ namespace WebCore { using namespace HTMLNames; -// FIXME: Factor out to avoid duplication with HTMLDocumentParser. -class NestingLevelIncrementer : public Noncopyable { -public: - explicit NestingLevelIncrementer(unsigned& nestingLevel) - : m_nestingLevel(&nestingLevel) - { - ++(*m_nestingLevel); - } - - ~NestingLevelIncrementer() - { - --(*m_nestingLevel); - } - -private: - unsigned* m_nestingLevel; -}; - HTMLScriptRunner::HTMLScriptRunner(Document* document, HTMLScriptRunnerHost* host) : m_document(document) , m_host(host) @@ -155,20 +138,16 @@ void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendi if (errorOccurred) scriptElement->dispatchEvent(createScriptErrorEvent()); else { - executeScript(scriptElement.get(), sourceCode); + executeScript(sourceCode); scriptElement->dispatchEvent(createScriptLoadEvent()); } } ASSERT(!m_scriptNestingLevel); } -void HTMLScriptRunner::executeScript(Element* element, const ScriptSourceCode& sourceCode) const +void HTMLScriptRunner::executeScript(const ScriptSourceCode& sourceCode) const { ASSERT(m_document); - ScriptElement* scriptElement = toScriptElement(element); - ASSERT(scriptElement); - if (!scriptElement->shouldExecuteAsJavaScript()) - return; ASSERT(isExecutingScript()); if (!m_document->frame()) return; @@ -317,9 +296,11 @@ void HTMLScriptRunner::runScript(Element* script, int startingLineNumber) InsertionPointRecord insertionPointRecord(m_host->inputStream()); NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel); - // Check script type and language, current code uses ScriptElement::shouldExecuteAsJavaScript(), but that may not be HTML5 compliant. - notImplemented(); // event for support - + ScriptElement* scriptElement = toScriptElement(script); + ASSERT(scriptElement); + if (!scriptElement->shouldExecuteAsJavaScript()) + return; + if (script->hasAttribute(srcAttr)) { if (script->hasAttribute(asyncAttr)) // Async takes precendence over defer. return; // Asynchronous scripts handle themselves. @@ -335,7 +316,7 @@ void HTMLScriptRunner::runScript(Element* script, int startingLineNumber) // ASSERT(document()->haveStylesheetsLoaded()); ASSERT(isExecutingScript()); ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), startingLineNumber); - executeScript(script, sourceCode); + executeScript(sourceCode); } } } diff --git a/WebCore/html/parser/HTMLScriptRunner.h b/WebCore/html/parser/HTMLScriptRunner.h index 47c96fd..be21dd2 100644 --- a/WebCore/html/parser/HTMLScriptRunner.h +++ b/WebCore/html/parser/HTMLScriptRunner.h @@ -68,7 +68,7 @@ private: void executeParsingBlockingScript(); void executePendingScriptAndDispatchEvent(PendingScript&); - void executeScript(Element*, const ScriptSourceCode&) const; + void executeScript(const ScriptSourceCode&) const; bool haveParsingBlockingScript() const; bool executeParsingBlockingScripts(); diff --git a/WebCore/html/parser/HTMLTokenizer.cpp b/WebCore/html/parser/HTMLTokenizer.cpp index f5405ff..305fca2 100644 --- a/WebCore/html/parser/HTMLTokenizer.cpp +++ b/WebCore/html/parser/HTMLTokenizer.cpp @@ -30,6 +30,7 @@ #include "HTMLEntityParser.h" #include "HTMLToken.h" +#include "HTMLTreeBuilder.h" #include "HTMLNames.h" #include "NotImplemented.h" #include <wtf/ASCIICType.h> @@ -102,8 +103,9 @@ inline bool isEndTagBufferingState(HTMLTokenizer::State state) } -HTMLTokenizer::HTMLTokenizer() +HTMLTokenizer::HTMLTokenizer(bool usePreHTML5ParserQuirks) : m_inputStreamPreprocessor(this) + , m_usePreHTML5ParserQuirks(usePreHTML5ParserQuirks) { reset(); } @@ -171,7 +173,7 @@ inline bool HTMLTokenizer::processEntity(SegmentedString& source) // Sometimes there's more complicated logic in the spec that separates when // we consume the next input character and when we switch to a particular -// state. We handle those cases by advancing the source directly and using +// state. We handle those cases by advancing the source directly and using // this macro to switch to the indicated state. #define SWITCH_TO(stateName) \ do { \ @@ -277,7 +279,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody // Note that this logic is different than the generic \r\n collapsing - // handled in the input stream preprocessor. This logic is here as an + // handled in the input stream preprocessor. This logic is here as an // "authoring convenience" so folks can write: // // <pre> @@ -435,6 +437,8 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) ADVANCE_TO(SelfClosingStartTagState); else if (cc == '>') return emitAndResumeIn(source, DataState); + else if (m_usePreHTML5ParserQuirks && cc == '<') + return emitAndReconsumeIn(source, DataState); else if (isASCIIUpper(cc)) { m_token->appendToName(toLowerCase(cc)); ADVANCE_TO(TagNameState); @@ -876,6 +880,8 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) ADVANCE_TO(SelfClosingStartTagState); else if (cc == '>') return emitAndResumeIn(source, DataState); + else if (m_usePreHTML5ParserQuirks && cc == '<') + return emitAndReconsumeIn(source, DataState); else if (isASCIIUpper(cc)) { m_token->addNewAttribute(); m_token->beginAttributeName(source.numberOfCharactersConsumed()); @@ -908,6 +914,9 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) } else if (cc == '>') { m_token->endAttributeName(source.numberOfCharactersConsumed()); return emitAndResumeIn(source, DataState); + } else if (m_usePreHTML5ParserQuirks && cc == '<') { + m_token->endAttributeName(source.numberOfCharactersConsumed()); + return emitAndReconsumeIn(source, DataState); } else if (isASCIIUpper(cc)) { m_token->appendToAttributeName(toLowerCase(cc)); ADVANCE_TO(AttributeNameState); @@ -933,6 +942,8 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) ADVANCE_TO(BeforeAttributeValueState); else if (cc == '>') return emitAndResumeIn(source, DataState); + else if (m_usePreHTML5ParserQuirks && cc == '<') + return emitAndReconsumeIn(source, DataState); else if (isASCIIUpper(cc)) { m_token->addNewAttribute(); m_token->beginAttributeName(source.numberOfCharactersConsumed()); @@ -1054,7 +1065,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) m_token->appendToAttributeValue(*iter); } // We're supposed to switch back to the attribute value state that - // we were in when we were switched into this state. Rather than + // we were in when we were switched into this state. Rather than // keeping track of this explictly, we observe that the previous // state can be determined by m_additionalAllowedCharacter. if (m_additionalAllowedCharacter == '"') @@ -1075,6 +1086,8 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) ADVANCE_TO(SelfClosingStartTagState); else if (cc == '>') return emitAndResumeIn(source, DataState); + else if (m_usePreHTML5ParserQuirks && cc == '<') + return emitAndReconsumeIn(source, DataState); else if (cc == InputStreamPreprocessor::endOfFileMarker) { parseError(); RECONSUME_IN(DataState); @@ -1213,13 +1226,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) BEGIN_STATE(CommentEndState) { if (cc == '>') return emitAndResumeIn(source, DataState); - else if (isTokenizerWhitespace(cc)) { - parseError(); - m_token->appendToComment('-'); - m_token->appendToComment('-'); - m_token->appendToComment(cc); - ADVANCE_TO(CommentEndSpaceState); - } else if (cc == '!') { + else if (cc == '!') { parseError(); ADVANCE_TO(CommentEndBangState); } else if (cc == '-') { @@ -1260,24 +1267,6 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) } END_STATE() - BEGIN_STATE(CommentEndSpaceState) { - if (isTokenizerWhitespace(cc)) { - m_token->appendToComment(cc); - ADVANCE_TO(CommentEndSpaceState); - } else if (cc == '-') - ADVANCE_TO(CommentEndDashState); - else if (cc == '>') - return emitAndResumeIn(source, DataState); - else if (cc == InputStreamPreprocessor::endOfFileMarker) { - parseError(); - return emitAndReconsumeIn(source, DataState); - } else { - m_token->appendToComment(cc); - ADVANCE_TO(CommentState); - } - } - END_STATE() - BEGIN_STATE(DOCTYPEState) { if (isTokenizerWhitespace(cc)) ADVANCE_TO(BeforeDOCTYPENameState); @@ -1656,6 +1645,23 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token) return false; } +void HTMLTokenizer::updateStateFor(const AtomicString& tagName, Frame* frame) +{ + if (tagName == textareaTag || tagName == titleTag) + setState(RCDATAState); + else if (tagName == plaintextTag) + setState(PLAINTEXTState); + else if (tagName == scriptTag) + setState(ScriptDataState); + else if (tagName == styleTag + || tagName == iframeTag + || tagName == xmpTag + || (tagName == noembedTag && HTMLTreeBuilder::pluginsEnabled(frame)) + || tagName == noframesTag + || (tagName == noscriptTag && HTMLTreeBuilder::scriptEnabled(frame))) + setState(RAWTEXTState); +} + inline bool HTMLTokenizer::temporaryBufferIs(const String& expectedString) { return vectorEqualsString(m_temporaryBuffer, expectedString); diff --git a/WebCore/html/parser/HTMLTokenizer.h b/WebCore/html/parser/HTMLTokenizer.h index bab77f3..f16b049 100644 --- a/WebCore/html/parser/HTMLTokenizer.h +++ b/WebCore/html/parser/HTMLTokenizer.h @@ -36,6 +36,7 @@ namespace WebCore { class Element; +class Frame; class HTMLToken; class HTMLTokenizer : public Noncopyable { @@ -96,7 +97,6 @@ public: CommentEndDashState, CommentEndState, CommentEndBangState, - CommentEndSpaceState, DOCTYPEState, BeforeDOCTYPENameState, DOCTYPENameState, @@ -119,12 +119,12 @@ public: CDATASectionDoubleRightSquareBracketState, }; - static PassOwnPtr<HTMLTokenizer> create() { return adoptPtr(new HTMLTokenizer); } + static PassOwnPtr<HTMLTokenizer> create(bool usePreHTML5ParserQuirks) { return adoptPtr(new HTMLTokenizer(usePreHTML5ParserQuirks)); } ~HTMLTokenizer(); void reset(); - // This function returns true if it emits a token. Otherwise, callers + // This function returns true if it emits a token. Otherwise, callers // must provide the same (in progress) token on the next call (unless // they call reset() first). bool nextToken(SegmentedString&, HTMLToken&); @@ -135,6 +135,22 @@ public: State state() const { return m_state; } void setState(State state) { m_state = state; } + // Updates the tokenizer's state according to the given tag name. This is + // an approximation of how the tree builder would update the tokenizer's + // state. This method is useful for approximating HTML tokenization. To + // get exactly the correct tokenization, you need the real tree builder. + // + // The main failures in the approximation are as follows: + // + // * The first set of character tokens emitted for a <pre> element might + // contain an extra leading newline. + // * The replacement of U+0000 with U+FFFD will not be sensitive to the + // tree builder's insertion mode. + // * CDATA sections in foreign content will be tokenized as bogus comments + // instead of as character tokens. + // + void updateStateFor(const AtomicString& tagName, Frame*); + // Hack to skip leading newline in <pre>/<listing> for authoring ease. // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody void setSkipLeadingNewLineForListing(bool value) { m_skipLeadingNewLineForListing = value; } @@ -177,8 +193,8 @@ private: // Every branch in this function is expensive, so we have a // fast-reject branch for characters that don't require special - // handling. Please run the parser benchmark whenever you touch - // this function. It's very hot. + // handling. Please run the parser benchmark whenever you touch + // this function. It's very hot. static const UChar specialCharacterMask = '\n' | '\r' | '\0'; if (m_nextInputCharacter & ~specialCharacterMask) { m_skipNextNewLine = false; @@ -238,7 +254,7 @@ private: bool m_skipNextNewLine; }; - HTMLTokenizer(); + HTMLTokenizer(bool usePreHTML5ParserQuirks); inline bool processEntity(SegmentedString&); @@ -257,7 +273,7 @@ private: inline bool temporaryBufferIs(const String&); // Sometimes we speculatively consume input characters and we don't - // know whether they represent end tags or RCDATA, etc. These + // know whether they represent end tags or RCDATA, etc. These // functions help manage these state. inline void addToPossibleEndTag(UChar cc); inline void saveEndTagNameIfNeeded(); @@ -269,7 +285,7 @@ private: Vector<UChar, 32> m_appropriateEndTagName; - // m_token is owned by the caller. If nextToken is not on the stack, + // m_token is owned by the caller. If nextToken is not on the stack, // this member might be pointing to unallocated memory. HTMLToken* m_token; int m_lineNumber; @@ -282,7 +298,7 @@ private: Vector<UChar, 32> m_temporaryBuffer; // We occationally want to emit both a character token and an end tag - // token (e.g., when lexing script). We buffer the name of the end tag + // token (e.g., when lexing script). We buffer the name of the end tag // token here so we remember it next time we re-enter the tokenizer. Vector<UChar, 32> m_bufferedEndTagName; @@ -291,6 +307,8 @@ private: // http://www.whatwg.org/specs/web-apps/current-work/#preprocessing-the-input-stream InputStreamPreprocessor m_inputStreamPreprocessor; + + bool m_usePreHTML5ParserQuirks; }; } diff --git a/WebCore/html/parser/HTMLTreeBuilder.cpp b/WebCore/html/parser/HTMLTreeBuilder.cpp index 406bb6c..afac2a0 100644 --- a/WebCore/html/parser/HTMLTreeBuilder.cpp +++ b/WebCore/html/parser/HTMLTreeBuilder.cpp @@ -26,16 +26,17 @@ #include "config.h" #include "HTMLTreeBuilder.h" +#include "CharacterNames.h" #include "Comment.h" #include "DocumentFragment.h" #include "DocumentType.h" -#include "Element.h" #include "Frame.h" #include "HTMLDocument.h" #include "HTMLElementFactory.h" #include "HTMLFormElement.h" #include "HTMLHtmlElement.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "HTMLScriptElement.h" #include "HTMLToken.h" #include "HTMLTokenizer.h" @@ -44,15 +45,10 @@ #include "NotImplemented.h" #include "SVGNames.h" #include "ScriptController.h" -#include "Settings.h" #include "Text.h" #include "XLinkNames.h" #include "XMLNSNames.h" #include "XMLNames.h" -// FIXME: Remove this include once we find a home for the free functions that -// are using it. -#include <wtf/dtoa.h> -#include <wtf/UnusedParam.h> namespace WebCore { @@ -62,42 +58,19 @@ static const int uninitializedLineNumberValue = -1; namespace { -inline bool isTreeBuilderWhitepace(UChar c) +inline bool isHTMLSpaceOrReplacementCharacter(UChar character) { - // FIXME: Consider branch permutations. - return c == '\t' || c == '\x0A' || c == '\x0C' || c == '\x0D' || c == ' '; -} - -inline bool isNotTreeBuilderWhitepace(UChar c) -{ - return !isTreeBuilderWhitepace(c); -} - -inline bool isTreeBuilderWhitepaceOrReplacementCharacter(UChar c) -{ - return isTreeBuilderWhitepace(c) || c == 0xFFFD; -} - -template<bool isSpecialCharacter(UChar c)> -inline bool isAllSpecialCharacters(const String& string) -{ - const UChar* characters = string.characters(); - const unsigned length = string.length(); - for (unsigned i = 0; i < length; ++i) { - if (!isSpecialCharacter(characters[i])) - return false; - } - return true; + return isHTMLSpace(character) || character == replacementCharacter; } inline bool isAllWhitespace(const String& string) { - return isAllSpecialCharacters<isTreeBuilderWhitepace>(string); + return string.isAllSpecialCharacters<isHTMLSpace>(); } inline bool isAllWhitespaceOrReplacementCharacters(const String& string) { - return isAllSpecialCharacters<isTreeBuilderWhitepaceOrReplacementCharacter>(string); + return string.isAllSpecialCharacters<isHTMLSpaceOrReplacementCharacter>(); } bool isNumberedHeaderTag(const AtomicString& tagName) @@ -132,11 +105,14 @@ bool isTableBodyContextTag(const AtomicString& tagName) // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#special bool isSpecialNode(Node* node) { + if (node->hasTagName(SVGNames::foreignObjectTag)) + return true; if (node->namespaceURI() != xhtmlNamespaceURI) return false; - // FIXME: This list is out of sync with the spec. const AtomicString& tagName = node->localName(); return tagName == addressTag + || tagName == appletTag + || tagName == areaTag || tagName == articleTag || tagName == asideTag || tagName == baseTag @@ -146,6 +122,7 @@ bool isSpecialNode(Node* node) || tagName == bodyTag || tagName == brTag || tagName == buttonTag + || tagName == captionTag || tagName == centerTag || tagName == colTag || tagName == colgroupTag @@ -158,6 +135,7 @@ bool isSpecialNode(Node* node) || tagName == dtTag || tagName == embedTag || tagName == fieldsetTag + || tagName == figcaptionTag || tagName == figureTag || tagName == footerTag || tagName == formTag @@ -176,12 +154,14 @@ bool isSpecialNode(Node* node) || tagName == liTag || tagName == linkTag || tagName == listingTag + || tagName == marqueeTag || tagName == menuTag || tagName == metaTag || tagName == navTag || tagName == noembedTag || tagName == noframesTag || tagName == noscriptTag + || tagName == objectTag || tagName == olTag || tagName == pTag || tagName == paramTag @@ -191,8 +171,12 @@ bool isSpecialNode(Node* node) || tagName == sectionTag || tagName == selectTag || tagName == styleTag + || tagName == summaryTag + || tagName == tableTag || isTableBodyContextTag(tagName) + || tagName == tdTag || tagName == textareaTag + || tagName == thTag || tagName == titleTag || tagName == trTag || tagName == ulTag @@ -268,17 +252,17 @@ public: void skipLeadingWhitespace() { - skipLeading<isTreeBuilderWhitepace>(); + skipLeading<isHTMLSpace>(); } String takeLeadingWhitespace() { - return takeLeading<isTreeBuilderWhitepace>(); + return takeLeading<isHTMLSpace>(); } String takeLeadingNonWhitespace() { - return takeLeading<isNotTreeBuilderWhitepace>(); + return takeLeading<isNotHTMLSpace>(); } String takeRemaining() @@ -301,7 +285,7 @@ public: Vector<UChar> whitespace; do { UChar cc = *m_current++; - if (isTreeBuilderWhitepace(cc)) + if (isHTMLSpace(cc)) whitespace.append(cc); } while (m_current < m_end); // Returning the null string when there aren't any whitespace @@ -402,7 +386,7 @@ HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext() } HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission) - : m_dummyDocumentForFragmentParsing(HTMLDocument::create(0, KURL())) + : m_dummyDocumentForFragmentParsing(HTMLDocument::create(0, KURL(), fragment->document()->baseURI())) , m_fragment(fragment) , m_contextElement(contextElement) , m_scriptingPermission(scriptingPermission) @@ -441,25 +425,6 @@ PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(int& scriptStartLine) return m_scriptToProcess.release(); } -HTMLTokenizer::State HTMLTreeBuilder::adjustedLexerState(HTMLTokenizer::State state, const AtomicString& tagName, Frame* frame) -{ - if (tagName == textareaTag || tagName == titleTag) - return HTMLTokenizer::RCDATAState; - - if (tagName == styleTag - || tagName == iframeTag - || tagName == xmpTag - || (tagName == noembedTag && pluginsEnabled(frame)) - || tagName == noframesTag - || (tagName == noscriptTag && scriptEnabled(frame))) - return HTMLTokenizer::RAWTEXTState; - - if (tagName == plaintextTag) - return HTMLTokenizer::PLAINTEXTState; - - return state; -} - void HTMLTreeBuilder::constructTreeFromToken(HTMLToken& rawToken) { AtomicHTMLToken token(rawToken); @@ -1121,8 +1086,6 @@ void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken& token) parseError(token); if (m_tree.form()) return; - // FIXME: This deviates from the spec: - // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10216 m_tree.insertHTMLFormElement(token, true); m_tree.openElements()->pop(); return; @@ -1477,7 +1440,6 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) processStartTag(token); break; case InForeignContentMode: { - // FIXME: We're missing a bunch of if branches here. if (shouldProcessUsingSecondaryInsertionMode(token, m_tree.currentElement())) { processUsingSecondaryInsertionModeAndAdjustInsertionMode(token); return; @@ -1522,8 +1484,10 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) || token.name() == ulTag || token.name() == varTag || (token.name() == fontTag && (token.getAttributeItem(colorAttr) || token.getAttributeItem(faceAttr) || token.getAttributeItem(sizeAttr)))) { - m_tree.openElements()->popUntilElementWithNamespace(xhtmlNamespaceURI); - setInsertionMode(m_secondaryInsertionMode); + parseError(token); + m_tree.openElements()->popUntilForeignContentScopeMarker(); + if (insertionMode() == InForeignContentMode && m_tree.openElements()->hasOnlyHTMLElementsInScope()) + setInsertionMode(m_secondaryInsertionMode); processStartTag(token); return; } @@ -1539,7 +1503,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) break; } case TextMode: - notImplemented(); + ASSERT_NOT_REACHED(); break; } } @@ -1601,21 +1565,6 @@ HTMLElementStack::ElementRecord* HTMLTreeBuilder::furthestBlockForFormattingElem return 0; } -// FIXME: This should have a whitty name. -// FIXME: This must be implemented in many other places in WebCore. -void HTMLTreeBuilder::reparentChildren(Element* oldParent, Element* newParent) -{ - Node* child = oldParent->firstChild(); - while (child) { - Node* nextChild = child->nextSibling(); - oldParent->parserRemoveChild(child); - newParent->parserAddChild(child); - if (newParent->attached() && !child->attached()) - child->attach(); - child = nextChild; - } -} - // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token) { @@ -1708,7 +1657,7 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token) // 8 RefPtr<Element> newElement = m_tree.createHTMLElementFromElementRecord(formattingElementRecord); // 9 - reparentChildren(furthestBlock->element(), newElement.get()); + newElement->takeAllChildrenFrom(furthestBlock->element()); // 10 Element* furthestBlockElement = furthestBlock->element(); // FIXME: All this creation / parserAddChild / attach business should @@ -1886,9 +1835,6 @@ void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken& token) m_tree.openElements()->popUntilPopped(token.name()); m_tree.activeFormattingElements()->clearToLastMarker(); setInsertionMode(InRowMode); - // FIXME: The fragment case of this ASSERT is a spec bug: - // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10338 - ASSERT(m_tree.currentElement()->hasTagName(trTag) || (isParsingFragment() && m_fragmentContext.contextElement()->hasTagName(trTag))); return; } if (token.name() == bodyTag @@ -1902,8 +1848,6 @@ void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken& token) || isTableBodyContextTag(token.name())) { if (!m_tree.openElements()->inTableScope(token.name())) { ASSERT(isParsingFragment()); - // FIXME: It is unclear what the exact ASSERT should be. - // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10098 parseError(token); return; } @@ -2020,10 +1964,6 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token) m_tree.openElements()->popUntilNumberedHeaderElementPopped(); return; } - if (token.name() == "sarcasm") { - notImplemented(); // Take a deep breath. - return; - } if (isFormattingTag(token.name())) { callTheAdoptionAgency(token); return; @@ -2608,14 +2548,15 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) // Fall through case InBodyMode: case InCellMode: - ASSERT(insertionMode() == InBodyMode || insertionMode() == InCellMode); - notImplemented(); // Emit parse error based on what elemtns are still open. + case InCaptionMode: + case InRowMode: + ASSERT(insertionMode() == InBodyMode || insertionMode() == InCellMode || insertionMode() == InCaptionMode || insertionMode() == InRowMode); + notImplemented(); // Emit parse error based on what elements are still open. break; case AfterBodyMode: case AfterAfterBodyMode: ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode); - notImplemented(); - break; + return; case InHeadNoscriptMode: ASSERT(insertionMode() == InHeadNoscriptMode); defaultForInHeadNoscript(); @@ -2647,9 +2588,11 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) return; case InForeignContentMode: parseError(token); - // FIXME: Following the spec would infinitely recurse on <svg><svg> - // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10115 - m_tree.openElements()->popUntilElementWithNamespace(xhtmlNamespaceURI); + m_tree.openElements()->popUntilForeignContentScopeMarker(); + // FIXME: The spec adds the following condition before setting the + // insertion mode. However, this condition causes an infinite loop. + // See http://www.w3.org/Bugs/Public/show_bug.cgi?id=10621 + // if (insertionMode() == InForeignContentMode && m_tree.openElements()->hasOnlyHTMLElementsInScope()) setInsertionMode(m_secondaryInsertionMode); processEndOfFile(token); return; @@ -2658,10 +2601,13 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) processEndOfFile(token); return; case TextMode: - case InCaptionMode: - case InRowMode: - notImplemented(); - break; + parseError(token); + if (m_tree.currentElement()->hasTagName(scriptTag)) + notImplemented(); // mark the script element as "already started". + m_tree.openElements()->pop(); + setInsertionMode(m_originalInsertionMode); + processEndOfFile(token); + return; } ASSERT(m_tree.openElements()->top()); m_tree.openElements()->popAll(); @@ -2813,9 +2759,7 @@ bool HTMLTreeBuilder::scriptEnabled(Frame* frame) { if (!frame) return false; - if (ScriptController* scriptController = frame->script()) - return scriptController->canExecuteScripts(NotAboutToExecuteScript); - return false; + return frame->script()->canExecuteScripts(NotAboutToExecuteScript); } bool HTMLTreeBuilder::pluginsEnabled(Frame* frame) @@ -2825,41 +2769,4 @@ bool HTMLTreeBuilder::pluginsEnabled(Frame* frame) return frame->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin); } -// FIXME: Move this function to a more appropriate place. -String serializeForNumberType(double number) -{ - // According to HTML5, "the best representation of the number n as a floating - // point number" is a string produced by applying ToString() to n. - NumberToStringBuffer buffer; - unsigned length = numberToString(number, buffer); - return String(buffer, length); -} - -// FIXME: Move this function to a more appropriate place. -bool parseToDoubleForNumberType(const String& src, double* out) -{ - // See HTML5 2.4.4.3 `Real numbers.' - - if (src.isEmpty()) - return false; - // String::toDouble() accepts leading + \t \n \v \f \r and SPACE, which are invalid in HTML5. - // So, check the first character. - if (src[0] != '-' && (src[0] < '0' || src[0] > '9')) - return false; - - bool valid = false; - double value = src.toDouble(&valid); - if (!valid) - return false; - // NaN and Infinity are not valid numbers according to the standard. - if (!isfinite(value)) - return false; - // -0 -> 0 - if (!value) - value = 0; - if (out) - *out = value; - return true; -} - } diff --git a/WebCore/html/parser/HTMLTreeBuilder.h b/WebCore/html/parser/HTMLTreeBuilder.h index 4634f0a..d522ea8 100644 --- a/WebCore/html/parser/HTMLTreeBuilder.h +++ b/WebCore/html/parser/HTMLTreeBuilder.h @@ -76,8 +76,6 @@ public: // Done, close any open tags, etc. void finished(); - static HTMLTokenizer::State adjustedLexerState(HTMLTokenizer::State, const AtomicString& tagName, Frame*); - static bool scriptEnabled(Frame*); static bool pluginsEnabled(Frame*); @@ -170,7 +168,6 @@ private: PassRefPtr<NamedNodeMap> attributesForIsindexInput(AtomicHTMLToken&); HTMLElementStack::ElementRecord* furthestBlockForFormattingElement(Element*); - void reparentChildren(Element* oldParent, Element* newParent); void callTheAdoptionAgency(AtomicHTMLToken&); void closeTheCell(); @@ -257,18 +254,6 @@ private: int m_lastScriptElementStartLine; }; -// FIXME: Move these functions to a more appropriate place. - -// Converts the specified string to a floating number. -// If the conversion fails, the return value is false. Take care that leading -// or trailing unnecessary characters make failures. This returns false for an -// empty string input. -// The double* parameter may be 0. -bool parseToDoubleForNumberType(const String&, double*); -// Converts the specified number to a string. This is an implementation of -// HTML5's "algorithm to convert a number to a string" for NUMBER/RANGE types. -String serializeForNumberType(double); - } #endif diff --git a/WebCore/html/parser/HTMLViewSourceParser.cpp b/WebCore/html/parser/HTMLViewSourceParser.cpp index 8a7984d..ace8590 100644 --- a/WebCore/html/parser/HTMLViewSourceParser.cpp +++ b/WebCore/html/parser/HTMLViewSourceParser.cpp @@ -26,15 +26,15 @@ #include "config.h" #include "HTMLViewSourceParser.h" +#include "HTMLDocumentParser.h" #include "HTMLNames.h" -#include "HTMLTreeBuilder.h" #include "HTMLViewSourceDocument.h" namespace WebCore { HTMLViewSourceParser::HTMLViewSourceParser(HTMLViewSourceDocument* document) : DecodedDataDocumentParser(document) - , m_tokenizer(HTMLTokenizer::create()) + , m_tokenizer(HTMLTokenizer::create(HTMLDocumentParser::usePreHTML5ParserQuirks(document))) { } @@ -87,13 +87,7 @@ void HTMLViewSourceParser::updateTokenizerState() return; AtomicString tagName(m_token.name().data(), m_token.name().size()); - m_tokenizer->setState(HTMLTreeBuilder::adjustedLexerState(m_tokenizer->state(), tagName, document()->frame())); - if (tagName == HTMLNames::scriptTag) { - // The tree builder handles scriptTag separately from the other tokenizer - // state adjustments, so we need to handle it separately too. - ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState); - m_tokenizer->setState(HTMLTokenizer::ScriptDataState); - } + m_tokenizer->updateStateFor(tagName, document()->frame()); } void HTMLViewSourceParser::finish() diff --git a/WebCore/html/parser/NestingLevelIncrementer.h b/WebCore/html/parser/NestingLevelIncrementer.h new file mode 100644 index 0000000..c597876 --- /dev/null +++ b/WebCore/html/parser/NestingLevelIncrementer.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 Google, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NestingLevelIncrementer_h +#define NestingLevelIncrementer_h + +namespace WebCore { + +class NestingLevelIncrementer : public Noncopyable { +public: + explicit NestingLevelIncrementer(unsigned& nestingLevel) + : m_nestingLevel(&nestingLevel) + { + ++(*m_nestingLevel); + } + + ~NestingLevelIncrementer() + { + --(*m_nestingLevel); + } + +private: + unsigned* m_nestingLevel; +}; + +} + +#endif |