summaryrefslogtreecommitdiffstats
path: root/WebCore/html
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-09-29 17:32:26 +0100
committerSteve Block <steveblock@google.com>2010-09-29 17:35:08 +0100
commit68513a70bcd92384395513322f1b801e7bf9c729 (patch)
tree161b50f75a5921d61731bb25e730005994fcec85 /WebCore/html
parentfd5c6425ce58eb75211be7718d5dee960842a37e (diff)
downloadexternal_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')
-rw-r--r--WebCore/html/HTMLAnchorElement.cpp229
-rw-r--r--WebCore/html/HTMLAnchorElement.h17
-rw-r--r--WebCore/html/HTMLBodyElement.cpp50
-rw-r--r--WebCore/html/HTMLCanvasElement.cpp2
-rw-r--r--WebCore/html/HTMLDocument.cpp9
-rw-r--r--WebCore/html/HTMLDocument.h7
-rw-r--r--WebCore/html/HTMLElement.cpp32
-rw-r--r--WebCore/html/HTMLFontElement.cpp159
-rw-r--r--WebCore/html/HTMLFormElement.cpp34
-rw-r--r--WebCore/html/HTMLFormElement.h12
-rw-r--r--WebCore/html/HTMLFrameElementBase.cpp53
-rw-r--r--WebCore/html/HTMLFrameElementBase.h22
-rw-r--r--WebCore/html/HTMLFrameOwnerElement.cpp5
-rw-r--r--WebCore/html/HTMLInputElement.cpp222
-rw-r--r--WebCore/html/HTMLInputElement.h61
-rw-r--r--WebCore/html/HTMLMarqueeElement.cpp2
-rw-r--r--WebCore/html/HTMLMarqueeElement.h2
-rw-r--r--WebCore/html/HTMLMediaElement.cpp43
-rw-r--r--WebCore/html/HTMLMediaElement.h2
-rw-r--r--WebCore/html/HTMLMeterElement.cpp2
-rw-r--r--WebCore/html/HTMLObjectElement.cpp22
-rw-r--r--WebCore/html/HTMLPlugInImageElement.h1
-rw-r--r--WebCore/html/HTMLProgressElement.cpp2
-rw-r--r--WebCore/html/HTMLTextAreaElement.cpp2
-rw-r--r--WebCore/html/ImageDocument.cpp12
-rw-r--r--WebCore/html/StepRange.cpp4
-rw-r--r--[-rwxr-xr-x]WebCore/html/canvas/CanvasRenderingContext2D.cpp2
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.cpp14
-rw-r--r--WebCore/html/parser/HTMLConstructionSite.cpp20
-rw-r--r--WebCore/html/parser/HTMLDocumentParser.cpp29
-rw-r--r--WebCore/html/parser/HTMLDocumentParser.h4
-rw-r--r--WebCore/html/parser/HTMLElementStack.cpp27
-rw-r--r--WebCore/html/parser/HTMLElementStack.h2
-rw-r--r--WebCore/html/parser/HTMLParserIdioms.cpp144
-rw-r--r--WebCore/html/parser/HTMLParserIdioms.h66
-rw-r--r--WebCore/html/parser/HTMLPreloadScanner.cpp12
-rw-r--r--WebCore/html/parser/HTMLScriptRunner.cpp37
-rw-r--r--WebCore/html/parser/HTMLScriptRunner.h2
-rw-r--r--WebCore/html/parser/HTMLTokenizer.cpp64
-rw-r--r--WebCore/html/parser/HTMLTokenizer.h36
-rw-r--r--WebCore/html/parser/HTMLTreeBuilder.cpp187
-rw-r--r--WebCore/html/parser/HTMLTreeBuilder.h15
-rw-r--r--WebCore/html/parser/HTMLViewSourceParser.cpp12
-rw-r--r--WebCore/html/parser/NestingLevelIncrementer.h50
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(&paramNames, &paramValues);
- // 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