Merge from Chromium at DEPS revision r198571

This commit was generated by merge_to_master.py.

Change-Id: I3a7f89ea6b8c017335bd52739166aed708cad1e5
diff --git a/Source/core/html/BaseButtonInputType.cpp b/Source/core/html/BaseButtonInputType.cpp
new file mode 100644
index 0000000..75f97ec
--- /dev/null
+++ b/Source/core/html/BaseButtonInputType.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/BaseButtonInputType.h"
+
+#include "HTMLNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/rendering/RenderButton.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+bool BaseButtonInputType::shouldSaveAndRestoreFormControlState() const
+{
+    return false;
+}
+
+bool BaseButtonInputType::appendFormData(FormDataList&, bool) const
+{
+    // Buttons except overridden types are never successful.
+    return false;
+}
+
+RenderObject* BaseButtonInputType::createRenderer(RenderArena* arena, RenderStyle*) const
+{
+    return new (arena) RenderButton(element());
+}
+
+bool BaseButtonInputType::storesValueSeparateFromAttribute()
+{
+    return false;
+}
+
+void BaseButtonInputType::setValue(const String& sanitizedValue, bool, TextFieldEventBehavior)
+{
+    element()->setAttribute(valueAttr, sanitizedValue);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/BaseButtonInputType.h b/Source/core/html/BaseButtonInputType.h
new file mode 100644
index 0000000..1549404
--- /dev/null
+++ b/Source/core/html/BaseButtonInputType.h
@@ -0,0 +1,53 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 BaseButtonInputType_h
+#define BaseButtonInputType_h
+
+#include "core/html/BaseClickableWithKeyInputType.h"
+
+namespace WebCore {
+
+// Base of button, file, image, reset, and submit types.
+class BaseButtonInputType : public BaseClickableWithKeyInputType {
+protected:
+    BaseButtonInputType(HTMLInputElement* element) : BaseClickableWithKeyInputType(element) { }
+
+private:
+    virtual bool shouldSaveAndRestoreFormControlState() const OVERRIDE;
+    virtual bool appendFormData(FormDataList&, bool) const OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
+    virtual bool storesValueSeparateFromAttribute() OVERRIDE;
+    virtual void setValue(const String&, bool, TextFieldEventBehavior) OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // BaseButtonInputType_h
diff --git a/Source/core/html/BaseCheckableInputType.cpp b/Source/core/html/BaseCheckableInputType.cpp
new file mode 100644
index 0000000..6867bd2
--- /dev/null
+++ b/Source/core/html/BaseCheckableInputType.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/BaseCheckableInputType.h"
+
+#include "HTMLNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/html/FormController.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLInputElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+FormControlState BaseCheckableInputType::saveFormControlState() const
+{
+    return FormControlState(element()->checked() ? "on" : "off");
+}
+
+void BaseCheckableInputType::restoreFormControlState(const FormControlState& state)
+{
+    element()->setChecked(state[0] == "on");
+}
+
+bool BaseCheckableInputType::appendFormData(FormDataList& encoding, bool) const
+{
+    if (!element()->checked())
+        return false;
+    encoding.appendData(element()->name(), element()->value());
+    return true;
+}
+
+void BaseCheckableInputType::handleKeydownEvent(KeyboardEvent* event)
+{
+    const String& key = event->keyIdentifier();
+    if (key == "U+0020") {
+        element()->setActive(true, true);
+        // No setDefaultHandled(), because IE dispatches a keypress in this case
+        // and the caller will only dispatch a keypress if we don't call setDefaultHandled().
+    }
+}
+
+void BaseCheckableInputType::handleKeypressEvent(KeyboardEvent* event)
+{
+    if (event->charCode() == ' ') {
+        // Prevent scrolling down the page.
+        event->setDefaultHandled();
+    }
+}
+
+bool BaseCheckableInputType::canSetStringValue() const
+{
+    return false;
+}
+
+// FIXME: Could share this with BaseClickableWithKeyInputType and RangeInputType if we had a common base class.
+void BaseCheckableInputType::accessKeyAction(bool sendMouseEvents)
+{
+    InputType::accessKeyAction(sendMouseEvents);
+
+    element()->dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
+}
+
+String BaseCheckableInputType::fallbackValue() const
+{
+    return "on";
+}
+
+bool BaseCheckableInputType::storesValueSeparateFromAttribute()
+{
+    return false;
+}
+
+void BaseCheckableInputType::setValue(const String& sanitizedValue, bool, TextFieldEventBehavior)
+{
+    element()->setAttribute(valueAttr, sanitizedValue);
+}
+
+bool BaseCheckableInputType::isCheckable()
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/BaseCheckableInputType.h b/Source/core/html/BaseCheckableInputType.h
new file mode 100644
index 0000000..429bd71
--- /dev/null
+++ b/Source/core/html/BaseCheckableInputType.h
@@ -0,0 +1,59 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 BaseCheckableInputType_h
+#define BaseCheckableInputType_h
+
+#include "core/html/InputType.h"
+
+namespace WebCore {
+
+// Base of checkbox and radio types.
+class BaseCheckableInputType : public InputType {
+protected:
+    BaseCheckableInputType(HTMLInputElement* element) : InputType(element) { }
+    virtual void handleKeydownEvent(KeyboardEvent*);
+
+private:
+    virtual FormControlState saveFormControlState() const OVERRIDE;
+    virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
+    virtual bool appendFormData(FormDataList&, bool) const OVERRIDE;
+    virtual void handleKeypressEvent(KeyboardEvent*) OVERRIDE;
+    virtual bool canSetStringValue() const OVERRIDE;
+    virtual void accessKeyAction(bool sendMouseEvents) OVERRIDE;
+    virtual String fallbackValue() const OVERRIDE;
+    virtual bool storesValueSeparateFromAttribute() OVERRIDE;
+    virtual void setValue(const String&, bool, TextFieldEventBehavior) OVERRIDE;
+    virtual bool isCheckable() OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // BaseCheckableInputType_h
diff --git a/Source/core/html/BaseChooserOnlyDateAndTimeInputType.cpp b/Source/core/html/BaseChooserOnlyDateAndTimeInputType.cpp
new file mode 100644
index 0000000..e164ef1
--- /dev/null
+++ b/Source/core/html/BaseChooserOnlyDateAndTimeInputType.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2012 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. 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"
+#if !ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/BaseChooserOnlyDateAndTimeInputType.h"
+
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/page/Chrome.h"
+#include "core/page/Page.h"
+
+namespace WebCore {
+
+BaseChooserOnlyDateAndTimeInputType::~BaseChooserOnlyDateAndTimeInputType()
+{
+    closeDateTimeChooser();
+}
+
+void BaseChooserOnlyDateAndTimeInputType::handleDOMActivateEvent(Event*)
+{
+    if (element()->isDisabledOrReadOnly() || !element()->renderer() || !ScriptController::processingUserGesture())
+        return;
+
+    if (m_dateTimeChooser)
+        return;
+    if (!element()->document()->page())
+        return;
+    Chrome* chrome = element()->document()->page()->chrome();
+    if (!chrome)
+        return;
+    DateTimeChooserParameters parameters;
+    if (!element()->setupDateTimeChooserParameters(parameters))
+        return;
+    m_dateTimeChooser = chrome->openDateTimeChooser(this, parameters);
+}
+
+void BaseChooserOnlyDateAndTimeInputType::createShadowSubtree()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, valueContainerPseudo, ("-webkit-date-and-time-value", AtomicString::ConstructFromLiteral));
+
+    RefPtr<HTMLDivElement> valueContainer = HTMLDivElement::create(element()->document());
+    valueContainer->setPseudo(valueContainerPseudo);
+    element()->userAgentShadowRoot()->appendChild(valueContainer.get());
+    updateAppearance();
+}
+
+void BaseChooserOnlyDateAndTimeInputType::updateAppearance()
+{
+    Node* node = element()->userAgentShadowRoot()->firstChild();
+    if (!node || !node->isHTMLElement())
+        return;
+    String displayValue = visibleValue();
+    if (displayValue.isEmpty()) {
+        // Need to put something to keep text baseline.
+        displayValue = ASCIILiteral(" ");
+    }
+    toHTMLElement(node)->setInnerText(displayValue, ASSERT_NO_EXCEPTION);
+}
+
+void BaseChooserOnlyDateAndTimeInputType::setValue(const String& value, bool valueChanged, TextFieldEventBehavior eventBehavior)
+{
+    BaseDateAndTimeInputType::setValue(value, valueChanged, eventBehavior);
+    if (valueChanged)
+        updateAppearance();
+}
+
+void BaseChooserOnlyDateAndTimeInputType::detach()
+{
+    closeDateTimeChooser();
+}
+
+void BaseChooserOnlyDateAndTimeInputType::didChooseValue(const String& value)
+{
+    element()->setValue(value, DispatchInputAndChangeEvent);
+}
+
+void BaseChooserOnlyDateAndTimeInputType::didEndChooser()
+{
+    m_dateTimeChooser.clear();
+}
+
+void BaseChooserOnlyDateAndTimeInputType::closeDateTimeChooser()
+{
+    if (m_dateTimeChooser)
+        m_dateTimeChooser->endChooser();
+}
+
+void BaseChooserOnlyDateAndTimeInputType::handleKeydownEvent(KeyboardEvent* event)
+{
+    BaseClickableWithKeyInputType::handleKeydownEvent(element(), event);
+}
+
+void BaseChooserOnlyDateAndTimeInputType::handleKeypressEvent(KeyboardEvent* event)
+{
+    BaseClickableWithKeyInputType::handleKeypressEvent(element(), event);
+}
+
+void BaseChooserOnlyDateAndTimeInputType::handleKeyupEvent(KeyboardEvent* event)
+{
+    BaseClickableWithKeyInputType::handleKeyupEvent(*this, event);
+}
+
+void BaseChooserOnlyDateAndTimeInputType::accessKeyAction(bool sendMouseEvents)
+{
+    BaseDateAndTimeInputType::accessKeyAction(sendMouseEvents);
+    BaseClickableWithKeyInputType::accessKeyAction(element(), sendMouseEvents);
+}
+
+bool BaseChooserOnlyDateAndTimeInputType::isMouseFocusable() const
+{
+    return element()->isFocusable();
+}
+
+}
+#endif
diff --git a/Source/core/html/BaseChooserOnlyDateAndTimeInputType.h b/Source/core/html/BaseChooserOnlyDateAndTimeInputType.h
new file mode 100644
index 0000000..645b2e2
--- /dev/null
+++ b/Source/core/html/BaseChooserOnlyDateAndTimeInputType.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 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. 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 BaseChooserOnlyDateAndTimeInputType_h
+#define BaseChooserOnlyDateAndTimeInputType_h
+
+#if !ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/BaseClickableWithKeyInputType.h"
+#include "core/html/BaseDateAndTimeInputType.h"
+#include "core/platform/DateTimeChooser.h"
+#include "core/platform/DateTimeChooserClient.h"
+
+namespace WebCore {
+
+class BaseChooserOnlyDateAndTimeInputType : public BaseDateAndTimeInputType, public DateTimeChooserClient {
+protected:
+    BaseChooserOnlyDateAndTimeInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { }
+    virtual ~BaseChooserOnlyDateAndTimeInputType();
+
+private:
+    void updateAppearance();
+    void closeDateTimeChooser();
+
+    // InputType functions:
+    virtual void createShadowSubtree() OVERRIDE;
+    virtual void detach() OVERRIDE;
+    virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE;
+    virtual void handleDOMActivateEvent(Event*) OVERRIDE;
+    virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
+    virtual void handleKeypressEvent(KeyboardEvent*) OVERRIDE;
+    virtual void handleKeyupEvent(KeyboardEvent*) OVERRIDE;
+    virtual void accessKeyAction(bool sendMouseEvents) OVERRIDE;
+    virtual bool isMouseFocusable() const OVERRIDE;
+
+    // DateTimeChooserClient functions:
+    virtual void didChooseValue(const String&) OVERRIDE;
+    virtual void didEndChooser() OVERRIDE;
+
+    RefPtr<DateTimeChooser> m_dateTimeChooser;
+};
+
+}
+#endif
+#endif
diff --git a/Source/core/html/BaseClickableWithKeyInputType.cpp b/Source/core/html/BaseClickableWithKeyInputType.cpp
new file mode 100644
index 0000000..063f2f9
--- /dev/null
+++ b/Source/core/html/BaseClickableWithKeyInputType.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010, 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/BaseClickableWithKeyInputType.h"
+
+#include "core/dom/KeyboardEvent.h"
+#include "core/html/HTMLInputElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+void BaseClickableWithKeyInputType::handleKeydownEvent(HTMLInputElement* element, KeyboardEvent* event)
+{
+    const String& key = event->keyIdentifier();
+    if (key == "U+0020") {
+        element->setActive(true, true);
+        // No setDefaultHandled(), because IE dispatches a keypress in this case
+        // and the caller will only dispatch a keypress if we don't call setDefaultHandled().
+    }
+}
+
+void BaseClickableWithKeyInputType::handleKeypressEvent(HTMLInputElement* element, KeyboardEvent* event)
+{
+    int charCode = event->charCode();
+    if (charCode == '\r') {
+        element->dispatchSimulatedClick(event);
+        event->setDefaultHandled();
+        return;
+    }
+    if (charCode == ' ') {
+        // Prevent scrolling down the page.
+        event->setDefaultHandled();
+    }
+}
+
+void BaseClickableWithKeyInputType::handleKeyupEvent(InputType& inputType, KeyboardEvent* event)
+{
+    const String& key = event->keyIdentifier();
+    if (key != "U+0020")
+        return;
+    // Simulate mouse click for spacebar for button types.
+    inputType.dispatchSimulatedClickIfActive(event);
+}
+
+// FIXME: Could share this with BaseCheckableInputType and RangeInputType if we had a common base class.
+void BaseClickableWithKeyInputType::accessKeyAction(HTMLInputElement* element, bool sendMouseEvents)
+{
+    element->dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
+}
+
+void BaseClickableWithKeyInputType::handleKeydownEvent(KeyboardEvent* event)
+{
+    handleKeydownEvent(element(), event);
+}
+
+void BaseClickableWithKeyInputType::handleKeypressEvent(KeyboardEvent* event)
+{
+    handleKeypressEvent(element(), event);
+}
+
+void BaseClickableWithKeyInputType::handleKeyupEvent(KeyboardEvent* event)
+{
+    handleKeyupEvent(*this, event);
+}
+
+void BaseClickableWithKeyInputType::accessKeyAction(bool sendMouseEvents)
+{
+    InputType::accessKeyAction(sendMouseEvents);
+    accessKeyAction(element(), sendMouseEvents);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/BaseClickableWithKeyInputType.h b/Source/core/html/BaseClickableWithKeyInputType.h
new file mode 100644
index 0000000..bf76f55
--- /dev/null
+++ b/Source/core/html/BaseClickableWithKeyInputType.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 BaseClickableWithKeyInputType_h
+#define BaseClickableWithKeyInputType_h
+
+#include "core/html/InputType.h"
+
+namespace WebCore {
+
+// Base of input types that dispatches a simulated click on space/return key.
+class BaseClickableWithKeyInputType : public InputType {
+public:
+    static void handleKeydownEvent(HTMLInputElement*, KeyboardEvent*);
+    static void handleKeypressEvent(HTMLInputElement*, KeyboardEvent*);
+    static void handleKeyupEvent(InputType&, KeyboardEvent*);
+    static void accessKeyAction(HTMLInputElement*, bool sendMouseEvents);
+    
+protected:
+    BaseClickableWithKeyInputType(HTMLInputElement* element) : InputType(element) { }
+
+private:
+    virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
+    virtual void handleKeypressEvent(KeyboardEvent*) OVERRIDE;
+    virtual void handleKeyupEvent(KeyboardEvent*) OVERRIDE;
+    virtual void accessKeyAction(bool sendMouseEvents) OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // BaseClickableWithKeyInputType_h
diff --git a/Source/core/html/BaseDateAndTimeInputType.cpp b/Source/core/html/BaseDateAndTimeInputType.cpp
new file mode 100644
index 0000000..e9ec785
--- /dev/null
+++ b/Source/core/html/BaseDateAndTimeInputType.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/BaseDateAndTimeInputType.h"
+
+#include <limits>
+#include "HTMLNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/platform/text/PlatformLocale.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/DateMath.h>
+#include <wtf/MathExtras.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace std;
+
+static const int msecPerMinute = 60 * 1000;
+static const int msecPerSecond = 1000;
+
+double BaseDateAndTimeInputType::valueAsDate() const
+{
+    return valueAsDouble();
+}
+
+void BaseDateAndTimeInputType::setValueAsDate(double value, ExceptionCode&) const
+{
+    element()->setValue(serializeWithMilliseconds(value));
+}
+
+double BaseDateAndTimeInputType::valueAsDouble() const
+{
+    const Decimal value = parseToNumber(element()->value(), Decimal::nan());
+    return value.isFinite() ? value.toDouble() : DateComponents::invalidMilliseconds();
+}
+
+void BaseDateAndTimeInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode&) const
+{
+    element()->setValue(serialize(newValue), eventBehavior);
+}
+
+bool BaseDateAndTimeInputType::typeMismatchFor(const String& value) const
+{
+    return !value.isEmpty() && !parseToDateComponents(value, 0);
+}
+
+bool BaseDateAndTimeInputType::typeMismatch() const
+{
+    return typeMismatchFor(element()->value());
+}
+
+Decimal BaseDateAndTimeInputType::defaultValueForStepUp() const
+{
+    double ms = currentTimeMS();
+    double utcOffset = calculateUTCOffset();
+    double dstOffset = calculateDSTOffset(ms, utcOffset);
+    int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+    return Decimal::fromDouble(ms + (offset * msPerMinute));
+}
+
+bool BaseDateAndTimeInputType::isSteppable() const
+{
+    return true;
+}
+
+Decimal BaseDateAndTimeInputType::parseToNumber(const String& source, const Decimal& defaultValue) const
+{
+    DateComponents date;
+    if (!parseToDateComponents(source, &date))
+        return defaultValue;
+    double msec = date.millisecondsSinceEpoch();
+    ASSERT(std::isfinite(msec));
+    return Decimal::fromDouble(msec);
+}
+
+bool BaseDateAndTimeInputType::parseToDateComponents(const String& source, DateComponents* out) const
+{
+    if (source.isEmpty())
+        return false;
+    DateComponents ignoredResult;
+    if (!out)
+        out = &ignoredResult;
+    return parseToDateComponentsInternal(source.characters(), source.length(), out);
+}
+
+String BaseDateAndTimeInputType::serialize(const Decimal& value) const
+{
+    if (!value.isFinite())
+        return String();
+    DateComponents date;
+    if (!setMillisecondToDateComponents(value.toDouble(), &date))
+        return String();
+    return serializeWithComponents(date);
+}
+
+String BaseDateAndTimeInputType::serializeWithComponents(const DateComponents& date) const
+{
+    Decimal step;
+    if (!element()->getAllowedValueStep(&step))
+        return date.toString();
+    if (step.remainder(msecPerMinute).isZero())
+        return date.toString(DateComponents::None);
+    if (step.remainder(msecPerSecond).isZero())
+        return date.toString(DateComponents::Second);
+    return date.toString(DateComponents::Millisecond);
+}
+
+String BaseDateAndTimeInputType::serializeWithMilliseconds(double value) const
+{
+    return serialize(Decimal::fromDouble(value));
+}
+
+String BaseDateAndTimeInputType::localizeValue(const String& proposedValue) const
+{
+    DateComponents date;
+    if (!parseToDateComponents(proposedValue, &date))
+        return proposedValue;
+
+    String localized = element()->locale().formatDateTime(date);
+    return localized.isEmpty() ? proposedValue : localized;
+}
+
+String BaseDateAndTimeInputType::visibleValue() const
+{
+    return localizeValue(element()->value());
+}
+
+String BaseDateAndTimeInputType::sanitizeValue(const String& proposedValue) const
+{
+    return typeMismatchFor(proposedValue) ? String() : proposedValue;
+}
+
+bool BaseDateAndTimeInputType::supportsReadOnly() const
+{
+    return true;
+}
+
+bool BaseDateAndTimeInputType::shouldRespectListAttribute()
+{
+    return InputType::themeSupportsDataListUI(this);
+}
+
+bool BaseDateAndTimeInputType::valueMissing(const String& value) const
+{
+    return element()->isRequired() && value.isEmpty();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/BaseDateAndTimeInputType.h b/Source/core/html/BaseDateAndTimeInputType.h
new file mode 100644
index 0000000..e68495c
--- /dev/null
+++ b/Source/core/html/BaseDateAndTimeInputType.h
@@ -0,0 +1,71 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 BaseDateAndTimeInputType_h
+#define BaseDateAndTimeInputType_h
+
+#include "core/html/InputType.h"
+#include "core/platform/DateComponents.h"
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+// A super class of date, datetime, datetime-local, month, time, and week types.
+class BaseDateAndTimeInputType : public InputType {
+protected:
+    BaseDateAndTimeInputType(HTMLInputElement* element) : InputType(element) { }
+    virtual Decimal parseToNumber(const String&, const Decimal&) const OVERRIDE;
+    virtual bool parseToDateComponents(const String&, DateComponents*) const OVERRIDE;
+    virtual String sanitizeValue(const String&) const OVERRIDE;
+    virtual String serialize(const Decimal&) const OVERRIDE;
+    String serializeWithComponents(const DateComponents&) const;
+    virtual bool setMillisecondToDateComponents(double, DateComponents*) const = 0;
+    virtual String visibleValue() const OVERRIDE;
+
+private:
+    virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const = 0;
+    virtual DateComponents::Type dateType() const = 0;
+    virtual double valueAsDate() const OVERRIDE;
+    virtual void setValueAsDate(double, ExceptionCode&) const OVERRIDE;
+    virtual double valueAsDouble() const OVERRIDE;
+    virtual void setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
+    virtual bool typeMismatchFor(const String&) const OVERRIDE;
+    virtual bool typeMismatch() const OVERRIDE;
+    virtual bool valueMissing(const String&) const OVERRIDE;
+    virtual Decimal defaultValueForStepUp() const OVERRIDE;
+    virtual bool isSteppable() const OVERRIDE;
+    virtual String serializeWithMilliseconds(double) const;
+    virtual String localizeValue(const String&) const OVERRIDE;
+    virtual bool supportsReadOnly() const OVERRIDE;
+    virtual bool shouldRespectListAttribute() OVERRIDE;
+};
+
+} // namespace WebCore
+#endif // BaseDateAndTimeInputType_h
diff --git a/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.cpp b/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.cpp
new file mode 100644
index 0000000..701fddf
--- /dev/null
+++ b/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.cpp
@@ -0,0 +1,588 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/BaseMultipleFieldsDateAndTimeInputType.h"
+
+#include "CSSValueKeywords.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/DateTimeFieldsState.h"
+#include "core/html/FormController.h"
+#include "core/html/HTMLDataListElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLOptionElement.h"
+#include "core/html/shadow/PickerIndicatorElement.h"
+#include "core/page/FocusController.h"
+#include "core/page/Page.h"
+#include "core/platform/DateComponents.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/text/DateTimeFormat.h"
+#include "core/platform/text/PlatformLocale.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/DateMath.h>
+
+namespace WebCore {
+
+class DateTimeFormatValidator : public DateTimeFormat::TokenHandler {
+public:
+    DateTimeFormatValidator()
+        : m_hasYear(false)
+        , m_hasMonth(false)
+        , m_hasWeek(false)
+        , m_hasDay(false)
+        , m_hasAMPM(false)
+        , m_hasHour(false)
+        , m_hasMinute(false)
+        , m_hasSecond(false) { }
+
+    virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL;
+    virtual void visitLiteral(const String&) OVERRIDE FINAL { }
+
+    bool validateFormat(const String& format, const BaseMultipleFieldsDateAndTimeInputType&);
+
+private:
+    bool m_hasYear;
+    bool m_hasMonth;
+    bool m_hasWeek;
+    bool m_hasDay;
+    bool m_hasAMPM;
+    bool m_hasHour;
+    bool m_hasMinute;
+    bool m_hasSecond;
+};
+
+void DateTimeFormatValidator::visitField(DateTimeFormat::FieldType fieldType, int)
+{
+    switch (fieldType) {
+    case DateTimeFormat::FieldTypeYear:
+        m_hasYear = true;
+        break;
+    case DateTimeFormat::FieldTypeMonth: // Fallthrough.
+    case DateTimeFormat::FieldTypeMonthStandAlone:
+        m_hasMonth = true;
+        break;
+    case DateTimeFormat::FieldTypeWeekOfYear:
+        m_hasWeek = true;
+        break;
+    case DateTimeFormat::FieldTypeDayOfMonth:
+        m_hasDay = true;
+        break;
+    case DateTimeFormat::FieldTypePeriod:
+        m_hasAMPM = true;
+        break;
+    case DateTimeFormat::FieldTypeHour11: // Fallthrough.
+    case DateTimeFormat::FieldTypeHour12:
+        m_hasHour = true;
+        break;
+    case DateTimeFormat::FieldTypeHour23: // Fallthrough.
+    case DateTimeFormat::FieldTypeHour24:
+        m_hasHour = true;
+        m_hasAMPM = true;
+        break;
+    case DateTimeFormat::FieldTypeMinute:
+        m_hasMinute = true;
+        break;
+    case DateTimeFormat::FieldTypeSecond:
+        m_hasSecond = true;
+        break;
+    default:
+        break;
+    }
+}
+
+bool DateTimeFormatValidator::validateFormat(const String& format, const BaseMultipleFieldsDateAndTimeInputType& inputType)
+{
+    if (!DateTimeFormat::parse(format, *this))
+        return false;
+    return inputType.isValidFormat(m_hasYear, m_hasMonth, m_hasWeek, m_hasDay, m_hasAMPM, m_hasHour, m_hasMinute, m_hasSecond);
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::didBlurFromControl()
+{
+    // We don't need to call blur(). This function is called when control
+    // lost focus.
+
+    // Remove focus ring by CSS "focus" pseudo class.
+    element()->setFocus(false);
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::didFocusOnControl()
+{
+    // We don't need to call focus(). This function is called when control
+    // got focus.
+
+    // Add focus ring by CSS "focus" pseudo class.
+    element()->setFocus(true);
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::editControlValueChanged()
+{
+    RefPtr<HTMLInputElement> input(element());
+    String oldValue = input->value();
+    String newValue = sanitizeValue(m_dateTimeEditElement->value());
+    // Even if oldValue is null and newValue is "", we should assume they are same.
+    if ((oldValue.isEmpty() && newValue.isEmpty()) || oldValue == newValue)
+        input->setNeedsValidityCheck();
+    else {
+        input->setValueInternal(newValue, DispatchNoEvent);
+        input->setNeedsStyleRecalc();
+        input->dispatchFormControlInputEvent();
+        input->dispatchFormControlChangeEvent();
+    }
+    input->notifyFormStateChanged();
+    input->updateClearButtonVisibility();
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::hasCustomFocusLogic() const
+{
+    return false;
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerDisabled() const
+{
+    return element()->isDisabledFormControl();
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerReadOnly() const
+{
+    return element()->isReadOnly();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectSpinButtonOwner()
+{
+    if (m_dateTimeEditElement)
+        m_dateTimeEditElement->focusIfNoFocus();
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToMouseEvents()
+{
+    return !element()->isDisabledOrReadOnly();
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToWheelEvents()
+{
+    if (!shouldSpinButtonRespondToMouseEvents())
+        return false;
+    return m_dateTimeEditElement && m_dateTimeEditElement->hasFocusedField();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepDown()
+{
+    if (m_dateTimeEditElement)
+        m_dateTimeEditElement->stepDown();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepUp()
+{
+    if (m_dateTimeEditElement)
+        m_dateTimeEditElement->stepUp();
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::isPickerIndicatorOwnerDisabledOrReadOnly() const
+{
+    return element()->isDisabledOrReadOnly();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorChooseValue(const String& value)
+{
+    if (element()->isValidValue(value)) {
+        element()->setValue(value, DispatchInputAndChangeEvent);
+        return;
+    }
+
+    if (!m_dateTimeEditElement)
+        return;
+    DateComponents date;
+    unsigned end;
+    if (date.parseDate(value.characters(), value.length(), 0, end) && end == value.length())
+        m_dateTimeEditElement->setOnlyYearMonthDay(date);
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
+{
+    return element()->setupDateTimeChooserParameters(parameters);
+}
+
+BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement* element)
+    : BaseDateAndTimeInputType(element)
+    , m_dateTimeEditElement(0)
+    , m_spinButtonElement(0)
+    , m_clearButton(0)
+    , m_pickerIndicatorElement(0)
+    , m_pickerIndicatorIsVisible(false)
+    , m_pickerIndicatorIsAlwaysVisible(false)
+{
+}
+
+BaseMultipleFieldsDateAndTimeInputType::~BaseMultipleFieldsDateAndTimeInputType()
+{
+    if (m_spinButtonElement)
+        m_spinButtonElement->removeSpinButtonOwner();
+    if (m_clearButton)
+        m_clearButton->removeClearButtonOwner();
+    if (m_dateTimeEditElement)
+        m_dateTimeEditElement->removeEditControlOwner();
+    if (m_pickerIndicatorElement)
+        m_pickerIndicatorElement->removePickerIndicatorOwner();
+}
+
+String BaseMultipleFieldsDateAndTimeInputType::badInputText() const
+{
+    return validationMessageBadInputForDateTimeText();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::blur()
+{
+    if (m_dateTimeEditElement)
+        m_dateTimeEditElement->blurByOwner();
+}
+
+PassRefPtr<RenderStyle> BaseMultipleFieldsDateAndTimeInputType::customStyleForRenderer(PassRefPtr<RenderStyle> originalStyle)
+{
+    EDisplay originalDisplay = originalStyle->display();
+    EDisplay newDisplay = originalDisplay;
+    if (originalDisplay == INLINE || originalDisplay == INLINE_BLOCK)
+        newDisplay = INLINE_FLEX;
+    else if (originalDisplay == BLOCK)
+        newDisplay = FLEX;
+    TextDirection contentDirection = element()->locale().isRTL() ? RTL : LTR;
+    if (originalStyle->direction() == contentDirection && originalDisplay == newDisplay)
+        return originalStyle;
+
+    RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
+    style->setDirection(contentDirection);
+    style->setDisplay(newDisplay);
+    return style.release();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::createShadowSubtree()
+{
+    ASSERT(element()->shadow());
+
+    Document* document = element()->document();
+    ContainerNode* container = element()->userAgentShadowRoot();
+
+    RefPtr<DateTimeEditElement> dateTimeEditElement(DateTimeEditElement::create(document, *this));
+    m_dateTimeEditElement = dateTimeEditElement.get();
+    container->appendChild(m_dateTimeEditElement);
+    updateInnerTextValue();
+
+    RefPtr<ClearButtonElement> clearButton = ClearButtonElement::create(document, *this);
+    m_clearButton = clearButton.get();
+    container->appendChild(clearButton);
+
+    RefPtr<SpinButtonElement> spinButton = SpinButtonElement::create(document, *this);
+    m_spinButtonElement = spinButton.get();
+    container->appendChild(spinButton);
+
+    bool shouldAddPickerIndicator = false;
+#if ENABLE(DATALIST_ELEMENT)
+    if (InputType::themeSupportsDataListUI(this))
+        shouldAddPickerIndicator = true;
+#endif
+    RefPtr<RenderTheme> theme = document->page() ? document->page()->theme() : RenderTheme::defaultTheme();
+    if (theme->supportsCalendarPicker(formControlType())) {
+        shouldAddPickerIndicator = true;
+        m_pickerIndicatorIsAlwaysVisible = true;
+    }
+    if (shouldAddPickerIndicator) {
+        RefPtr<PickerIndicatorElement> pickerElement = PickerIndicatorElement::create(document, *this);
+        m_pickerIndicatorElement = pickerElement.get();
+        container->appendChild(m_pickerIndicatorElement);
+        m_pickerIndicatorIsVisible = true;
+        updatePickerIndicatorVisibility();
+    }
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::destroyShadowSubtree()
+{
+    if (m_spinButtonElement) {
+        m_spinButtonElement->removeSpinButtonOwner();
+        m_spinButtonElement = 0;
+    }
+    if (m_clearButton) {
+        m_clearButton->removeClearButtonOwner();
+        m_clearButton = 0;
+    }
+    if (m_dateTimeEditElement) {
+        m_dateTimeEditElement->removeEditControlOwner();
+        m_dateTimeEditElement = 0;
+    }
+    if (m_pickerIndicatorElement) {
+        m_pickerIndicatorElement->removePickerIndicatorOwner();
+        m_pickerIndicatorElement = 0;
+    }
+    BaseDateAndTimeInputType::destroyShadowSubtree();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::handleFocusEvent(Node* oldFocusedNode, FocusDirection direction)
+{
+    if (!m_dateTimeEditElement)
+        return;
+    if (direction == FocusDirectionBackward) {
+        if (element()->document()->page())
+            element()->document()->page()->focusController()->advanceFocus(direction, 0);
+    } else if (direction == FocusDirectionNone) {
+        m_dateTimeEditElement->focusByOwner(oldFocusedNode);
+    } else
+        m_dateTimeEditElement->focusByOwner();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::forwardEvent(Event* event)
+{
+    if (m_spinButtonElement) {
+        m_spinButtonElement->forwardEvent(event);
+        if (event->defaultHandled())
+            return;
+    }
+        
+    if (m_dateTimeEditElement)
+        m_dateTimeEditElement->defaultEventHandler(event);
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::disabledAttributeChanged()
+{
+    m_spinButtonElement->releaseCapture();
+    m_clearButton->releaseCapture();
+    if (m_dateTimeEditElement)
+        m_dateTimeEditElement->disabledStateChanged();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::requiredAttributeChanged()
+{
+    m_clearButton->releaseCapture();
+    updateClearButtonVisibility();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::handleKeydownEvent(KeyboardEvent* event)
+{
+    Document* document = element()->document();
+    RefPtr<RenderTheme> theme = document->page() ? document->page()->theme() : RenderTheme::defaultTheme();
+    if (m_pickerIndicatorIsVisible
+        && ((event->keyIdentifier() == "Down" && event->getModifierState("Alt")) || (theme->shouldOpenPickerWithF4Key() && event->keyIdentifier() == "F4"))) {
+        if (m_pickerIndicatorElement)
+            m_pickerIndicatorElement->openPopup();
+        event->setDefaultHandled();
+    } else
+        forwardEvent(event);
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::hasBadInput() const
+{
+    return element()->value().isEmpty() && m_dateTimeEditElement && m_dateTimeEditElement->anyEditableFieldsHaveValues();
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::isKeyboardFocusable(KeyboardEvent*) const
+{
+    return element()->isFocusable();
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::isMouseFocusable() const
+{
+    return element()->isFocusable();
+}
+
+AtomicString BaseMultipleFieldsDateAndTimeInputType::localeIdentifier() const
+{
+    return element()->computeInheritedLanguage();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::minOrMaxAttributeChanged()
+{
+    updateInnerTextValue();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::readonlyAttributeChanged()
+{
+    m_spinButtonElement->releaseCapture();
+    m_clearButton->releaseCapture();
+    if (m_dateTimeEditElement)
+        m_dateTimeEditElement->readOnlyStateChanged();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::restoreFormControlState(const FormControlState& state)
+{
+    if (!m_dateTimeEditElement)
+        return;
+    DateTimeFieldsState dateTimeFieldsState = DateTimeFieldsState::restoreFormControlState(state);
+    m_dateTimeEditElement->setValueAsDateTimeFieldsState(dateTimeFieldsState);
+    element()->setValueInternal(sanitizeValue(m_dateTimeEditElement->value()), DispatchNoEvent);
+    updateClearButtonVisibility();
+}
+
+FormControlState BaseMultipleFieldsDateAndTimeInputType::saveFormControlState() const
+{
+    if (!m_dateTimeEditElement)
+        return FormControlState();
+
+    return m_dateTimeEditElement->valueAsDateTimeFieldsState().saveFormControlState();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
+{
+    InputType::setValue(sanitizedValue, valueChanged, eventBehavior);
+    if (valueChanged || (sanitizedValue.isEmpty() && m_dateTimeEditElement && m_dateTimeEditElement->anyEditableFieldsHaveValues())) {
+        updateInnerTextValue();
+        element()->setNeedsValidityCheck();
+    }
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::shouldUseInputMethod() const
+{
+    return false;
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::stepAttributeChanged()
+{
+    updateInnerTextValue();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::updateInnerTextValue()
+{
+    if (!m_dateTimeEditElement)
+        return;
+
+    DateTimeEditElement::LayoutParameters layoutParameters(element()->locale(), createStepRange(AnyIsDefaultStep));
+
+    DateComponents date;
+    const bool hasValue = parseToDateComponents(element()->value(), &date);
+    if (!hasValue)
+        setMillisecondToDateComponents(layoutParameters.stepRange.minimum().toDouble(), &date);
+
+    setupLayoutParameters(layoutParameters, date);
+
+    const AtomicString pattern = m_dateTimeEditElement->fastGetAttribute(HTMLNames::patternAttr);
+    if (!pattern.isEmpty())
+        layoutParameters.dateTimeFormat = pattern;
+
+    if (!DateTimeFormatValidator().validateFormat(layoutParameters.dateTimeFormat, *this))
+        layoutParameters.dateTimeFormat = layoutParameters.fallbackDateTimeFormat;
+
+    if (hasValue)
+        m_dateTimeEditElement->setValueAsDate(layoutParameters, date);
+    else
+        m_dateTimeEditElement->setEmptyValue(layoutParameters, date);
+    updateClearButtonVisibility();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::valueAttributeChanged()
+{
+    if (!element()->hasDirtyValue())
+        updateInnerTextValue();
+}
+
+#if ENABLE(DATALIST_ELEMENT)
+void BaseMultipleFieldsDateAndTimeInputType::listAttributeTargetChanged()
+{
+    updatePickerIndicatorVisibility();
+}
+#endif
+
+void BaseMultipleFieldsDateAndTimeInputType::updatePickerIndicatorVisibility()
+{
+    if (m_pickerIndicatorIsAlwaysVisible) {
+        showPickerIndicator();
+        return;
+    }
+#if ENABLE(DATALIST_ELEMENT)
+    if (HTMLDataListElement* dataList = element()->dataList()) {
+        RefPtr<HTMLCollection> options = dataList->options();
+        for (unsigned i = 0; HTMLOptionElement* option = toHTMLOptionElement(options->item(i)); ++i) {
+            if (element()->isValidValue(option->value())) {
+                showPickerIndicator();
+                return;
+            }
+        }
+    }
+    hidePickerIndicator();
+#endif
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::hidePickerIndicator()
+{
+    if (!m_pickerIndicatorIsVisible)
+        return;
+    m_pickerIndicatorIsVisible = false;
+    ASSERT(m_pickerIndicatorElement);
+    m_pickerIndicatorElement->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::showPickerIndicator()
+{
+    if (m_pickerIndicatorIsVisible)
+        return;
+    m_pickerIndicatorIsVisible = true;
+    ASSERT(m_pickerIndicatorElement);
+    m_pickerIndicatorElement->removeInlineStyleProperty(CSSPropertyDisplay);
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::shouldHaveSecondField(const DateComponents& date) const
+{
+    StepRange stepRange = createStepRange(AnyIsDefaultStep);
+    return date.second() || date.millisecond()
+        || !stepRange.minimum().remainder(static_cast<int>(msPerMinute)).isZero()
+        || !stepRange.step().remainder(static_cast<int>(msPerMinute)).isZero();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectClearButtonOwner()
+{
+    element()->focus();
+}
+
+bool BaseMultipleFieldsDateAndTimeInputType::shouldClearButtonRespondToMouseEvents()
+{
+    return !element()->isDisabledOrReadOnly() && !element()->isRequired();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::clearValue()
+{
+    RefPtr<HTMLInputElement> input(element());
+    input->setValue("", DispatchInputAndChangeEvent);
+    input->updateClearButtonVisibility();
+}
+
+void BaseMultipleFieldsDateAndTimeInputType::updateClearButtonVisibility()
+{
+    if (!m_clearButton)
+        return;
+
+    if (element()->isRequired() || !m_dateTimeEditElement->anyEditableFieldsHaveValues())
+        m_clearButton->setInlineStyleProperty(CSSPropertyVisibility, CSSValueHidden);
+    else
+        m_clearButton->removeInlineStyleProperty(CSSPropertyVisibility);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.h b/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.h
new file mode 100644
index 0000000..033bb89
--- /dev/null
+++ b/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.h
@@ -0,0 +1,130 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 BaseMultipleFieldsDateAndTimeInputType_h
+#define BaseMultipleFieldsDateAndTimeInputType_h
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/BaseDateAndTimeInputType.h"
+
+#include "core/html/shadow/ClearButtonElement.h"
+#include "core/html/shadow/DateTimeEditElement.h"
+#include "core/html/shadow/PickerIndicatorElement.h"
+#include "core/html/shadow/SpinButtonElement.h"
+
+namespace WebCore {
+
+struct DateTimeChooserParameters;
+
+class BaseMultipleFieldsDateAndTimeInputType
+    : public BaseDateAndTimeInputType
+    , protected DateTimeEditElement::EditControlOwner
+    , protected PickerIndicatorElement::PickerIndicatorOwner
+    , protected SpinButtonElement::SpinButtonOwner
+    , protected ClearButtonElement::ClearButtonOwner {
+public:
+    virtual bool isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const = 0;
+
+protected:
+    BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement*);
+    virtual ~BaseMultipleFieldsDateAndTimeInputType();
+
+    virtual void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const = 0;
+    bool shouldHaveSecondField(const DateComponents&) const;
+
+private:
+    // DateTimeEditElement::EditControlOwner functions
+    virtual void didBlurFromControl() OVERRIDE FINAL;
+    virtual void didFocusOnControl() OVERRIDE FINAL;
+    virtual void editControlValueChanged() OVERRIDE FINAL;
+    virtual bool isEditControlOwnerDisabled() const OVERRIDE FINAL;
+    virtual bool isEditControlOwnerReadOnly() const OVERRIDE FINAL;
+    virtual AtomicString localeIdentifier() const OVERRIDE FINAL;
+
+    // SpinButtonElement::SpinButtonOwner functions.
+    virtual void focusAndSelectSpinButtonOwner() OVERRIDE;
+    virtual bool shouldSpinButtonRespondToMouseEvents() OVERRIDE;
+    virtual bool shouldSpinButtonRespondToWheelEvents() OVERRIDE;
+    virtual void spinButtonStepDown() OVERRIDE;
+    virtual void spinButtonStepUp() OVERRIDE;
+
+    // PickerIndicatorElement::PickerIndicatorOwner functions
+    virtual bool isPickerIndicatorOwnerDisabledOrReadOnly() const OVERRIDE FINAL;
+    virtual void pickerIndicatorChooseValue(const String&) OVERRIDE FINAL;
+    virtual bool setupDateTimeChooserParameters(DateTimeChooserParameters&) OVERRIDE FINAL;
+
+    // ClearButtonElement::ClearButtonOwner functions.
+    virtual void focusAndSelectClearButtonOwner() OVERRIDE;
+    virtual bool shouldClearButtonRespondToMouseEvents() OVERRIDE;
+    virtual void clearValue() OVERRIDE;
+
+    // InputType functions
+    virtual String badInputText() const OVERRIDE;
+    virtual void blur() OVERRIDE FINAL;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer(PassRefPtr<RenderStyle>) OVERRIDE;
+    virtual void createShadowSubtree() OVERRIDE FINAL;
+    virtual void destroyShadowSubtree() OVERRIDE FINAL;
+    virtual void disabledAttributeChanged() OVERRIDE FINAL;
+    virtual void forwardEvent(Event*) OVERRIDE FINAL;
+    virtual void handleFocusEvent(Node* oldFocusedNode, FocusDirection) OVERRIDE;
+    virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE FINAL;
+    virtual bool hasBadInput() const OVERRIDE;
+    virtual bool hasCustomFocusLogic() const OVERRIDE FINAL;
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const OVERRIDE FINAL;
+    virtual bool isMouseFocusable() const OVERRIDE FINAL;
+    virtual void minOrMaxAttributeChanged() OVERRIDE FINAL;
+    virtual void readonlyAttributeChanged() OVERRIDE FINAL;
+    virtual void requiredAttributeChanged() OVERRIDE FINAL;
+    virtual void restoreFormControlState(const FormControlState&) OVERRIDE FINAL;
+    virtual FormControlState saveFormControlState() const OVERRIDE FINAL;
+    virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE FINAL;
+    virtual bool shouldUseInputMethod() const OVERRIDE FINAL;
+    virtual void stepAttributeChanged() OVERRIDE FINAL;
+    virtual void updateInnerTextValue() OVERRIDE FINAL;
+    virtual void valueAttributeChanged() OVERRIDE;
+    virtual void listAttributeTargetChanged() OVERRIDE FINAL;
+    virtual void updateClearButtonVisibility() OVERRIDE FINAL;
+
+    void showPickerIndicator();
+    void hidePickerIndicator();
+    void updatePickerIndicatorVisibility();
+
+    DateTimeEditElement* m_dateTimeEditElement;
+    SpinButtonElement* m_spinButtonElement;
+    ClearButtonElement* m_clearButton;
+    PickerIndicatorElement* m_pickerIndicatorElement;
+    bool m_pickerIndicatorIsVisible;
+    bool m_pickerIndicatorIsAlwaysVisible;
+};
+
+} // namespace WebCore
+
+#endif
+#endif // BaseMultipleFieldsDateAndTimeInputType_h
diff --git a/Source/core/html/BaseTextInputType.cpp b/Source/core/html/BaseTextInputType.cpp
new file mode 100644
index 0000000..f51a7bd
--- /dev/null
+++ b/Source/core/html/BaseTextInputType.cpp
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2009 Michelangelo De Simone <micdesim@gmail.com>
+ * Copyright (C) 2010 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/BaseTextInputType.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/platform/text/RegularExpression.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+bool BaseTextInputType::isTextType() const
+{
+    return true;
+}
+
+bool BaseTextInputType::patternMismatch(const String& value) const
+{
+    const AtomicString& rawPattern = element()->fastGetAttribute(patternAttr);
+    // Empty values can't be mismatched
+    if (rawPattern.isNull() || value.isEmpty() || !RegularExpression(rawPattern, TextCaseSensitive).isValid())
+        return false;
+    String pattern = "^(?:" + rawPattern + ")$";
+    int matchLength = 0;
+    int valueLength = value.length();
+    int matchOffset = RegularExpression(pattern, TextCaseSensitive).match(value, 0, &matchLength);
+    return matchOffset || matchLength != valueLength;
+}
+
+bool BaseTextInputType::supportsPlaceholder() const
+{
+    return true;
+}
+
+bool BaseTextInputType::supportsSelectionAPI() const
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/BaseTextInputType.h b/Source/core/html/BaseTextInputType.h
new file mode 100644
index 0000000..6d1737b
--- /dev/null
+++ b/Source/core/html/BaseTextInputType.h
@@ -0,0 +1,53 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 BaseTextInputType_h
+#define BaseTextInputType_h
+
+#include "core/html/TextFieldInputType.h"
+
+namespace WebCore {
+
+// Base of email, password, search, tel, text, and URL types.
+// They support maxlength, selection functions, and so on.
+class BaseTextInputType : public TextFieldInputType {
+protected:
+    BaseTextInputType(HTMLInputElement* element) : TextFieldInputType(element) { }
+
+private:
+    virtual bool isTextType() const OVERRIDE;
+    virtual bool patternMismatch(const String&) const OVERRIDE;
+    virtual bool supportsPlaceholder() const OVERRIDE;
+    virtual bool supportsSelectionAPI() const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // BaseTextInputType_h
diff --git a/Source/core/html/ButtonInputType.cpp b/Source/core/html/ButtonInputType.cpp
new file mode 100644
index 0000000..787dcae
--- /dev/null
+++ b/Source/core/html/ButtonInputType.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/ButtonInputType.h"
+
+#include "core/html/InputTypeNames.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<InputType> ButtonInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new ButtonInputType(element));
+}
+
+const AtomicString& ButtonInputType::formControlType() const
+{
+    return InputTypeNames::button();
+}
+
+bool ButtonInputType::supportsValidation() const
+{
+    return false;
+}
+
+bool ButtonInputType::isTextButton() const
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/ButtonInputType.h b/Source/core/html/ButtonInputType.h
new file mode 100644
index 0000000..6ad4098
--- /dev/null
+++ b/Source/core/html/ButtonInputType.h
@@ -0,0 +1,51 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 ButtonInputType_h
+#define ButtonInputType_h
+
+#include "core/html/BaseButtonInputType.h"
+
+namespace WebCore {
+
+class ButtonInputType : public BaseButtonInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    ButtonInputType(HTMLInputElement* element) : BaseButtonInputType(element) { }
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool supportsValidation() const OVERRIDE;
+    virtual bool isTextButton() const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // ButtonInputType_h
diff --git a/Source/core/html/CheckboxInputType.cpp b/Source/core/html/CheckboxInputType.cpp
new file mode 100644
index 0000000..376e0e4
--- /dev/null
+++ b/Source/core/html/CheckboxInputType.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/CheckboxInputType.h"
+
+#include "core/dom/KeyboardEvent.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/platform/LocalizedStrings.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<InputType> CheckboxInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new CheckboxInputType(element));
+}
+
+const AtomicString& CheckboxInputType::formControlType() const
+{
+    return InputTypeNames::checkbox();
+}
+
+bool CheckboxInputType::valueMissing(const String&) const
+{
+    return element()->isRequired() && !element()->checked();
+}
+
+String CheckboxInputType::valueMissingText() const
+{
+    return validationMessageValueMissingForCheckboxText();
+}
+
+void CheckboxInputType::handleKeyupEvent(KeyboardEvent* event)
+{
+    const String& key = event->keyIdentifier();
+    if (key != "U+0020")
+        return;
+    dispatchSimulatedClickIfActive(event);
+}
+
+PassOwnPtr<ClickHandlingState> CheckboxInputType::willDispatchClick()
+{
+    // An event handler can use preventDefault or "return false" to reverse the checking we do here.
+    // The ClickHandlingState object contains what we need to undo what we did here in didDispatchClick.
+
+    OwnPtr<ClickHandlingState> state = adoptPtr(new ClickHandlingState);
+
+    state->checked = element()->checked();
+    state->indeterminate = element()->indeterminate();
+
+    if (state->indeterminate)
+        element()->setIndeterminate(false);
+
+    element()->setChecked(!state->checked, DispatchChangeEvent);
+
+    return state.release();
+}
+
+void CheckboxInputType::didDispatchClick(Event* event, const ClickHandlingState& state)
+{
+    if (event->defaultPrevented() || event->defaultHandled()) {
+        element()->setIndeterminate(state.indeterminate);
+        element()->setChecked(state.checked);
+    }
+
+    // The work we did in willDispatchClick was default handling.
+    event->setDefaultHandled();
+}
+
+bool CheckboxInputType::isCheckbox() const
+{
+    return true;
+}
+
+bool CheckboxInputType::supportsIndeterminateAppearance() const
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/CheckboxInputType.h b/Source/core/html/CheckboxInputType.h
new file mode 100644
index 0000000..a4b7701
--- /dev/null
+++ b/Source/core/html/CheckboxInputType.h
@@ -0,0 +1,56 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 CheckboxInputType_h
+#define CheckboxInputType_h
+
+#include "core/html/BaseCheckableInputType.h"
+
+namespace WebCore {
+
+class CheckboxInputType : public BaseCheckableInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    CheckboxInputType(HTMLInputElement* element) : BaseCheckableInputType(element) { }
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool valueMissing(const String&) const OVERRIDE;
+    virtual String valueMissingText() const OVERRIDE;
+    virtual void handleKeyupEvent(KeyboardEvent*) OVERRIDE;
+    virtual PassOwnPtr<ClickHandlingState> willDispatchClick() OVERRIDE;
+    virtual void didDispatchClick(Event*, const ClickHandlingState&) OVERRIDE;
+    virtual bool isCheckbox() const OVERRIDE;
+    virtual bool supportsIndeterminateAppearance() const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // CheckboxInputType_h
diff --git a/Source/core/html/ClassList.cpp b/Source/core/html/ClassList.cpp
new file mode 100644
index 0000000..5e60f0c
--- /dev/null
+++ b/Source/core/html/ClassList.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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. 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 "core/html/ClassList.h"
+
+#include "core/dom/SpaceSplitString.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+ClassList::ClassList(Element* element) : m_element(element) { }
+
+void ClassList::ref()
+{
+    m_element->ref();
+}
+
+void ClassList::deref()
+{
+    m_element->deref();
+}
+
+unsigned ClassList::length() const
+{
+    return m_element->hasClass() ? classNames().size() : 0;
+}
+
+const AtomicString ClassList::item(unsigned index) const
+{
+    if (index >= length())
+        return AtomicString();
+    return classNames()[index];
+}
+
+bool ClassList::containsInternal(const AtomicString& token) const
+{
+    return m_element->hasClass() && classNames().contains(token);
+}
+
+const SpaceSplitString& ClassList::classNames() const
+{
+    ASSERT(m_element->hasClass());
+    if (m_element->document()->inQuirksMode()) {
+        if (!m_classNamesForQuirksMode)
+            m_classNamesForQuirksMode = adoptPtr(new SpaceSplitString(value(), false));
+        return *m_classNamesForQuirksMode.get();
+    }
+    return m_element->elementData()->classNames();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/ClassList.h b/Source/core/html/ClassList.h
new file mode 100644
index 0000000..af032d2
--- /dev/null
+++ b/Source/core/html/ClassList.h
@@ -0,0 +1,75 @@
+/*
+ * 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. 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 ClassList_h
+#define ClassList_h
+
+#include "HTMLNames.h"
+#include "core/dom/Element.h"
+#include "core/dom/SpaceSplitString.h"
+#include "core/html/DOMTokenList.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Element;
+
+typedef int ExceptionCode;
+
+class ClassList : public DOMTokenList {
+public:
+    static PassOwnPtr<ClassList> create(Element* element)
+    {
+        return adoptPtr(new ClassList(element));
+    }
+
+    virtual void ref() OVERRIDE;
+    virtual void deref() OVERRIDE;
+
+    virtual unsigned length() const OVERRIDE;
+    virtual const AtomicString item(unsigned index) const OVERRIDE;
+
+    virtual Element* element() OVERRIDE { return m_element; }
+
+    void clearValueForQuirksMode() { m_classNamesForQuirksMode = nullptr; }
+
+private:
+    ClassList(Element*);
+
+    virtual bool containsInternal(const AtomicString&) const OVERRIDE;
+
+    const SpaceSplitString& classNames() const;
+
+    virtual AtomicString value() const OVERRIDE { return m_element->getAttribute(HTMLNames::classAttr); }
+    virtual void setValue(const AtomicString& value) OVERRIDE { m_element->setAttribute(HTMLNames::classAttr, value); }
+
+    Element* m_element;
+    mutable OwnPtr<SpaceSplitString> m_classNamesForQuirksMode;
+};
+
+} // namespace WebCore
+
+#endif // ClassList_h
diff --git a/Source/core/html/CollectionType.h b/Source/core/html/CollectionType.h
new file mode 100644
index 0000000..c576c11
--- /dev/null
+++ b/Source/core/html/CollectionType.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CollectionType_h
+#define CollectionType_h
+
+namespace WebCore {
+
+enum CollectionType {
+    // Unnamed HTMLCollection types cached in the document.
+    DocImages,    // all <img> elements in the document
+    DocApplets,   // all <object> and <applet> elements
+    DocEmbeds,    // all <embed> elements
+    DocForms,     // all <form> elements
+    DocLinks,     // all <a> _and_ <area> elements with a value for href
+    DocAnchors,   // all <a> elements with a value for name
+    DocScripts,   // all <script> elements
+    DocAll,       // "all" elements (IE)
+
+    // Named collection types cached in the document.
+    WindowNamedItems,
+    DocumentNamedItems,
+
+    // Unnamed HTMLCollection types cached in elements.
+    NodeChildren, // first-level children (IE)
+    TableTBodies, // all <tbody> elements in this table
+    TSectionRows, // all row elements in this table section
+    TableRows,
+    TRCells,      // all cells in this row
+    SelectOptions,
+    SelectedOptions,
+    DataListOptions,
+    MapAreas,
+    FormControls,
+
+    // Live NodeList.
+    ChildNodeListType,
+    ClassNodeListType,
+    NameNodeListType,
+    TagNodeListType,
+    HTMLTagNodeListType,
+    RadioNodeListType,
+    LabelsNodeListType,
+};
+
+static const CollectionType FirstNodeListType = ChildNodeListType;
+
+inline bool isNodeList(CollectionType type)
+{
+    return type >= FirstNodeListType;
+}
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/ColorInputType.cpp b/Source/core/html/ColorInputType.cpp
new file mode 100644
index 0000000..bffe778
--- /dev/null
+++ b/Source/core/html/ColorInputType.cpp
@@ -0,0 +1,251 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#if ENABLE(INPUT_TYPE_COLOR)
+#include "core/html/ColorInputType.h"
+
+#include "CSSPropertyNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/HTMLDataListElement.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLOptionElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/page/Chrome.h"
+#include "core/platform/graphics/Color.h"
+#include "core/rendering/RenderObject.h"
+#include "core/rendering/RenderView.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static bool isValidColorString(const String& value)
+{
+    if (value.isEmpty())
+        return false;
+    if (value[0] != '#')
+        return false;
+
+    // We don't accept #rgb and #aarrggbb formats.
+    if (value.length() != 7)
+        return false;
+    Color color(value);
+    return color.isValid() && !color.hasAlpha();
+}
+
+PassOwnPtr<InputType> ColorInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new ColorInputType(element));
+}
+
+ColorInputType::~ColorInputType()
+{
+    endColorChooser();
+}
+
+void ColorInputType::attach()
+{
+    observeFeatureIfVisible(UseCounter::InputTypeColor);
+}
+
+bool ColorInputType::isColorControl() const
+{
+    return true;
+}
+
+const AtomicString& ColorInputType::formControlType() const
+{
+    return InputTypeNames::color();
+}
+
+bool ColorInputType::supportsRequired() const
+{
+    return false;
+}
+
+String ColorInputType::fallbackValue() const
+{
+    return String("#000000");
+}
+
+String ColorInputType::sanitizeValue(const String& proposedValue) const
+{
+    if (!isValidColorString(proposedValue))
+        return fallbackValue();
+
+    return proposedValue.lower();
+}
+
+Color ColorInputType::valueAsColor() const
+{
+    return Color(element()->value());
+}
+
+void ColorInputType::createShadowSubtree()
+{
+    ASSERT(element()->shadow());
+
+    Document* document = element()->document();
+    RefPtr<HTMLDivElement> wrapperElement = HTMLDivElement::create(document);
+    wrapperElement->setPseudo(AtomicString("-webkit-color-swatch-wrapper", AtomicString::ConstructFromLiteral));
+    RefPtr<HTMLDivElement> colorSwatch = HTMLDivElement::create(document);
+    colorSwatch->setPseudo(AtomicString("-webkit-color-swatch", AtomicString::ConstructFromLiteral));
+    wrapperElement->appendChild(colorSwatch.release(), ASSERT_NO_EXCEPTION);
+    element()->userAgentShadowRoot()->appendChild(wrapperElement.release(), ASSERT_NO_EXCEPTION);
+    
+    updateColorSwatch();
+}
+
+void ColorInputType::setValue(const String& value, bool valueChanged, TextFieldEventBehavior eventBehavior)
+{
+    InputType::setValue(value, valueChanged, eventBehavior);
+
+    if (!valueChanged)
+        return;
+
+    updateColorSwatch();
+    if (m_chooser)
+        m_chooser->setSelectedColor(valueAsColor());
+}
+
+void ColorInputType::handleDOMActivateEvent(Event* event)
+{
+    if (element()->isDisabledOrReadOnly() || !element()->renderer())
+        return;
+
+    if (!ScriptController::processingUserGesture())
+        return;
+
+    Chrome* chrome = this->chrome();
+    if (chrome && !m_chooser)
+        m_chooser = chrome->createColorChooser(this, valueAsColor());
+
+    event->setDefaultHandled();
+}
+
+void ColorInputType::detach()
+{
+    endColorChooser();
+}
+
+bool ColorInputType::shouldRespectListAttribute()
+{
+    return InputType::themeSupportsDataListUI(this);
+}
+
+bool ColorInputType::typeMismatchFor(const String& value) const
+{
+    return !isValidColorString(value);
+}
+
+void ColorInputType::didChooseColor(const Color& color)
+{
+    if (element()->isDisabledOrReadOnly() || color == valueAsColor())
+        return;
+    element()->setValueFromRenderer(color.serialized());
+    updateColorSwatch();
+    element()->dispatchFormControlChangeEvent();
+}
+
+void ColorInputType::didEndChooser()
+{
+    m_chooser.clear();
+}
+
+void ColorInputType::endColorChooser()
+{
+    if (m_chooser)
+        m_chooser->endChooser();
+}
+
+void ColorInputType::updateColorSwatch()
+{
+    HTMLElement* colorSwatch = shadowColorSwatch();
+    if (!colorSwatch)
+        return;
+
+    colorSwatch->setInlineStyleProperty(CSSPropertyBackgroundColor, element()->value(), false);
+}
+
+HTMLElement* ColorInputType::shadowColorSwatch() const
+{
+    ShadowRoot* shadow = element()->userAgentShadowRoot();
+    return shadow ? toHTMLElement(shadow->firstChild()->firstChild()) : 0;
+}
+
+IntRect ColorInputType::elementRectRelativeToRootView() const
+{
+    return element()->document()->view()->contentsToRootView(element()->pixelSnappedBoundingBox());
+}
+
+Color ColorInputType::currentColor()
+{
+    return valueAsColor();
+}
+
+bool ColorInputType::shouldShowSuggestions() const
+{
+#if ENABLE(DATALIST_ELEMENT)
+    return element()->fastHasAttribute(listAttr);
+#else
+    return false;
+#endif
+}
+
+Vector<Color> ColorInputType::suggestions() const
+{
+    Vector<Color> suggestions;
+#if ENABLE(DATALIST_ELEMENT)
+    HTMLDataListElement* dataList = element()->dataList();
+    if (dataList) {
+        RefPtr<HTMLCollection> options = dataList->options();
+        for (unsigned i = 0; HTMLOptionElement* option = toHTMLOptionElement(options->item(i)); i++) {
+            if (!element()->isValidValue(option->value()))
+                continue;
+            Color color(option->value());
+            if (!color.isValid())
+                continue;
+            suggestions.append(color);
+        }
+    }
+#endif
+    return suggestions;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_TYPE_COLOR)
diff --git a/Source/core/html/ColorInputType.h b/Source/core/html/ColorInputType.h
new file mode 100644
index 0000000..79477dd
--- /dev/null
+++ b/Source/core/html/ColorInputType.h
@@ -0,0 +1,80 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 ColorInputType_h
+#define ColorInputType_h
+
+#if ENABLE(INPUT_TYPE_COLOR)
+#include "core/html/BaseClickableWithKeyInputType.h"
+#include "core/platform/ColorChooserClient.h"
+
+namespace WebCore {
+
+class ColorInputType : public BaseClickableWithKeyInputType, public ColorChooserClient {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+    virtual ~ColorInputType();
+
+    // ColorChooserClient implementation.
+    virtual void didChooseColor(const Color&) OVERRIDE;
+    virtual void didEndChooser() OVERRIDE;
+    virtual IntRect elementRectRelativeToRootView() const OVERRIDE;
+    virtual Color currentColor() OVERRIDE;
+    virtual bool shouldShowSuggestions() const OVERRIDE;
+    virtual Vector<Color> suggestions() const OVERRIDE;
+
+private:
+    ColorInputType(HTMLInputElement* element) : BaseClickableWithKeyInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual bool isColorControl() const OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool supportsRequired() const OVERRIDE;
+    virtual String fallbackValue() const OVERRIDE;
+    virtual String sanitizeValue(const String&) const OVERRIDE;
+    virtual void createShadowSubtree() OVERRIDE;
+    virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE;
+    virtual void handleDOMActivateEvent(Event*) OVERRIDE;
+    virtual void detach() OVERRIDE;
+    virtual bool shouldRespectListAttribute() OVERRIDE;
+    virtual bool typeMismatchFor(const String&) const OVERRIDE;
+
+    Color valueAsColor() const;
+    void endColorChooser();
+    void updateColorSwatch();
+    HTMLElement* shadowColorSwatch() const;
+
+    OwnPtr<ColorChooser> m_chooser;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_TYPE_COLOR)
+
+#endif // ColorInputType_h
diff --git a/Source/core/html/DOMFormData.cpp b/Source/core/html/DOMFormData.cpp
new file mode 100644
index 0000000..38d6855
--- /dev/null
+++ b/Source/core/html/DOMFormData.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/DOMFormData.h"
+
+#include "core/fileapi/Blob.h"
+#include "core/html/HTMLFormControlElement.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/platform/text/TextEncoding.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+DOMFormData::DOMFormData(const TextEncoding& encoding)
+    : FormDataList(encoding)
+{
+}
+
+DOMFormData::DOMFormData(HTMLFormElement* form)
+    : FormDataList(UTF8Encoding())
+{
+    if (!form)
+        return;
+
+    for (unsigned i = 0; i < form->associatedElements().size(); ++i) {
+        FormAssociatedElement* element = form->associatedElements()[i];
+        if (!toHTMLElement(element)->isDisabledFormControl())
+            element->appendFormData(*this, true);
+    }
+}
+
+void DOMFormData::append(const String& name, const String& value)
+{
+    if (!name.isEmpty())
+        appendData(name, value);
+}
+
+void DOMFormData::append(const String& name, Blob* blob, const String& filename)
+{
+    if (!name.isEmpty())
+        appendBlob(name, blob, filename);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/DOMFormData.h b/Source/core/html/DOMFormData.h
new file mode 100644
index 0000000..ea873e5
--- /dev/null
+++ b/Source/core/html/DOMFormData.h
@@ -0,0 +1,60 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 DOMFormData_h
+#define DOMFormData_h
+
+#include "core/html/FormDataList.h"
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class Blob;
+class HTMLFormElement;
+class TextEncoding;
+
+class DOMFormData : public FormDataList, public RefCounted<DOMFormData> {
+public:
+    static PassRefPtr<DOMFormData> create(HTMLFormElement* form) { return adoptRef(new DOMFormData(form)); }
+    static PassRefPtr<DOMFormData> create(const TextEncoding& encoding) { return adoptRef(new DOMFormData(encoding)); }
+
+    void append(const String& name, const String& value);
+    void append(const String& name, Blob*, const String& filename = String());
+
+private:
+    explicit DOMFormData(const TextEncoding&);
+    explicit DOMFormData(HTMLFormElement*);
+};
+
+} // namespace WebCore
+
+#endif // DOMFormData_h
diff --git a/Source/core/html/DOMFormData.idl b/Source/core/html/DOMFormData.idl
new file mode 100644
index 0000000..25d9ed1
--- /dev/null
+++ b/Source/core/html/DOMFormData.idl
@@ -0,0 +1,42 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+[
+    CustomConstructor(optional HTMLFormElement form),
+    InterfaceName=FormData,
+    ImplementationLacksVTable
+] interface DOMFormData {
+    // void append(DOMString name, DOMString value);
+    // void append(DOMString name, Blob value, optional DOMString filename);
+    [Custom] void append([Default=Undefined] optional DOMString name, 
+                         [Default=Undefined] optional DOMString value,
+                         [Default=Undefined] optional DOMString filename);
+};
+
diff --git a/Source/core/html/DOMSettableTokenList.cpp b/Source/core/html/DOMSettableTokenList.cpp
new file mode 100644
index 0000000..4b34dba
--- /dev/null
+++ b/Source/core/html/DOMSettableTokenList.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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. 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 "core/html/DOMSettableTokenList.h"
+
+namespace WebCore {
+
+DOMSettableTokenList::DOMSettableTokenList()
+    : m_value()
+    , m_tokens()
+{
+}
+
+DOMSettableTokenList::~DOMSettableTokenList()
+{
+}
+
+const AtomicString DOMSettableTokenList::item(unsigned index) const
+{
+    if (index >= length())
+        return AtomicString();
+    return m_tokens[index];
+}
+
+bool DOMSettableTokenList::containsInternal(const AtomicString& token) const
+{
+    return m_tokens.contains(token);
+}
+
+void DOMSettableTokenList::add(const Vector<String>& tokens, ExceptionCode& ec)
+{
+    DOMTokenList::add(tokens, ec);
+
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (m_tokens.isNull())
+            m_tokens.set(tokens[i], false);
+        else
+            m_tokens.add(tokens[i]);
+    }
+}
+
+void DOMSettableTokenList::addInternal(const AtomicString& token)
+{
+    DOMTokenList::addInternal(token);
+    if (m_tokens.isNull())
+        m_tokens.set(token, false);
+    else
+        m_tokens.add(token);
+}
+
+void DOMSettableTokenList::remove(const Vector<String>& tokens, ExceptionCode& ec)
+{
+    DOMTokenList::remove(tokens, ec);
+    for (size_t i = 0; i < tokens.size(); ++i)
+        m_tokens.remove(tokens[i]);
+}
+
+void DOMSettableTokenList::removeInternal(const AtomicString& token)
+{
+    DOMTokenList::removeInternal(token);
+    m_tokens.remove(token);
+}
+
+void DOMSettableTokenList::setValue(const AtomicString& value)
+{
+    m_value = value;
+    m_tokens.set(value, false);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/DOMSettableTokenList.h b/Source/core/html/DOMSettableTokenList.h
new file mode 100644
index 0000000..0b11920
--- /dev/null
+++ b/Source/core/html/DOMSettableTokenList.h
@@ -0,0 +1,75 @@
+/*
+ * 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. 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 DOMSettableTokenList_h
+#define DOMSettableTokenList_h
+
+#include "core/dom/SpaceSplitString.h"
+#include "core/html/DOMTokenList.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+typedef int ExceptionCode;
+
+class DOMSettableTokenList : public DOMTokenList, public RefCounted<DOMSettableTokenList> {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassRefPtr<DOMSettableTokenList> create()
+    {
+        return adoptRef(new DOMSettableTokenList());
+    }
+    virtual ~DOMSettableTokenList();
+
+    virtual void ref() OVERRIDE { RefCounted<DOMSettableTokenList>::ref(); }
+    virtual void deref() OVERRIDE { RefCounted<DOMSettableTokenList>::deref(); }
+
+    virtual unsigned length() const OVERRIDE { return m_tokens.size(); }
+    virtual const AtomicString item(unsigned index) const OVERRIDE;
+
+    virtual void add(const Vector<String>&, ExceptionCode&) OVERRIDE;
+    virtual void remove(const Vector<String>&, ExceptionCode&) OVERRIDE;
+
+    virtual AtomicString value() const OVERRIDE { return m_value; }
+    virtual void setValue(const AtomicString&) OVERRIDE;
+
+    const SpaceSplitString& tokens() const { return m_tokens; }
+
+protected:
+    DOMSettableTokenList();
+
+private:
+    virtual void addInternal(const AtomicString&) OVERRIDE;
+    virtual bool containsInternal(const AtomicString&) const OVERRIDE;
+    virtual void removeInternal(const AtomicString&) OVERRIDE;
+
+    AtomicString m_value;
+    SpaceSplitString m_tokens;
+};
+
+} // namespace WebCore
+
+#endif // DOMSettableTokenList_h
diff --git a/Source/core/html/DOMSettableTokenList.idl b/Source/core/html/DOMSettableTokenList.idl
new file mode 100644
index 0000000..ab242f7
--- /dev/null
+++ b/Source/core/html/DOMSettableTokenList.idl
@@ -0,0 +1,30 @@
+/*
+ * 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. 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.
+ */
+
+[
+    SkipVTableValidation
+] interface DOMSettableTokenList : DOMTokenList {
+    attribute DOMString value;
+};
+
diff --git a/Source/core/html/DOMTokenList.cpp b/Source/core/html/DOMTokenList.cpp
new file mode 100644
index 0000000..3f36935
--- /dev/null
+++ b/Source/core/html/DOMTokenList.cpp
@@ -0,0 +1,237 @@
+/*
+ * 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. 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 "core/html/DOMTokenList.h"
+
+#include "core/dom/ExceptionCode.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+bool DOMTokenList::validateToken(const AtomicString& token, ExceptionCode& ec)
+{
+    if (token.isEmpty()) {
+        ec = SYNTAX_ERR;
+        return false;
+    }
+
+    unsigned length = token.length();
+    for (unsigned i = 0; i < length; ++i) {
+        if (isHTMLSpace(token[i])) {
+            ec = INVALID_CHARACTER_ERR;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool DOMTokenList::validateTokens(const Vector<String>& tokens, ExceptionCode& ec)
+{
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (!validateToken(tokens[i], ec))
+            return false;
+    }
+
+    return true;
+}
+
+bool DOMTokenList::contains(const AtomicString& token, ExceptionCode& ec) const
+{
+    if (!validateToken(token, ec))
+        return false;
+    return containsInternal(token);
+}
+
+void DOMTokenList::add(const AtomicString& token, ExceptionCode& ec)
+{
+    Vector<String> tokens;
+    tokens.append(token.string());
+    add(tokens, ec);
+}
+
+void DOMTokenList::add(const Vector<String>& tokens, ExceptionCode& ec)
+{
+    Vector<String> filteredTokens;
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (!validateToken(tokens[i], ec))
+            return;
+        if (!containsInternal(tokens[i]))
+            filteredTokens.append(tokens[i]);
+    }
+
+    if (filteredTokens.isEmpty())
+        return;
+
+    setValue(addTokens(value(), filteredTokens));
+}
+
+void DOMTokenList::remove(const AtomicString& token, ExceptionCode& ec)
+{
+    Vector<String> tokens;
+    tokens.append(token.string());
+    remove(tokens, ec);
+}
+
+void DOMTokenList::remove(const Vector<String>& tokens, ExceptionCode& ec)
+{
+    if (!validateTokens(tokens, ec))
+        return;
+
+    // Check using containsInternal first since it is a lot faster than going
+    // through the string character by character.
+    bool found = false;
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (containsInternal(tokens[i])) {
+            found = true;
+            break;
+        }
+    }
+
+    if (found)
+        setValue(removeTokens(value(), tokens));
+}
+
+bool DOMTokenList::toggle(const AtomicString& token, ExceptionCode& ec)
+{
+    if (!validateToken(token, ec))
+        return false;
+
+    if (containsInternal(token)) {
+        removeInternal(token);
+        return false;
+    }
+    addInternal(token);
+    return true;
+}
+
+bool DOMTokenList::toggle(const AtomicString& token, bool force, ExceptionCode& ec)
+{
+    if (!validateToken(token, ec))
+        return false;
+
+    if (force)
+        addInternal(token);
+    else
+        removeInternal(token);
+
+    return force;
+}
+
+void DOMTokenList::addInternal(const AtomicString& token)
+{
+    if (!containsInternal(token))
+        setValue(addToken(value(), token));
+}
+
+void DOMTokenList::removeInternal(const AtomicString& token)
+{
+    // Check using contains first since it uses AtomicString comparisons instead
+    // of character by character testing.
+    if (!containsInternal(token))
+        return;
+    setValue(removeToken(value(), token));
+}
+
+String DOMTokenList::addToken(const AtomicString& input, const AtomicString& token)
+{
+    Vector<String> tokens;
+    tokens.append(token.string());
+    return addTokens(input, tokens);
+}
+
+String DOMTokenList::addTokens(const AtomicString& input, const Vector<String>& tokens)
+{
+    bool needsSpace = false;
+
+    StringBuilder builder;
+    if (!input.isEmpty()) {
+        builder.append(input);
+        needsSpace = !isHTMLSpace(input[input.length() - 1]);
+    }
+
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (needsSpace)
+            builder.append(' ');
+        builder.append(tokens[i]);
+        needsSpace = true;
+    }
+
+    return builder.toString();
+}
+
+String DOMTokenList::removeToken(const AtomicString& input, const AtomicString& token)
+{
+    Vector<String> tokens;
+    tokens.append(token.string());
+    return removeTokens(input, tokens);
+}
+
+String DOMTokenList::removeTokens(const AtomicString& input, const Vector<String>& tokens)
+{
+    // Algorithm defined at http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#remove-a-token-from-a-string
+    // New spec is at http://dom.spec.whatwg.org/#remove-a-token-from-a-string
+
+    unsigned inputLength = input.length();
+    StringBuilder output; // 3
+    output.reserveCapacity(inputLength);
+    unsigned position = 0; // 4
+
+    // Step 5
+    while (position < inputLength) {
+        if (isHTMLSpace(input[position])) { // 6
+            output.append(input[position++]); // 6.1, 6.2
+            continue; // 6.3
+        }
+
+        // Step 7
+        StringBuilder s;
+        while (position < inputLength && isNotHTMLSpace(input[position]))
+            s.append(input[position++]);
+
+        // Step 8
+        if (tokens.contains(s.toStringPreserveCapacity())) {
+            // Step 8.1
+            while (position < inputLength && isHTMLSpace(input[position]))
+                ++position;
+
+            // Step 8.2
+            size_t j = output.length();
+            while (j > 0 && isHTMLSpace(output[j - 1]))
+                --j;
+            output.resize(j);
+
+            // Step 8.3
+            if (position < inputLength && !output.isEmpty())
+                output.append(' ');
+        } else
+            output.append(s.toStringPreserveCapacity()); // Step 9
+    }
+
+    return output.toString();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/DOMTokenList.h b/Source/core/html/DOMTokenList.h
new file mode 100644
index 0000000..31fc342
--- /dev/null
+++ b/Source/core/html/DOMTokenList.h
@@ -0,0 +1,79 @@
+/*
+ * 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. 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 DOMTokenList_h
+#define DOMTokenList_h
+
+#include <wtf/text/AtomicString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Element;
+
+typedef int ExceptionCode;
+
+class DOMTokenList {
+    WTF_MAKE_NONCOPYABLE(DOMTokenList); WTF_MAKE_FAST_ALLOCATED;
+public:
+    DOMTokenList() { }
+    virtual ~DOMTokenList() {};
+
+    virtual void ref() = 0;
+    virtual void deref() = 0;
+
+    virtual unsigned length() const = 0;
+    virtual const AtomicString item(unsigned index) const = 0;
+
+    bool contains(const AtomicString&, ExceptionCode&) const;
+    virtual void add(const Vector<String>&, ExceptionCode&);
+    void add(const AtomicString&, ExceptionCode&);
+    virtual void remove(const Vector<String>&, ExceptionCode&);
+    void remove(const AtomicString&, ExceptionCode&);
+    bool toggle(const AtomicString&, ExceptionCode&);
+    bool toggle(const AtomicString&, bool force, ExceptionCode&);
+
+    AtomicString toString() const { return value(); }
+
+    virtual Element* element() { return 0; }
+
+protected:
+    virtual AtomicString value() const = 0;
+    virtual void setValue(const AtomicString&) = 0;
+
+    virtual void addInternal(const AtomicString&);
+    virtual bool containsInternal(const AtomicString&) const = 0;
+    virtual void removeInternal(const AtomicString&);
+
+    static bool validateToken(const AtomicString&, ExceptionCode&);
+    static bool validateTokens(const Vector<String>&, ExceptionCode&);
+    static String addToken(const AtomicString&, const AtomicString&);
+    static String addTokens(const AtomicString&, const Vector<String>&);
+    static String removeToken(const AtomicString&, const AtomicString&);
+    static String removeTokens(const AtomicString&, const Vector<String>&);
+};
+
+} // namespace WebCore
+
+#endif // DOMTokenList_h
diff --git a/Source/core/html/DOMTokenList.idl b/Source/core/html/DOMTokenList.idl
new file mode 100644
index 0000000..64bc636
--- /dev/null
+++ b/Source/core/html/DOMTokenList.idl
@@ -0,0 +1,37 @@
+/*
+ * 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. 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.
+ */
+
+[
+    GenerateIsReachable=ImplElementRoot,
+    SkipVTableValidation
+] interface DOMTokenList {
+    readonly attribute unsigned long length;
+    [TreatReturnedNullStringAs=Null] getter DOMString item(unsigned long index);
+    [RaisesException] boolean contains(DOMString token);
+    [RaisesException] void add(DOMString... tokens);
+    [RaisesException] void remove(DOMString... tokens);
+    [RaisesException] boolean toggle(DOMString token, optional boolean force);
+    [NotEnumerable] DOMString toString();
+};
+
diff --git a/Source/core/html/DOMURL.cpp b/Source/core/html/DOMURL.cpp
new file mode 100644
index 0000000..def4ca3
--- /dev/null
+++ b/Source/core/html/DOMURL.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2012 Motorola Mobility Inc.
+ *
+ * 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 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 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 "core/html/DOMURL.h"
+
+#include "core/dom/ActiveDOMObject.h"
+#include "core/dom/ScriptExecutionContext.h"
+#include "core/fileapi/Blob.h"
+#include "core/fileapi/BlobURL.h"
+#include "core/fileapi/ThreadableBlobRegistry.h"
+#include "core/html/PublicURLManager.h"
+#include "core/loader/cache/MemoryCache.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/platform/KURL.h"
+#include "core/platform/network/ResourceRequest.h"
+#include "modules/mediasource/MediaSource.h"
+#include "modules/mediasource/MediaSourceRegistry.h"
+#include "modules/mediastream/MediaStream.h"
+#include "modules/mediastream/MediaStreamRegistry.h"
+#include <wtf/MainThread.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+String DOMURL::createObjectURL(ScriptExecutionContext* scriptExecutionContext, MediaSource* source)
+{
+    // Since WebWorkers cannot obtain MediaSource objects, we should be on the main thread.
+    ASSERT(isMainThread());
+
+    if (!scriptExecutionContext || !source)
+        return String();
+
+    KURL publicURL = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin());
+    if (publicURL.isEmpty())
+        return String();
+
+    MediaSourceRegistry::registry().registerMediaSourceURL(publicURL, source);
+    scriptExecutionContext->publicURLManager().sourceURLs().add(publicURL.string());
+
+    return publicURL.string();
+}
+
+String DOMURL::createObjectURL(ScriptExecutionContext* scriptExecutionContext, MediaStream* stream)
+{
+    if (!scriptExecutionContext || !stream)
+        return String();
+
+    KURL publicURL = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin());
+    if (publicURL.isEmpty())
+        return String();
+
+    // Since WebWorkers cannot obtain Stream objects, we should be on the main thread.
+    ASSERT(isMainThread());
+
+    MediaStreamRegistry::registry().registerMediaStreamURL(publicURL, stream);
+    scriptExecutionContext->publicURLManager().streamURLs().add(publicURL.string());
+
+    return publicURL.string();
+}
+
+String DOMURL::createObjectURL(ScriptExecutionContext* scriptExecutionContext, Blob* blob)
+{
+    if (!scriptExecutionContext || !blob)
+        return String();
+
+    KURL publicURL = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin());
+    if (publicURL.isEmpty())
+        return String();
+
+    ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), publicURL, blob->url());
+    scriptExecutionContext->publicURLManager().blobURLs().add(publicURL.string());
+
+    return publicURL.string();
+}
+
+void DOMURL::revokeObjectURL(ScriptExecutionContext* scriptExecutionContext, const String& urlString)
+{
+    if (!scriptExecutionContext)
+        return;
+
+    KURL url(KURL(), urlString);
+    MemoryCache::removeUrlFromCache(scriptExecutionContext, urlString);
+
+    HashSet<String>& blobURLs = scriptExecutionContext->publicURLManager().blobURLs();
+    if (blobURLs.contains(url.string())) {
+        ThreadableBlobRegistry::unregisterBlobURL(url);
+        blobURLs.remove(url.string());
+    }
+
+    HashSet<String>& sourceURLs = scriptExecutionContext->publicURLManager().sourceURLs();
+    if (sourceURLs.contains(url.string())) {
+        MediaSourceRegistry::registry().unregisterMediaSourceURL(url);
+        sourceURLs.remove(url.string());
+    }
+    HashSet<String>& streamURLs = scriptExecutionContext->publicURLManager().streamURLs();
+    if (streamURLs.contains(url.string())) {
+        // FIXME: make sure of this assertion below. Raise a spec question if required.
+        // Since WebWorkers cannot obtain Stream objects, we should be on the main thread.
+        ASSERT(isMainThread());
+        MediaStreamRegistry::registry().unregisterMediaStreamURL(url);
+        streamURLs.remove(url.string());
+    }
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/DOMURL.h b/Source/core/html/DOMURL.h
new file mode 100644
index 0000000..8a59b24
--- /dev/null
+++ b/Source/core/html/DOMURL.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2012 Motorola Mobility Inc.
+ *
+ * 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 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 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 DOMURL_h
+#define DOMURL_h
+
+#include "core/platform/KURL.h"
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Blob;
+class MediaSource;
+class MediaStream;
+class ScriptExecutionContext;
+
+class DOMURL : public RefCounted<DOMURL> {
+
+public:
+    static PassRefPtr<DOMURL> create() { return adoptRef(new DOMURL); }
+
+    static void contextDestroyed(ScriptExecutionContext*);
+
+    static String createObjectURL(ScriptExecutionContext*, Blob*);
+    static void revokeObjectURL(ScriptExecutionContext*, const String&);
+    static String createObjectURL(ScriptExecutionContext*, MediaSource*);
+    static String createObjectURL(ScriptExecutionContext*, MediaStream*);
+};
+
+} // namespace WebCore
+
+#endif // DOMURL_h
diff --git a/Source/core/html/DOMURL.idl b/Source/core/html/DOMURL.idl
new file mode 100644
index 0000000..c9fdd0a
--- /dev/null
+++ b/Source/core/html/DOMURL.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2012 Motorola Mobility Inc.
+ *
+ * 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 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 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.
+ */
+
+[
+    Constructor,
+    InterfaceName=URL,
+    ImplementationLacksVTable
+] interface DOMURL {
+    [CallWith=ScriptExecutionContext,TreatReturnedNullStringAs=Null] static DOMString createObjectURL(MediaSource? source);
+    [CallWith=ScriptExecutionContext,TreatReturnedNullStringAs=Null] static DOMString createObjectURL(MediaStream? stream);
+    [CallWith=ScriptExecutionContext,TreatReturnedNullStringAs=Null] static DOMString createObjectURL(Blob? blob);
+    [CallWith=ScriptExecutionContext] static void revokeObjectURL(DOMString url);
+};
diff --git a/Source/core/html/DateInputType.cpp b/Source/core/html/DateInputType.cpp
new file mode 100644
index 0000000..2fa4b01
--- /dev/null
+++ b/Source/core/html/DateInputType.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/DateInputType.h"
+
+#include "HTMLNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/html/DateTimeFieldsState.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/html/shadow/PickerIndicatorElement.h"
+#include "core/platform/DateComponents.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/text/PlatformLocale.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const int dateDefaultStep = 1;
+static const int dateDefaultStepBase = 0;
+static const int dateStepScaleFactor = 86400000;
+
+inline DateInputType::DateInputType(HTMLInputElement* element)
+    : BaseDateInputType(element)
+{
+}
+
+PassOwnPtr<InputType> DateInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new DateInputType(element));
+}
+
+void DateInputType::attach()
+{
+    observeFeatureIfVisible(UseCounter::InputTypeDate);
+}
+
+const AtomicString& DateInputType::formControlType() const
+{
+    return InputTypeNames::date();
+}
+
+DateComponents::Type DateInputType::dateType() const
+{
+    return DateComponents::Date;
+}
+
+StepRange DateInputType::createStepRange(AnyStepHandling anyStepHandling) const
+{
+    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (dateDefaultStep, dateDefaultStepBase, dateStepScaleFactor, StepRange::ParsedStepValueShouldBeInteger));
+
+    const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0);
+    const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumDate()));
+    const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumDate()));
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+    return StepRange(stepBase, minimum, maximum, step, stepDescription);
+}
+
+bool DateInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const
+{
+    ASSERT(out);
+    unsigned end;
+    return out->parseDate(characters, length, 0, end) && end == length;
+}
+
+bool DateInputType::setMillisecondToDateComponents(double value, DateComponents* date) const
+{
+    ASSERT(date);
+    return date->setMillisecondsSinceEpochForDate(value);
+}
+
+bool DateInputType::isDateField() const
+{
+    return true;
+}
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+String DateInputType::formatDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) const
+{
+    if (!dateTimeFieldsState.hasDayOfMonth() || !dateTimeFieldsState.hasMonth() || !dateTimeFieldsState.hasYear())
+        return emptyString();
+
+    return String::format("%04u-%02u-%02u", dateTimeFieldsState.year(), dateTimeFieldsState.month(), dateTimeFieldsState.dayOfMonth());
+}
+
+void DateInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& date) const
+{
+    layoutParameters.dateTimeFormat = layoutParameters.locale.dateFormat();
+    layoutParameters.fallbackDateTimeFormat = ASCIILiteral("yyyy-MM-dd");
+    if (!parseToDateComponents(element()->fastGetAttribute(minAttr), &layoutParameters.minimum))
+        layoutParameters.minimum = DateComponents();
+    if (!parseToDateComponents(element()->fastGetAttribute(maxAttr), &layoutParameters.maximum))
+        layoutParameters.maximum = DateComponents();
+    layoutParameters.placeholderForDay = placeholderForDayOfMonthField();
+    layoutParameters.placeholderForMonth = placeholderForMonthField();
+    layoutParameters.placeholderForYear = placeholderForYearField();
+}
+
+bool DateInputType::isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const
+{
+    return hasYear && hasMonth && hasDay;
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/core/html/DateInputType.h b/Source/core/html/DateInputType.h
new file mode 100644
index 0000000..78575ee
--- /dev/null
+++ b/Source/core/html/DateInputType.h
@@ -0,0 +1,72 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 DateInputType_h
+#define DateInputType_h
+
+#include "core/html/BaseChooserOnlyDateAndTimeInputType.h"
+#include "core/html/BaseMultipleFieldsDateAndTimeInputType.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class PickerIndicatorElement;
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+typedef BaseMultipleFieldsDateAndTimeInputType BaseDateInputType;
+#else
+typedef BaseChooserOnlyDateAndTimeInputType BaseDateInputType;
+#endif
+
+class DateInputType : public BaseDateInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    DateInputType(HTMLInputElement*);
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual DateComponents::Type dateType() const OVERRIDE;
+    virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
+    virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
+    virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
+    virtual bool isDateField() const OVERRIDE;
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+    // BaseMultipleFieldsDateAndTimeInputType functions
+    virtual String formatDateTimeFieldsState(const DateTimeFieldsState&) const OVERRIDE;
+    virtual void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const OVERRIDE;
+    virtual bool isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // DateInputType_h
diff --git a/Source/core/html/DateTimeFieldsState.cpp b/Source/core/html/DateTimeFieldsState.cpp
new file mode 100644
index 0000000..314af5a
--- /dev/null
+++ b/Source/core/html/DateTimeFieldsState.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 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. 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"
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/DateTimeFieldsState.h"
+
+#include "core/html/FormController.h"
+
+namespace WebCore {
+
+const unsigned DateTimeFieldsState::emptyValue = static_cast<unsigned>(-1);
+
+static unsigned getNumberFromFormControlState(const FormControlState& state, size_t index)
+{
+    if (index >= state.valueSize())
+        return DateTimeFieldsState::emptyValue;
+    bool parsed;
+    unsigned const value = state[index].toUInt(&parsed);
+    return parsed ? value : DateTimeFieldsState::emptyValue;
+}
+
+static DateTimeFieldsState::AMPMValue getAMPMFromFormControlState(const FormControlState& state, size_t index)
+{
+    if (index >= state.valueSize())
+        return DateTimeFieldsState::AMPMValueEmpty;
+    const String value = state[index];
+    if (value == "A")
+        return DateTimeFieldsState::AMPMValueAM;
+    if (value == "P")
+        return DateTimeFieldsState::AMPMValuePM;
+    return DateTimeFieldsState::AMPMValueEmpty;
+}
+
+DateTimeFieldsState::DateTimeFieldsState()
+    : m_year(emptyValue)
+    , m_month(emptyValue)
+    , m_dayOfMonth(emptyValue)
+    , m_hour(emptyValue)
+    , m_minute(emptyValue)
+    , m_second(emptyValue)
+    , m_millisecond(emptyValue)
+    , m_weekOfYear(emptyValue)
+    , m_ampm(AMPMValueEmpty)
+{
+}
+
+unsigned DateTimeFieldsState::hour23() const
+{
+    if (!hasHour() || !hasAMPM())
+        return emptyValue;
+    return (m_hour % 12) + (m_ampm == AMPMValuePM ? 12 : 0);
+}
+
+DateTimeFieldsState DateTimeFieldsState::restoreFormControlState(const FormControlState& state)
+{
+    DateTimeFieldsState dateTimeFieldsState;
+    dateTimeFieldsState.setYear(getNumberFromFormControlState(state, 0));
+    dateTimeFieldsState.setMonth(getNumberFromFormControlState(state, 1));
+    dateTimeFieldsState.setDayOfMonth(getNumberFromFormControlState(state, 2));
+    dateTimeFieldsState.setHour(getNumberFromFormControlState(state, 3));
+    dateTimeFieldsState.setMinute(getNumberFromFormControlState(state, 4));
+    dateTimeFieldsState.setSecond(getNumberFromFormControlState(state, 5));
+    dateTimeFieldsState.setMillisecond(getNumberFromFormControlState(state, 6));
+    dateTimeFieldsState.setWeekOfYear(getNumberFromFormControlState(state, 7));
+    dateTimeFieldsState.setAMPM(getAMPMFromFormControlState(state, 8));
+    return dateTimeFieldsState;
+}
+
+FormControlState DateTimeFieldsState::saveFormControlState() const
+{
+    FormControlState state;
+    state.append(hasYear() ? String::number(m_year) : emptyString());
+    state.append(hasMonth() ? String::number(m_month) : emptyString());
+    state.append(hasDayOfMonth() ? String::number(m_dayOfMonth) : emptyString());
+    state.append(hasHour() ? String::number(m_hour) : emptyString());
+    state.append(hasMinute() ? String::number(m_minute) : emptyString());
+    state.append(hasSecond() ? String::number(m_second) : emptyString());
+    state.append(hasMillisecond() ? String::number(m_millisecond) : emptyString());
+    state.append(hasWeekOfYear() ? String::number(m_weekOfYear) : emptyString());
+    if (hasAMPM())
+        state.append(m_ampm == AMPMValueAM ? "A" : "P");
+    else
+        state.append(emptyString());
+    return state;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/DateTimeFieldsState.h b/Source/core/html/DateTimeFieldsState.h
new file mode 100644
index 0000000..2dd2195
--- /dev/null
+++ b/Source/core/html/DateTimeFieldsState.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 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. 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 DateTimeFieldsState_h
+#define DateTimeFieldsState_h
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class FormControlState;
+
+// DateTimeFieldsState represents fields in date/time for form state
+// save/restore for input type "date", "datetime", "datetime-local", "month",
+// "time", and "week" with multiple fields input UI.
+//
+// Each field can contain invalid value for date, e.g. day of month field can
+// be 30 even if month field is February.
+class DateTimeFieldsState {
+public:
+    enum AMPMValue {
+        AMPMValueEmpty = -1,
+        AMPMValueAM,
+        AMPMValuePM,
+    };
+
+    static const unsigned emptyValue;
+
+    DateTimeFieldsState();
+
+    static DateTimeFieldsState restoreFormControlState(const FormControlState&);
+    FormControlState saveFormControlState() const;
+
+    AMPMValue ampm() const { return m_ampm; }
+    unsigned dayOfMonth() const { return m_dayOfMonth; }
+    unsigned hour() const { return m_hour; }
+    unsigned hour23() const;
+    unsigned millisecond() const { return m_millisecond; }
+    unsigned minute() const { return m_minute; }
+    unsigned month() const { return m_month; }
+    unsigned second() const { return m_second; }
+    unsigned weekOfYear() const { return m_weekOfYear; }
+    unsigned year() const { return m_year; }
+
+    bool hasAMPM() const { return m_ampm != AMPMValueEmpty; }
+    bool hasDayOfMonth() const { return m_dayOfMonth != emptyValue; }
+    bool hasHour() const { return m_hour != emptyValue; }
+    bool hasMillisecond() const { return m_millisecond != emptyValue; }
+    bool hasMinute() const { return m_minute != emptyValue; }
+    bool hasMonth() const { return m_month != emptyValue; }
+    bool hasSecond() const { return m_second != emptyValue; }
+    bool hasWeekOfYear() const { return m_weekOfYear != emptyValue; }
+    bool hasYear() const { return m_year != emptyValue; }
+
+    void setAMPM(AMPMValue ampm) { m_ampm = ampm; }
+    void setDayOfMonth(unsigned dayOfMonth) { m_dayOfMonth = dayOfMonth; }
+    void setHour(unsigned hour12) { m_hour = hour12; }
+    void setMillisecond(unsigned millisecond) { m_millisecond = millisecond; }
+    void setMinute(unsigned minute) { m_minute = minute; }
+    void setMonth(unsigned month) { m_month = month; }
+    void setSecond(unsigned second) { m_second = second; }
+    void setWeekOfYear(unsigned weekOfYear) { m_weekOfYear = weekOfYear; }
+    void setYear(unsigned year) { m_year = year; }
+
+private:
+    unsigned m_year;
+    unsigned m_month; // 1 to 12.
+    unsigned m_dayOfMonth;
+    unsigned m_hour; // 1 to 12.
+    unsigned m_minute;
+    unsigned m_second;
+    unsigned m_millisecond;
+    unsigned m_weekOfYear;
+    AMPMValue m_ampm;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/DateTimeInputType.cpp b/Source/core/html/DateTimeInputType.cpp
new file mode 100644
index 0000000..45e45b3
--- /dev/null
+++ b/Source/core/html/DateTimeInputType.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#if ENABLE(INPUT_TYPE_DATETIME_INCOMPLETE)
+#include "core/html/DateTimeInputType.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/platform/DateComponents.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/PassOwnPtr.h>
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/DateTimeFieldsState.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/text/PlatformLocale.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const int dateTimeDefaultStep = 60;
+static const int dateTimeDefaultStepBase = 0;
+static const int dateTimeStepScaleFactor = 1000;
+
+PassOwnPtr<InputType> DateTimeInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new DateTimeInputType(element));
+}
+
+void DateTimeInputType::attach()
+{
+    observeFeatureIfVisible(UseCounter::InputTypeDateTime);
+}
+
+const AtomicString& DateTimeInputType::formControlType() const
+{
+    return InputTypeNames::datetime();
+}
+
+DateComponents::Type DateTimeInputType::dateType() const
+{
+    return DateComponents::DateTime;
+}
+
+Decimal DateTimeInputType::defaultValueForStepUp() const
+{
+    return Decimal::fromDouble(currentTimeMS());
+}
+
+StepRange DateTimeInputType::createStepRange(AnyStepHandling anyStepHandling) const
+{
+    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (dateTimeDefaultStep, dateTimeDefaultStepBase, dateTimeStepScaleFactor, StepRange::ScaledStepValueShouldBeInteger));
+
+    const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0);
+    const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumDateTime()));
+    const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumDateTime()));
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+    return StepRange(stepBase, minimum, maximum, step, stepDescription);
+}
+
+bool DateTimeInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const
+{
+    ASSERT(out);
+    unsigned end;
+    return out->parseDateTime(characters, length, 0, end) && end == length;
+}
+
+bool DateTimeInputType::setMillisecondToDateComponents(double value, DateComponents* date) const
+{
+    ASSERT(date);
+    return date->setMillisecondsSinceEpochForDateTime(value);
+}
+
+bool DateTimeInputType::isDateTimeField() const
+{
+    return true;
+}
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+// FIXME: It is better to share code for DateTimeInputType::formatDateTimeFieldsState()
+// and DateTimeInputLocalType::formatDateTimeFieldsState().
+String DateTimeInputType::formatDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) const
+{
+    if (!dateTimeFieldsState.hasDayOfMonth() || !dateTimeFieldsState.hasMonth() || !dateTimeFieldsState.hasYear()
+        || !dateTimeFieldsState.hasHour() || !dateTimeFieldsState.hasMinute() || !dateTimeFieldsState.hasAMPM())
+        return emptyString();
+
+    if (dateTimeFieldsState.hasMillisecond() && dateTimeFieldsState.millisecond()) {
+        return String::format("%04u-%02u-%02uT%02u:%02u:%02u.%03uZ",
+            dateTimeFieldsState.year(),
+            dateTimeFieldsState.month(),
+            dateTimeFieldsState.dayOfMonth(),
+            dateTimeFieldsState.hour23(),
+            dateTimeFieldsState.minute(),
+            dateTimeFieldsState.hasSecond() ? dateTimeFieldsState.second() : 0,
+            dateTimeFieldsState.millisecond());
+    }
+
+    if (dateTimeFieldsState.hasSecond() && dateTimeFieldsState.second()) {
+        return String::format("%04u-%02u-%02uT%02u:%02u:%02uZ",
+            dateTimeFieldsState.year(),
+            dateTimeFieldsState.month(),
+            dateTimeFieldsState.dayOfMonth(),
+            dateTimeFieldsState.hour23(),
+            dateTimeFieldsState.minute(),
+            dateTimeFieldsState.second());
+    }
+
+    return String::format("%04u-%02u-%02uT%02u:%02uZ",
+        dateTimeFieldsState.year(),
+        dateTimeFieldsState.month(),
+        dateTimeFieldsState.dayOfMonth(),
+        dateTimeFieldsState.hour23(),
+        dateTimeFieldsState.minute());
+}
+
+void DateTimeInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& date) const
+{
+    if (shouldHaveSecondField(date)) {
+        layoutParameters.dateTimeFormat = layoutParameters.locale.dateTimeFormatWithSeconds();
+        layoutParameters.fallbackDateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+    } else {
+        layoutParameters.dateTimeFormat = layoutParameters.locale.dateTimeFormatWithoutSeconds();
+        layoutParameters.fallbackDateTimeFormat = "yyyy-MM-dd'T'HH:mm'Z'";
+    }
+    if (!parseToDateComponents(element()->fastGetAttribute(minAttr), &layoutParameters.minimum))
+        layoutParameters.minimum = DateComponents();
+    if (!parseToDateComponents(element()->fastGetAttribute(maxAttr), &layoutParameters.maximum))
+        layoutParameters.maximum = DateComponents();
+    layoutParameters.placeholderForDay = placeholderForDayOfMonthField();
+    layoutParameters.placeholderForMonth = placeholderForMonthField();
+    layoutParameters.placeholderForYear = placeholderForYearField();
+}
+
+bool DateTimeInputType::isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const
+{
+    return hasYear && hasMonth && hasDay && hasAMPM && hasHour && hasMinute;
+}
+#endif
+
+String DateTimeInputType::sanitizeValue(const String& proposedValue) const
+{
+    DateComponents date;
+    if (!parseToDateComponents(proposedValue, &date))
+        return String();
+    return date.toString();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/DateTimeInputType.h b/Source/core/html/DateTimeInputType.h
new file mode 100644
index 0000000..78c15d5
--- /dev/null
+++ b/Source/core/html/DateTimeInputType.h
@@ -0,0 +1,74 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 DateTimeInputType_h
+#define DateTimeInputType_h
+
+#if ENABLE(INPUT_TYPE_DATETIME_INCOMPLETE)
+#include "core/html/BaseChooserOnlyDateAndTimeInputType.h"
+#include "core/html/BaseDateAndTimeInputType.h"
+#include "core/html/BaseMultipleFieldsDateAndTimeInputType.h"
+
+namespace WebCore {
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+typedef BaseMultipleFieldsDateAndTimeInputType BaseDateTimeInputType;
+#else
+typedef BaseChooserOnlyDateAndTimeInputType BaseDateTimeInputType;
+#endif
+
+class DateTimeInputType : public BaseDateTimeInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    DateTimeInputType(HTMLInputElement* element) : BaseDateTimeInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual DateComponents::Type dateType() const OVERRIDE;
+    virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
+    virtual Decimal defaultValueForStepUp() const OVERRIDE;
+    virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
+    virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
+    virtual bool isDateTimeField() const OVERRIDE;
+    virtual String sanitizeValue(const String&) const OVERRIDE;
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+    // BaseMultipleFieldsDateAndTimeInputType functions
+    virtual String formatDateTimeFieldsState(const DateTimeFieldsState&) const OVERRIDE FINAL;
+    virtual void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const OVERRIDE FINAL;
+    virtual bool isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const;
+#endif
+};
+
+} // namespace WebCore
+
+#endif
+#endif // DateTimeInputType_h
diff --git a/Source/core/html/DateTimeLocalInputType.cpp b/Source/core/html/DateTimeLocalInputType.cpp
new file mode 100644
index 0000000..7fb9e66
--- /dev/null
+++ b/Source/core/html/DateTimeLocalInputType.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/DateTimeLocalInputType.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/platform/DateComponents.h"
+#include <wtf/PassOwnPtr.h>
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/DateTimeFieldsState.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/text/PlatformLocale.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const int dateTimeLocalDefaultStep = 60;
+static const int dateTimeLocalDefaultStepBase = 0;
+static const int dateTimeLocalStepScaleFactor = 1000;
+
+PassOwnPtr<InputType> DateTimeLocalInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new DateTimeLocalInputType(element));
+}
+
+void DateTimeLocalInputType::attach()
+{
+    observeFeatureIfVisible(UseCounter::InputTypeDateTimeLocal);
+}
+
+const AtomicString& DateTimeLocalInputType::formControlType() const
+{
+    return InputTypeNames::datetimelocal();
+}
+
+DateComponents::Type DateTimeLocalInputType::dateType() const
+{
+    return DateComponents::DateTimeLocal;
+}
+
+double DateTimeLocalInputType::valueAsDate() const
+{
+    // valueAsDate doesn't work for the datetime-local type according to the standard.
+    return DateComponents::invalidMilliseconds();
+}
+
+void DateTimeLocalInputType::setValueAsDate(double value, ExceptionCode& ec) const
+{
+    // valueAsDate doesn't work for the datetime-local type according to the standard.
+    InputType::setValueAsDate(value, ec);
+}
+
+StepRange DateTimeLocalInputType::createStepRange(AnyStepHandling anyStepHandling) const
+{
+    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (dateTimeLocalDefaultStep, dateTimeLocalDefaultStepBase, dateTimeLocalStepScaleFactor, StepRange::ScaledStepValueShouldBeInteger));
+
+    const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0);
+    const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumDateTime()));
+    const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumDateTime()));
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+    return StepRange(stepBase, minimum, maximum, step, stepDescription);
+}
+
+bool DateTimeLocalInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const
+{
+    ASSERT(out);
+    unsigned end;
+    return out->parseDateTimeLocal(characters, length, 0, end) && end == length;
+}
+
+bool DateTimeLocalInputType::setMillisecondToDateComponents(double value, DateComponents* date) const
+{
+    ASSERT(date);
+    return date->setMillisecondsSinceEpochForDateTimeLocal(value);
+}
+
+bool DateTimeLocalInputType::isDateTimeLocalField() const
+{
+    return true;
+}
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+// FIXME: It is better to share code for DateTimeInputType::formatDateTimeFieldsState()
+// and DateTimeInputLocalType::formatDateTimeFieldsState().
+String DateTimeLocalInputType::formatDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) const
+{
+    if (!dateTimeFieldsState.hasDayOfMonth() || !dateTimeFieldsState.hasMonth() || !dateTimeFieldsState.hasYear()
+        || !dateTimeFieldsState.hasHour() || !dateTimeFieldsState.hasMinute() || !dateTimeFieldsState.hasAMPM())
+        return emptyString();
+
+    if (dateTimeFieldsState.hasMillisecond() && dateTimeFieldsState.millisecond()) {
+        return String::format("%04u-%02u-%02uT%02u:%02u:%02u.%03u",
+            dateTimeFieldsState.year(),
+            dateTimeFieldsState.month(),
+            dateTimeFieldsState.dayOfMonth(),
+            dateTimeFieldsState.hour23(),
+            dateTimeFieldsState.minute(),
+            dateTimeFieldsState.hasSecond() ? dateTimeFieldsState.second() : 0,
+            dateTimeFieldsState.millisecond());
+    }
+
+    if (dateTimeFieldsState.hasSecond() && dateTimeFieldsState.second()) {
+        return String::format("%04u-%02u-%02uT%02u:%02u:%02u",
+            dateTimeFieldsState.year(),
+            dateTimeFieldsState.month(),
+            dateTimeFieldsState.dayOfMonth(),
+            dateTimeFieldsState.hour23(),
+            dateTimeFieldsState.minute(),
+            dateTimeFieldsState.second());
+    }
+
+    return String::format("%04u-%02u-%02uT%02u:%02u",
+        dateTimeFieldsState.year(),
+        dateTimeFieldsState.month(),
+        dateTimeFieldsState.dayOfMonth(),
+        dateTimeFieldsState.hour23(),
+        dateTimeFieldsState.minute());
+}
+
+void DateTimeLocalInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& date) const
+{
+    if (shouldHaveSecondField(date)) {
+        layoutParameters.dateTimeFormat = layoutParameters.locale.dateTimeFormatWithSeconds();
+        layoutParameters.fallbackDateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss";
+    } else {
+        layoutParameters.dateTimeFormat = layoutParameters.locale.dateTimeFormatWithoutSeconds();
+        layoutParameters.fallbackDateTimeFormat = "yyyy-MM-dd'T'HH:mm";
+    }
+    if (!parseToDateComponents(element()->fastGetAttribute(minAttr), &layoutParameters.minimum))
+        layoutParameters.minimum = DateComponents();
+    if (!parseToDateComponents(element()->fastGetAttribute(maxAttr), &layoutParameters.maximum))
+        layoutParameters.maximum = DateComponents();
+    layoutParameters.placeholderForDay = placeholderForDayOfMonthField();
+    layoutParameters.placeholderForMonth = placeholderForMonthField();
+    layoutParameters.placeholderForYear = placeholderForYearField();
+}
+
+bool DateTimeLocalInputType::isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const
+{
+    return hasYear && hasMonth && hasDay && hasAMPM && hasHour && hasMinute;
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/core/html/DateTimeLocalInputType.h b/Source/core/html/DateTimeLocalInputType.h
new file mode 100644
index 0000000..e2e083e
--- /dev/null
+++ b/Source/core/html/DateTimeLocalInputType.h
@@ -0,0 +1,71 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 DateTimeLocalInputType_h
+#define DateTimeLocalInputType_h
+
+#include "core/html/BaseChooserOnlyDateAndTimeInputType.h"
+#include "core/html/BaseMultipleFieldsDateAndTimeInputType.h"
+
+namespace WebCore {
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+typedef BaseMultipleFieldsDateAndTimeInputType BaseDateTimeLocalInputType;
+#else
+typedef BaseChooserOnlyDateAndTimeInputType BaseDateTimeLocalInputType;
+#endif
+
+class DateTimeLocalInputType : public BaseDateTimeLocalInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    DateTimeLocalInputType(HTMLInputElement* element) : BaseDateTimeLocalInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual DateComponents::Type dateType() const OVERRIDE;
+    virtual double valueAsDate() const OVERRIDE;
+    virtual void setValueAsDate(double, ExceptionCode&) const OVERRIDE;
+    virtual StepRange createStepRange(AnyStepHandling) const;
+    virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
+    virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
+    virtual bool isDateTimeLocalField() const OVERRIDE;
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+    // BaseMultipleFieldsDateAndTimeInputType functions
+    virtual String formatDateTimeFieldsState(const DateTimeFieldsState&) const OVERRIDE FINAL;
+    virtual void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const OVERRIDE FINAL;
+    virtual bool isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // DateTimeLocalInputType_h
diff --git a/Source/core/html/EmailInputType.cpp b/Source/core/html/EmailInputType.cpp
new file mode 100644
index 0000000..ec5e295
--- /dev/null
+++ b/Source/core/html/EmailInputType.cpp
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2009 Michelangelo De Simone <micdesim@gmail.com>
+ * Copyright (C) 2010 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/EmailInputType.h"
+
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/text/RegularExpression.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+static const char emailPattern[] =
+    "[a-z0-9!#$%&'*+/=?^_`{|}~.-]+" // local part
+    "@"
+    "[a-z0-9-]+(\\.[a-z0-9-]+)*"; // domain part
+
+static bool isValidEmailAddress(const String& address)
+{
+    int addressLength = address.length();
+    if (!addressLength)
+        return false;
+
+    DEFINE_STATIC_LOCAL(const RegularExpression, regExp, (emailPattern, TextCaseInsensitive));
+
+    int matchLength;
+    int matchOffset = regExp.match(address, 0, &matchLength);
+
+    return !matchOffset && matchLength == addressLength;
+}
+
+PassOwnPtr<InputType> EmailInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new EmailInputType(element));
+}
+
+void EmailInputType::attach()
+{
+    TextFieldInputType::attach();
+    observeFeatureIfVisible(UseCounter::InputTypeEmail);
+}
+
+const AtomicString& EmailInputType::formControlType() const
+{
+    return InputTypeNames::email();
+}
+
+bool EmailInputType::typeMismatchFor(const String& value) const
+{
+    if (value.isEmpty())
+        return false;
+    if (!element()->multiple())
+        return !isValidEmailAddress(value);
+    Vector<String> addresses;
+    value.split(',', true, addresses);
+    for (unsigned i = 0; i < addresses.size(); ++i) {
+        if (!isValidEmailAddress(stripLeadingAndTrailingHTMLSpaces(addresses[i])))
+            return true;
+    }
+    return false;
+}
+
+bool EmailInputType::typeMismatch() const
+{
+    return typeMismatchFor(element()->value());
+}
+
+String EmailInputType::typeMismatchText() const
+{
+    return element()->multiple() ? validationMessageTypeMismatchForMultipleEmailText() : validationMessageTypeMismatchForEmailText();
+}
+
+bool EmailInputType::isEmailField() const
+{
+    return true;
+}
+
+bool EmailInputType::supportsSelectionAPI() const
+{
+    return false;
+}
+
+String EmailInputType::sanitizeValue(const String& proposedValue) const
+{
+    String noLineBreakValue = proposedValue.removeCharacters(isHTMLLineBreak);
+    if (!element()->multiple())
+        return stripLeadingAndTrailingHTMLSpaces(noLineBreakValue);
+    Vector<String> addresses;
+    noLineBreakValue.split(',', true, addresses);
+    StringBuilder strippedValue;
+    for (unsigned i = 0; i < addresses.size(); ++i) {
+        if (i > 0)
+            strippedValue.append(",");
+        strippedValue.append(stripLeadingAndTrailingHTMLSpaces(addresses[i]));
+    }
+    return strippedValue.toString();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/EmailInputType.h b/Source/core/html/EmailInputType.h
new file mode 100644
index 0000000..b33689e
--- /dev/null
+++ b/Source/core/html/EmailInputType.h
@@ -0,0 +1,56 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 EmailInputType_h
+#define EmailInputType_h
+
+#include "core/html/BaseTextInputType.h"
+
+namespace WebCore {
+
+class EmailInputType : public BaseTextInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    EmailInputType(HTMLInputElement* element) : BaseTextInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool typeMismatchFor(const String&) const OVERRIDE;
+    virtual bool typeMismatch() const OVERRIDE;
+    virtual String typeMismatchText() const OVERRIDE;
+    virtual bool isEmailField() const OVERRIDE;
+    virtual bool supportsSelectionAPI() const OVERRIDE;
+    virtual String sanitizeValue(const String&) const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // ButtonInputType_h
diff --git a/Source/core/html/FileInputType.cpp b/Source/core/html/FileInputType.cpp
new file mode 100644
index 0000000..b61e2cb
--- /dev/null
+++ b/Source/core/html/FileInputType.cpp
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/FileInputType.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/Event.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/fileapi/File.h"
+#include "core/fileapi/FileList.h"
+#include "core/html/FormController.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/page/Chrome.h"
+#include "core/page/Frame.h"
+#include "RuntimeEnabledFeatures.h"
+#include "core/platform/DragData.h"
+#include "core/platform/FileSystem.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/graphics/Icon.h"
+#include "core/rendering/RenderFileUploadControl.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+class UploadButtonElement : public HTMLInputElement {
+public:
+    static PassRefPtr<UploadButtonElement> create(Document*);
+    static PassRefPtr<UploadButtonElement> createForMultiple(Document*);
+
+private:
+    UploadButtonElement(Document*);
+
+    virtual const AtomicString& shadowPseudoId() const;
+};
+
+PassRefPtr<UploadButtonElement> UploadButtonElement::create(Document* document)
+{
+    RefPtr<UploadButtonElement> button = adoptRef(new UploadButtonElement(document));
+    button->setType("button");
+    button->setValue(fileButtonChooseFileLabel());
+    return button.release();
+}
+
+PassRefPtr<UploadButtonElement> UploadButtonElement::createForMultiple(Document* document)
+{
+    RefPtr<UploadButtonElement> button = adoptRef(new UploadButtonElement(document));
+    button->setType("button");
+    button->setValue(fileButtonChooseMultipleFilesLabel());
+    return button.release();
+}
+
+UploadButtonElement::UploadButtonElement(Document* document)
+    : HTMLInputElement(inputTag, document, 0, false)
+{
+}
+
+const AtomicString& UploadButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-file-upload-button", AtomicString::ConstructFromLiteral));
+    return pseudoId;
+}
+
+inline FileInputType::FileInputType(HTMLInputElement* element)
+    : BaseClickableWithKeyInputType(element)
+    , m_fileList(FileList::create())
+{
+}
+
+PassOwnPtr<InputType> FileInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new FileInputType(element));
+}
+
+Vector<FileChooserFileInfo> FileInputType::filesFromFormControlState(const FormControlState& state)
+{
+    Vector<FileChooserFileInfo> files;
+    for (size_t i = 0; i < state.valueSize(); i += 2) {
+        if (!state[i + 1].isEmpty())
+            files.append(FileChooserFileInfo(state[i], state[i + 1]));
+        else
+            files.append(FileChooserFileInfo(state[i]));
+    }
+    return files;
+}
+
+const AtomicString& FileInputType::formControlType() const
+{
+    return InputTypeNames::file();
+}
+
+FormControlState FileInputType::saveFormControlState() const
+{
+    if (m_fileList->isEmpty())
+        return FormControlState();
+    FormControlState state;
+    unsigned numFiles = m_fileList->length();
+    for (unsigned i = 0; i < numFiles; ++i) {
+        state.append(m_fileList->item(i)->path());
+        state.append(m_fileList->item(i)->name());
+    }
+    return state;
+}
+
+void FileInputType::restoreFormControlState(const FormControlState& state)
+{
+    if (state.valueSize() % 2)
+        return;
+    filesChosen(filesFromFormControlState(state));
+}
+
+bool FileInputType::appendFormData(FormDataList& encoding, bool multipart) const
+{
+    FileList* fileList = element()->files();
+    unsigned numFiles = fileList->length();
+    if (!multipart) {
+        // Send only the basenames.
+        // 4.10.16.4 and 4.10.16.6 sections in HTML5.
+
+        // Unlike the multipart case, we have no special handling for the empty
+        // fileList because Netscape doesn't support for non-multipart
+        // submission of file inputs, and Firefox doesn't add "name=" query
+        // parameter.
+        for (unsigned i = 0; i < numFiles; ++i)
+            encoding.appendData(element()->name(), fileList->item(i)->name());
+        return true;
+    }
+
+    // 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(element()->name(), File::create(""));
+        return true;
+    }
+
+    for (unsigned i = 0; i < numFiles; ++i)
+        encoding.appendBlob(element()->name(), fileList->item(i));
+    return true;
+}
+
+bool FileInputType::valueMissing(const String& value) const
+{
+    return element()->isRequired() && value.isEmpty();
+}
+
+String FileInputType::valueMissingText() const
+{
+    return element()->multiple() ? validationMessageValueMissingForMultipleFileText() : validationMessageValueMissingForFileText();
+}
+
+void FileInputType::handleDOMActivateEvent(Event* event)
+{
+    if (element()->isDisabledFormControl())
+        return;
+
+    if (!ScriptController::processingUserGesture())
+        return;
+
+    if (Chrome* chrome = this->chrome()) {
+        FileChooserSettings settings;
+        HTMLInputElement* input = element();
+        settings.allowsDirectoryUpload = RuntimeEnabledFeatures::directoryUploadEnabled() && input->fastHasAttribute(webkitdirectoryAttr);
+        settings.allowsMultipleFiles = settings.allowsDirectoryUpload || input->fastHasAttribute(multipleAttr);
+        settings.acceptMIMETypes = input->acceptMIMETypes();
+        settings.acceptFileExtensions = input->acceptFileExtensions();
+        settings.selectedFiles = m_fileList->paths();
+#if ENABLE(MEDIA_CAPTURE)
+        settings.capture = input->capture();
+#endif
+        chrome->runOpenPanel(input->document()->frame(), newFileChooser(settings));
+    }
+    event->setDefaultHandled();
+}
+
+RenderObject* FileInputType::createRenderer(RenderArena* arena, RenderStyle*) const
+{
+    return new (arena) RenderFileUploadControl(element());
+}
+
+bool FileInputType::canSetStringValue() const
+{
+    return false;
+}
+
+bool FileInputType::canChangeFromAnotherType() const
+{
+    // Don't allow the type to be changed to file after the first type change.
+    // In other engines this might mean a JavaScript programmer could set a text
+    // field's value to something like /etc/passwd and then change it to a file input.
+    // I don't think this would actually occur in WebKit, but this rule still may be
+    // important for compatibility.
+    return false;
+}
+
+FileList* FileInputType::files()
+{
+    return m_fileList.get();
+}
+
+bool FileInputType::canSetValue(const String& value)
+{
+    // 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 at all, but for now we are keeping this behavior
+    // to avoid breaking existing websites that may be relying on this.
+    return value.isEmpty();
+}
+
+bool FileInputType::getTypeSpecificValue(String& value)
+{
+    if (m_fileList->isEmpty()) {
+        value = String();
+        return true;
+    }
+
+    // HTML5 tells us that we're supposed to use this goofy value for
+    // file input controls. Historically, browsers revealed the real
+    // file path, but that's a privacy problem. Code on the web
+    // decided to try to parse the value by looking for backslashes
+    // (because that's what Windows file paths use). To be compatible
+    // with that code, we make up a fake path for the file.
+    value = "C:\\fakepath\\" + m_fileList->item(0)->name();
+    return true;
+}
+
+void FileInputType::setValue(const String&, bool, TextFieldEventBehavior)
+{
+    m_fileList->clear();
+    m_icon.clear();
+    element()->setNeedsStyleRecalc();
+}
+
+PassRefPtr<FileList> FileInputType::createFileList(const Vector<FileChooserFileInfo>& files) const
+{
+    RefPtr<FileList> fileList(FileList::create());
+    size_t size = files.size();
+
+    // If a directory is being selected, the UI allows a directory to be chosen
+    // and the paths provided here share a root directory somewhere up the tree;
+    // we want to store only the relative paths from that point.
+    if (size && element()->fastHasAttribute(webkitdirectoryAttr) && RuntimeEnabledFeatures::directoryUploadEnabled()) {
+        // Find the common root path.
+        String rootPath = directoryName(files[0].path);
+        for (size_t i = 1; i < size; i++) {
+            while (!files[i].path.startsWith(rootPath))
+                rootPath = directoryName(rootPath);
+        }
+        rootPath = directoryName(rootPath);
+        ASSERT(rootPath.length());
+        int rootLength = rootPath.length();
+        if (rootPath[rootLength - 1] != '\\' && rootPath[rootLength - 1] != '/')
+            rootLength += 1;
+        for (size_t i = 0; i < size; i++) {
+            // Normalize backslashes to slashes before exposing the relative path to script.
+            String relativePath = files[i].path.substring(rootLength).replace('\\', '/');
+            fileList->append(File::createWithRelativePath(files[i].path, relativePath));
+        }
+        return fileList;
+    }
+
+    for (size_t i = 0; i < size; i++)
+        fileList->append(File::createWithName(files[i].path, files[i].displayName, File::AllContentTypes));
+    return fileList;
+}
+
+bool FileInputType::isFileUpload() const
+{
+    return true;
+}
+
+void FileInputType::createShadowSubtree()
+{
+    ASSERT(element()->shadow());
+    element()->userAgentShadowRoot()->appendChild(element()->multiple() ? UploadButtonElement::createForMultiple(element()->document()): UploadButtonElement::create(element()->document()), IGNORE_EXCEPTION);
+}
+
+void FileInputType::disabledAttributeChanged()
+{
+    ASSERT(element()->shadow());
+    UploadButtonElement* button = static_cast<UploadButtonElement*>(element()->userAgentShadowRoot()->firstChild());
+    if (button)
+        button->setBooleanAttribute(disabledAttr, element()->isDisabledFormControl());
+}
+
+void FileInputType::multipleAttributeChanged()
+{
+    ASSERT(element()->shadow());
+    UploadButtonElement* button = static_cast<UploadButtonElement*>(element()->userAgentShadowRoot()->firstChild());
+    if (button)
+        button->setValue(element()->multiple() ? fileButtonChooseMultipleFilesLabel() : fileButtonChooseFileLabel());
+}
+
+void FileInputType::requestIcon(const Vector<String>& paths)
+{
+    if (!paths.size())
+        return;
+
+    if (Chrome* chrome = this->chrome())
+        chrome->loadIconForFiles(paths, newFileIconLoader());
+}
+
+void FileInputType::setFiles(PassRefPtr<FileList> files)
+{
+    if (!files)
+        return;
+
+    RefPtr<HTMLInputElement> input = element();
+
+    bool pathsChanged = false;
+    if (files->length() != m_fileList->length())
+        pathsChanged = true;
+    else {
+        for (unsigned i = 0; i < files->length(); ++i) {
+            if (files->item(i)->path() != m_fileList->item(i)->path()) {
+                pathsChanged = true;
+                break;
+            }
+        }
+    }
+
+    m_fileList = files;
+
+    input->setFormControlValueMatchesRenderer(true);
+    input->notifyFormStateChanged();
+    input->setNeedsValidityCheck();
+
+    Vector<String> paths;
+    for (unsigned i = 0; i < m_fileList->length(); ++i)
+        paths.append(m_fileList->item(i)->path());
+    requestIcon(paths);
+
+    if (input->renderer())
+        input->renderer()->repaint();
+
+    if (pathsChanged) {
+        // This call may cause destruction of this instance.
+        // input instance is safe since it is ref-counted.
+        input->HTMLElement::dispatchChangeEvent();
+    }
+    input->setChangedSinceLastFormControlChangeEvent(false);
+}
+
+void FileInputType::filesChosen(const Vector<FileChooserFileInfo>& files)
+{
+    setFiles(createFileList(files));
+}
+
+void FileInputType::receiveDropForDirectoryUpload(const Vector<String>& paths)
+{
+    if (Chrome* chrome = this->chrome()) {
+        FileChooserSettings settings;
+        HTMLInputElement* input = element();
+        settings.allowsDirectoryUpload = true;
+        settings.allowsMultipleFiles = true;
+        settings.selectedFiles.append(paths[0]);
+        settings.acceptMIMETypes = input->acceptMIMETypes();
+        settings.acceptFileExtensions = input->acceptFileExtensions();
+        chrome->enumerateChosenDirectory(newFileChooser(settings));
+    }
+}
+
+void FileInputType::updateRendering(PassRefPtr<Icon> icon)
+{
+    if (m_icon == icon)
+        return;
+
+    m_icon = icon;
+    if (element()->renderer())
+        element()->renderer()->repaint();
+}
+
+bool FileInputType::receiveDroppedFiles(const DragData* dragData)
+{
+    Vector<String> paths;
+    dragData->asFilenames(paths);
+    if (paths.isEmpty())
+        return false;
+
+    HTMLInputElement* input = element();
+    if (input->fastHasAttribute(webkitdirectoryAttr) && RuntimeEnabledFeatures::directoryUploadEnabled()) {
+        receiveDropForDirectoryUpload(paths);
+        return true;
+    }
+
+    m_droppedFileSystemId = dragData->droppedFileSystemId();
+
+    Vector<FileChooserFileInfo> files;
+    for (unsigned i = 0; i < paths.size(); ++i)
+        files.append(FileChooserFileInfo(paths[i]));
+
+    if (input->fastHasAttribute(multipleAttr))
+        filesChosen(files);
+    else {
+        Vector<FileChooserFileInfo> firstFileOnly;
+        firstFileOnly.append(files[0]);
+        filesChosen(firstFileOnly);
+    }
+    return true;
+}
+
+String FileInputType::droppedFileSystemId()
+{
+    return m_droppedFileSystemId;
+}
+
+Icon* FileInputType::icon() const
+{
+    return m_icon.get();
+}
+
+String FileInputType::defaultToolTip() const
+{
+    FileList* fileList = m_fileList.get();
+    unsigned listSize = fileList->length();
+    if (!listSize) {
+        if (element()->multiple())
+            return fileButtonNoFilesSelectedLabel();
+        return fileButtonNoFileSelectedLabel();
+    }
+
+    StringBuilder names;
+    for (size_t i = 0; i < listSize; ++i) {
+        names.append(fileList->item(i)->name());
+        if (i != listSize - 1)
+            names.append('\n');
+    }
+    return names.toString();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/FileInputType.h b/Source/core/html/FileInputType.h
new file mode 100644
index 0000000..104fc84
--- /dev/null
+++ b/Source/core/html/FileInputType.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 FileInputType_h
+#define FileInputType_h
+
+#include "core/html/BaseClickableWithKeyInputType.h"
+#include "core/platform/FileChooser.h"
+#include "core/platform/FileIconLoader.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class DragData;
+class FileList;
+
+class FileInputType : public BaseClickableWithKeyInputType, private FileChooserClient, private FileIconLoaderClient {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+    static Vector<FileChooserFileInfo> filesFromFormControlState(const FormControlState&);
+
+private:
+    FileInputType(HTMLInputElement*);
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual FormControlState saveFormControlState() const OVERRIDE;
+    virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
+    virtual bool appendFormData(FormDataList&, bool) const OVERRIDE;
+    virtual bool valueMissing(const String&) const OVERRIDE;
+    virtual String valueMissingText() const OVERRIDE;
+    virtual void handleDOMActivateEvent(Event*) OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
+    virtual bool canSetStringValue() const OVERRIDE;
+    virtual bool canChangeFromAnotherType() const OVERRIDE;
+    virtual FileList* files() OVERRIDE;
+    virtual void setFiles(PassRefPtr<FileList>) OVERRIDE;
+    virtual bool canSetValue(const String&) OVERRIDE;
+    virtual bool getTypeSpecificValue(String&) OVERRIDE; // Checked first, before internal storage or the value attribute.
+    virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE;
+    virtual bool receiveDroppedFiles(const DragData*) OVERRIDE;
+    virtual String droppedFileSystemId() OVERRIDE;
+    virtual Icon* icon() const OVERRIDE;
+    virtual bool isFileUpload() const OVERRIDE;
+    virtual void createShadowSubtree() OVERRIDE;
+    virtual void disabledAttributeChanged() OVERRIDE;
+    virtual void multipleAttributeChanged() OVERRIDE;
+    virtual String defaultToolTip() const OVERRIDE;
+
+    // FileChooserClient implementation.
+    virtual void filesChosen(const Vector<FileChooserFileInfo>&) OVERRIDE;
+
+    // FileIconLoaderClient implementation.
+    virtual void updateRendering(PassRefPtr<Icon>) OVERRIDE;
+
+    PassRefPtr<FileList> createFileList(const Vector<FileChooserFileInfo>& files) const;
+    void receiveDropForDirectoryUpload(const Vector<String>&);
+    void requestIcon(const Vector<String>&);
+
+    RefPtr<FileList> m_fileList;
+    RefPtr<Icon> m_icon;
+
+    String m_droppedFileSystemId;
+};
+
+} // namespace WebCore
+
+#endif // FileInputType_h
diff --git a/Source/core/html/FormAssociatedElement.cpp b/Source/core/html/FormAssociatedElement.cpp
new file mode 100644
index 0000000..d0c51fc
--- /dev/null
+++ b/Source/core/html/FormAssociatedElement.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/FormAssociatedElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/IdTargetObserver.h"
+#include "core/html/FormController.h"
+#include "core/html/HTMLFormControlElement.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLObjectElement.h"
+#include "core/html/ValidityState.h"
+#include "core/page/EditorClient.h"
+#include "core/page/Frame.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+class FormAttributeTargetObserver : IdTargetObserver {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*);
+    virtual void idTargetChanged() OVERRIDE;
+
+private:
+    FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement*);
+
+    FormAssociatedElement* m_element;
+};
+
+FormAssociatedElement::FormAssociatedElement()
+    : m_form(0)
+{
+}
+
+FormAssociatedElement::~FormAssociatedElement()
+{
+    setForm(0);
+}
+
+ValidityState* FormAssociatedElement::validity()
+{
+    if (!m_validityState)
+        m_validityState = ValidityState::create(this);
+
+    return m_validityState.get();
+}
+
+void FormAssociatedElement::didMoveToNewDocument(Document* oldDocument)
+{
+    HTMLElement* element = toHTMLElement(this);
+    if (oldDocument && element->fastHasAttribute(formAttr))
+        resetFormAttributeTargetObserver();
+}
+
+void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
+{
+    resetFormOwner();
+    if (!insertionPoint->inDocument())
+        return;
+
+    HTMLElement* element = toHTMLElement(this);
+    if (element->fastHasAttribute(formAttr))
+        resetFormAttributeTargetObserver();
+}
+
+void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint)
+{
+    HTMLElement* element = toHTMLElement(this);
+    if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr))
+        m_formAttributeTargetObserver = nullptr;
+    // If the form and element are both in the same tree, preserve the connection to the form.
+    // Otherwise, null out our form and remove ourselves from the form's list of elements.
+    if (m_form && element->highestAncestor() != m_form->highestAncestor())
+        setForm(0);
+}
+
+HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element, HTMLFormElement* currentAssociatedForm)
+{
+    const AtomicString& formId(element->fastGetAttribute(formAttr));
+    if (!formId.isNull() && element->inDocument()) {
+        // The HTML5 spec says that the element should be associated with
+        // the first element in the document to have an ID that equal to
+        // the value of form attribute, so we put the result of
+        // treeScope()->getElementById() over the given element.
+        HTMLFormElement* newForm = 0;
+        Element* newFormCandidate = element->treeScope()->getElementById(formId);
+        if (newFormCandidate && newFormCandidate->hasTagName(formTag))
+            newForm = static_cast<HTMLFormElement*>(newFormCandidate);
+        return newForm;
+    }
+
+    if (!currentAssociatedForm)
+        return element->findFormAncestor();
+
+    return currentAssociatedForm;
+}
+
+void FormAssociatedElement::formRemovedFromTree(const Node* formRoot)
+{
+    ASSERT(m_form);
+    if (toHTMLElement(this)->highestAncestor() != formRoot)
+        setForm(0);
+}
+
+void FormAssociatedElement::setForm(HTMLFormElement* newForm)
+{
+    if (m_form == newForm)
+        return;
+    willChangeForm();
+    if (m_form)
+        m_form->removeFormElement(this);
+    m_form = newForm;
+    if (m_form)
+        m_form->registerFormElement(this);
+    didChangeForm();
+}
+
+void FormAssociatedElement::willChangeForm()
+{
+}
+
+void FormAssociatedElement::didChangeForm()
+{
+}
+
+void FormAssociatedElement::formWillBeDestroyed()
+{
+    ASSERT(m_form);
+    if (!m_form)
+        return;
+    willChangeForm();
+    m_form = 0;
+    didChangeForm();
+}
+
+void FormAssociatedElement::resetFormOwner()
+{
+    HTMLFormElement* originalForm = m_form;
+    setForm(findAssociatedForm(toHTMLElement(this), m_form));
+    HTMLElement* element = toHTMLElement(this);     
+    if (m_form && m_form != originalForm && m_form->inDocument())
+        element->document()->didAssociateFormControl(element);
+}
+
+void FormAssociatedElement::formAttributeChanged()
+{
+    HTMLElement* element = toHTMLElement(this);
+    if (!element->fastHasAttribute(formAttr)) {
+        // The form attribute removed. We need to reset form owner here.
+        HTMLFormElement* originalForm = m_form;
+        setForm(element->findFormAncestor());
+        HTMLElement* element = toHTMLElement(this);
+        if (m_form && m_form != originalForm && m_form->inDocument())
+            element->document()->didAssociateFormControl(element);
+        m_formAttributeTargetObserver = nullptr;
+    } else {
+        resetFormOwner();
+        resetFormAttributeTargetObserver();
+    }
+}
+
+bool FormAssociatedElement::customError() const
+{
+    const HTMLElement* element = toHTMLElement(this);
+    return element->willValidate() && !m_customValidationMessage.isEmpty();
+}
+
+bool FormAssociatedElement::hasBadInput() const
+{
+    return false;
+}
+
+bool FormAssociatedElement::patternMismatch() const
+{
+    return false;
+}
+
+bool FormAssociatedElement::rangeOverflow() const
+{
+    return false;
+}
+
+bool FormAssociatedElement::rangeUnderflow() const
+{
+    return false;
+}
+
+bool FormAssociatedElement::stepMismatch() const
+{
+    return false;
+}
+
+bool FormAssociatedElement::tooLong() const
+{
+    return false;
+}
+
+bool FormAssociatedElement::typeMismatch() const
+{
+    return false;
+}
+
+bool FormAssociatedElement::valid() const
+{
+    bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
+        || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
+    return !someError;
+}
+
+bool FormAssociatedElement::valueMissing() const
+{
+    return false;
+}
+
+String FormAssociatedElement::customValidationMessage() const
+{
+    return m_customValidationMessage;
+}
+
+String FormAssociatedElement::validationMessage() const
+{
+    return customError() ? m_customValidationMessage : String();
+}
+
+void FormAssociatedElement::setCustomValidity(const String& error)
+{
+    m_customValidationMessage = error;
+}
+
+void FormAssociatedElement::resetFormAttributeTargetObserver()
+{
+    m_formAttributeTargetObserver = FormAttributeTargetObserver::create(toHTMLElement(this)->fastGetAttribute(formAttr), this);
+}
+
+void FormAssociatedElement::formAttributeTargetChanged()
+{
+    resetFormOwner();
+}
+
+const AtomicString& FormAssociatedElement::name() const
+{
+    const AtomicString& name = toHTMLElement(this)->getNameAttribute();
+    return name.isNull() ? emptyAtom : name;
+}
+
+bool FormAssociatedElement::isFormControlElementWithState() const
+{
+    return false;
+}
+
+const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
+{
+    if (associatedElement->isFormControlElement())
+        return static_cast<const HTMLFormControlElement*>(associatedElement);
+    // Assumes the element is an HTMLObjectElement
+    const HTMLElement* element = static_cast<const HTMLObjectElement*>(associatedElement);
+    ASSERT(element->hasTagName(objectTag));
+    return element;
+}
+
+HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
+{
+    return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
+}
+
+PassOwnPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
+{
+    return adoptPtr(new FormAttributeTargetObserver(id, element));
+}
+
+FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
+    : IdTargetObserver(toHTMLElement(element)->treeScope()->idTargetObserverRegistry(), id)
+    , m_element(element)
+{
+}
+
+void FormAttributeTargetObserver::idTargetChanged()
+{
+    m_element->formAttributeTargetChanged();
+}
+
+} // namespace Webcore
diff --git a/Source/core/html/FormAssociatedElement.h b/Source/core/html/FormAssociatedElement.h
new file mode 100644
index 0000000..40f2b36
--- /dev/null
+++ b/Source/core/html/FormAssociatedElement.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FormAssociatedElement_h
+#define FormAssociatedElement_h
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class ContainerNode;
+class Document;
+class FormAttributeTargetObserver;
+class FormDataList;
+class HTMLElement;
+class HTMLFormElement;
+class Node;
+class ValidationMessage;
+class ValidityState;
+class VisibleSelection;
+
+class FormAssociatedElement {
+public:
+    virtual ~FormAssociatedElement();
+
+    void ref() { refFormAssociatedElement(); }
+    void deref() { derefFormAssociatedElement(); }
+
+    static HTMLFormElement* findAssociatedForm(const HTMLElement*, HTMLFormElement*);
+    HTMLFormElement* form() const { return m_form; }
+    ValidityState* validity();
+
+    virtual bool isFormControlElement() const = 0;
+    virtual bool isFormControlElementWithState() const;
+    virtual bool isEnumeratable() const = 0;
+
+    // Returns the 'name' attribute value. If this element has no name
+    // attribute, it returns an empty string instead of null string.
+    // Note that the 'name' IDL attribute doesn't use this function.
+    virtual const AtomicString& name() const;
+
+    // Override in derived classes to get the encoded name=value pair for submitting.
+    // Return true for a successful control (see HTML4-17.13.2).
+    virtual bool appendFormData(FormDataList&, bool) { return false; }
+
+    void formWillBeDestroyed();
+
+    void resetFormOwner();
+
+    void formRemovedFromTree(const Node* formRoot);
+
+    // ValidityState attribute implementations
+    bool customError() const;
+
+    // Override functions for patterMismatch, rangeOverflow, rangerUnderflow,
+    // stepMismatch, tooLong and valueMissing must call willValidate method.
+    virtual bool hasBadInput() const;
+    virtual bool patternMismatch() const;
+    virtual bool rangeOverflow() const;
+    virtual bool rangeUnderflow() const;
+    virtual bool stepMismatch() const;
+    virtual bool tooLong() const;
+    virtual bool typeMismatch() const;
+    virtual bool valueMissing() const;
+    virtual String validationMessage() const;
+    bool valid() const;
+    virtual void setCustomValidity(const String&);
+
+    void formAttributeTargetChanged();
+
+protected:
+    FormAssociatedElement();
+
+    void insertedInto(ContainerNode*);
+    void removedFrom(ContainerNode*);
+    void didMoveToNewDocument(Document* oldDocument);
+
+    void setForm(HTMLFormElement*);
+    void formAttributeChanged();
+
+    // If you add an override of willChangeForm() or didChangeForm() to a class
+    // derived from this one, you will need to add a call to setForm(0) to the
+    // destructor of that class.
+    virtual void willChangeForm();
+    virtual void didChangeForm();
+
+    String customValidationMessage() const;
+
+private:
+    virtual void refFormAssociatedElement() = 0;
+    virtual void derefFormAssociatedElement() = 0;
+
+    void resetFormAttributeTargetObserver();
+
+    OwnPtr<FormAttributeTargetObserver> m_formAttributeTargetObserver;
+    HTMLFormElement* m_form;
+    OwnPtr<ValidityState> m_validityState;
+    String m_customValidationMessage;
+};
+
+HTMLElement* toHTMLElement(FormAssociatedElement*);
+const HTMLElement* toHTMLElement(const FormAssociatedElement*);
+
+} // namespace
+
+#endif // FormAssociatedElement_h
diff --git a/Source/core/html/FormController.cpp b/Source/core/html/FormController.cpp
new file mode 100644
index 0000000..e6c64d9
--- /dev/null
+++ b/Source/core/html/FormController.cpp
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2012 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/FormController.h"
+
+#include "core/html/HTMLFormControlElementWithState.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/platform/FileChooser.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static inline HTMLFormElement* ownerFormForState(const HTMLFormControlElementWithState& control)
+{
+    // Assume controls with form attribute have no owners because we restore
+    // state during parsing and form owners of such controls might be
+    // indeterminate.
+    return control.fastHasAttribute(formAttr) ? 0 : control.form();
+}
+
+// ----------------------------------------------------------------------------
+
+// Serilized form of FormControlState:
+//  (',' means strings around it are separated in stateVector.)
+//
+// SerializedControlState ::= SkipState | RestoreState
+// SkipState ::= '0'
+// RestoreState ::= UnsignedNumber, ControlValue+
+// UnsignedNumber ::= [0-9]+
+// ControlValue ::= arbitrary string
+//
+// RestoreState has a sequence of ControlValues. The length of the
+// sequence is represented by UnsignedNumber.
+
+void FormControlState::serializeTo(Vector<String>& stateVector) const
+{
+    ASSERT(!isFailure());
+    stateVector.append(String::number(m_values.size()));
+    for (size_t i = 0; i < m_values.size(); ++i)
+        stateVector.append(m_values[i].isNull() ? emptyString() : m_values[i]);
+}
+
+FormControlState FormControlState::deserialize(const Vector<String>& stateVector, size_t& index)
+{
+    if (index >= stateVector.size())
+        return FormControlState(TypeFailure);
+    size_t valueSize = stateVector[index++].toUInt();
+    if (!valueSize)
+        return FormControlState();
+    if (index + valueSize > stateVector.size())
+        return FormControlState(TypeFailure);
+    FormControlState state;
+    state.m_values.reserveCapacity(valueSize);
+    for (size_t i = 0; i < valueSize; ++i)
+        state.append(stateVector[index++]);
+    return state;
+}
+
+// ----------------------------------------------------------------------------
+
+class FormElementKey {
+public:
+    FormElementKey(AtomicStringImpl* = 0, AtomicStringImpl* = 0);
+    ~FormElementKey();
+    FormElementKey(const FormElementKey&);
+    FormElementKey& operator=(const FormElementKey&);
+
+    AtomicStringImpl* name() const { return m_name; }
+    AtomicStringImpl* type() const { return m_type; }
+
+    // Hash table deleted values, which are only constructed and never copied or destroyed.
+    FormElementKey(WTF::HashTableDeletedValueType) : m_name(hashTableDeletedValue()) { }
+    bool isHashTableDeletedValue() const { return m_name == hashTableDeletedValue(); }
+
+private:
+    void ref() const;
+    void deref() const;
+
+    static AtomicStringImpl* hashTableDeletedValue() { return reinterpret_cast<AtomicStringImpl*>(-1); }
+
+    AtomicStringImpl* m_name;
+    AtomicStringImpl* m_type;
+};
+
+FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type)
+    : m_name(name)
+    , m_type(type)
+{
+    ref();
+}
+
+FormElementKey::~FormElementKey()
+{
+    deref();
+}
+
+FormElementKey::FormElementKey(const FormElementKey& other)
+    : m_name(other.name())
+    , m_type(other.type())
+{
+    ref();
+}
+
+FormElementKey& FormElementKey::operator=(const FormElementKey& other)
+{
+    other.ref();
+    deref();
+    m_name = other.name();
+    m_type = other.type();
+    return *this;
+}
+
+void FormElementKey::ref() const
+{
+    if (name())
+        name()->ref();
+    if (type())
+        type()->ref();
+}
+
+void FormElementKey::deref() const
+{
+    if (name())
+        name()->deref();
+    if (type())
+        type()->deref();
+}
+
+inline bool operator==(const FormElementKey& a, const FormElementKey& b)
+{
+    return a.name() == b.name() && a.type() == b.type();
+}
+
+struct FormElementKeyHash {
+    static unsigned hash(const FormElementKey&);
+    static bool equal(const FormElementKey& a, const FormElementKey& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+unsigned FormElementKeyHash::hash(const FormElementKey& key)
+{
+    return StringHasher::hashMemory<sizeof(FormElementKey)>(&key);
+}
+
+struct FormElementKeyHashTraits : WTF::GenericHashTraits<FormElementKey> {
+    static void constructDeletedValue(FormElementKey& slot) { new (NotNull, &slot) FormElementKey(WTF::HashTableDeletedValue); }
+    static bool isDeletedValue(const FormElementKey& value) { return value.isHashTableDeletedValue(); }
+};
+
+// ----------------------------------------------------------------------------
+
+class SavedFormState {
+    WTF_MAKE_NONCOPYABLE(SavedFormState);
+    WTF_MAKE_FAST_ALLOCATED;
+
+public:
+    static PassOwnPtr<SavedFormState> create();
+    static PassOwnPtr<SavedFormState> deserialize(const Vector<String>&, size_t& index);
+    void serializeTo(Vector<String>&) const;
+    bool isEmpty() const { return m_stateForNewFormElements.isEmpty(); }
+    void appendControlState(const AtomicString& name, const AtomicString& type, const FormControlState&);
+    FormControlState takeControlState(const AtomicString& name, const AtomicString& type);
+
+    Vector<String> getReferencedFilePaths() const;
+
+private:
+    SavedFormState() : m_controlStateCount(0) { }
+
+    typedef HashMap<FormElementKey, Deque<FormControlState>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap;
+    FormElementStateMap m_stateForNewFormElements;
+    size_t m_controlStateCount;
+};
+
+PassOwnPtr<SavedFormState> SavedFormState::create()
+{
+    return adoptPtr(new SavedFormState);
+}
+
+static bool isNotFormControlTypeCharacter(UChar ch)
+{
+    return ch != '-' && (ch > 'z' || ch < 'a');
+}
+
+PassOwnPtr<SavedFormState> SavedFormState::deserialize(const Vector<String>& stateVector, size_t& index)
+{
+    if (index >= stateVector.size())
+        return nullptr;
+    // FIXME: We need String::toSizeT().
+    size_t itemCount = stateVector[index++].toUInt();
+    if (!itemCount)
+        return nullptr;
+    OwnPtr<SavedFormState> savedFormState = adoptPtr(new SavedFormState);
+    while (itemCount--) {
+        if (index + 1 >= stateVector.size())
+            return nullptr;
+        String name = stateVector[index++];
+        String type = stateVector[index++];
+        FormControlState state = FormControlState::deserialize(stateVector, index);
+        if (type.isEmpty() || type.find(isNotFormControlTypeCharacter) != notFound || state.isFailure())
+            return nullptr;
+        savedFormState->appendControlState(name, type, state);
+    }
+    return savedFormState.release();
+}
+
+void SavedFormState::serializeTo(Vector<String>& stateVector) const
+{
+    stateVector.append(String::number(m_controlStateCount));
+    for (FormElementStateMap::const_iterator it = m_stateForNewFormElements.begin(); it != m_stateForNewFormElements.end(); ++it) {
+        const FormElementKey& key = it->key;
+        const Deque<FormControlState>& queue = it->value;
+        for (Deque<FormControlState>::const_iterator queIterator = queue.begin(); queIterator != queue.end(); ++queIterator) {
+            stateVector.append(key.name());
+            stateVector.append(key.type());
+            queIterator->serializeTo(stateVector);
+        }
+    }
+}
+
+void SavedFormState::appendControlState(const AtomicString& name, const AtomicString& type, const FormControlState& state)
+{
+    FormElementKey key(name.impl(), type.impl());
+    FormElementStateMap::iterator it = m_stateForNewFormElements.find(key);
+    if (it != m_stateForNewFormElements.end())
+        it->value.append(state);
+    else {
+        Deque<FormControlState> stateList;
+        stateList.append(state);
+        m_stateForNewFormElements.set(key, stateList);
+    }
+    m_controlStateCount++;
+}
+
+FormControlState SavedFormState::takeControlState(const AtomicString& name, const AtomicString& type)
+{
+    if (m_stateForNewFormElements.isEmpty())
+        return FormControlState();
+    FormElementStateMap::iterator it = m_stateForNewFormElements.find(FormElementKey(name.impl(), type.impl()));
+    if (it == m_stateForNewFormElements.end())
+        return FormControlState();
+    ASSERT(it->value.size());
+    FormControlState state = it->value.takeFirst();
+    m_controlStateCount--;
+    if (!it->value.size())
+        m_stateForNewFormElements.remove(it);
+    return state;
+}
+
+Vector<String> SavedFormState::getReferencedFilePaths() const
+{
+    Vector<String> toReturn;
+    for (FormElementStateMap::const_iterator it = m_stateForNewFormElements.begin(); it != m_stateForNewFormElements.end(); ++it) {
+        const FormElementKey& key = it->key;
+        if (!equal(key.type(), "file", 4))
+            continue;
+        const Deque<FormControlState>& queue = it->value;
+        for (Deque<FormControlState>::const_iterator queIterator = queue.begin(); queIterator != queue.end(); ++queIterator) {
+            const Vector<FileChooserFileInfo>& selectedFiles = HTMLInputElement::filesFromFileInputFormControlState(*queIterator);
+            for (size_t i = 0; i < selectedFiles.size(); ++i)
+                toReturn.append(selectedFiles[i].path);
+        }
+    }
+    return toReturn;
+}
+
+// ----------------------------------------------------------------------------
+
+class FormKeyGenerator {
+    WTF_MAKE_NONCOPYABLE(FormKeyGenerator);
+    WTF_MAKE_FAST_ALLOCATED;
+
+public:
+    static PassOwnPtr<FormKeyGenerator> create() { return adoptPtr(new FormKeyGenerator); }
+    AtomicString formKey(const HTMLFormControlElementWithState&);
+    void willDeleteForm(HTMLFormElement*);
+
+private:
+    FormKeyGenerator() { }
+
+    typedef HashMap<HTMLFormElement*, AtomicString> FormToKeyMap;
+    typedef HashMap<String, unsigned> FormSignatureToNextIndexMap;
+    FormToKeyMap m_formToKeyMap;
+    FormSignatureToNextIndexMap m_formSignatureToNextIndexMap;
+};
+
+static inline void recordFormStructure(const HTMLFormElement& form, StringBuilder& builder)
+{
+    // 2 is enough to distinguish forms in webkit.org/b/91209#c0
+    const size_t namedControlsToBeRecorded = 2;
+    const Vector<FormAssociatedElement*>& controls = form.associatedElements();
+    builder.append(" [");
+    for (size_t i = 0, namedControls = 0; i < controls.size() && namedControls < namedControlsToBeRecorded; ++i) {
+        if (!controls[i]->isFormControlElementWithState())
+            continue;
+        HTMLFormControlElementWithState* control = static_cast<HTMLFormControlElementWithState*>(controls[i]);
+        if (!ownerFormForState(*control))
+            continue;
+        AtomicString name = control->name();
+        if (name.isEmpty())
+            continue;
+        namedControls++;
+        builder.append(name);
+        builder.append(" ");
+    }
+    builder.append("]");
+}
+
+static inline String formSignature(const HTMLFormElement& form)
+{
+    KURL actionURL = form.getURLAttribute(actionAttr);
+    // Remove the query part because it might contain volatile parameters such
+    // as a session key.
+    actionURL.setQuery(String());
+    StringBuilder builder;
+    if (!actionURL.isEmpty())
+        builder.append(actionURL.string());
+
+    recordFormStructure(form, builder);
+    return builder.toString();
+}
+
+AtomicString FormKeyGenerator::formKey(const HTMLFormControlElementWithState& control)
+{
+    HTMLFormElement* form = ownerFormForState(control);
+    if (!form) {
+        DEFINE_STATIC_LOCAL(AtomicString, formKeyForNoOwner, ("No owner", AtomicString::ConstructFromLiteral));
+        return formKeyForNoOwner;
+    }
+    FormToKeyMap::const_iterator it = m_formToKeyMap.find(form);
+    if (it != m_formToKeyMap.end())
+        return it->value;
+
+    String signature = formSignature(*form);
+    ASSERT(!signature.isNull());
+    FormSignatureToNextIndexMap::AddResult result = m_formSignatureToNextIndexMap.add(signature, 0);
+    unsigned nextIndex = result.iterator->value++;
+
+    StringBuilder builder;
+    builder.append(signature);
+    builder.appendLiteral(" #");
+    builder.appendNumber(nextIndex);
+    AtomicString formKey = builder.toAtomicString();
+    m_formToKeyMap.add(form, formKey);
+    return formKey;
+}
+
+void FormKeyGenerator::willDeleteForm(HTMLFormElement* form)
+{
+    ASSERT(form);
+    if (m_formToKeyMap.isEmpty())
+        return;
+    FormToKeyMap::iterator it = m_formToKeyMap.find(form);
+    if (it == m_formToKeyMap.end())
+        return;
+    m_formToKeyMap.remove(it);
+}
+
+// ----------------------------------------------------------------------------
+
+FormController::FormController()
+{
+}
+
+FormController::~FormController()
+{
+}
+
+static String formStateSignature()
+{
+    // In the legacy version of serialized state, the first item was a name
+    // attribute value of a form control. The following string literal should
+    // contain some characters which are rarely used for name attribute values.
+    DEFINE_STATIC_LOCAL(String, signature, (ASCIILiteral("\n\r?% WebKit serialized form state version 8 \n\r=&")));
+    return signature;
+}
+
+PassOwnPtr<FormController::SavedFormStateMap> FormController::createSavedFormStateMap(const FormElementListHashSet& controlList)
+{
+    OwnPtr<FormKeyGenerator> keyGenerator = FormKeyGenerator::create();
+    OwnPtr<SavedFormStateMap> stateMap = adoptPtr(new SavedFormStateMap);
+    for (FormElementListHashSet::const_iterator it = controlList.begin(); it != controlList.end(); ++it) {
+        HTMLFormControlElementWithState* control = *it;
+        if (!control->shouldSaveAndRestoreFormControlState())
+            continue;
+        SavedFormStateMap::AddResult result = stateMap->add(keyGenerator->formKey(*control).impl(), nullptr);
+        if (result.isNewEntry)
+            result.iterator->value = SavedFormState::create();
+        result.iterator->value->appendControlState(control->name(), control->type(), control->saveFormControlState());
+    }
+    return stateMap.release();
+}
+
+Vector<String> FormController::formElementsState() const
+{
+    OwnPtr<SavedFormStateMap> stateMap = createSavedFormStateMap(m_formElementsWithState);
+    Vector<String> stateVector;
+    stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 4);
+    stateVector.append(formStateSignature());
+    for (SavedFormStateMap::const_iterator it = stateMap->begin(); it != stateMap->end(); ++it) {
+        stateVector.append(it->key.get());
+        it->value->serializeTo(stateVector);
+    }
+    bool hasOnlySignature = stateVector.size() == 1;
+    if (hasOnlySignature)
+        stateVector.clear();
+    return stateVector;
+}
+
+void FormController::setStateForNewFormElements(const Vector<String>& stateVector)
+{
+    formStatesFromStateVector(stateVector, m_savedFormStateMap);
+}
+
+FormControlState FormController::takeStateForFormElement(const HTMLFormControlElementWithState& control)
+{
+    if (m_savedFormStateMap.isEmpty())
+        return FormControlState();
+    if (!m_formKeyGenerator)
+        m_formKeyGenerator = FormKeyGenerator::create();
+    SavedFormStateMap::iterator it = m_savedFormStateMap.find(m_formKeyGenerator->formKey(control).impl());
+    if (it == m_savedFormStateMap.end())
+        return FormControlState();
+    FormControlState state = it->value->takeControlState(control.name(), control.type());
+    if (it->value->isEmpty())
+        m_savedFormStateMap.remove(it);
+    return state;
+}
+
+void FormController::formStatesFromStateVector(const Vector<String>& stateVector, SavedFormStateMap& map)
+{
+    map.clear();
+
+    size_t i = 0;
+    if (stateVector.size() < 1 || stateVector[i++] != formStateSignature())
+        return;
+
+    while (i + 1 < stateVector.size()) {
+        AtomicString formKey = stateVector[i++];
+        OwnPtr<SavedFormState> state = SavedFormState::deserialize(stateVector, i);
+        if (!state) {
+            i = 0;
+            break;
+        }
+        map.add(formKey.impl(), state.release());
+    }
+    if (i != stateVector.size())
+        map.clear();
+}
+
+void FormController::willDeleteForm(HTMLFormElement* form)
+{
+    if (m_formKeyGenerator)
+        m_formKeyGenerator->willDeleteForm(form);
+}
+
+void FormController::restoreControlStateFor(HTMLFormControlElementWithState& control)
+{
+    // We don't save state of a control with shouldSaveAndRestoreFormControlState()
+    // == false. But we need to skip restoring process too because a control in
+    // another form might have the same pair of name and type and saved its state.
+    if (!control.shouldSaveAndRestoreFormControlState())
+        return;
+    if (ownerFormForState(control))
+        return;
+    FormControlState state = takeStateForFormElement(control);
+    if (state.valueSize() > 0)
+        control.restoreFormControlState(state);
+}
+
+void FormController::restoreControlStateIn(HTMLFormElement& form)
+{
+    const Vector<FormAssociatedElement*>& elements = form.associatedElements();
+    for (size_t i = 0; i < elements.size(); ++i) {
+        if (!elements[i]->isFormControlElementWithState())
+            continue;
+        HTMLFormControlElementWithState* control = static_cast<HTMLFormControlElementWithState*>(elements[i]);
+        if (!control->shouldSaveAndRestoreFormControlState())
+            continue;
+        if (ownerFormForState(*control) != &form)
+            continue;
+        FormControlState state = takeStateForFormElement(*control);
+        if (state.valueSize() > 0)
+            control->restoreFormControlState(state);
+    }
+}
+
+Vector<String> FormController::getReferencedFilePaths(const Vector<String>& stateVector)
+{
+    Vector<String> toReturn;
+    SavedFormStateMap map;
+    formStatesFromStateVector(stateVector, map);
+    for (SavedFormStateMap::const_iterator it = map.begin(); it != map.end(); ++it)
+        toReturn.append(it->value->getReferencedFilePaths());
+    return toReturn;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/FormController.h b/Source/core/html/FormController.h
new file mode 100644
index 0000000..2dbfef7
--- /dev/null
+++ b/Source/core/html/FormController.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2012 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FormController_h
+#define FormController_h
+
+#include "core/dom/CheckedRadioButtons.h"
+#include <wtf/Deque.h>
+#include <wtf/Forward.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class FormAssociatedElement;
+class FormKeyGenerator;
+class HTMLFormControlElementWithState;
+class HTMLFormElement;
+class SavedFormState;
+
+class FormControlState {
+public:
+    FormControlState() : m_type(TypeSkip) { }
+    explicit FormControlState(const String& value) : m_type(TypeRestore) { m_values.append(value); }
+    static FormControlState deserialize(const Vector<String>& stateVector, size_t& index);
+    FormControlState(const FormControlState& another) : m_type(another.m_type), m_values(another.m_values) { }
+    FormControlState& operator=(const FormControlState&);
+
+    bool isFailure() const { return m_type == TypeFailure; }
+    size_t valueSize() const { return m_values.size(); }
+    const String& operator[](size_t i) const { return m_values[i]; }
+    void append(const String&);
+    void serializeTo(Vector<String>& stateVector) const;
+
+private:
+    enum Type { TypeSkip, TypeRestore, TypeFailure };
+    explicit FormControlState(Type type) : m_type(type) { }
+
+    Type m_type;
+    Vector<String> m_values;
+};
+
+inline FormControlState& FormControlState::operator=(const FormControlState& another)
+{
+    m_type = another.m_type;
+    m_values = another.m_values;
+    return *this;
+}
+
+inline void FormControlState::append(const String& value)
+{
+    m_type = TypeRestore;
+    m_values.append(value);
+}
+
+class FormController {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<FormController> create()
+    {
+        return adoptPtr(new FormController);
+    }
+    ~FormController();
+
+    CheckedRadioButtons& checkedRadioButtons() { return m_checkedRadioButtons; }
+    
+    void registerFormElementWithState(HTMLFormControlElementWithState* control) { m_formElementsWithState.add(control); }
+    void unregisterFormElementWithState(HTMLFormControlElementWithState* control) { m_formElementsWithState.remove(control); }
+    // This should be callled only by Document::formElementsState().
+    Vector<String> formElementsState() const;
+    // This should be callled only by Document::setStateForNewFormElements().
+    void setStateForNewFormElements(const Vector<String>&);
+    void willDeleteForm(HTMLFormElement*);
+    void restoreControlStateFor(HTMLFormControlElementWithState&);
+    void restoreControlStateIn(HTMLFormElement&);
+
+    static Vector<String> getReferencedFilePaths(const Vector<String>& stateVector);
+
+private:
+    typedef ListHashSet<HTMLFormControlElementWithState*, 64> FormElementListHashSet;
+    typedef HashMap<RefPtr<AtomicStringImpl>, OwnPtr<SavedFormState> > SavedFormStateMap;
+
+    FormController();
+    static PassOwnPtr<SavedFormStateMap> createSavedFormStateMap(const FormElementListHashSet&);
+    FormControlState takeStateForFormElement(const HTMLFormControlElementWithState&);
+    static void formStatesFromStateVector(const Vector<String>&, SavedFormStateMap&);
+
+    CheckedRadioButtons m_checkedRadioButtons;
+    FormElementListHashSet m_formElementsWithState;
+    SavedFormStateMap m_savedFormStateMap;
+    OwnPtr<FormKeyGenerator> m_formKeyGenerator;
+};
+
+} // namespace WebCore
+#endif
diff --git a/Source/core/html/FormDataList.cpp b/Source/core/html/FormDataList.cpp
new file mode 100644
index 0000000..e1b6e71
--- /dev/null
+++ b/Source/core/html/FormDataList.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2005, 2006, 2008 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/FormDataList.h"
+
+#include "core/platform/text/LineEnding.h"
+
+namespace WebCore {
+
+FormDataList::FormDataList(const TextEncoding& c)
+    : m_encoding(c)
+{
+}
+
+void FormDataList::appendString(const String& s)
+{
+    CString cstr = m_encoding.encode(s.characters(), s.length(), EntitiesForUnencodables);
+    m_items.append(normalizeLineEndingsToCRLF(cstr));
+}
+
+void FormDataList::appendString(const CString& s)
+{
+    m_items.append(s);
+}
+
+void FormDataList::appendBlob(PassRefPtr<Blob> blob, const String& filename)
+{
+    m_items.append(Item(blob, filename));
+}
+
+} // namespace
diff --git a/Source/core/html/FormDataList.h b/Source/core/html/FormDataList.h
new file mode 100644
index 0000000..d83d4f2
--- /dev/null
+++ b/Source/core/html/FormDataList.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2005, 2006, 2008 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FormDataList_h
+#define FormDataList_h
+
+#include "core/fileapi/Blob.h"
+#include "core/platform/text/TextEncoding.h"
+#include <wtf/Forward.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+class FormDataList {
+public:
+    class Item {
+    public:
+        Item() { }
+        Item(const WTF::CString& data) : m_data(data) { }
+        Item(PassRefPtr<Blob> blob, const String& filename) : m_blob(blob), m_filename(filename) { }
+
+        const WTF::CString& data() const { return m_data; }
+        Blob* blob() const { return m_blob.get(); }
+        const String& filename() const { return m_filename; }
+
+    private:
+        WTF::CString m_data;
+        RefPtr<Blob> m_blob;
+        String m_filename;
+    };
+
+    FormDataList(const TextEncoding&);
+
+    void appendData(const String& key, const String& value)
+    {
+        appendString(key);
+        appendString(value);
+    }
+    void appendData(const String& key, const CString& value)
+    {
+        appendString(key);
+        appendString(value);
+    }
+    void appendData(const String& key, int value)
+    {
+        appendString(key);
+        appendString(String::number(value));
+    }
+    void appendBlob(const String& key, PassRefPtr<Blob> blob, const String& filename = String())
+    {
+        appendString(key);
+        appendBlob(blob, filename);
+    }
+
+    const Vector<Item>& items() const { return m_items; }
+    const TextEncoding& encoding() const { return m_encoding; }
+
+private:
+    void appendString(const CString&);
+    void appendString(const String&);
+    void appendBlob(PassRefPtr<Blob>, const String& filename);
+
+    TextEncoding m_encoding;
+    Vector<Item> m_items;
+};
+
+} // namespace WebCore
+
+#endif // FormDataList_h
diff --git a/Source/core/html/HTMLAllCollection.cpp b/Source/core/html/HTMLAllCollection.cpp
new file mode 100644
index 0000000..b3ffad3
--- /dev/null
+++ b/Source/core/html/HTMLAllCollection.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009, 2011, 2012 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. ``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. 
+ */
+
+#include "config.h"
+#include "core/html/HTMLAllCollection.h"
+
+#include "core/dom/Element.h"
+
+namespace WebCore {
+
+PassRefPtr<HTMLAllCollection> HTMLAllCollection::create(Node* node, CollectionType type)
+{
+    return adoptRef(new HTMLAllCollection(node, type));
+}
+
+HTMLAllCollection::HTMLAllCollection(Node* node, CollectionType type)
+    : HTMLCollection(node, type, DoesNotOverrideItemAfter)
+{
+    ScriptWrappable::init(this);
+}
+
+HTMLAllCollection::~HTMLAllCollection()
+{
+}
+
+Node* HTMLAllCollection::namedItemWithIndex(const AtomicString& name, unsigned index) const
+{
+    updateNameCache();
+
+    if (Vector<Element*>* cache = idCache(name)) {
+        if (index < cache->size())
+            return cache->at(index);
+        index -= cache->size();
+    }
+
+    if (Vector<Element*>* cache = nameCache(name)) {
+        if (index < cache->size())
+            return cache->at(index);
+    }
+
+    return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLAllCollection.h b/Source/core/html/HTMLAllCollection.h
new file mode 100644
index 0000000..ad21e25
--- /dev/null
+++ b/Source/core/html/HTMLAllCollection.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009, 2011 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. ``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 HTMLAllCollection_h
+#define HTMLAllCollection_h
+
+#include "core/html/HTMLCollection.h"
+
+namespace WebCore {
+
+class HTMLAllCollection : public HTMLCollection {
+public:
+    static PassRefPtr<HTMLAllCollection> create(Node*, CollectionType);
+    virtual ~HTMLAllCollection();
+
+    Node* namedItemWithIndex(const AtomicString& name, unsigned index) const;
+
+private:
+    HTMLAllCollection(Node*, CollectionType);
+};
+
+} // namespace WebCore
+
+#endif // HTMLAllCollection_h
diff --git a/Source/core/html/HTMLAllCollection.idl b/Source/core/html/HTMLAllCollection.idl
new file mode 100644
index 0000000..f421caf
--- /dev/null
+++ b/Source/core/html/HTMLAllCollection.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 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. ``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. 
+ */
+
+[
+    CustomNamedGetter,
+    CustomCall,
+    MasqueradesAsUndefined,
+    GenerateIsReachable=ImplOwnerNodeRoot,
+    DependentLifetime,
+] interface HTMLAllCollection {
+    readonly attribute unsigned long length;
+    [Custom] getter Node item([Default=Undefined] optional unsigned long index);
+    [Custom] Node namedItem(DOMString name);
+    // FIXME: This should return an HTMLAllCollection.
+    NodeList tags(DOMString name);
+};
+
diff --git a/Source/core/html/HTMLAnchorElement.cpp b/Source/core/html/HTMLAnchorElement.cpp
new file mode 100644
index 0000000..acf202b
--- /dev/null
+++ b/Source/core/html/HTMLAnchorElement.cpp
@@ -0,0 +1,715 @@
+/*
+ * 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, 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
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLAnchorElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/MouseEvent.h"
+#include "core/editing/FrameSelection.h"
+#include "core/html/HTMLImageElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/loader/FrameLoaderTypes.h"
+#include "core/loader/PingLoader.h"
+#include "core/page/Chrome.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/page/SecurityPolicy.h"
+#include "core/page/Settings.h"
+#include "core/platform/HistogramSupport.h"
+#include "core/platform/PlatformMouseEvent.h"
+#include "core/platform/network/DNS.h"
+#include "core/platform/network/ResourceRequest.h"
+#include "core/rendering/RenderImage.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+class HTMLAnchorElement::PrefetchEventHandler {
+public:
+    static PassOwnPtr<PrefetchEventHandler> create()
+    {
+        return adoptPtr(new HTMLAnchorElement::PrefetchEventHandler());
+    }
+
+    void handleEvent(Event* e);
+
+private:
+    PrefetchEventHandler();
+
+    void handleMouseOver(Event* event);
+    void handleMouseOut(Event* event);
+    void handleLeftMouseDown(Event* event);
+    void handleClick(Event* event);
+
+    double m_mouseOverTimestamp;
+    double m_mouseDownTimestamp;
+};
+
+using namespace HTMLNames;
+
+HTMLAnchorElement::HTMLAnchorElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_hasRootEditableElementForSelectionOnMouseDown(false)
+    , m_wasShiftKeyDownOnMouseDown(false)
+    , m_linkRelations(0)
+    , m_cachedVisitedLinkHash(0)
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLAnchorElement> HTMLAnchorElement::create(Document* document)
+{
+    return adoptRef(new HTMLAnchorElement(aTag, document));
+}
+
+PassRefPtr<HTMLAnchorElement> HTMLAnchorElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLAnchorElement(tagName, document));
+}
+
+HTMLAnchorElement::~HTMLAnchorElement()
+{
+    clearRootEditableElementForSelectionOnMouseDown();
+}
+
+// This function does not allow leading spaces before the port number.
+static unsigned parsePortFromStringPosition(const String& value, unsigned portStart, unsigned& portEnd)
+{
+    portEnd = portStart;
+    while (isASCIIDigit(value[portEnd]))
+        ++portEnd;
+    return value.substring(portStart, portEnd - portStart).toUInt();
+}
+
+bool HTMLAnchorElement::supportsFocus() const
+{
+    if (rendererIsEditable())
+        return HTMLElement::supportsFocus();
+    // If not a link we should still be able to focus the element if it has tabIndex.
+    return isLink() || HTMLElement::supportsFocus();
+}
+
+bool HTMLAnchorElement::isMouseFocusable() const
+{
+    // Anchor elements should be mouse focusable, https://bugs.webkit.org/show_bug.cgi?id=26856
+    if (isLink())
+        // Only allow links with tabIndex or contentEditable to be mouse focusable.
+        return HTMLElement::supportsFocus();
+
+    // Allow tab index etc to control focus.
+    return HTMLElement::isMouseFocusable();
+}
+
+bool HTMLAnchorElement::isKeyboardFocusable(KeyboardEvent* event) const
+{
+    if (!isLink())
+        return HTMLElement::isKeyboardFocusable(event);
+
+    if (!isFocusable())
+        return false;
+    
+    Page* page = document()->page();
+    if (!page)
+        return false;
+
+    if (!page->chrome()->client()->tabsToLinks())
+        return false;
+
+    if (isInCanvasSubtree())
+        return true;
+
+    return hasNonEmptyBoundingBox();
+}
+
+static void appendServerMapMousePosition(StringBuilder& url, Event* event)
+{
+    if (!event->isMouseEvent())
+        return;
+
+    ASSERT(event->target());
+    Node* target = event->target()->toNode();
+    ASSERT(target);
+    if (!target->hasTagName(imgTag))
+        return;
+
+    HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(event->target()->toNode());
+    if (!imageElement || !imageElement->isServerMap())
+        return;
+
+    if (!imageElement->renderer() || !imageElement->renderer()->isRenderImage())
+        return;
+    RenderImage* renderer = toRenderImage(imageElement->renderer());
+
+    // 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.append('?');
+    url.appendNumber(x);
+    url.append(',');
+    url.appendNumber(y);
+}
+
+void HTMLAnchorElement::defaultEventHandler(Event* event)
+{
+    if (isLink()) {
+        if (focused() && isEnterKeyKeydownEvent(event) && treatLinkAsLiveForEventType(NonMouseEvent)) {
+            event->setDefaultHandled();
+            dispatchSimulatedClick(event);
+            return;
+        }
+
+        prefetchEventHandler()->handleEvent(event);
+
+        if (isLinkClick(event) && treatLinkAsLiveForEventType(eventType(event))) {
+            handleClick(event);
+            return;
+        }
+
+        if (rendererIsEditable()) {
+            // 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()) {
+                setRootEditableElementForSelectionOnMouseDown(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.
+                clearRootEditableElementForSelectionOnMouseDown();
+                m_wasShiftKeyDownOnMouseDown = false;
+            }
+        }
+    }
+
+    HTMLElement::defaultEventHandler(event);
+}
+
+void HTMLAnchorElement::setActive(bool down, bool pause)
+{
+    if (rendererIsEditable()) {
+        EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior;
+        if (Settings* settings = document()->settings())
+            editableLinkBehavior = settings->editableLinkBehavior();
+            
+        switch (editableLinkBehavior) {
+            default:
+            case EditableLinkDefaultBehavior:
+            case EditableLinkAlwaysLive:
+                break;
+
+            case EditableLinkNeverLive:
+                return;
+
+            // Don't set the link to be active if the current selection is in the same editable block as
+            // this link
+            case EditableLinkLiveWhenNotFocused:
+                if (down && document()->frame() && document()->frame()->selection()->rootEditableElement() == rootEditableElement())
+                    return;
+                break;
+            
+            case EditableLinkOnlyLiveWithShiftKey:
+                return;
+        }
+
+    }
+    
+    ContainerNode::setActive(down, pause);
+}
+
+void HTMLAnchorElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == hrefAttr) {
+        bool wasLink = isLink();
+        setIsLink(!value.isNull());
+        if (wasLink != isLink())
+            didAffectSelector(AffectedSelectorLink | AffectedSelectorVisited | AffectedSelectorEnabled);
+        if (isLink()) {
+            String parsedURL = stripLeadingAndTrailingHTMLSpaces(value);
+            if (document()->isDNSPrefetchEnabled()) {
+                if (protocolIs(parsedURL, "http") || protocolIs(parsedURL, "https") || parsedURL.startsWith("//"))
+                    prefetchDNS(document()->completeURL(parsedURL).host());
+            }
+        }
+        invalidateCachedVisitedLinkHash();
+    } else if (name == nameAttr || name == titleAttr) {
+        // Do nothing.
+    } else if (name == relAttr)
+        setRel(value);
+    else
+        HTMLElement::parseAttribute(name, value);
+}
+
+void HTMLAnchorElement::accessKeyAction(bool sendMouseEvents)
+{
+    dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
+}
+
+bool HTMLAnchorElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+bool HTMLAnchorElement::canStartSelection() const
+{
+    // FIXME: We probably want this same behavior in SVGAElement too
+    if (!isLink())
+        return HTMLElement::canStartSelection();
+    return rendererIsEditable();
+}
+
+bool HTMLAnchorElement::draggable() const
+{
+    // Should be draggable if we have an href attribute.
+    const AtomicString& value = getAttribute(draggableAttr);
+    if (equalIgnoringCase(value, "true"))
+        return true;
+    if (equalIgnoringCase(value, "false"))
+        return false;
+    return hasAttribute(hrefAttr);
+}
+
+KURL HTMLAnchorElement::href() const
+{
+    return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(hrefAttr)));
+}
+
+void HTMLAnchorElement::setHref(const AtomicString& value)
+{
+    setAttribute(hrefAttr, value);
+}
+
+bool HTMLAnchorElement::hasRel(uint32_t relation) const
+{
+    return m_linkRelations & relation;
+}
+
+void HTMLAnchorElement::setRel(const String& value)
+{
+    m_linkRelations = 0;
+    SpaceSplitString newLinkRelations(value, true);
+    // FIXME: Add link relations as they are implemented
+    if (newLinkRelations.contains("noreferrer"))
+        m_linkRelations |= RelationNoReferrer;
+}
+
+const AtomicString& HTMLAnchorElement::name() const
+{
+    return getNameAttribute();
+}
+
+short HTMLAnchorElement::tabIndex() const
+{
+    // Skip the supportsFocus check in HTMLElement.
+    return Element::tabIndex();
+}
+
+String HTMLAnchorElement::target() const
+{
+    return getAttribute(targetAttr);
+}
+
+String HTMLAnchorElement::hash() const
+{
+    String fragmentIdentifier = href().fragmentIdentifier();
+    return fragmentIdentifier.isEmpty() ? emptyString() : "#" + fragmentIdentifier;
+}
+
+void HTMLAnchorElement::setHash(const String& value)
+{
+    KURL url = href();
+    if (value[0] == '#')
+        url.setFragmentIdentifier(value.substring(1));
+    else
+        url.setFragmentIdentifier(value);
+    setHref(url.string());
+}
+
+String HTMLAnchorElement::host() const
+{
+    const KURL& url = href();
+    if (url.hostEnd() == url.pathStart())
+        return url.host();
+    if (isDefaultPortForProtocol(url.port(), url.protocol()))
+        return url.host();
+    return url.host() + ":" + String::number(url.port());
+}
+
+void HTMLAnchorElement::setHost(const String& value)
+{
+    if (value.isEmpty())
+        return;
+    KURL url = href();
+    if (!url.canSetHostOrPort())
+        return;
+
+    size_t separator = value.find(':');
+    if (!separator)
+        return;
+
+    if (separator == notFound)
+        url.setHostAndPort(value);
+    else {
+        unsigned portEnd;
+        unsigned port = parsePortFromStringPosition(value, separator + 1, portEnd);
+        if (!port) {
+            // http://dev.w3.org/html5/spec/infrastructure.html#url-decomposition-idl-attributes
+            // specifically goes against RFC 3986 (p3.2) and
+            // requires setting the port to "0" if it is set to empty string.
+            url.setHostAndPort(value.substring(0, separator + 1) + "0");
+        } else {
+            if (isDefaultPortForProtocol(port, url.protocol()))
+                url.setHostAndPort(value.substring(0, separator));
+            else
+                url.setHostAndPort(value.substring(0, portEnd));
+        }
+    }
+    setHref(url.string());
+}
+
+String HTMLAnchorElement::hostname() const
+{
+    return href().host();
+}
+
+void HTMLAnchorElement::setHostname(const String& value)
+{
+    // Before setting new value:
+    // Remove all leading U+002F SOLIDUS ("/") characters.
+    unsigned i = 0;
+    unsigned hostLength = value.length();
+    while (value[i] == '/')
+        i++;
+
+    if (i == hostLength)
+        return;
+
+    KURL url = href();
+    if (!url.canSetHostOrPort())
+        return;
+
+    url.setHost(value.substring(i));
+    setHref(url.string());
+}
+
+String HTMLAnchorElement::pathname() const
+{
+    return href().path();
+}
+
+void HTMLAnchorElement::setPathname(const String& value)
+{
+    KURL url = href();
+    if (!url.canSetPathname())
+        return;
+
+    if (value[0] == '/')
+        url.setPath(value);
+    else
+        url.setPath("/" + value);
+
+    setHref(url.string());
+}
+
+String HTMLAnchorElement::port() const
+{
+    if (href().hasPort())
+        return String::number(href().port());
+
+    return emptyString();
+}
+
+void HTMLAnchorElement::setPort(const String& value)
+{
+    KURL url = href();
+    if (!url.canSetHostOrPort())
+        return;
+
+    // http://dev.w3.org/html5/spec/infrastructure.html#url-decomposition-idl-attributes
+    // specifically goes against RFC 3986 (p3.2) and
+    // requires setting the port to "0" if it is set to empty string.
+    unsigned port = value.toUInt();
+    if (isDefaultPortForProtocol(port, url.protocol()))
+        url.removePort();
+    else
+        url.setPort(port);
+
+    setHref(url.string());
+}
+
+String HTMLAnchorElement::protocol() const
+{
+    return href().protocol() + ":";
+}
+
+void HTMLAnchorElement::setProtocol(const String& value)
+{
+    KURL url = href();
+    url.setProtocol(value);
+    setHref(url.string());
+}
+
+String HTMLAnchorElement::search() const
+{
+    String query = href().query();
+    return query.isEmpty() ? emptyString() : "?" + query;
+}
+
+String HTMLAnchorElement::origin() const
+{
+    RefPtr<SecurityOrigin> origin = SecurityOrigin::create(href());
+    return origin->toString();
+}
+
+void HTMLAnchorElement::setSearch(const String& value)
+{
+    KURL url = href();
+    String newSearch = (value[0] == '?') ? value.substring(1) : value;
+    // Make sure that '#' in the query does not leak to the hash.
+    url.setQuery(newSearch.replaceWithLiteral('#', "%23"));
+
+    setHref(url.string());
+}
+
+String HTMLAnchorElement::text()
+{
+    return innerText();
+}
+
+String HTMLAnchorElement::toString() const
+{
+    return href().string();
+}
+
+bool HTMLAnchorElement::isLiveLink() const
+{
+    return isLink() && treatLinkAsLiveForEventType(m_wasShiftKeyDownOnMouseDown ? MouseEventWithShiftKey : MouseEventWithoutShiftKey);
+}
+
+void HTMLAnchorElement::sendPings(const KURL& destinationURL)
+{
+    if (!hasAttribute(pingAttr) || !document()->settings()->hyperlinkAuditingEnabled())
+        return;
+
+    SpaceSplitString pingURLs(getAttribute(pingAttr), false);
+    for (unsigned i = 0; i < pingURLs.size(); i++)
+        PingLoader::sendPing(document()->frame(), document()->completeURL(pingURLs[i]), destinationURL);
+}
+
+void HTMLAnchorElement::handleClick(Event* event)
+{
+    event->setDefaultHandled();
+
+    Frame* frame = document()->frame();
+    if (!frame)
+        return;
+
+    StringBuilder url;
+    url.append(stripLeadingAndTrailingHTMLSpaces(fastGetAttribute(hrefAttr)));
+    appendServerMapMousePosition(url, event);
+    KURL kurl = document()->completeURL(url.toString());
+
+    if (hasAttribute(downloadAttr)) {
+        ResourceRequest request(kurl);
+
+        if (!hasRel(RelationNoReferrer)) {
+            String referrer = SecurityPolicy::generateReferrerHeader(document()->referrerPolicy(), kurl, frame->loader()->outgoingReferrer());
+            if (!referrer.isEmpty())
+                request.setHTTPReferrer(referrer);
+        }
+
+        frame->loader()->client()->startDownload(request, fastGetAttribute(downloadAttr));
+    } else
+        frame->loader()->urlSelected(kurl, target(), event, false, false, hasRel(RelationNoReferrer) ? NeverSendReferrer : MaybeSendReferrer);
+
+    sendPings(kurl);
+}
+
+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 (!rendererIsEditable())
+        return true;
+
+    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 && 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 isLinkClick(Event* event)
+{
+    return event->type() == eventNames().clickEvent && (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button() != RightButton);
+}
+
+bool HTMLAnchorElement::willRespondToMouseClickEvents()
+{
+    return isLink() || HTMLElement::willRespondToMouseClickEvents();
+}
+
+typedef HashMap<const HTMLAnchorElement*, RefPtr<Element> > RootEditableElementMap;
+
+static RootEditableElementMap& rootEditableElementMap()
+{
+    DEFINE_STATIC_LOCAL(RootEditableElementMap, map, ());
+    return map;
+}
+
+Element* HTMLAnchorElement::rootEditableElementForSelectionOnMouseDown() const
+{
+    if (!m_hasRootEditableElementForSelectionOnMouseDown)
+        return 0;
+    return rootEditableElementMap().get(this).get();
+}
+
+void HTMLAnchorElement::clearRootEditableElementForSelectionOnMouseDown()
+{
+    if (!m_hasRootEditableElementForSelectionOnMouseDown)
+        return;
+    rootEditableElementMap().remove(this);
+    m_hasRootEditableElementForSelectionOnMouseDown = false;
+}
+
+void HTMLAnchorElement::setRootEditableElementForSelectionOnMouseDown(Element* element)
+{
+    if (!element) {
+        clearRootEditableElementForSelectionOnMouseDown();
+        return;
+    }
+
+    rootEditableElementMap().set(this, element);
+    m_hasRootEditableElementForSelectionOnMouseDown = true;
+}
+
+HTMLAnchorElement::PrefetchEventHandler* HTMLAnchorElement::prefetchEventHandler()
+{
+    if (!m_prefetchEventHandler)
+        m_prefetchEventHandler = PrefetchEventHandler::create();
+
+    return m_prefetchEventHandler.get();
+}
+
+HTMLAnchorElement::PrefetchEventHandler::PrefetchEventHandler()
+    : m_mouseOverTimestamp(0.0)
+    , m_mouseDownTimestamp(0.0)
+{
+}
+
+void HTMLAnchorElement::PrefetchEventHandler::handleEvent(Event* event)
+{
+    if (event->type() == eventNames().mouseoverEvent)
+        handleMouseOver(event);
+    else if (event->type() == eventNames().mouseoutEvent)
+        handleMouseOut(event);
+    else if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton)
+        handleLeftMouseDown(event);
+    else if (isLinkClick(event))
+        handleClick(event);
+}
+
+void HTMLAnchorElement::PrefetchEventHandler::handleMouseOver(Event* event)
+{
+    if (m_mouseOverTimestamp == 0.0) {
+        m_mouseOverTimestamp = event->timeStamp();
+
+        HistogramSupport::histogramEnumeration("MouseEventPrefetch.MouseOvers", 0, 2);
+    }
+}
+
+void HTMLAnchorElement::PrefetchEventHandler::handleMouseOut(Event* event)
+{
+    if (m_mouseOverTimestamp > 0.0) {
+        double mouseOverDuration = convertDOMTimeStampToSeconds(event->timeStamp() - m_mouseOverTimestamp);
+        HistogramSupport::histogramCustomCounts("MouseEventPrefetch.MouseOverDuration_NoClick", mouseOverDuration * 1000, 0, 10000, 100);
+
+        m_mouseOverTimestamp = 0.0;
+    }
+}
+
+void HTMLAnchorElement::PrefetchEventHandler::handleLeftMouseDown(Event* event)
+{
+    m_mouseDownTimestamp = event->timeStamp();
+
+    HistogramSupport::histogramEnumeration("MouseEventPrefetch.MouseDowns", 0, 2);
+}
+
+void HTMLAnchorElement::PrefetchEventHandler::handleClick(Event* event)
+{
+    bool capturedMouseOver = (m_mouseOverTimestamp > 0.0);
+    if (capturedMouseOver) {
+        double mouseOverDuration = convertDOMTimeStampToSeconds(event->timeStamp() - m_mouseOverTimestamp);
+
+        HistogramSupport::histogramCustomCounts("MouseEventPrefetch.MouseOverDuration_Click", mouseOverDuration * 1000, 0, 10000, 100);
+    }
+
+    bool capturedMouseDown = (m_mouseDownTimestamp > 0.0);
+    HistogramSupport::histogramEnumeration("MouseEventPrefetch.MouseDownFollowedByClick", capturedMouseDown, 2);
+
+    if (capturedMouseDown) {
+        double mouseDownDuration = convertDOMTimeStampToSeconds(event->timeStamp() - m_mouseDownTimestamp);
+
+        HistogramSupport::histogramCustomCounts("MouseEventPrefetch.MouseDownDuration_Click", mouseDownDuration * 1000, 0, 10000, 100);
+    }
+
+    m_mouseOverTimestamp = 0;
+    m_mouseDownTimestamp = 0;
+}
+
+}
diff --git a/Source/core/html/HTMLAnchorElement.h b/Source/core/html/HTMLAnchorElement.h
new file mode 100644
index 0000000..5cc83ca
--- /dev/null
+++ b/Source/core/html/HTMLAnchorElement.h
@@ -0,0 +1,163 @@
+/*
+ * 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, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLAnchorElement_h
+#define HTMLAnchorElement_h
+
+#include "HTMLNames.h"
+#include "core/html/HTMLElement.h"
+#include "core/platform/LinkHash.h"
+
+namespace WebCore {
+
+// Link relation bitmask values.
+// FIXME: Uncomment as the various link relations are implemented.
+enum {
+//     RelationAlternate   = 0x00000001,
+//     RelationArchives    = 0x00000002,
+//     RelationAuthor      = 0x00000004,
+//     RelationBoomark     = 0x00000008,
+//     RelationExternal    = 0x00000010,
+//     RelationFirst       = 0x00000020,
+//     RelationHelp        = 0x00000040,
+//     RelationIndex       = 0x00000080,
+//     RelationLast        = 0x00000100,
+//     RelationLicense     = 0x00000200,
+//     RelationNext        = 0x00000400,
+//     RelationNoFolow    = 0x00000800,
+    RelationNoReferrer     = 0x00001000,
+//     RelationPrev        = 0x00002000,
+//     RelationSearch      = 0x00004000,
+//     RelationSidebar     = 0x00008000,
+//     RelationTag         = 0x00010000,
+//     RelationUp          = 0x00020000,
+};
+
+class HTMLAnchorElement : public HTMLElement {
+public:
+    static PassRefPtr<HTMLAnchorElement> create(Document*);
+    static PassRefPtr<HTMLAnchorElement> create(const QualifiedName&, Document*);
+
+    virtual ~HTMLAnchorElement();
+
+    KURL href() const;
+    void setHref(const AtomicString&);
+
+    const AtomicString& name() const;
+
+    String hash() const;
+    void setHash(const String&);
+
+    String host() const;
+    void setHost(const String&);
+
+    String hostname() const;
+    void setHostname(const String&);
+
+    String pathname() const;
+    void setPathname(const String&);
+
+    String port() const;
+    void setPort(const String&);
+
+    String protocol() const;
+    void setProtocol(const String&);
+
+    String search() const;
+    void setSearch(const String&);
+
+    String origin() const;
+
+    String text();
+
+    String toString() const;
+
+    bool isLiveLink() const;
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+    bool hasRel(uint32_t relation) const;
+    void setRel(const String&);
+    
+    LinkHash visitedLinkHash() const;
+    void invalidateCachedVisitedLinkHash() { m_cachedVisitedLinkHash = 0; }
+
+protected:
+    HTMLAnchorElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+private:
+    virtual bool supportsFocus() const;
+    virtual bool isMouseFocusable() const;
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual void defaultEventHandler(Event*);
+    virtual void setActive(bool active = true, bool pause = false);
+    virtual void accessKeyAction(bool sendMouseEvents);
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+    virtual bool canStartSelection() const;
+    virtual String target() const;
+    virtual short tabIndex() const;
+    virtual bool draggable() const;
+
+    void sendPings(const KURL& destinationURL);
+
+    void handleClick(Event*);
+
+    enum EventType {
+        MouseEventWithoutShiftKey,
+        MouseEventWithShiftKey,
+        NonMouseEvent,
+    };
+    static EventType eventType(Event*);
+    bool treatLinkAsLiveForEventType(EventType) const;
+
+    Element* rootEditableElementForSelectionOnMouseDown() const;
+    void setRootEditableElementForSelectionOnMouseDown(Element*);
+    void clearRootEditableElementForSelectionOnMouseDown();
+
+    class PrefetchEventHandler;
+    PrefetchEventHandler* prefetchEventHandler();
+
+    bool m_hasRootEditableElementForSelectionOnMouseDown : 1;
+    bool m_wasShiftKeyDownOnMouseDown : 1;
+    uint32_t m_linkRelations : 30;
+    OwnPtr<PrefetchEventHandler> m_prefetchEventHandler;
+    mutable LinkHash m_cachedVisitedLinkHash;
+};
+
+inline LinkHash HTMLAnchorElement::visitedLinkHash() const
+{
+    if (!m_cachedVisitedLinkHash)
+        m_cachedVisitedLinkHash = WebCore::visitedLinkHash(document()->baseURL(), fastGetAttribute(HTMLNames::hrefAttr));
+    return m_cachedVisitedLinkHash; 
+}
+
+// Functions shared with the other anchor elements (i.e., SVG).
+
+bool isEnterKeyKeydownEvent(Event*);
+bool isLinkClick(Event*);
+
+} // namespace WebCore
+
+#endif // HTMLAnchorElement_h
diff --git a/Source/core/html/HTMLAnchorElement.idl b/Source/core/html/HTMLAnchorElement.idl
new file mode 100644
index 0000000..e0c7068
--- /dev/null
+++ b/Source/core/html/HTMLAnchorElement.idl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2006, 2007, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLAnchorElement : HTMLElement {
+    [Reflect] attribute DOMString charset;
+    [Reflect] attribute DOMString coords;
+    [Reflect] attribute DOMString download;
+    [Reflect, URL] attribute DOMString href;
+    [Reflect] attribute DOMString hreflang;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute DOMString ping;
+    [Reflect] attribute DOMString rel;
+    [Reflect] attribute DOMString rev;
+    [Reflect] attribute DOMString shape;
+    [Reflect] attribute DOMString target;
+    [Reflect] attribute DOMString type;
+
+    [TreatNullAs=NullString] attribute DOMString hash;
+    [TreatNullAs=NullString] attribute DOMString host;
+    [TreatNullAs=NullString] attribute DOMString hostname;
+    [TreatNullAs=NullString] attribute DOMString pathname;
+    [TreatNullAs=NullString] attribute DOMString port;
+    [TreatNullAs=NullString] attribute DOMString protocol;
+    [TreatNullAs=NullString] attribute DOMString search;
+
+    [TreatNullAs=NullString] readonly attribute DOMString origin;
+
+    readonly attribute DOMString text;
+
+    [NotEnumerable] DOMString toString();
+};
+
diff --git a/Source/core/html/HTMLAppletElement.cpp b/Source/core/html/HTMLAppletElement.cpp
new file mode 100644
index 0000000..9707085
--- /dev/null
+++ b/Source/core/html/HTMLAppletElement.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
+ * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLAppletElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLParamElement.h"
+#include "core/loader/FrameLoader.h"
+#include "core/page/Frame.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/page/Settings.h"
+#include "core/platform/Widget.h"
+#include "core/rendering/RenderApplet.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLAppletElement::HTMLAppletElement(const QualifiedName& tagName, Document* document, bool createdByParser)
+    : HTMLPlugInImageElement(tagName, document, createdByParser, ShouldNotPreferPlugInsForImages)
+{
+    ASSERT(hasTagName(appletTag));
+    ScriptWrappable::init(this);
+
+    m_serviceType = "application/x-java-applet";
+}
+
+PassRefPtr<HTMLAppletElement> HTMLAppletElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
+{
+    return adoptRef(new HTMLAppletElement(tagName, document, createdByParser));
+}
+
+void HTMLAppletElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == altAttr
+        || name == archiveAttr
+        || name == codeAttr
+        || name == codebaseAttr
+        || name == mayscriptAttr
+        || name == objectAttr) {
+        // Do nothing.
+        return;
+    }
+
+    HTMLPlugInImageElement::parseAttribute(name, value);
+}
+
+bool HTMLAppletElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    if (!fastHasAttribute(codeAttr))
+        return false;
+    return HTMLPlugInImageElement::rendererIsNeeded(context);
+}
+
+RenderObject* HTMLAppletElement::createRenderer(RenderArena*, RenderStyle* style)
+{
+    if (!canEmbedJava())
+        return RenderObject::createObject(this, style);
+
+    return new (document()->renderArena()) RenderApplet(this);
+}
+
+RenderWidget* HTMLAppletElement::renderWidgetForJSBindings() const
+{
+    if (!canEmbedJava())
+        return 0;
+
+    document()->updateLayoutIgnorePendingStylesheets();
+    return renderPart();
+}
+
+void HTMLAppletElement::updateWidget(PluginCreationOption)
+{
+    setNeedsWidgetUpdate(false);
+    // FIXME: This should ASSERT isFinishedParsingChildren() instead.
+    if (!isFinishedParsingChildren())
+        return;
+
+    RenderEmbeddedObject* renderer = renderEmbeddedObject();
+
+    LayoutUnit contentWidth = renderer->style()->width().isFixed() ? LayoutUnit(renderer->style()->width().value()) :
+        renderer->width() - renderer->borderAndPaddingWidth();
+    LayoutUnit contentHeight = renderer->style()->height().isFixed() ? LayoutUnit(renderer->style()->height().value()) :
+        renderer->height() - renderer->borderAndPaddingHeight();
+
+    Vector<String> paramNames;
+    Vector<String> paramValues;
+
+    paramNames.append("code");
+    paramValues.append(getAttribute(codeAttr).string());
+
+    const AtomicString& codeBase = getAttribute(codebaseAttr);
+    if (!codeBase.isNull()) {
+        paramNames.append("codeBase");
+        paramValues.append(codeBase.string());
+    }
+
+    const AtomicString& name = document()->isHTMLDocument() ? getNameAttribute() : getIdAttribute();
+    if (!name.isNull()) {
+        paramNames.append("name");
+        paramValues.append(name.string());
+    }
+
+    const AtomicString& archive = getAttribute(archiveAttr);
+    if (!archive.isNull()) {
+        paramNames.append("archive");
+        paramValues.append(archive.string());
+    }
+
+    paramNames.append("baseURL");
+    paramValues.append(document()->baseURL().string());
+
+    const AtomicString& mayScript = getAttribute(mayscriptAttr);
+    if (!mayScript.isNull()) {
+        paramNames.append("mayScript");
+        paramValues.append(mayScript.string());
+    }
+
+    for (Node* child = firstChild(); child; child = child->nextSibling()) {
+        if (!child->hasTagName(paramTag))
+            continue;
+
+        HTMLParamElement* param = static_cast<HTMLParamElement*>(child);
+        if (param->name().isEmpty())
+            continue;
+
+        paramNames.append(param->name());
+        paramValues.append(param->value());
+    }
+
+    Frame* frame = document()->frame();
+    ASSERT(frame);
+
+    renderer->setWidget(frame->loader()->subframeLoader()->createJavaAppletWidget(roundedIntSize(LayoutSize(contentWidth, contentHeight)), this, paramNames, paramValues));
+}
+
+bool HTMLAppletElement::canEmbedJava() const
+{
+    if (document()->isSandboxed(SandboxPlugins))
+        return false;
+
+    Settings* settings = document()->settings();
+    if (!settings)
+        return false;
+
+    if (!settings->isJavaEnabled())
+        return false;
+
+    return true;
+}
+
+}
diff --git a/Source/core/html/HTMLAppletElement.h b/Source/core/html/HTMLAppletElement.h
new file mode 100644
index 0000000..affbc68
--- /dev/null
+++ b/Source/core/html/HTMLAppletElement.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2006, 2008, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLAppletElement_h
+#define HTMLAppletElement_h
+
+#include "core/html/HTMLPlugInImageElement.h"
+
+namespace WebCore {
+
+class HTMLAppletElement FINAL : public HTMLPlugInImageElement {
+public:
+    static PassRefPtr<HTMLAppletElement> create(const QualifiedName&, Document*, bool createdByParser);
+
+private:
+    HTMLAppletElement(const QualifiedName&, Document*, bool createdByParser);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    
+    virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE;
+
+    virtual RenderWidget* renderWidgetForJSBindings() const;
+    virtual void updateWidget(PluginCreationOption) OVERRIDE;
+
+    bool canEmbedJava() const;
+
+    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return true; }
+    virtual bool shouldRegisterAsExtraNamedItem() const OVERRIDE { return true; }
+};
+
+}
+
+#endif
diff --git a/Source/core/html/HTMLAppletElement.idl b/Source/core/html/HTMLAppletElement.idl
new file mode 100644
index 0000000..e5f8707
--- /dev/null
+++ b/Source/core/html/HTMLAppletElement.idl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006, 2007, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomNamedGetter,
+    CustomNamedSetter,
+    CustomIndexedGetter,
+    CustomIndexedSetter,
+    CustomCall
+] interface HTMLAppletElement : HTMLElement {
+    [Reflect] attribute DOMString align;
+    [Reflect] attribute DOMString alt;
+    [Reflect] attribute DOMString archive;
+    [Reflect] attribute DOMString code;
+    [Reflect] attribute DOMString codeBase;
+    [Reflect] attribute DOMString height;
+    [Reflect] attribute DOMString hspace;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute DOMString object;
+    [Reflect] attribute DOMString vspace;
+    [Reflect] attribute DOMString width;
+};
+
diff --git a/Source/core/html/HTMLAreaElement.cpp b/Source/core/html/HTMLAreaElement.cpp
new file mode 100644
index 0000000..afbfe2c
--- /dev/null
+++ b/Source/core/html/HTMLAreaElement.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2009, 2011 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLAreaElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/html/HTMLImageElement.h"
+#include "core/html/HTMLMapElement.h"
+#include "core/page/Frame.h"
+#include "core/platform/graphics/Path.h"
+#include "core/platform/graphics/transforms/AffineTransform.h"
+#include "core/rendering/HitTestResult.h"
+#include "core/rendering/RenderImage.h"
+#include "core/rendering/RenderView.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLAreaElement::HTMLAreaElement(const QualifiedName& tagName, Document* document)
+    : HTMLAnchorElement(tagName, document)
+    , m_coordsLen(0)
+    , m_lastSize(-1, -1)
+    , m_shape(Unknown)
+{
+    ASSERT(hasTagName(areaTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLAreaElement> HTMLAreaElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLAreaElement(tagName, document));
+}
+
+void HTMLAreaElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == shapeAttr) {
+        if (equalIgnoringCase(value, "default"))
+            m_shape = Default;
+        else if (equalIgnoringCase(value, "circle"))
+            m_shape = Circle;
+        else if (equalIgnoringCase(value, "poly"))
+            m_shape = Poly;
+        else if (equalIgnoringCase(value, "rect"))
+            m_shape = Rect;
+        invalidateCachedRegion();
+    } else if (name == coordsAttr) {
+        m_coords = newCoordsArray(value.string(), m_coordsLen);
+        invalidateCachedRegion();
+    } else if (name == altAttr || name == accesskeyAttr) {
+        // Do nothing.
+    } else
+        HTMLAnchorElement::parseAttribute(name, value);
+}
+
+void HTMLAreaElement::invalidateCachedRegion()
+{
+    m_lastSize = LayoutSize(-1, -1);
+}
+
+bool HTMLAreaElement::mapMouseEvent(LayoutPoint location, const LayoutSize& size, HitTestResult& result)
+{
+    if (m_lastSize != size) {
+        m_region = adoptPtr(new Path(getRegion(size)));
+        m_lastSize = size;
+    }
+
+    if (!m_region->contains(location))
+        return false;
+    
+    result.setInnerNode(this);
+    result.setURLElement(this);
+    return true;
+}
+
+Path HTMLAreaElement::computePath(RenderObject* obj) const
+{
+    if (!obj)
+        return Path();
+    
+    // FIXME: This doesn't work correctly with transforms.
+    FloatPoint absPos = obj->localToAbsolute();
+
+    // Default should default to the size of the containing object.
+    LayoutSize size = m_lastSize;
+    if (m_shape == Default)
+        size = obj->absoluteOutlineBounds().size();
+    
+    Path p = getRegion(size);
+    float zoomFactor = obj->style()->effectiveZoom();
+    if (zoomFactor != 1.0f) {
+        AffineTransform zoomTransform;
+        zoomTransform.scale(zoomFactor);
+        p.transform(zoomTransform);
+    }
+
+    p.translate(toFloatSize(absPos));
+    return p;
+}
+    
+LayoutRect HTMLAreaElement::computeRect(RenderObject* obj) const
+{
+    return enclosingLayoutRect(computePath(obj).boundingRect());
+}
+
+Path HTMLAreaElement::getRegion(const LayoutSize& size) const
+{
+    if (!m_coords && m_shape != Default)
+        return Path();
+
+    LayoutUnit width = size.width();
+    LayoutUnit height = size.height();
+
+    // If element omits the shape attribute, select shape based on number of coordinates.
+    Shape shape = m_shape;
+    if (shape == Unknown) {
+        if (m_coordsLen == 3)
+            shape = Circle;
+        else if (m_coordsLen == 4)
+            shape = Rect;
+        else if (m_coordsLen >= 6)
+            shape = Poly;
+    }
+
+    Path path;
+    RenderView* renderView = document()->renderView();
+    switch (shape) {
+        case Poly:
+            if (m_coordsLen >= 6) {
+                int numPoints = m_coordsLen / 2;
+                path.moveTo(FloatPoint(minimumValueForLength(m_coords[0], width, renderView), minimumValueForLength(m_coords[1], height, renderView)));
+                for (int i = 1; i < numPoints; ++i)
+                    path.addLineTo(FloatPoint(minimumValueForLength(m_coords[i * 2], width, renderView), minimumValueForLength(m_coords[i * 2 + 1], height, renderView)));
+                path.closeSubpath();
+            }
+            break;
+        case Circle:
+            if (m_coordsLen >= 3) {
+                Length radius = m_coords[2];
+                int r = min(minimumValueForLength(radius, width, renderView), minimumValueForLength(radius, height, renderView));
+                path.addEllipse(FloatRect(minimumValueForLength(m_coords[0], width, renderView) - r, minimumValueForLength(m_coords[1], height, renderView) - r, 2 * r, 2 * r));
+            }
+            break;
+        case Rect:
+            if (m_coordsLen >= 4) {
+                int x0 = minimumValueForLength(m_coords[0], width, renderView);
+                int y0 = minimumValueForLength(m_coords[1], height, renderView);
+                int x1 = minimumValueForLength(m_coords[2], width, renderView);
+                int y1 = minimumValueForLength(m_coords[3], height, renderView);
+                path.addRect(FloatRect(x0, y0, x1 - x0, y1 - y0));
+            }
+            break;
+        case Default:
+            path.addRect(FloatRect(0, 0, width, height));
+            break;
+        case Unknown:
+            break;
+    }
+
+    return path;
+}
+
+HTMLImageElement* HTMLAreaElement::imageElement() const
+{
+    Node* mapElement = parentNode();
+    if (!mapElement || !mapElement->hasTagName(mapTag))
+        return 0;
+    
+    return static_cast<HTMLMapElement*>(mapElement)->imageElement();
+}
+
+bool HTMLAreaElement::isKeyboardFocusable(KeyboardEvent*) const
+{
+    return isFocusable();
+}
+    
+bool HTMLAreaElement::isMouseFocusable() const
+{
+    return isFocusable();
+}
+
+bool HTMLAreaElement::isFocusable() const
+{
+    HTMLImageElement* image = imageElement();
+    if (!image || !image->renderer() || image->renderer()->style()->visibility() != VISIBLE)
+        return false;
+
+    return supportsFocus() && Element::tabIndex() >= 0;
+}
+    
+void HTMLAreaElement::setFocus(bool shouldBeFocused)
+{
+    if (focused() == shouldBeFocused)
+        return;
+
+    HTMLAnchorElement::setFocus(shouldBeFocused);
+
+    HTMLImageElement* imageElement = this->imageElement();
+    if (!imageElement)
+        return;
+
+    RenderObject* renderer = imageElement->renderer();
+    if (!renderer || !renderer->isImage())
+        return;
+
+    toRenderImage(renderer)->areaElementFocusChanged(this);
+}
+    
+void HTMLAreaElement::updateFocusAppearance(bool restorePreviousSelection)
+{
+    if (!isFocusable())
+        return;
+
+    HTMLImageElement* imageElement = this->imageElement();
+    if (!imageElement)
+        return;
+
+    imageElement->updateFocusAppearance(restorePreviousSelection);
+}
+    
+bool HTMLAreaElement::supportsFocus() const
+{
+    // If the AREA element was a link, it should support focus.
+    // The inherited method is not used because it assumes that a render object must exist 
+    // for the element to support focus. AREA elements do not have render objects.
+    return isLink();
+}
+
+String HTMLAreaElement::target() const
+{
+    return getAttribute(targetAttr);
+}
+
+}
diff --git a/Source/core/html/HTMLAreaElement.h b/Source/core/html/HTMLAreaElement.h
new file mode 100644
index 0000000..d1f3cb6
--- /dev/null
+++ b/Source/core/html/HTMLAreaElement.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2008, 2009, 2011 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLAreaElement_h
+#define HTMLAreaElement_h
+
+#include "core/html/HTMLAnchorElement.h"
+#include "core/platform/graphics/LayoutRect.h"
+#include <wtf/OwnArrayPtr.h>
+
+namespace WebCore {
+
+class HitTestResult;
+class HTMLImageElement;
+class Path;
+
+class HTMLAreaElement FINAL : public HTMLAnchorElement {
+public:
+    static PassRefPtr<HTMLAreaElement> create(const QualifiedName&, Document*);
+
+    bool isDefault() const { return m_shape == Default; }
+
+    bool mapMouseEvent(LayoutPoint location, const LayoutSize&, HitTestResult&);
+
+    LayoutRect computeRect(RenderObject*) const;
+    Path computePath(RenderObject*) const;
+
+    // The parent map's image.
+    HTMLImageElement* imageElement() const;
+    
+private:
+    HTMLAreaElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool supportsFocus() const;
+    virtual String target() const;
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual bool isMouseFocusable() const;
+    virtual bool isFocusable() const;
+    virtual void updateFocusAppearance(bool /*restorePreviousSelection*/);
+    virtual void setFocus(bool) OVERRIDE;
+
+    enum Shape { Default, Poly, Rect, Circle, Unknown };
+    Path getRegion(const LayoutSize&) const;
+    void invalidateCachedRegion();
+
+    OwnPtr<Path> m_region;
+    OwnArrayPtr<Length> m_coords;
+    int m_coordsLen;
+    LayoutSize m_lastSize;
+    Shape m_shape;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLAreaElement.idl b/Source/core/html/HTMLAreaElement.idl
new file mode 100644
index 0000000..a9c1fa7
--- /dev/null
+++ b/Source/core/html/HTMLAreaElement.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLAreaElement : HTMLElement {
+    [Reflect] attribute DOMString alt;
+    [Reflect] attribute DOMString coords;
+    [Reflect, URL] attribute DOMString href;
+    [Reflect] attribute boolean noHref;
+    [Reflect] attribute DOMString ping;
+    [Reflect] attribute DOMString shape;
+    [Reflect] attribute DOMString target;
+
+    // IE Extensions
+    readonly attribute DOMString hash;
+    readonly attribute DOMString host;
+    readonly attribute DOMString hostname;
+    readonly attribute DOMString pathname;
+    readonly attribute DOMString port;
+    readonly attribute DOMString protocol;
+    readonly attribute DOMString search;
+};
+
diff --git a/Source/core/html/HTMLAttributeNames.in b/Source/core/html/HTMLAttributeNames.in
new file mode 100644
index 0000000..deed951
--- /dev/null
+++ b/Source/core/html/HTMLAttributeNames.in
@@ -0,0 +1,340 @@
+namespace="HTML"
+namespacePrefix="xhtml"
+namespaceURI="http://www.w3.org/1999/xhtml"
+attrsNullNamespace
+
+abbr
+accept_charset
+accept
+accesskey
+action
+align
+alink
+allowfullscreen
+alt
+archive
+aria-activedescendant
+aria-atomic
+aria-busy
+aria-checked
+aria-controls
+aria-describedby
+aria-disabled
+aria-dropeffect
+aria-expanded
+aria-flowto
+aria-grabbed
+aria-haspopup
+aria-help
+aria-hidden
+aria-invalid
+aria-label
+aria-labeledby
+aria-labelledby
+aria-level
+aria-live
+aria-multiline
+aria-multiselectable
+aria-orientation
+aria-owns
+aria-posinset
+aria-pressed
+aria-readonly
+aria-relevant
+aria-required
+aria-selected
+aria-setsize
+aria-sort
+aria-valuemax
+aria-valuemin
+aria-valuenow
+aria-valuetext
+async
+autocomplete
+autofocus
+autoplay
+autosave
+axis
+background
+behavior
+bgcolor
+bgproperties
+border
+bordercolor
+capture
+cellpadding
+cellspacing
+char
+challenge
+charoff
+charset
+checked
+cellborder
+cite
+class
+classid
+clear
+code
+codebase
+codetype
+color
+cols
+colspan
+compact
+composite
+content
+contenteditable
+controls
+coords
+crossorigin
+data
+datetime
+declare
+default
+defer
+dir
+direction
+dirname
+disabled
+disposition
+download
+draggable
+webkitdropzone
+enctype
+end
+event
+expanded
+face
+focused
+for
+form
+formaction
+formenctype
+formmethod
+formnovalidate
+formtarget
+frame
+frameborder
+headers
+height
+hidden
+high
+href
+hreflang
+hspace
+http_equiv
+id
+incremental
+indeterminate
+is
+ismap
+itemid
+itemprop
+itemref
+itemscope
+itemtype
+keytype
+kind
+label
+lang
+language
+leftmargin
+link
+list
+longdesc
+loop
+low
+playcount
+loopend
+loopstart
+lowsrc
+manifest
+marginheight
+marginwidth
+max
+maxlength
+mayscript
+media
+mediagroup
+method
+min
+multiple
+muted
+name
+nohref
+nonce
+noresize
+noshade
+novalidate
+nowrap
+object
+onabort
+onautocomplete
+onautocompleteerror
+onbeforecopy
+onbeforecut
+onbeforeload
+onbeforepaste
+onbeforeunload
+onblur
+oncanplay
+oncanplaythrough
+onchange
+onclick
+oncontextmenu
+oncopy
+oncut
+ondblclick
+ondrag
+ondragend
+ondragenter
+ondragleave
+ondragover
+ondragstart
+ondrop
+ondurationchange
+onemptied
+onended
+onerror
+onfocus
+onfocusin
+onfocusout
+onhashchange
+oninput
+oninvalid
+onkeydown
+onkeypress
+onkeyup
+onload
+onloadeddata
+onloadedmetadata
+onloadstart
+onmousedown
+onmousemove
+onmouseout
+onmouseover
+onmouseup
+onmousewheel
+ononline
+onoffline
+onorientationchange
+onpagehide
+onpageshow
+onpaste
+onpause
+onplay
+onplaying
+onpopstate
+onprogress
+onratechange
+onreset
+onresize
+onscroll
+onsearch
+onseeked
+onseeking
+onselect
+onselectstart
+onselectionchange
+onwebkitspeechchange
+onstalled
+onstorage
+onsuspend
+onsubmit
+ontimeupdate
+ontouchstart
+ontouchmove
+ontouchend
+ontouchcancel
+ontransitionend
+onunload
+onvolumechange
+onwaiting
+onwebkitanimationstart
+onwebkitanimationiteration
+onwebkitanimationend
+onwebkitfullscreenchange
+onwebkitfullscreenerror
+onwebkitkeyadded
+onwebkitkeyerror
+onwebkitkeymessage
+onwebkitneedkey
+onwebkitsourceclose
+onwebkitsourceended
+onwebkitsourceopen
+onwebkittransitionend
+open
+optimum
+pattern
+placeholder
+pluginspage
+pluginurl
+ping
+poster
+precision
+preload
+primary
+profile
+progress
+prompt
+pseudo
+readonly
+rel
+required
+reset-style-inheritance
+results
+rev
+reversed
+role
+rows
+rowspan
+rules
+sandbox
+scheme
+scope
+scoped
+scrollamount
+scrolldelay
+scrolling
+seamless
+select
+selected
+shape
+size
+sizes
+sortable
+sortdirection
+span
+x-webkit-speech
+x-webkit-grammar
+spellcheck
+src
+srcdoc
+srclang
+standby
+start
+step
+style
+summary
+tabindex
+tableborder
+target
+text
+title
+top
+topmargin
+translate
+truespeed
+type
+usemap
+valign
+value
+valuetype
+version
+viewsource
+vlink
+vspace
+webkitallowfullscreen
+webkitdirectory
+width
+wrap
diff --git a/Source/core/html/HTMLAudioElement.cpp b/Source/core/html/HTMLAudioElement.cpp
new file mode 100644
index 0000000..f3084ab
--- /dev/null
+++ b/Source/core/html/HTMLAudioElement.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007, 2010, 2011, 2012, 2013 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+#include "core/html/HTMLAudioElement.h"
+
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLAudioElement::HTMLAudioElement(const QualifiedName& tagName, Document* document, bool createdByParser)
+    : HTMLMediaElement(tagName, document, createdByParser)
+{
+    ASSERT(hasTagName(audioTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLAudioElement> HTMLAudioElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
+{
+    RefPtr<HTMLAudioElement> audioElement(adoptRef(new HTMLAudioElement(tagName, document, createdByParser)));
+    audioElement->suspendIfNeeded();
+    return audioElement.release();
+}
+
+PassRefPtr<HTMLAudioElement> HTMLAudioElement::createForJSConstructor(Document* document, const String& src)
+{
+    RefPtr<HTMLAudioElement> audio = adoptRef(new HTMLAudioElement(audioTag, document, false));
+    audio->setPreload("auto");
+    if (!src.isNull()) {
+        audio->setSrc(src);
+        audio->scheduleDelayedAction(HTMLMediaElement::LoadMediaResource);
+    }
+    audio->suspendIfNeeded();
+    return audio.release();
+}
+
+}
diff --git a/Source/core/html/HTMLAudioElement.h b/Source/core/html/HTMLAudioElement.h
new file mode 100644
index 0000000..131f450
--- /dev/null
+++ b/Source/core/html/HTMLAudioElement.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007, 2010 Apple Inc. All rights reserved.
+ * 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 COMPUTER, 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 COMPUTER, 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 HTMLAudioElement_h
+#define HTMLAudioElement_h
+
+#include "core/html/HTMLMediaElement.h"
+
+namespace WebCore {
+
+class Document;
+
+class HTMLAudioElement FINAL : public HTMLMediaElement {
+public:
+    static PassRefPtr<HTMLAudioElement> create(const QualifiedName&, Document*, bool);
+    static PassRefPtr<HTMLAudioElement> createForJSConstructor(Document*, const String& src);
+
+private:
+    HTMLAudioElement(const QualifiedName&, Document*, bool);
+
+    virtual bool isVideo() const { return false; }
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLAudioElement.idl b/Source/core/html/HTMLAudioElement.idl
new file mode 100644
index 0000000..3be47e5
--- /dev/null
+++ b/Source/core/html/HTMLAudioElement.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2007 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    NamedConstructor=Audio([Default=NullString] optional DOMString src)
+] interface HTMLAudioElement : HTMLMediaElement {
+};
diff --git a/Source/core/html/HTMLBDIElement.h b/Source/core/html/HTMLBDIElement.h
new file mode 100644
index 0000000..94a41b9
--- /dev/null
+++ b/Source/core/html/HTMLBDIElement.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLBDIElement_h
+#define HTMLBDIElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLBDIElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLBDIElement> create(const QualifiedName& name, Document* document)
+    {
+        return adoptRef(new HTMLBDIElement(name, document));
+    }
+
+private:
+    HTMLBDIElement(const QualifiedName& name, Document* document)
+        : HTMLElement(name, document)
+    {
+        // FIXME: Rename setSelfOrAncestorHasDirAutoAttribute to reflect the fact bdi also uses this flag.
+        setSelfOrAncestorHasDirAutoAttribute(true);
+    }
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/HTMLBRElement.cpp b/Source/core/html/HTMLBRElement.cpp
new file mode 100644
index 0000000..67fd102
--- /dev/null
+++ b/Source/core/html/HTMLBRElement.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLBRElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/rendering/RenderBR.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLBRElement::HTMLBRElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(brTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLBRElement> HTMLBRElement::create(Document* document)
+{
+    return adoptRef(new HTMLBRElement(brTag, document));
+}
+
+PassRefPtr<HTMLBRElement> HTMLBRElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLBRElement(tagName, document));
+}
+
+bool HTMLBRElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == clearAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLBRElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == clearAttr) {
+        // If the string is empty, then don't add the clear property.
+        // <br clear> and <br clear=""> are just treated like <br> by Gecko, Mac IE, etc. -dwh
+        if (!value.isEmpty()) {
+            if (equalIgnoringCase(value, "all"))
+                addPropertyToPresentationAttributeStyle(style, CSSPropertyClear, CSSValueBoth);
+            else
+                addPropertyToPresentationAttributeStyle(style, CSSPropertyClear, value);
+        }
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+RenderObject* HTMLBRElement::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+     if (style->hasContent())
+        return RenderObject::createObject(this, style);
+
+     return new (arena) RenderBR(this);
+}
+
+}
diff --git a/Source/core/html/HTMLBRElement.h b/Source/core/html/HTMLBRElement.h
new file mode 100644
index 0000000..7034507
--- /dev/null
+++ b/Source/core/html/HTMLBRElement.h
@@ -0,0 +1,49 @@
+/*
+ * 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, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLBRElement_h
+#define HTMLBRElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLBRElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLBRElement> create(Document*);
+    static PassRefPtr<HTMLBRElement> create(const QualifiedName&, Document*);
+
+    virtual bool canContainRangeEndPoint() const { return false; }
+
+private:
+    HTMLBRElement(const QualifiedName&, Document*);
+
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLBRElement.idl b/Source/core/html/HTMLBRElement.idl
new file mode 100644
index 0000000..c909dc1
--- /dev/null
+++ b/Source/core/html/HTMLBRElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLBRElement : HTMLElement {
+    [Reflect] attribute DOMString clear;
+};
+
diff --git a/Source/core/html/HTMLBaseElement.cpp b/Source/core/html/HTMLBaseElement.cpp
new file mode 100644
index 0000000..1d6f237
--- /dev/null
+++ b/Source/core/html/HTMLBaseElement.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLBaseElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/TextResourceDecoder.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLBaseElement::HTMLBaseElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(baseTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLBaseElement> HTMLBaseElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLBaseElement(tagName, document));
+}
+
+void HTMLBaseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == hrefAttr || name == targetAttr)
+        document()->processBaseElement();
+    else
+        HTMLElement::parseAttribute(name, value);
+}
+
+Node::InsertionNotificationRequest HTMLBaseElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+    if (insertionPoint->inDocument())
+        document()->processBaseElement();
+    return InsertionDone;
+}
+
+void HTMLBaseElement::removedFrom(ContainerNode* insertionPoint)
+{
+    HTMLElement::removedFrom(insertionPoint);
+    if (insertionPoint->inDocument())
+        document()->processBaseElement();
+}
+
+bool HTMLBaseElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+String HTMLBaseElement::target() const
+{
+    return fastGetAttribute(targetAttr);
+}
+
+KURL HTMLBaseElement::href() const
+{
+    // This does not use the getURLAttribute function because that will resolve relative to the document's base URL;
+    // base elements like this one can be used to set that base URL. Thus we need to resolve relative to the document's
+    // URL and ignore the base URL.
+
+    const AtomicString& attributeValue = fastGetAttribute(hrefAttr);
+    if (attributeValue.isNull())
+        return document()->url();
+
+    KURL url = !document()->decoder() ?
+        KURL(document()->url(), stripLeadingAndTrailingHTMLSpaces(attributeValue)) :
+        KURL(document()->url(), stripLeadingAndTrailingHTMLSpaces(attributeValue), document()->decoder()->encoding());
+
+    if (!url.isValid())
+        return KURL();
+
+    return url;
+}
+
+void HTMLBaseElement::setHref(const AtomicString& value)
+{
+    setAttribute(hrefAttr, value);
+}
+
+}
diff --git a/Source/core/html/HTMLBaseElement.h b/Source/core/html/HTMLBaseElement.h
new file mode 100644
index 0000000..d8d5b45
--- /dev/null
+++ b/Source/core/html/HTMLBaseElement.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLBaseElement_h
+#define HTMLBaseElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLBaseElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLBaseElement> create(const QualifiedName&, Document*);
+
+    KURL href() const;
+    void setHref(const AtomicString&);
+
+private:
+    HTMLBaseElement(const QualifiedName&, Document*);
+
+    virtual String target() const;
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLBaseElement.idl b/Source/core/html/HTMLBaseElement.idl
new file mode 100644
index 0000000..4d9d39f
--- /dev/null
+++ b/Source/core/html/HTMLBaseElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLBaseElement : HTMLElement {
+    [TreatNullAs=NullString] attribute DOMString href;
+    [Reflect] attribute DOMString target;
+};
diff --git a/Source/core/html/HTMLBaseFontElement.cpp b/Source/core/html/HTMLBaseFontElement.cpp
new file mode 100644
index 0000000..39dfd65
--- /dev/null
+++ b/Source/core/html/HTMLBaseFontElement.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLBaseFontElement.h"
+
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLBaseFontElement::HTMLBaseFontElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(basefontTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLBaseFontElement> HTMLBaseFontElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLBaseFontElement(tagName, document));
+}
+
+}
diff --git a/Source/core/html/HTMLBaseFontElement.h b/Source/core/html/HTMLBaseFontElement.h
new file mode 100644
index 0000000..94a8d58
--- /dev/null
+++ b/Source/core/html/HTMLBaseFontElement.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLBaseFontElement_h
+#define HTMLBaseFontElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLBaseFontElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLBaseFontElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLBaseFontElement(const QualifiedName&, Document*);
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLBaseFontElement.idl b/Source/core/html/HTMLBaseFontElement.idl
new file mode 100644
index 0000000..b885a05
--- /dev/null
+++ b/Source/core/html/HTMLBaseFontElement.idl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLBaseFontElement : HTMLElement {
+    [Reflect] attribute DOMString color;
+    [Reflect] attribute DOMString face;
+    [Reflect] attribute long size;
+};
diff --git a/Source/core/html/HTMLBodyElement.cpp b/Source/core/html/HTMLBodyElement.cpp
new file mode 100644
index 0000000..1d82c13
--- /dev/null
+++ b/Source/core/html/HTMLBodyElement.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann (hausmann@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLBodyElement.h"
+
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/css/CSSImageValue.h"
+#include "core/css/CSSParser.h"
+#include "core/css/StylePropertySet.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/EventNames.h"
+#include "core/html/HTMLFrameElementBase.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLBodyElement::HTMLBodyElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(bodyTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(Document* document)
+{
+    return adoptRef(new HTMLBodyElement(bodyTag, document));
+}
+
+PassRefPtr<HTMLBodyElement> HTMLBodyElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLBodyElement(tagName, document));
+}
+
+HTMLBodyElement::~HTMLBodyElement()
+{
+}
+
+bool HTMLBodyElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == backgroundAttr || name == marginwidthAttr || name == leftmarginAttr || name == marginheightAttr || name == topmarginAttr || name == bgcolorAttr || name == textAttr || name == bgpropertiesAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLBodyElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == backgroundAttr) {
+        String url = stripLeadingAndTrailingHTMLSpaces(value);
+        if (!url.isEmpty()) {
+            RefPtr<CSSImageValue> imageValue = CSSImageValue::create(document()->completeURL(url).string());
+            imageValue->setInitiator(localName());
+            style->setProperty(CSSProperty(CSSPropertyBackgroundImage, imageValue));
+        }
+    } else if (name == marginwidthAttr || name == leftmarginAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
+    } else if (name == marginheightAttr || name == topmarginAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
+    } else if (name == bgcolorAttr) {
+        addHTMLColorToStyle(style, CSSPropertyBackgroundColor, value);
+    } else if (name == textAttr) {
+        addHTMLColorToStyle(style, CSSPropertyColor, value);
+    } else if (name == bgpropertiesAttr) {
+        if (equalIgnoringCase(value, "fixed"))
+           addPropertyToPresentationAttributeStyle(style, CSSPropertyBackgroundAttachment, CSSValueFixed);
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLBodyElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == vlinkAttr || name == alinkAttr || name == linkAttr) {
+        if (value.isNull()) {
+            if (name == linkAttr)
+                document()->resetLinkColor();
+            else if (name == vlinkAttr)
+                document()->resetVisitedLinkColor();
+            else
+                document()->resetActiveLinkColor();
+        } else {
+            RGBA32 color;
+            if (CSSParser::parseColor(color, value, !document()->inQuirksMode())) {
+                if (name == linkAttr)
+                    document()->setLinkColor(color);
+                else if (name == vlinkAttr)
+                    document()->setVisitedLinkColor(color);
+                else
+                    document()->setActiveLinkColor(color);
+            }
+        }
+
+        setNeedsStyleRecalc();
+    } else if (name == onloadAttr)
+        document()->setWindowAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onbeforeunloadAttr)
+        document()->setWindowAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onunloadAttr)
+        document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onpagehideAttr)
+        document()->setWindowAttributeEventListener(eventNames().pagehideEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onpageshowAttr)
+        document()->setWindowAttributeEventListener(eventNames().pageshowEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onpopstateAttr)
+        document()->setWindowAttributeEventListener(eventNames().popstateEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onblurAttr)
+        document()->setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onfocusAttr)
+        document()->setWindowAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(document()->frame(), name, value));
+#if ENABLE(ORIENTATION_EVENTS)
+    else if (name == onorientationchangeAttr)
+        document()->setWindowAttributeEventListener(eventNames().orientationchangeEvent, createAttributeEventListener(document()->frame(), name, value));
+#endif
+    else if (name == onhashchangeAttr)
+        document()->setWindowAttributeEventListener(eventNames().hashchangeEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onresizeAttr)
+        document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onscrollAttr)
+        document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onselectionchangeAttr)
+        document()->setAttributeEventListener(eventNames().selectionchangeEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onstorageAttr)
+        document()->setWindowAttributeEventListener(eventNames().storageEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == ononlineAttr)
+        document()->setWindowAttributeEventListener(eventNames().onlineEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onofflineAttr)
+        document()->setWindowAttributeEventListener(eventNames().offlineEvent, createAttributeEventListener(document()->frame(), name, value));
+    else
+        HTMLElement::parseAttribute(name, value);
+}
+
+Node::InsertionNotificationRequest HTMLBodyElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+    if (insertionPoint->inDocument())
+        return InsertionShouldCallDidNotifySubtreeInsertions;
+    return InsertionDone;
+}
+
+void HTMLBodyElement::didNotifySubtreeInsertions(ContainerNode* insertionPoint)
+{
+    ASSERT_UNUSED(insertionPoint, insertionPoint->inDocument());
+    ASSERT(document());
+
+    // FIXME: Perhaps this code should be in attach() instead of here.
+    Element* ownerElement = document()->ownerElement();
+    if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
+        HTMLFrameElementBase* ownerFrameElement = static_cast<HTMLFrameElementBase*>(ownerElement);
+        int marginWidth = ownerFrameElement->marginWidth();
+        if (marginWidth != -1)
+            setAttribute(marginwidthAttr, String::number(marginWidth));
+        int marginHeight = ownerFrameElement->marginHeight();
+        if (marginHeight != -1)
+            setAttribute(marginheightAttr, String::number(marginHeight));
+    }
+
+    // FIXME: This call to scheduleRelayout should not be needed here.
+    // But without it we hang during WebKit tests; need to fix that and remove this.
+    if (FrameView* view = document()->view())
+        view->scheduleRelayout();
+}
+
+bool HTMLBodyElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == backgroundAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+bool HTMLBodyElement::supportsFocus() const
+{
+    return rendererIsEditable() || HTMLElement::supportsFocus();
+}
+
+String HTMLBodyElement::aLink() const
+{
+    return getAttribute(alinkAttr);
+}
+
+void HTMLBodyElement::setALink(const String& value)
+{
+    setAttribute(alinkAttr, value);
+}
+
+String HTMLBodyElement::bgColor() const
+{
+    return getAttribute(bgcolorAttr);
+}
+
+void HTMLBodyElement::setBgColor(const String& value)
+{
+    setAttribute(bgcolorAttr, value);
+}
+
+String HTMLBodyElement::link() const
+{
+    return getAttribute(linkAttr);
+}
+
+void HTMLBodyElement::setLink(const String& value)
+{
+    setAttribute(linkAttr, value);
+}
+
+String HTMLBodyElement::text() const
+{
+    return getAttribute(textAttr);
+}
+
+void HTMLBodyElement::setText(const String& value)
+{
+    setAttribute(textAttr, value);
+}
+
+String HTMLBodyElement::vLink() const
+{
+    return getAttribute(vlinkAttr);
+}
+
+void HTMLBodyElement::setVLink(const String& value)
+{
+    setAttribute(vlinkAttr, value);
+}
+
+static int adjustForZoom(int value, Document* document)
+{
+    Frame* frame = document->frame();
+    float zoomFactor = frame->pageZoomFactor();
+    if (zoomFactor == 1)
+        return value;
+    // Needed because of truncation (rather than rounding) when scaling up.
+    if (zoomFactor > 1)
+        value++;
+    return static_cast<int>(value / zoomFactor);
+}
+
+int HTMLBodyElement::scrollLeft()
+{
+    // Update the document's layout.
+    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();
+    Frame* frame = document->frame();
+    if (!frame)
+        return;
+    FrameView* view = frame->view();
+    if (!view)
+        return;
+    view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor()), view->scrollY()));
+}
+
+int HTMLBodyElement::scrollTop()
+{
+    // Update the document's layout.
+    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();
+    Frame* frame = document->frame();
+    if (!frame)
+        return;
+    FrameView* view = frame->view();
+    if (!view)
+        return;
+    view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor())));
+}
+
+int HTMLBodyElement::scrollHeight()
+{
+    // Update the document's layout.
+    Document* document = this->document();
+    document->updateLayoutIgnorePendingStylesheets();
+    FrameView* view = document->view();
+    return view ? adjustForZoom(view->contentsHeight(), document) : 0;    
+}
+
+int HTMLBodyElement::scrollWidth()
+{
+    // Update the document's layout.
+    Document* document = this->document();
+    document->updateLayoutIgnorePendingStylesheets();
+    FrameView* view = document->view();
+    return view ? adjustForZoom(view->contentsWidth(), document) : 0;    
+}
+
+void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLElement::addSubresourceAttributeURLs(urls);
+
+    addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr)));
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLBodyElement.h b/Source/core/html/HTMLBodyElement.h
new file mode 100644
index 0000000..fe7e259
--- /dev/null
+++ b/Source/core/html/HTMLBodyElement.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2004, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLBodyElement_h
+#define HTMLBodyElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class Document;
+
+class HTMLBodyElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLBodyElement> create(Document*);
+    static PassRefPtr<HTMLBodyElement> create(const QualifiedName&, Document*);
+    virtual ~HTMLBodyElement();
+
+    String aLink() const;
+    void setALink(const String&);
+    String bgColor() const;
+    void setBgColor(const String&);
+    String link() const;
+    void setLink(const String&);
+    String text() const;
+    void setText(const String&);
+    String vLink() const;
+    void setVLink(const String&);
+
+    // Declared virtual in Element
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(blur);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(error);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(focus);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(load);
+
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(beforeunload);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(hashchange);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(message);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(offline);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(online);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(popstate);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(resize);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(storage);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(unload);
+
+#if ENABLE(ORIENTATION_EVENTS)
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(orientationchange);
+#endif
+
+private:
+    HTMLBodyElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void didNotifySubtreeInsertions(ContainerNode*) OVERRIDE;
+    
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+    
+    virtual bool supportsFocus() const;
+
+    virtual int scrollLeft();
+    virtual void setScrollLeft(int scrollLeft);
+    
+    virtual int scrollTop();
+    virtual void setScrollTop(int scrollTop);
+    
+    virtual int scrollHeight();
+    virtual int scrollWidth();
+    
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLBodyElement.idl b/Source/core/html/HTMLBodyElement.idl
new file mode 100644
index 0000000..f65097a
--- /dev/null
+++ b/Source/core/html/HTMLBodyElement.idl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLBodyElement : HTMLElement {
+    [Reflect] attribute DOMString aLink;
+    [Reflect] attribute DOMString background;
+    [Reflect] attribute DOMString bgColor;
+    [Reflect] attribute DOMString link;
+    [Reflect] attribute DOMString text;
+    [Reflect] attribute DOMString vLink;
+
+    // Event handler attributes
+    [NotEnumerable] attribute EventListener onbeforeunload;
+    [NotEnumerable] attribute EventListener onhashchange;
+    [NotEnumerable] attribute EventListener onmessage;
+    [NotEnumerable] attribute EventListener onoffline;
+    [NotEnumerable] attribute EventListener ononline;
+    [NotEnumerable] attribute EventListener onpopstate;
+    [NotEnumerable] attribute EventListener onresize;
+    [NotEnumerable] attribute EventListener onstorage;
+    [NotEnumerable] attribute EventListener onunload;
+
+    [Conditional=ORIENTATION_EVENTS, NotEnumerable] attribute EventListener onorientationchange;
+
+    // Overrides of Element attributes (with different implementation in bindings).
+    [NotEnumerable] attribute EventListener onblur;
+    [NotEnumerable] attribute EventListener onerror;
+    [NotEnumerable] attribute EventListener onfocus;
+    [NotEnumerable] attribute EventListener onload;
+
+    // Not implemented yet.
+    // attribute [NotEnumerable] EventListener onafterprint;
+    // attribute [NotEnumerable] EventListener onbeforeprint;
+    // attribute [NotEnumerable] EventListener onredo;
+    // attribute [NotEnumerable] EventListener onundo;
+};
+
diff --git a/Source/core/html/HTMLButtonElement.cpp b/Source/core/html/HTMLButtonElement.cpp
new file mode 100644
index 0000000..82a44dd
--- /dev/null
+++ b/Source/core/html/HTMLButtonElement.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLButtonElement.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/rendering/RenderButton.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLButtonElement::HTMLButtonElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+    : HTMLFormControlElement(tagName, document, form)
+    , m_type(SUBMIT)
+    , m_isActivatedSubmit(false)
+{
+    ASSERT(hasTagName(buttonTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLButtonElement> HTMLButtonElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+{
+    return adoptRef(new HTMLButtonElement(tagName, document, form));
+}
+
+void HTMLButtonElement::setType(const AtomicString& type)
+{
+    setAttribute(typeAttr, type);
+}
+
+RenderObject* HTMLButtonElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderButton(this);
+}
+
+const AtomicString& HTMLButtonElement::formControlType() const
+{
+    switch (m_type) {
+        case SUBMIT: {
+            DEFINE_STATIC_LOCAL(const AtomicString, submit, ("submit", AtomicString::ConstructFromLiteral));
+            return submit;
+        }
+        case BUTTON: {
+            DEFINE_STATIC_LOCAL(const AtomicString, button, ("button", AtomicString::ConstructFromLiteral));
+            return button;
+        }
+        case RESET: {
+            DEFINE_STATIC_LOCAL(const AtomicString, reset, ("reset", AtomicString::ConstructFromLiteral));
+            return reset;
+        }
+    }
+
+    ASSERT_NOT_REACHED();
+    return emptyAtom;
+}
+
+bool HTMLButtonElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == alignAttr) {
+        // Don't map 'align' attribute.  This matches what Firefox and IE do, but not Opera.
+        // See http://bugs.webkit.org/show_bug.cgi?id=12071
+        return false;
+    }
+
+    return HTMLFormControlElement::isPresentationAttribute(name);
+}
+
+void HTMLButtonElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == typeAttr) {
+        if (equalIgnoringCase(value, "reset"))
+            m_type = RESET;
+        else if (equalIgnoringCase(value, "button"))
+            m_type = BUTTON;
+        else
+            m_type = SUBMIT;
+        setNeedsWillValidateCheck();
+    } else
+        HTMLFormControlElement::parseAttribute(name, value);
+}
+
+void HTMLButtonElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().DOMActivateEvent && !isDisabledFormControl()) {
+        if (form() && m_type == SUBMIT) {
+            m_isActivatedSubmit = true;
+            form()->prepareForSubmission(event);
+            event->setDefaultHandled();
+            m_isActivatedSubmit = false; // Do this in case submission was canceled.
+        }
+        if (form() && m_type == RESET) {
+            form()->reset();
+            event->setDefaultHandled();
+        }
+    }
+
+    if (event->isKeyboardEvent()) {
+        if (event->type() == eventNames().keydownEvent && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "U+0020") {
+            setActive(true, true);
+            // No setDefaultHandled() - IE dispatches a keypress in this case.
+            return;
+        }
+        if (event->type() == eventNames().keypressEvent) {
+            switch (static_cast<KeyboardEvent*>(event)->charCode()) {
+                case '\r':
+                    dispatchSimulatedClick(event);
+                    event->setDefaultHandled();
+                    return;
+                case ' ':
+                    // Prevent scrolling down the page.
+                    event->setDefaultHandled();
+                    return;
+            }
+        }
+        if (event->type() == eventNames().keyupEvent && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "U+0020") {
+            if (active())
+                dispatchSimulatedClick(event);
+            event->setDefaultHandled();
+            return;
+        }
+    }
+
+    HTMLFormControlElement::defaultEventHandler(event);
+}
+
+bool HTMLButtonElement::willRespondToMouseClickEvents()
+{
+    if (!isDisabledFormControl() && form() && (m_type == SUBMIT || m_type == RESET))
+        return true;
+    return HTMLFormControlElement::willRespondToMouseClickEvents();
+}
+
+bool HTMLButtonElement::isSuccessfulSubmitButton() const
+{
+    // HTML spec says that buttons must have names to be considered successful.
+    // However, other browsers do not impose this constraint.
+    return m_type == SUBMIT && !isDisabledFormControl();
+}
+
+bool HTMLButtonElement::isActivatedSubmit() const
+{
+    return m_isActivatedSubmit;
+}
+
+void HTMLButtonElement::setActivatedSubmit(bool flag)
+{
+    m_isActivatedSubmit = flag;
+}
+
+bool HTMLButtonElement::appendFormData(FormDataList& formData, bool)
+{
+    if (m_type != SUBMIT || name().isEmpty() || !m_isActivatedSubmit)
+        return false;
+    formData.appendData(name(), value());
+    return true;
+}
+
+void HTMLButtonElement::accessKeyAction(bool sendMouseEvents)
+{
+    focus();
+
+    dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
+}
+
+bool HTMLButtonElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == formactionAttr || HTMLFormControlElement::isURLAttribute(attribute);
+}
+
+String HTMLButtonElement::value() const
+{
+    return getAttribute(valueAttr);
+}
+
+bool HTMLButtonElement::recalcWillValidate() const
+{
+    return m_type == SUBMIT && HTMLFormControlElement::recalcWillValidate();
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLButtonElement.h b/Source/core/html/HTMLButtonElement.h
new file mode 100644
index 0000000..80c096d
--- /dev/null
+++ b/Source/core/html/HTMLButtonElement.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLButtonElement_h
+#define HTMLButtonElement_h
+
+#include "core/html/HTMLFormControlElement.h"
+
+namespace WebCore {
+
+class HTMLButtonElement FINAL : public HTMLFormControlElement {
+public:
+    static PassRefPtr<HTMLButtonElement> create(const QualifiedName&, Document*, HTMLFormElement*);
+
+    void setType(const AtomicString&);
+    
+    String value() const;
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+private:
+    HTMLButtonElement(const QualifiedName& tagName, Document*, HTMLFormElement*);
+
+    enum Type { SUBMIT, RESET, BUTTON };
+
+    virtual const AtomicString& formControlType() const;
+
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+
+    // HTMLFormControlElement always creates one, but buttons don't need it.
+    virtual bool alwaysCreateUserAgentShadowRoot() const OVERRIDE { return false; }
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void defaultEventHandler(Event*);
+
+    virtual bool appendFormData(FormDataList&, bool);
+
+    virtual bool isEnumeratable() const { return true; } 
+    virtual bool supportLabels() const OVERRIDE { return true; }
+
+    virtual bool isSuccessfulSubmitButton() const;
+    virtual bool isActivatedSubmit() const;
+    virtual void setActivatedSubmit(bool flag);
+
+    virtual void accessKeyAction(bool sendMouseEvents);
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+    virtual bool canStartSelection() const { return false; }
+
+    virtual bool isOptionalFormControl() const { return true; }
+    virtual bool recalcWillValidate() const;
+
+    Type m_type;
+    bool m_isActivatedSubmit;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLButtonElement.idl b/Source/core/html/HTMLButtonElement.idl
new file mode 100644
index 0000000..eb3832f
--- /dev/null
+++ b/Source/core/html/HTMLButtonElement.idl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLButtonElement : HTMLElement {
+    [Reflect] attribute boolean autofocus;
+    [Reflect] attribute boolean disabled;
+    readonly attribute HTMLFormElement form;
+    [Reflect, URL] attribute DOMString formAction;
+    [TreatNullAs=NullString] attribute DOMString formEnctype;
+    [TreatNullAs=NullString] attribute DOMString formMethod;
+    [Reflect] attribute boolean formNoValidate;
+    [Reflect] attribute DOMString formTarget;
+    [Reflect] attribute DOMString name;
+    [TreatNullAs=NullString] attribute DOMString type;
+    [Reflect] attribute DOMString value;
+
+    readonly attribute boolean willValidate;
+    readonly attribute ValidityState validity;
+    readonly attribute DOMString validationMessage;
+    boolean checkValidity();
+    void setCustomValidity([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString error);
+
+    readonly attribute NodeList labels;
+};
diff --git a/Source/core/html/HTMLCanvasElement.cpp b/Source/core/html/HTMLCanvasElement.cpp
new file mode 100644
index 0000000..d44846e
--- /dev/null
+++ b/Source/core/html/HTMLCanvasElement.cpp
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+#include "core/html/HTMLCanvasElement.h"
+
+#include <math.h>
+#include <stdio.h>
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include "core/html/ImageData.h"
+#include "core/html/canvas/Canvas2DContextAttributes.h"
+#include "core/html/canvas/CanvasGradient.h"
+#include "core/html/canvas/CanvasPattern.h"
+#include "core/html/canvas/CanvasRenderingContext2D.h"
+#include "core/html/canvas/CanvasStyle.h"
+#include "core/page/Chrome.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "RuntimeEnabledFeatures.h"
+#include "core/page/Settings.h"
+#include "core/platform/MIMETypeRegistry.h"
+#include "core/platform/graphics/GraphicsContext.h"
+#include "core/platform/graphics/ImageBuffer.h"
+#include "core/rendering/RenderHTMLCanvas.h"
+
+#include "core/html/canvas/WebGLContextAttributes.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+#include <public/Platform.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// These values come from the WhatWG spec.
+static const int DefaultWidth = 300;
+static const int DefaultHeight = 150;
+
+// Firefox limits width/height to 32767 pixels, but slows down dramatically before it
+// reaches that limit. We limit by area instead, giving us larger maximum dimensions,
+// in exchange for a smaller maximum canvas size.
+static const float MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels
+
+//In Skia, we will also limit width/height to 32767.
+static const float MaxSkiaDim = 32767.0F; // Maximum width/height in CSS pixels.
+
+HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_size(DefaultWidth, DefaultHeight)
+    , m_rendererIsCanvas(false)
+    , m_ignoreReset(false)
+    , m_deviceScaleFactor(targetDeviceScaleFactor())
+    , m_originClean(true)
+    , m_hasCreatedImageBuffer(false)
+    , m_didClearImageBuffer(false)
+{
+    ASSERT(hasTagName(canvasTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLCanvasElement> HTMLCanvasElement::create(Document* document)
+{
+    return adoptRef(new HTMLCanvasElement(canvasTag, document));
+}
+
+PassRefPtr<HTMLCanvasElement> HTMLCanvasElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLCanvasElement(tagName, document));
+}
+
+HTMLCanvasElement::~HTMLCanvasElement()
+{
+    HashSet<CanvasObserver*>::iterator end = m_observers.end();
+    for (HashSet<CanvasObserver*>::iterator it = m_observers.begin(); it != end; ++it)
+        (*it)->canvasDestroyed(this);
+
+    m_context.clear(); // Ensure this goes away before the ImageBuffer.
+}
+
+void HTMLCanvasElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == widthAttr || name == heightAttr)
+        reset();
+    HTMLElement::parseAttribute(name, value);
+}
+
+RenderObject* HTMLCanvasElement::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+    Frame* frame = document()->frame();
+    if (frame && frame->script()->canExecuteScripts(NotAboutToExecuteScript)) {
+        m_rendererIsCanvas = true;
+        return new (arena) RenderHTMLCanvas(this);
+    }
+
+    m_rendererIsCanvas = false;
+    return HTMLElement::createRenderer(arena, style);
+}
+
+void HTMLCanvasElement::attach()
+{
+    setIsInCanvasSubtree(true);
+    HTMLElement::attach();
+}
+
+void HTMLCanvasElement::addObserver(CanvasObserver* observer)
+{
+    m_observers.add(observer);
+}
+
+void HTMLCanvasElement::removeObserver(CanvasObserver* observer)
+{
+    m_observers.remove(observer);
+}
+
+void HTMLCanvasElement::setHeight(int value)
+{
+    setAttribute(heightAttr, String::number(value));
+}
+
+void HTMLCanvasElement::setWidth(int value)
+{
+    setAttribute(widthAttr, String::number(value));
+}
+
+CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, CanvasContextAttributes* attrs)
+{
+    // A Canvas can either be "2D" or "webgl" but never both. If you request a 2D canvas and the existing
+    // context is already 2D, just return that. If the existing context is WebGL, then destroy it
+    // before creating a new 2D context. Vice versa when requesting a WebGL canvas. Requesting a
+    // context with any other type string will destroy any existing context.
+
+    // FIXME - The code depends on the context not going away once created, to prevent JS from
+    // seeing a dangling pointer. So for now we will disallow the context from being changed
+    // once it is created.
+    if (type == "2d") {
+        if (m_context && !m_context->is2d())
+            return 0;
+        if (!m_context) {
+            m_context = CanvasRenderingContext2D::create(this, RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() ? static_cast<Canvas2DContextAttributes*>(attrs) : 0, document()->inQuirksMode());
+            if (m_context) {
+                // Need to make sure a RenderLayer and compositing layer get created for the Canvas
+                setNeedsStyleRecalc(SyntheticStyleChange);
+            }
+        }
+        return m_context.get();
+    }
+
+    Settings* settings = document()->settings();
+    if (settings && settings->webGLEnabled()) {
+
+        // Accept the legacy "webkit-3d" name as well as the provisional "experimental-webgl" name.
+        bool is3dContext = (type == "webkit-3d") || (type == "experimental-webgl");
+
+#if !OS(ANDROID)
+        // Now that WebGL is ratified, we will also accept "webgl" as the context name in Chrome.
+        is3dContext |= (type == "webgl");
+#endif
+
+        if (is3dContext) {
+            if (m_context && !m_context->is3d())
+                return 0;
+            if (!m_context) {
+                m_context = WebGLRenderingContext::create(this, static_cast<WebGLContextAttributes*>(attrs));
+                if (m_context) {
+                    // Need to make sure a RenderLayer and compositing layer get created for the Canvas
+                    setNeedsStyleRecalc(SyntheticStyleChange);
+                }
+            }
+            return m_context.get();
+        }
+    }
+    return 0;
+}
+
+void HTMLCanvasElement::didDraw(const FloatRect& rect)
+{
+    clearCopiedImage();
+
+    if (RenderBox* ro = renderBox()) {
+        FloatRect destRect = ro->contentBoxRect();
+        FloatRect r = mapRect(rect, FloatRect(0, 0, size().width(), size().height()), destRect);
+        r.intersect(destRect);
+        if (r.isEmpty() || m_dirtyRect.contains(r))
+            return;
+
+        m_dirtyRect.unite(r);
+        ro->repaintRectangle(enclosingIntRect(m_dirtyRect));
+    }
+
+    notifyObserversCanvasChanged(rect);
+}
+
+void HTMLCanvasElement::notifyObserversCanvasChanged(const FloatRect& rect)
+{
+    HashSet<CanvasObserver*>::iterator end = m_observers.end();
+    for (HashSet<CanvasObserver*>::iterator it = m_observers.begin(); it != end; ++it)
+        (*it)->canvasChanged(this, rect);
+}
+
+void HTMLCanvasElement::reset()
+{
+    if (m_ignoreReset)
+        return;
+
+    bool ok;
+    bool hadImageBuffer = hasCreatedImageBuffer();
+
+    int w = getAttribute(widthAttr).toInt(&ok);
+    if (!ok || w < 0)
+        w = DefaultWidth;
+
+    int h = getAttribute(heightAttr).toInt(&ok);
+    if (!ok || h < 0)
+        h = DefaultHeight;
+
+    if (m_contextStateSaver) {
+        // Reset to the initial graphics context state.
+        m_contextStateSaver->restore();
+        m_contextStateSaver->save();
+    }
+
+    if (m_context && m_context->is2d()) {
+        CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext2D*>(m_context.get());
+        context2D->reset();
+    }
+
+    IntSize oldSize = size();
+    IntSize newSize(w, h);
+    float newDeviceScaleFactor = targetDeviceScaleFactor();
+
+    // If the size of an existing buffer matches, we can just clear it instead of reallocating.
+    // This optimization is only done for 2D canvases for now.
+    if (m_hasCreatedImageBuffer && oldSize == newSize && m_deviceScaleFactor == newDeviceScaleFactor && m_context && m_context->is2d()) {
+        if (!m_didClearImageBuffer)
+            clearImageBuffer();
+        return;
+    }
+
+    m_deviceScaleFactor = newDeviceScaleFactor;
+
+    setSurfaceSize(newSize);
+
+    if (m_context && m_context->is3d() && oldSize != size())
+        static_cast<WebGLRenderingContext*>(m_context.get())->reshape(width(), height());
+
+    if (RenderObject* renderer = this->renderer()) {
+        if (m_rendererIsCanvas) {
+            if (oldSize != size()) {
+                toRenderHTMLCanvas(renderer)->canvasSizeChanged();
+                if (renderBox() && renderBox()->hasAcceleratedCompositing())
+                    renderBox()->contentChanged(CanvasChanged);
+            }
+            if (hadImageBuffer)
+                renderer->repaint();
+        }
+    }
+
+    HashSet<CanvasObserver*>::iterator end = m_observers.end();
+    for (HashSet<CanvasObserver*>::iterator it = m_observers.begin(); it != end; ++it)
+        (*it)->canvasResized(this);
+}
+
+float HTMLCanvasElement::targetDeviceScaleFactor() const
+{
+#if ENABLE(HIGH_DPI_CANVAS)
+    return document()->frame() ? document()->frame()->page()->deviceScaleFactor() : 1;
+#else
+    return 1;
+#endif
+}
+
+bool HTMLCanvasElement::paintsIntoCanvasBuffer() const
+{
+    ASSERT(m_context);
+
+    if (!m_context->isAccelerated())
+        return true;
+
+    if (renderBox() && renderBox()->hasAcceleratedCompositing())
+        return false;
+
+    return true;
+}
+
+
+void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r, bool useLowQualityScale)
+{
+    // Clear the dirty rect
+    m_dirtyRect = FloatRect();
+
+    if (context->paintingDisabled())
+        return;
+
+    if (m_context) {
+        if (!paintsIntoCanvasBuffer() && !document()->printing())
+            return;
+        m_context->paintRenderingResultsToCanvas();
+    }
+
+    if (hasCreatedImageBuffer()) {
+        ImageBuffer* imageBuffer = buffer();
+        if (imageBuffer) {
+            CompositeOperator compositeOperator = !m_context || m_context->hasAlpha() ? CompositeSourceOver : CompositeCopy;
+            if (m_presentedImage)
+                context->drawImage(m_presentedImage.get(), ColorSpaceDeviceRGB, pixelSnappedIntRect(r), compositeOperator, DoNotRespectImageOrientation, useLowQualityScale);
+            else
+                context->drawImageBuffer(imageBuffer, ColorSpaceDeviceRGB, pixelSnappedIntRect(r), compositeOperator, BlendModeNormal, useLowQualityScale);
+        }
+    }
+
+    if (is3D())
+        static_cast<WebGLRenderingContext*>(m_context.get())->markLayerComposited();
+}
+
+bool HTMLCanvasElement::is3D() const
+{
+    return m_context && m_context->is3d();
+}
+
+void HTMLCanvasElement::makeRenderingResultsAvailable()
+{
+    if (m_context)
+        m_context->paintRenderingResultsToCanvas();
+}
+
+void HTMLCanvasElement::makePresentationCopy()
+{
+    if (!m_presentedImage) {
+        // The buffer contains the last presented data, so save a copy of it.
+        m_presentedImage = buffer()->copyImage(CopyBackingStore, Unscaled);
+    }
+}
+
+void HTMLCanvasElement::clearPresentationCopy()
+{
+    m_presentedImage.clear();
+}
+
+void HTMLCanvasElement::setSurfaceSize(const IntSize& size)
+{
+    m_size = size;
+    m_hasCreatedImageBuffer = false;
+    m_contextStateSaver.clear();
+    m_imageBuffer.clear();
+    clearCopiedImage();
+}
+
+String HTMLCanvasElement::toEncodingMimeType(const String& mimeType)
+{
+    String lowercaseMimeType = mimeType.lower();
+
+    // FIXME: Make isSupportedImageMIMETypeForEncoding threadsafe (to allow this method to be used on a worker thread).
+    if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(lowercaseMimeType))
+        lowercaseMimeType = "image/png";
+
+    return lowercaseMimeType;
+}
+
+String HTMLCanvasElement::toDataURL(const String& mimeType, const double* quality, ExceptionCode& ec)
+{
+    if (!m_originClean) {
+        ec = SECURITY_ERR;
+        return String();
+    }
+
+    if (m_size.isEmpty() || !buffer())
+        return String("data:,");
+
+    String encodingMimeType = toEncodingMimeType(mimeType);
+
+    // Try to get ImageData first, as that may avoid lossy conversions.
+    RefPtr<ImageData> imageData = getImageData();
+
+    if (imageData)
+        return ImageDataToDataURL(*imageData, encodingMimeType, quality);
+
+    makeRenderingResultsAvailable();
+
+    return buffer()->toDataURL(encodingMimeType, quality);
+}
+
+PassRefPtr<ImageData> HTMLCanvasElement::getImageData()
+{
+    if (!m_context || !m_context->is3d())
+       return 0;
+
+    WebGLRenderingContext* ctx = static_cast<WebGLRenderingContext*>(m_context.get());
+
+    return ctx->paintRenderingResultsToImageData();
+}
+
+FloatRect HTMLCanvasElement::convertLogicalToDevice(const FloatRect& logicalRect) const
+{
+    FloatRect deviceRect(logicalRect);
+    deviceRect.scale(m_deviceScaleFactor);
+
+    float x = floorf(deviceRect.x());
+    float y = floorf(deviceRect.y());
+    float w = ceilf(deviceRect.maxX() - x);
+    float h = ceilf(deviceRect.maxY() - y);
+    deviceRect.setX(x);
+    deviceRect.setY(y);
+    deviceRect.setWidth(w);
+    deviceRect.setHeight(h);
+
+    return deviceRect;
+}
+
+FloatSize HTMLCanvasElement::convertLogicalToDevice(const FloatSize& logicalSize) const
+{
+    float width = ceilf(logicalSize.width() * m_deviceScaleFactor);
+    float height = ceilf(logicalSize.height() * m_deviceScaleFactor);
+    return FloatSize(width, height);
+}
+
+FloatSize HTMLCanvasElement::convertDeviceToLogical(const FloatSize& deviceSize) const
+{
+    float width = ceilf(deviceSize.width() / m_deviceScaleFactor);
+    float height = ceilf(deviceSize.height() / m_deviceScaleFactor);
+    return FloatSize(width, height);
+}
+
+SecurityOrigin* HTMLCanvasElement::securityOrigin() const
+{
+    return document()->securityOrigin();
+}
+
+StyleResolver* HTMLCanvasElement::styleResolver()
+{
+    return document()->styleResolver();
+}
+
+bool HTMLCanvasElement::shouldAccelerate(const IntSize& size) const
+{
+    if (m_context && !m_context->is2d())
+        return false;
+
+    Settings* settings = document()->settings();
+    if (!settings || !settings->accelerated2dCanvasEnabled())
+        return false;
+
+    // Do not use acceleration for small canvas.
+    if (size.width() * size.height() < settings->minimumAccelerated2dCanvasSize())
+        return false;
+
+    if (!WebKit::Platform::current()->canAccelerate2dCanvas())
+        return false;
+
+    return true;
+}
+
+void HTMLCanvasElement::createImageBuffer() const
+{
+    ASSERT(!m_imageBuffer);
+
+    m_hasCreatedImageBuffer = true;
+    m_didClearImageBuffer = true;
+
+    FloatSize logicalSize = size();
+    FloatSize deviceSize = convertLogicalToDevice(logicalSize);
+    if (!deviceSize.isExpressibleAsIntSize())
+        return;
+
+    if (deviceSize.width() * deviceSize.height() > MaxCanvasArea)
+        return;
+
+    if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim)
+        return;
+
+    IntSize bufferSize(deviceSize.width(), deviceSize.height());
+    if (!bufferSize.width() || !bufferSize.height())
+        return;
+
+    RenderingMode renderingMode = shouldAccelerate(bufferSize) ? Accelerated : UnacceleratedNonPlatformBuffer;
+    OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque;
+    m_imageBuffer = ImageBuffer::create(size(), m_deviceScaleFactor, ColorSpaceDeviceRGB, renderingMode, opacityMode);
+    if (!m_imageBuffer)
+        return;
+    m_imageBuffer->context()->setShadowsIgnoreTransforms(true);
+    m_imageBuffer->context()->setImageInterpolationQuality(DefaultInterpolationQuality);
+    if (document()->settings() && !document()->settings()->antialiased2dCanvasEnabled())
+        m_imageBuffer->context()->setShouldAntialias(false);
+    m_imageBuffer->context()->setStrokeThickness(1);
+    m_contextStateSaver = adoptPtr(new GraphicsContextStateSaver(*m_imageBuffer->context()));
+
+    if (m_context && m_context->is2d()) {
+        // Recalculate compositing requirements if acceleration state changed.
+        const_cast<HTMLCanvasElement*>(this)->setNeedsStyleRecalc(SyntheticStyleChange);
+    }
+}
+
+GraphicsContext* HTMLCanvasElement::drawingContext() const
+{
+    return buffer() ? m_imageBuffer->context() : 0;
+}
+
+GraphicsContext* HTMLCanvasElement::existingDrawingContext() const
+{
+    if (!m_hasCreatedImageBuffer)
+        return 0;
+
+    return drawingContext();
+}
+
+ImageBuffer* HTMLCanvasElement::buffer() const
+{
+    if (!m_hasCreatedImageBuffer)
+        createImageBuffer();
+    return m_imageBuffer.get();
+}
+
+Image* HTMLCanvasElement::copiedImage() const
+{
+    if (!m_copiedImage && buffer()) {
+        if (m_context)
+            m_context->paintRenderingResultsToCanvas();
+        m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled);
+    }
+    return m_copiedImage.get();
+}
+
+void HTMLCanvasElement::clearImageBuffer() const
+{
+    ASSERT(m_hasCreatedImageBuffer);
+    ASSERT(!m_didClearImageBuffer);
+    ASSERT(m_context);
+
+    m_didClearImageBuffer = true;
+
+    if (m_context->is2d()) {
+        CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext2D*>(m_context.get());
+        // No need to undo transforms/clip/etc. because we are called right after the context is reset.
+        context2D->clearRect(0, 0, width(), height());
+    }
+}
+
+void HTMLCanvasElement::clearCopiedImage()
+{
+    m_copiedImage.clear();
+    m_didClearImageBuffer = false;
+}
+
+AffineTransform HTMLCanvasElement::baseTransform() const
+{
+    ASSERT(m_hasCreatedImageBuffer);
+    FloatSize unscaledSize = size();
+    FloatSize deviceSize = convertLogicalToDevice(unscaledSize);
+    IntSize size(deviceSize.width(), deviceSize.height());
+    AffineTransform transform;
+    if (size.width() && size.height())
+        transform.scaleNonUniform(size.width() / unscaledSize.width(), size.height() / unscaledSize.height());
+    return m_imageBuffer->baseTransform() * transform;
+}
+
+void HTMLCanvasElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
+    HTMLElement::reportMemoryUsage(memoryObjectInfo);
+    info.addMember(m_observers, "observers");
+    info.addMember(m_context, "context");
+    info.addMember(m_imageBuffer, "imageBuffer");
+    info.addMember(m_contextStateSaver, "contextStateSaver");
+    info.addMember(m_presentedImage, "presentedImage");
+    info.addMember(m_copiedImage, "copiedImage");
+}
+
+}
diff --git a/Source/core/html/HTMLCanvasElement.h b/Source/core/html/HTMLCanvasElement.h
new file mode 100644
index 0000000..8bfe7f5
--- /dev/null
+++ b/Source/core/html/HTMLCanvasElement.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2004, 2006, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. 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 COMPUTER, 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 COMPUTER, 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 HTMLCanvasElement_h
+#define HTMLCanvasElement_h
+
+#include "core/html/HTMLElement.h"
+#include "core/platform/graphics/FloatRect.h"
+#include "core/platform/graphics/IntSize.h"
+#include <wtf/Forward.h>
+
+#define DefaultInterpolationQuality InterpolationMedium
+
+namespace WebCore {
+
+class CanvasContextAttributes;
+class CanvasRenderingContext;
+class GraphicsContext;
+class GraphicsContextStateSaver;
+class HTMLCanvasElement;
+class Image;
+class ImageData;
+class ImageBuffer;
+class IntSize;
+
+class CanvasObserver {
+public:
+    virtual ~CanvasObserver() { }
+
+    virtual void canvasChanged(HTMLCanvasElement*, const FloatRect& changedRect) = 0;
+    virtual void canvasResized(HTMLCanvasElement*) = 0;
+    virtual void canvasDestroyed(HTMLCanvasElement*) = 0;
+};
+
+class HTMLCanvasElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLCanvasElement> create(Document*);
+    static PassRefPtr<HTMLCanvasElement> create(const QualifiedName&, Document*);
+    virtual ~HTMLCanvasElement();
+
+    void addObserver(CanvasObserver*);
+    void removeObserver(CanvasObserver*);
+
+    // Attributes and functions exposed to script
+    int width() const { return size().width(); }
+    int height() const { return size().height(); }
+
+    const IntSize& size() const { return m_size; }
+
+    void setWidth(int);
+    void setHeight(int);
+
+    void setSize(const IntSize& newSize)
+    { 
+        if (newSize == size() && targetDeviceScaleFactor() == m_deviceScaleFactor)
+            return;
+        m_ignoreReset = true; 
+        setWidth(newSize.width());
+        setHeight(newSize.height());
+        m_ignoreReset = false;
+        reset();
+    }
+
+    CanvasRenderingContext* getContext(const String&, CanvasContextAttributes* attributes = 0);
+
+    static String toEncodingMimeType(const String& mimeType);
+    String toDataURL(const String& mimeType, const double* quality, ExceptionCode&);
+    String toDataURL(const String& mimeType, ExceptionCode& ec) { return toDataURL(mimeType, 0, ec); }
+
+    // Used for rendering
+    void didDraw(const FloatRect&);
+    void notifyObserversCanvasChanged(const FloatRect&);
+
+    void paint(GraphicsContext*, const LayoutRect&, bool useLowQualityScale = false);
+
+    GraphicsContext* drawingContext() const;
+    GraphicsContext* existingDrawingContext() const;
+
+    CanvasRenderingContext* renderingContext() const { return m_context.get(); }
+
+    ImageBuffer* buffer() const;
+    Image* copiedImage() const;
+    void clearCopiedImage();
+    PassRefPtr<ImageData> getImageData();
+    void makePresentationCopy();
+    void clearPresentationCopy();
+
+    FloatRect convertLogicalToDevice(const FloatRect&) const;
+    FloatSize convertLogicalToDevice(const FloatSize&) const;
+
+    FloatSize convertDeviceToLogical(const FloatSize&) const;
+
+    SecurityOrigin* securityOrigin() const;
+    void setOriginTainted() { m_originClean = false; }
+    bool originClean() const { return m_originClean; }
+
+    StyleResolver* styleResolver();
+
+    AffineTransform baseTransform() const;
+
+    bool is3D() const;
+
+    void makeRenderingResultsAvailable();
+    bool hasCreatedImageBuffer() const { return m_hasCreatedImageBuffer; }
+
+    bool shouldAccelerate(const IntSize&) const;
+
+    float deviceScaleFactor() const { return m_deviceScaleFactor; }
+
+    virtual bool canContainRangeEndPoint() const { return false; }
+
+    virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+
+private:
+    HTMLCanvasElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual void attach();
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+
+    void reset();
+
+    float targetDeviceScaleFactor() const;
+
+    void createImageBuffer() const;
+    void clearImageBuffer() const;
+
+    void setSurfaceSize(const IntSize&);
+
+    bool paintsIntoCanvasBuffer() const;
+
+    HashSet<CanvasObserver*> m_observers;
+
+    IntSize m_size;
+
+    OwnPtr<CanvasRenderingContext> m_context;
+
+    bool m_rendererIsCanvas;
+
+    bool m_ignoreReset;
+    FloatRect m_dirtyRect;
+
+    float m_deviceScaleFactor;
+    bool m_originClean;
+
+    // m_createdImageBuffer means we tried to malloc the buffer.  We didn't necessarily get it.
+    mutable bool m_hasCreatedImageBuffer;
+    mutable bool m_didClearImageBuffer;
+    mutable OwnPtr<ImageBuffer> m_imageBuffer;
+    mutable OwnPtr<GraphicsContextStateSaver> m_contextStateSaver;
+    
+    mutable RefPtr<Image> m_presentedImage;
+    mutable RefPtr<Image> m_copiedImage; // FIXME: This is temporary for platforms that have to copy the image buffer to render (and for CSSCanvasValue).
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLCanvasElement.idl b/Source/core/html/HTMLCanvasElement.idl
new file mode 100644
index 0000000..28af6fa
--- /dev/null
+++ b/Source/core/html/HTMLCanvasElement.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2006, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+interface HTMLCanvasElement : HTMLElement {
+
+    attribute long width;
+    attribute long height;
+
+    [Custom, RaisesException] DOMString toDataURL([TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString type);
+
+    // The custom binding is needed to handle context creation attributes.
+    [Custom, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds] any getContext([Default=Undefined] optional DOMString contextId);
+};
+
diff --git a/Source/core/html/HTMLCollection.cpp b/Source/core/html/HTMLCollection.cpp
new file mode 100644
index 0000000..f53be21
--- /dev/null
+++ b/Source/core/html/HTMLCollection.cpp
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLCollection.h"
+
+#include "HTMLNames.h"
+#include "core/dom/ClassNodeList.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/NodeRareData.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLElement.h"
+#include "core/html/HTMLObjectElement.h"
+#include "core/html/HTMLOptionElement.h"
+
+#include <utility>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static bool shouldOnlyIncludeDirectChildren(CollectionType type)
+{
+    switch (type) {
+    case DocAll:
+    case DocAnchors:
+    case DocApplets:
+    case DocEmbeds:
+    case DocForms:
+    case DocImages:
+    case DocLinks:
+    case DocScripts:
+    case DocumentNamedItems:
+    case MapAreas:
+    case TableRows:
+    case SelectOptions:
+    case SelectedOptions:
+    case DataListOptions:
+    case WindowNamedItems:
+    case FormControls:
+        return false;
+    case NodeChildren:
+    case TRCells:
+    case TSectionRows:
+    case TableTBodies:
+        return true;
+    case ChildNodeListType:
+    case ClassNodeListType:
+    case NameNodeListType:
+    case TagNodeListType:
+    case HTMLTagNodeListType:
+    case RadioNodeListType:
+    case LabelsNodeListType:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+static NodeListRootType rootTypeFromCollectionType(CollectionType type)
+{
+    switch (type) {
+    case DocImages:
+    case DocApplets:
+    case DocEmbeds:
+    case DocForms:
+    case DocLinks:
+    case DocAnchors:
+    case DocScripts:
+    case DocAll:
+    case WindowNamedItems:
+    case DocumentNamedItems:
+    case FormControls:
+        return NodeListIsRootedAtDocument;
+    case NodeChildren:
+    case TableTBodies:
+    case TSectionRows:
+    case TableRows:
+    case TRCells:
+    case SelectOptions:
+    case SelectedOptions:
+    case DataListOptions:
+    case MapAreas:
+        return NodeListIsRootedAtNode;
+    case ChildNodeListType:
+    case ClassNodeListType:
+    case NameNodeListType:
+    case TagNodeListType:
+    case HTMLTagNodeListType:
+    case RadioNodeListType:
+    case LabelsNodeListType:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return NodeListIsRootedAtNode;
+}
+
+static NodeListInvalidationType invalidationTypeExcludingIdAndNameAttributes(CollectionType type)
+{
+    switch (type) {
+    case DocImages:
+    case DocEmbeds:
+    case DocForms:
+    case DocScripts:
+    case DocAll:
+    case NodeChildren:
+    case TableTBodies:
+    case TSectionRows:
+    case TableRows:
+    case TRCells:
+    case SelectOptions:
+    case MapAreas:
+        return DoNotInvalidateOnAttributeChanges;
+    case DocApplets:
+    case SelectedOptions:
+    case DataListOptions:
+        // FIXME: We can do better some day.
+        return InvalidateOnAnyAttrChange;
+    case DocAnchors:
+        return InvalidateOnNameAttrChange;
+    case DocLinks:
+        return InvalidateOnHRefAttrChange;
+    case WindowNamedItems:
+        return InvalidateOnIdNameAttrChange;
+    case DocumentNamedItems:
+        return InvalidateOnIdNameAttrChange;
+    case FormControls:
+        return InvalidateForFormControls;
+    case ChildNodeListType:
+    case ClassNodeListType:
+    case NameNodeListType:
+    case TagNodeListType:
+    case HTMLTagNodeListType:
+    case RadioNodeListType:
+    case LabelsNodeListType:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return DoNotInvalidateOnAttributeChanges;
+}
+
+HTMLCollection::HTMLCollection(Node* ownerNode, CollectionType type, ItemAfterOverrideType itemAfterOverrideType)
+    : LiveNodeListBase(ownerNode, rootTypeFromCollectionType(type), invalidationTypeExcludingIdAndNameAttributes(type),
+        WebCore::shouldOnlyIncludeDirectChildren(type), type, itemAfterOverrideType)
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLCollection> HTMLCollection::create(Node* base, CollectionType type)
+{
+    return adoptRef(new HTMLCollection(base, type, DoesNotOverrideItemAfter));
+}
+
+HTMLCollection::~HTMLCollection()
+{
+    // HTMLNameCollection removes cache by itself.
+    if (type() != WindowNamedItems && type() != DocumentNamedItems)
+        ownerNode()->nodeLists()->removeCacheWithAtomicName(this, type());
+}
+
+template <class NodeListType>
+inline bool isMatchingElement(const NodeListType*, Element*);
+
+template <> inline bool isMatchingElement(const HTMLCollection* htmlCollection, Element* element)
+{
+    CollectionType type = htmlCollection->type();
+    if (!element->isHTMLElement() && !(type == DocAll || type == NodeChildren))
+        return false;
+
+    switch (type) {
+    case DocImages:
+        return element->hasLocalName(imgTag);
+    case DocScripts:
+        return element->hasLocalName(scriptTag);
+    case DocForms:
+        return element->hasLocalName(formTag);
+    case TableTBodies:
+        return element->hasLocalName(tbodyTag);
+    case TRCells:
+        return element->hasLocalName(tdTag) || element->hasLocalName(thTag);
+    case TSectionRows:
+        return element->hasLocalName(trTag);
+    case SelectOptions:
+        return element->hasLocalName(optionTag);
+    case SelectedOptions:
+        return element->hasLocalName(optionTag) && toHTMLOptionElement(element)->selected();
+    case DataListOptions:
+        if (element->hasLocalName(optionTag)) {
+            HTMLOptionElement* option = static_cast<HTMLOptionElement*>(element);
+            if (!option->isDisabledFormControl() && !option->value().isEmpty())
+                return true;
+        }
+        return false;
+    case MapAreas:
+        return element->hasLocalName(areaTag);
+    case DocApplets:
+        return element->hasLocalName(appletTag) || (element->hasLocalName(objectTag) && static_cast<HTMLObjectElement*>(element)->containsJavaApplet());
+    case DocEmbeds:
+        return element->hasLocalName(embedTag);
+    case DocLinks:
+        return (element->hasLocalName(aTag) || element->hasLocalName(areaTag)) && element->fastHasAttribute(hrefAttr);
+    case DocAnchors:
+        return element->hasLocalName(aTag) && element->fastHasAttribute(nameAttr);
+    case DocAll:
+    case NodeChildren:
+        return true;
+    case FormControls:
+    case DocumentNamedItems:
+    case TableRows:
+    case WindowNamedItems:
+    case ChildNodeListType:
+    case ClassNodeListType:
+    case NameNodeListType:
+    case TagNodeListType:
+    case HTMLTagNodeListType:
+    case RadioNodeListType:
+    case LabelsNodeListType:
+        ASSERT_NOT_REACHED();
+    }
+    return false;
+}
+
+template <> inline bool isMatchingElement(const LiveNodeList* nodeList, Element* element)
+{
+    return nodeList->nodeMatches(element);
+}
+
+template <> inline bool isMatchingElement(const HTMLTagNodeList* nodeList, Element* element)
+{
+    return nodeList->nodeMatchesInlined(element);
+}
+
+template <> inline bool isMatchingElement(const ClassNodeList* nodeList, Element* element)
+{
+    return nodeList->nodeMatchesInlined(element);
+}
+
+static Node* previousNode(Node* base, Node* previous, bool onlyIncludeDirectChildren)
+{
+    return onlyIncludeDirectChildren ? previous->previousSibling() : NodeTraversal::previous(previous, base);
+}
+
+static inline Node* lastDescendent(Node* node)
+{
+    node = node->lastChild();
+    for (Node* current = node; current; current = current->lastChild())
+        node = current;
+    return node;
+}
+
+static Node* lastNode(Node* rootNode, bool onlyIncludeDirectChildren)
+{
+    return onlyIncludeDirectChildren ? rootNode->lastChild() : lastDescendent(rootNode);
+}
+
+ALWAYS_INLINE Node* LiveNodeListBase::iterateForPreviousNode(Node* current) const
+{
+    bool onlyIncludeDirectChildren = shouldOnlyIncludeDirectChildren();
+    CollectionType collectionType = type();
+    Node* rootNode = this->rootNode();
+    for (; current; current = previousNode(rootNode, current, onlyIncludeDirectChildren)) {
+        if (isNodeList(collectionType)) {
+            if (current->isElementNode() && isMatchingElement(static_cast<const LiveNodeList*>(this), toElement(current)))
+                return toElement(current);
+        } else {
+            if (current->isElementNode() && isMatchingElement(static_cast<const HTMLCollection*>(this), toElement(current)))
+                return toElement(current);
+        }
+    }
+    return 0;
+}
+
+ALWAYS_INLINE Node* LiveNodeListBase::itemBefore(Node* previous) const
+{
+    Node* current;
+    if (LIKELY(!!previous)) // Without this LIKELY, length() and item() can be 10% slower.
+        current = previousNode(rootNode(), previous, shouldOnlyIncludeDirectChildren());
+    else
+        current = lastNode(rootNode(), shouldOnlyIncludeDirectChildren());
+
+    if (type() == ChildNodeListType)
+        return current;
+    return iterateForPreviousNode(current);
+}
+
+template <class NodeListType>
+inline Element* firstMatchingElement(const NodeListType* nodeList, ContainerNode* root)
+{
+    Element* element = ElementTraversal::firstWithin(root);
+    while (element && !isMatchingElement(nodeList, element))
+        element = ElementTraversal::next(element, root);
+    return element;
+}
+
+template <class NodeListType>
+inline Element* nextMatchingElement(const NodeListType* nodeList, Element* current, ContainerNode* root)
+{
+    do {
+        current = ElementTraversal::next(current, root);
+    } while (current && !isMatchingElement(nodeList, current));
+    return current;
+}
+
+template <class NodeListType>
+inline Element* traverseMatchingElementsForwardToOffset(const NodeListType* nodeList, unsigned offset, Element* currentElement, unsigned& currentOffset, ContainerNode* root)
+{
+    ASSERT(currentOffset < offset);
+    while ((currentElement = nextMatchingElement(nodeList, currentElement, root))) {
+        if (++currentOffset == offset)
+            return currentElement;
+    }
+    return 0;
+}
+
+// FIXME: This should be in ChildNodeList
+inline Node* LiveNodeListBase::traverseChildNodeListForwardToOffset(unsigned offset, Node* currentNode, unsigned& currentOffset) const
+{
+    ASSERT(type() == ChildNodeListType);
+    ASSERT(currentOffset < offset);
+    while ((currentNode = currentNode->nextSibling())) {
+        if (++currentOffset == offset)
+            return currentNode;
+    }
+    return 0;
+}
+
+// FIXME: This should be in LiveNodeList
+inline Element* LiveNodeListBase::traverseLiveNodeListFirstElement(ContainerNode* root) const
+{
+    ASSERT(isNodeList(type()));
+    ASSERT(type() != ChildNodeListType);
+    if (type() == HTMLTagNodeListType)
+        return firstMatchingElement(static_cast<const HTMLTagNodeList*>(this), root);
+    if (type() == ClassNodeListType)
+        return firstMatchingElement(static_cast<const ClassNodeList*>(this), root);
+    return firstMatchingElement(static_cast<const LiveNodeList*>(this), root);
+}
+
+// FIXME: This should be in LiveNodeList
+inline Element* LiveNodeListBase::traverseLiveNodeListForwardToOffset(unsigned offset, Element* currentElement, unsigned& currentOffset, ContainerNode* root) const
+{
+    ASSERT(isNodeList(type()));
+    ASSERT(type() != ChildNodeListType);
+    if (type() == HTMLTagNodeListType)
+        return traverseMatchingElementsForwardToOffset(static_cast<const HTMLTagNodeList*>(this), offset, currentElement, currentOffset, root);
+    if (type() == ClassNodeListType)
+        return traverseMatchingElementsForwardToOffset(static_cast<const ClassNodeList*>(this), offset, currentElement, currentOffset, root);
+    return traverseMatchingElementsForwardToOffset(static_cast<const LiveNodeList*>(this), offset, currentElement, currentOffset, root);
+}
+
+bool ALWAYS_INLINE LiveNodeListBase::isLastItemCloserThanLastOrCachedItem(unsigned offset) const
+{
+    ASSERT(isLengthCacheValid());
+    unsigned distanceFromLastItem = cachedLength() - offset;
+    if (!isItemCacheValid())
+        return distanceFromLastItem < offset;
+
+    return cachedItemOffset() < offset && distanceFromLastItem < offset - cachedItemOffset();
+}
+    
+bool ALWAYS_INLINE LiveNodeListBase::isFirstItemCloserThanCachedItem(unsigned offset) const
+{
+    ASSERT(isItemCacheValid());
+    if (cachedItemOffset() < offset)
+        return false;
+
+    unsigned distanceFromCachedItem = cachedItemOffset() - offset;
+    return offset < distanceFromCachedItem;
+}
+
+ALWAYS_INLINE void LiveNodeListBase::setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const
+{
+    setItemCache(item, offset);
+    if (overridesItemAfter()) {
+        ASSERT_WITH_SECURITY_IMPLICATION(item->isElementNode());
+        static_cast<const HTMLCollection*>(this)->m_cachedElementsArrayOffset = elementsArrayOffset;
+    } else
+        ASSERT(!elementsArrayOffset);
+}
+
+unsigned LiveNodeListBase::length() const
+{
+    if (isLengthCacheValid())
+        return cachedLength();
+
+    item(UINT_MAX);
+    ASSERT(isLengthCacheValid());
+    
+    return cachedLength();
+}
+
+// FIXME: It is silly that these functions are in HTMLCollection.cpp.
+Node* LiveNodeListBase::item(unsigned offset) const
+{
+    if (isItemCacheValid() && cachedItemOffset() == offset)
+        return cachedItem();
+
+    if (isLengthCacheValid() && cachedLength() <= offset)
+        return 0;
+
+    ContainerNode* root = rootContainerNode();
+    if (!root) {
+        // FIMXE: In someTextNode.childNodes case the root is Text. We shouldn't even make a LiveNodeList for that.
+        setLengthCache(0);
+        return 0;
+    }
+
+    if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLastOrCachedItem(offset)) {
+        Node* lastItem = itemBefore(0);
+        ASSERT(lastItem);
+        setItemCache(lastItem, cachedLength() - 1, 0);
+    } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || (overridesItemAfter() && offset < cachedItemOffset())) {
+        unsigned offsetInArray = 0;
+        Node* firstItem;
+        if (type() == ChildNodeListType)
+            firstItem = root->firstChild();
+        else if (isNodeList(type()))
+            firstItem = traverseLiveNodeListFirstElement(root);
+        else
+            firstItem = static_cast<const HTMLCollection*>(this)->traverseFirstElement(offsetInArray, root);
+
+        if (!firstItem) {
+            setLengthCache(0);
+            return 0;
+        }
+        setItemCache(firstItem, 0, offsetInArray);
+        ASSERT(!cachedItemOffset());
+    }
+
+    if (cachedItemOffset() == offset)
+        return cachedItem();
+
+    return itemBeforeOrAfterCachedItem(offset, root);
+}
+
+inline Node* LiveNodeListBase::itemBeforeOrAfterCachedItem(unsigned offset, ContainerNode* root) const
+{
+    unsigned currentOffset = cachedItemOffset();
+    Node* currentItem = cachedItem();
+    ASSERT(currentItem);
+    ASSERT(currentOffset != offset);
+
+    if (offset < cachedItemOffset()) {
+        ASSERT(!overridesItemAfter());
+        while ((currentItem = itemBefore(currentItem))) {
+            ASSERT(currentOffset);
+            currentOffset--;
+            if (currentOffset == offset) {
+                setItemCache(currentItem, currentOffset, 0);
+                return currentItem;
+            }
+        }
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+
+    unsigned offsetInArray = 0;
+    if (type() == ChildNodeListType)
+        currentItem = traverseChildNodeListForwardToOffset(offset, currentItem, currentOffset);
+    else if (isNodeList(type()))
+        currentItem = traverseLiveNodeListForwardToOffset(offset, toElement(currentItem), currentOffset, root);
+    else
+        currentItem = static_cast<const HTMLCollection*>(this)->traverseForwardToOffset(offset, toElement(currentItem), currentOffset, offsetInArray, root);
+
+    if (!currentItem) {
+        // Did not find the item. On plus side, we now know the length.
+        setLengthCache(currentOffset + 1);
+        return 0;
+    }
+    setItemCache(currentItem, currentOffset, offsetInArray);
+    return currentItem;
+}
+
+Element* HTMLCollection::virtualItemAfter(unsigned&, Element*) const
+{
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+static inline bool nameShouldBeVisibleInDocumentAll(HTMLElement* element)
+{
+    // The document.all collection returns only certain types of elements by name,
+    // although it returns any type of element by id.
+    return element->hasLocalName(appletTag)
+        || element->hasLocalName(embedTag)
+        || element->hasLocalName(formTag)
+        || element->hasLocalName(imgTag)
+        || element->hasLocalName(inputTag)
+        || element->hasLocalName(objectTag)
+        || element->hasLocalName(selectTag);
+}
+
+bool HTMLCollection::checkForNameMatch(Element* element, bool checkName, const AtomicString& name) const
+{
+    if (!element->isHTMLElement())
+        return false;
+    
+    HTMLElement* e = toHTMLElement(element);
+    if (!checkName)
+        return e->getIdAttribute() == name;
+
+    if (type() == DocAll && !nameShouldBeVisibleInDocumentAll(e))
+        return false;
+
+    return e->getNameAttribute() == name && e->getIdAttribute() != name;
+}
+
+inline Element* firstMatchingChildElement(const HTMLCollection* nodeList, ContainerNode* root)
+{
+    Element* element = ElementTraversal::firstWithin(root);
+    while (element && !isMatchingElement(nodeList, element))
+        element = ElementTraversal::nextSkippingChildren(element, root);
+    return element;
+}
+
+inline Element* nextMatchingChildElement(const HTMLCollection* nodeList, Element* current, ContainerNode* root)
+{
+    do {
+        current = ElementTraversal::nextSkippingChildren(current, root);
+    } while (current && !isMatchingElement(nodeList, current));
+    return current;
+}
+
+inline Element* HTMLCollection::traverseFirstElement(unsigned& offsetInArray, ContainerNode* root) const
+{
+    if (overridesItemAfter())
+        return virtualItemAfter(offsetInArray, 0);
+    ASSERT(!offsetInArray);
+    if (shouldOnlyIncludeDirectChildren())
+        return firstMatchingChildElement(static_cast<const HTMLCollection*>(this), root);
+    return firstMatchingElement(static_cast<const HTMLCollection*>(this), root);
+}
+
+inline Element* HTMLCollection::traverseNextElement(unsigned& offsetInArray, Element* previous, ContainerNode* root) const
+{
+    if (overridesItemAfter())
+        return virtualItemAfter(offsetInArray, previous);
+    ASSERT(!offsetInArray);
+    if (shouldOnlyIncludeDirectChildren())
+        return nextMatchingChildElement(this, previous, root);
+    return nextMatchingElement(this, previous, root);
+}
+
+inline Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element* currentElement, unsigned& currentOffset, unsigned& offsetInArray, ContainerNode* root) const
+{
+    ASSERT(currentOffset < offset);
+    if (overridesItemAfter()) {
+        offsetInArray = m_cachedElementsArrayOffset;
+        while ((currentElement = virtualItemAfter(offsetInArray, currentElement))) {
+            if (++currentOffset == offset)
+                return currentElement;
+        }
+        return 0;
+    }
+    if (shouldOnlyIncludeDirectChildren()) {
+        while ((currentElement = nextMatchingChildElement(this, currentElement, root))) {
+            if (++currentOffset == offset)
+                return currentElement;
+        }
+        return 0;
+    }
+    return traverseMatchingElementsForwardToOffset(this, offset, currentElement, currentOffset, root);
+}
+
+Node* HTMLCollection::namedItem(const AtomicString& name) const
+{
+    // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp
+    // This method first searches for an object with a matching id
+    // attribute. If a match is not found, the method then searches for an
+    // object with a matching name attribute, but only on those elements
+    // that are allowed a name attribute.
+
+    ContainerNode* root = rootContainerNode();
+    if (!root)
+        return 0;
+
+    unsigned arrayOffset = 0;
+    unsigned i = 0;
+    for (Element* element = traverseFirstElement(arrayOffset, root); element; element = traverseNextElement(arrayOffset, element, root)) {
+        if (checkForNameMatch(element, /* checkName */ false, name)) {
+            setItemCache(element, i, arrayOffset);
+            return element;
+        }
+        i++;
+    }
+
+    i = 0;
+    for (Element* element = traverseFirstElement(arrayOffset, root); element; element = traverseNextElement(arrayOffset, element, root)) {
+        if (checkForNameMatch(element, /* checkName */ true, name)) {
+            setItemCache(element, i, arrayOffset);
+            return element;
+        }
+        i++;
+    }
+
+    return 0;
+}
+
+void HTMLCollection::updateNameCache() const
+{
+    if (hasNameCache())
+        return;
+
+    ContainerNode* root = rootContainerNode();
+    if (!root)
+        return;
+
+    unsigned arrayOffset = 0;
+    for (Element* element = traverseFirstElement(arrayOffset, root); element; element = traverseNextElement(arrayOffset, element, root)) {
+        if (!element->isHTMLElement())
+            continue;
+        HTMLElement* htmlElement = toHTMLElement(element);
+        const AtomicString& idAttrVal = htmlElement->getIdAttribute();
+        const AtomicString& nameAttrVal = htmlElement->getNameAttribute();
+        if (!idAttrVal.isEmpty())
+            appendIdCache(idAttrVal, htmlElement);
+        if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && (type() != DocAll || nameShouldBeVisibleInDocumentAll(htmlElement)))
+            appendNameCache(nameAttrVal, htmlElement);
+    }
+
+    setHasNameCache();
+}
+
+bool HTMLCollection::hasNamedItem(const AtomicString& name) const
+{
+    if (name.isEmpty())
+        return false;
+
+    updateNameCache();
+
+    if (Vector<Element*>* cache = idCache(name)) {
+        if (!cache->isEmpty())
+            return true;
+    }
+
+    if (Vector<Element*>* cache = nameCache(name)) {
+        if (!cache->isEmpty())
+            return true;
+    }
+
+    return false;
+}
+
+void HTMLCollection::namedItems(const AtomicString& name, Vector<RefPtr<Node> >& result) const
+{
+    ASSERT(result.isEmpty());
+    if (name.isEmpty())
+        return;
+
+    updateNameCache();
+
+    Vector<Element*>* idResults = idCache(name);
+    Vector<Element*>* nameResults = nameCache(name);
+
+    for (unsigned i = 0; idResults && i < idResults->size(); ++i)
+        result.append(idResults->at(i));
+
+    for (unsigned i = 0; nameResults && i < nameResults->size(); ++i)
+        result.append(nameResults->at(i));
+}
+
+PassRefPtr<NodeList> HTMLCollection::tags(const String& name)
+{
+    return ownerNode()->getElementsByTagName(name);
+}
+
+void HTMLCollection::append(NodeCacheMap& map, const AtomicString& key, Element* element)
+{
+    OwnPtr<Vector<Element*> >& vector = map.add(key.impl(), nullptr).iterator->value;
+    if (!vector)
+        vector = adoptPtr(new Vector<Element*>);
+    vector->append(element);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLCollection.h b/Source/core/html/HTMLCollection.h
new file mode 100644
index 0000000..a971961
--- /dev/null
+++ b/Source/core/html/HTMLCollection.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLCollection_h
+#define HTMLCollection_h
+
+#include "bindings/v8/ScriptWrappable.h"
+#include "core/dom/LiveNodeList.h"
+#include "core/html/CollectionType.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class HTMLCollection : public LiveNodeListBase {
+public:
+    static PassRefPtr<HTMLCollection> create(Node* base, CollectionType);
+    virtual ~HTMLCollection();
+
+    // DOM API
+    virtual Node* namedItem(const AtomicString& name) const;
+    PassRefPtr<NodeList> tags(const String&);
+
+    // Non-DOM API
+    virtual bool hasNamedItem(const AtomicString& name) const;
+    void namedItems(const AtomicString& name, Vector<RefPtr<Node> >&) const;
+    bool isEmpty() const
+    {
+        if (isLengthCacheValid())
+            return !cachedLength();
+        if (isItemCacheValid())
+            return !cachedItem();
+        return !item(0);
+    }
+    bool hasExactlyOneItem() const
+    {
+        if (isLengthCacheValid())
+            return cachedLength() == 1;
+        if (isItemCacheValid())
+            return cachedItem() && !cachedItemOffset() && !item(1);
+        return item(0) && !item(1);
+    }
+
+    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const;
+
+    Element* traverseFirstElement(unsigned& offsetInArray, ContainerNode* root) const;
+    Element* traverseForwardToOffset(unsigned offset, Element* currentElement, unsigned& currentOffset, unsigned& offsetInArray, ContainerNode* root) const;
+
+protected:
+    HTMLCollection(Node* base, CollectionType, ItemAfterOverrideType);
+
+    virtual void updateNameCache() const;
+
+    typedef HashMap<AtomicStringImpl*, OwnPtr<Vector<Element*> > > NodeCacheMap;
+    Vector<Element*>* idCache(const AtomicString& name) const { return m_idCache.get(name.impl()); }
+    Vector<Element*>* nameCache(const AtomicString& name) const { return m_nameCache.get(name.impl()); }
+    void appendIdCache(const AtomicString& name, Element* element) const { append(m_idCache, name, element); }
+    void appendNameCache(const AtomicString& name, Element* element) const { append(m_nameCache, name, element); }
+
+private:
+    bool checkForNameMatch(Element*, bool checkName, const AtomicString& name) const;
+    Element* traverseNextElement(unsigned& offsetInArray, Element* previous, ContainerNode* root) const;
+
+    virtual bool isLiveNodeList() const OVERRIDE { ASSERT_NOT_REACHED(); return true; }
+
+    static void append(NodeCacheMap&, const AtomicString&, Element*);
+
+    mutable NodeCacheMap m_idCache;
+    mutable NodeCacheMap m_nameCache;
+    mutable unsigned m_cachedElementsArrayOffset;
+
+    friend class LiveNodeListBase;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLCollection.idl b/Source/core/html/HTMLCollection.idl
new file mode 100644
index 0000000..ee1d158
--- /dev/null
+++ b/Source/core/html/HTMLCollection.idl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomToV8,
+    GenerateIsReachable=ImplOwnerNodeRoot,
+    DependentLifetime,
+    
+    SkipVTableValidation
+] interface HTMLCollection {
+    readonly attribute unsigned long length;
+    getter Node item([Default=Undefined] optional unsigned long index);
+    getter Node namedItem([Default=Undefined] optional DOMString name);
+};
+
diff --git a/Source/core/html/HTMLDListElement.cpp b/Source/core/html/HTMLDListElement.cpp
new file mode 100644
index 0000000..673ff41
--- /dev/null
+++ b/Source/core/html/HTMLDListElement.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLDListElement.h"
+
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLDListElement::HTMLDListElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(dlTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLDListElement> HTMLDListElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLDListElement(tagName, document));
+}
+
+}
diff --git a/Source/core/html/HTMLDListElement.h b/Source/core/html/HTMLDListElement.h
new file mode 100644
index 0000000..77aca94
--- /dev/null
+++ b/Source/core/html/HTMLDListElement.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLDListElement_h
+#define HTMLDListElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLDListElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLDListElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLDListElement(const QualifiedName&, Document*);
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLDListElement.idl b/Source/core/html/HTMLDListElement.idl
new file mode 100644
index 0000000..95a97ff
--- /dev/null
+++ b/Source/core/html/HTMLDListElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLDListElement : HTMLElement {
+    [Reflect] attribute boolean compact;
+};
+
diff --git a/Source/core/html/HTMLDataListElement.cpp b/Source/core/html/HTMLDataListElement.cpp
new file mode 100644
index 0000000..145e30a
--- /dev/null
+++ b/Source/core/html/HTMLDataListElement.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#if ENABLE(DATALIST_ELEMENT)
+#include "core/html/HTMLDataListElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/IdTargetObserverRegistry.h"
+#include "core/page/UseCounter.h"
+
+namespace WebCore {
+
+inline HTMLDataListElement::HTMLDataListElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLDataListElement> HTMLDataListElement::create(const QualifiedName& tagName, Document* document)
+{
+    UseCounter::count(document, UseCounter::DataListElement);
+    return adoptRef(new HTMLDataListElement(tagName, document));
+}
+
+PassRefPtr<HTMLCollection> HTMLDataListElement::options()
+{
+    return ensureCachedHTMLCollection(DataListOptions);
+}
+
+void HTMLDataListElement::optionElementChildrenChanged()
+{
+    treeScope()->idTargetObserverRegistry().notifyObservers(getIdAttribute());
+}
+
+} // namespace WebCore
+#endif // ENABLE(DATALIST_ELEMENT)
diff --git a/Source/core/html/HTMLDataListElement.h b/Source/core/html/HTMLDataListElement.h
new file mode 100644
index 0000000..2aa5b8e
--- /dev/null
+++ b/Source/core/html/HTMLDataListElement.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, Google Inc. All rights reserved.
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 HTMLDataListElement_h
+#define HTMLDataListElement_h
+
+#if ENABLE(DATALIST_ELEMENT)
+#include "core/html/HTMLCollection.h"
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLDataListElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLDataListElement> create(const QualifiedName&, Document*);
+
+    PassRefPtr<HTMLCollection> options();
+
+    void optionElementChildrenChanged();
+
+private:
+    HTMLDataListElement(const QualifiedName&, Document*);
+};
+
+} // namespace WebCore
+#endif // ENABLE(DATALIST_ELEMENT)
+
+#endif // HTMLDataListElement_h
diff --git a/Source/core/html/HTMLDataListElement.idl b/Source/core/html/HTMLDataListElement.idl
new file mode 100644
index 0000000..13fdaa4
--- /dev/null
+++ b/Source/core/html/HTMLDataListElement.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2009, 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+[
+    Conditional=DATALIST_ELEMENT,
+] interface HTMLDataListElement : HTMLElement {
+    readonly attribute HTMLCollection options;
+};
diff --git a/Source/core/html/HTMLDetailsElement.cpp b/Source/core/html/HTMLDetailsElement.cpp
new file mode 100644
index 0000000..2118ef9
--- /dev/null
+++ b/Source/core/html/HTMLDetailsElement.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLDetailsElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLSummaryElement.h"
+#include "core/html/shadow/HTMLContentElement.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/rendering/RenderBlock.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const AtomicString& summaryQuerySelector()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, selector, ("summary:first-of-type", AtomicString::ConstructFromLiteral));
+    return selector;
+};
+
+PassRefPtr<HTMLDetailsElement> HTMLDetailsElement::create(const QualifiedName& tagName, Document* document)
+{
+    RefPtr<HTMLDetailsElement> details = adoptRef(new HTMLDetailsElement(tagName, document));
+    details->ensureUserAgentShadowRoot();
+    return details.release();
+}
+
+HTMLDetailsElement::HTMLDetailsElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_isOpen(false)
+{
+    ASSERT(hasTagName(detailsTag));
+    ScriptWrappable::init(this);
+}
+
+RenderObject* HTMLDetailsElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderBlock(this);
+}
+
+void HTMLDetailsElement::didAddUserAgentShadowRoot(ShadowRoot* root)
+{
+    RefPtr<HTMLSummaryElement> defaultSummary = HTMLSummaryElement::create(summaryTag, document());
+    defaultSummary->appendChild(Text::create(document(), defaultDetailsSummaryText()), ASSERT_NO_EXCEPTION);
+
+    RefPtr<HTMLContentElement> content = HTMLContentElement::create(document());
+    content->setSelect(summaryQuerySelector());
+    content->appendChild(defaultSummary);
+
+    root->appendChild(content, ASSERT_NO_EXCEPTION, AttachLazily);
+    root->appendChild(HTMLContentElement::create(document()), ASSERT_NO_EXCEPTION, AttachLazily);
+}
+
+Element* HTMLDetailsElement::findMainSummary() const
+{
+    for (Node* child = firstChild(); child; child = child->nextSibling()) {
+        if (child->hasTagName(summaryTag))
+            return toElement(child);
+    }
+
+    HTMLContentElement* content = toHTMLContentElement(userAgentShadowRoot()->firstChild());
+    ASSERT(content->firstChild() && content->firstChild()->hasTagName(summaryTag));
+    return toElement(content->firstChild());
+}
+
+void HTMLDetailsElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == openAttr) {
+        bool oldValue = m_isOpen;
+        m_isOpen = !value.isNull();
+        if (oldValue != m_isOpen)
+            reattachIfAttached();
+    } else
+        HTMLElement::parseAttribute(name, value);
+}
+
+bool HTMLDetailsElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
+{
+    if (!childContext.isOnEncapsulationBoundary())
+        return false;
+
+    if (m_isOpen)
+        return HTMLElement::childShouldCreateRenderer(childContext);
+
+    if (!childContext.node()->hasTagName(summaryTag))
+        return false;
+
+    return childContext.node() == findMainSummary() && HTMLElement::childShouldCreateRenderer(childContext);
+}
+
+void HTMLDetailsElement::toggleOpen()
+{
+    setAttribute(openAttr, m_isOpen ? nullAtom : emptyAtom);
+}
+
+}
diff --git a/Source/core/html/HTMLDetailsElement.h b/Source/core/html/HTMLDetailsElement.h
new file mode 100644
index 0000000..16d97c2
--- /dev/null
+++ b/Source/core/html/HTMLDetailsElement.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLDetailsElement_h
+#define HTMLDetailsElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLDetailsElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLDetailsElement> create(const QualifiedName& tagName, Document* document);
+    void toggleOpen();
+
+    Element* findMainSummary() const;
+
+private:
+    HTMLDetailsElement(const QualifiedName&, Document*);
+
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const OVERRIDE;
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    virtual void didAddUserAgentShadowRoot(ShadowRoot*) OVERRIDE;
+
+    bool m_isOpen;
+};
+
+} // namespace WebCore
+
+#endif // HTMLDetailsElement_h
diff --git a/Source/core/html/HTMLDetailsElement.idl b/Source/core/html/HTMLDetailsElement.idl
new file mode 100644
index 0000000..8909fc8
--- /dev/null
+++ b/Source/core/html/HTMLDetailsElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLDetailsElement : HTMLElement {
+    [Reflect] attribute boolean open;
+};
+
diff --git a/Source/core/html/HTMLDialogElement.cpp b/Source/core/html/HTMLDialogElement.cpp
new file mode 100644
index 0000000..f8d85eb
--- /dev/null
+++ b/Source/core/html/HTMLDialogElement.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012 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 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 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 "core/html/HTMLDialogElement.h"
+
+#include "core/css/StyleResolver.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/page/FrameView.h"
+#include "core/rendering/RenderBlock.h"
+#include "core/rendering/style/RenderStyle.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLDialogElement::HTMLDialogElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_topIsValid(false)
+    , m_top(0)
+{
+    ASSERT(hasTagName(dialogTag));
+    setHasCustomStyleCallbacks();
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLDialogElement> HTMLDialogElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLDialogElement(tagName, document));
+}
+
+void HTMLDialogElement::close(ExceptionCode& ec)
+{
+    if (!fastHasAttribute(openAttr)) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    setBooleanAttribute(openAttr, false);
+    document()->removeFromTopLayer(this);
+    m_topIsValid = false;
+}
+
+static bool needsCenteredPositioning(const RenderStyle* style)
+{
+    return style->position() == AbsolutePosition && style->hasAutoTopAndBottom();
+}
+
+PassRefPtr<RenderStyle> HTMLDialogElement::customStyleForRenderer()
+{
+    RefPtr<RenderStyle> originalStyle = document()->styleResolver()->styleForElement(this);
+    RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
+
+    // Override top to remain centered after style recalcs.
+    if (needsCenteredPositioning(style.get()) && m_topIsValid)
+        style->setTop(Length(m_top.toInt(), WebCore::Fixed));
+
+    return style.release();
+}
+
+void HTMLDialogElement::positionAndReattach()
+{
+    // Layout because we need to know our ancestors' positions and our own height.
+    document()->updateLayoutIgnorePendingStylesheets();
+
+    RenderBox* box = renderBox();
+    if (!box || !needsCenteredPositioning(box->style()))
+        return;
+
+    // Set up dialog's position to be safe-centered in the viewport.
+    // FIXME: Figure out what to do in vertical writing mode.
+    FrameView* frameView = document()->view();
+    int scrollTop = frameView->scrollOffset().height();
+    FloatPoint absolutePoint(0, scrollTop);
+    int visibleHeight = frameView->visibleContentRect(ScrollableArea::IncludeScrollbars).height();
+    if (box->height() < visibleHeight)
+        absolutePoint.move(0, (visibleHeight - box->height()) / 2);
+    FloatPoint localPoint = box->containingBlock()->absoluteToLocal(absolutePoint);
+
+    m_top = localPoint.y();
+    m_topIsValid = true;
+
+    // FIXME: It's inefficient to reattach here. We could do better by mutating style directly and forcing another layout.
+    reattach();
+}
+
+void HTMLDialogElement::show()
+{
+    if (fastHasAttribute(openAttr))
+        return;
+    setBooleanAttribute(openAttr, true);
+    positionAndReattach();
+}
+
+void HTMLDialogElement::showModal(ExceptionCode& ec)
+{
+    if (fastHasAttribute(openAttr) || !inDocument()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    document()->addToTopLayer(this);
+    setBooleanAttribute(openAttr, true);
+    positionAndReattach();
+}
+
+bool HTMLDialogElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    // FIXME: Workaround for <https://bugs.webkit.org/show_bug.cgi?id=91058>: modifying an attribute for which there is an attribute selector
+    // in html.css sometimes does not trigger a style recalc.
+    if (name == openAttr)
+        return true;
+
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLDialogElement.h b/Source/core/html/HTMLDialogElement.h
new file mode 100644
index 0000000..7cdb739
--- /dev/null
+++ b/Source/core/html/HTMLDialogElement.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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 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 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 HTMLDialogElement_h
+#define HTMLDialogElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class Document;
+class QualifiedName;
+
+class HTMLDialogElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLDialogElement> create(const QualifiedName&, Document*);
+
+    void close(ExceptionCode&);
+    void show();
+    void showModal(ExceptionCode&);
+
+private:
+    HTMLDialogElement(const QualifiedName&, Document*);
+
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    void positionAndReattach();
+
+    bool m_topIsValid;
+    LayoutUnit m_top;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/HTMLDialogElement.idl b/Source/core/html/HTMLDialogElement.idl
new file mode 100644
index 0000000..874cbcf
--- /dev/null
+++ b/Source/core/html/HTMLDialogElement.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 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 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 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.
+ */
+
+[
+    SkipVTableValidation
+] interface HTMLDialogElement : HTMLElement {
+    [Reflect] attribute boolean open;
+    [RaisesException] void close();
+    void show();
+    [RaisesException] void showModal();
+};
+
diff --git a/Source/core/html/HTMLDirectoryElement.cpp b/Source/core/html/HTMLDirectoryElement.cpp
new file mode 100644
index 0000000..1a14d6e
--- /dev/null
+++ b/Source/core/html/HTMLDirectoryElement.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLDirectoryElement.h"
+
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLDirectoryElement::HTMLDirectoryElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(dirTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLDirectoryElement> HTMLDirectoryElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLDirectoryElement(tagName, document));
+}
+
+}
diff --git a/Source/core/html/HTMLDirectoryElement.h b/Source/core/html/HTMLDirectoryElement.h
new file mode 100644
index 0000000..9b77575
--- /dev/null
+++ b/Source/core/html/HTMLDirectoryElement.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLDirectoryElement_h
+#define HTMLDirectoryElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLDirectoryElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLDirectoryElement> create(const QualifiedName& tagName, Document*);
+
+private:
+    HTMLDirectoryElement(const QualifiedName&, Document*);
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLDirectoryElement.idl b/Source/core/html/HTMLDirectoryElement.idl
new file mode 100644
index 0000000..541ae00
--- /dev/null
+++ b/Source/core/html/HTMLDirectoryElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLDirectoryElement : HTMLElement {
+    [Reflect] attribute boolean compact;
+};
+
diff --git a/Source/core/html/HTMLDivElement.cpp b/Source/core/html/HTMLDivElement.cpp
new file mode 100644
index 0000000..ff292f4
--- /dev/null
+++ b/Source/core/html/HTMLDivElement.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLDivElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLDivElement::HTMLDivElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(divTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLDivElement> HTMLDivElement::create(Document* document)
+{
+    return adoptRef(new HTMLDivElement(divTag, document));
+}
+
+PassRefPtr<HTMLDivElement> HTMLDivElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLDivElement(tagName, document));
+}
+
+bool HTMLDivElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == alignAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLDivElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == alignAttr) {
+        if (equalIgnoringCase(value, "middle") || equalIgnoringCase(value, "center"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueWebkitCenter);
+        else if (equalIgnoringCase(value, "left"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueWebkitLeft);
+        else if (equalIgnoringCase(value, "right"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueWebkitRight);
+        else
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, value);
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+}
diff --git a/Source/core/html/HTMLDivElement.h b/Source/core/html/HTMLDivElement.h
new file mode 100644
index 0000000..a927fab
--- /dev/null
+++ b/Source/core/html/HTMLDivElement.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLDivElement_h
+#define HTMLDivElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLDivElement : public HTMLElement {
+public:
+    static PassRefPtr<HTMLDivElement> create(Document*);
+    static PassRefPtr<HTMLDivElement> create(const QualifiedName&, Document*);
+
+protected:
+    HTMLDivElement(const QualifiedName&, Document*);
+
+private:
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // HTMLDivElement_h
diff --git a/Source/core/html/HTMLDivElement.idl b/Source/core/html/HTMLDivElement.idl
new file mode 100644
index 0000000..dd17326
--- /dev/null
+++ b/Source/core/html/HTMLDivElement.idl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    SkipVTableValidation
+] interface HTMLDivElement : HTMLElement {
+    [Reflect] attribute DOMString align;
+};
+
diff --git a/Source/core/html/HTMLDocument.cpp b/Source/core/html/HTMLDocument.cpp
new file mode 100644
index 0000000..c5e144a
--- /dev/null
+++ b/Source/core/html/HTMLDocument.cpp
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Portions are Copyright (C) 2002 Netscape Communications Corporation.
+ * Other contributors: David Baron <dbaron@fas.harvard.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Alternatively, the document type parsing portions of this file may be used
+ * under the terms of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above.  If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#include "config.h"
+#include "core/html/HTMLDocument.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLElementFactory.h"
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/DocumentType.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/html/HTMLBodyElement.h"
+#include "core/html/HTMLFrameOwnerElement.h"
+#include "core/html/parser/HTMLDocumentParser.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/loader/CookieJar.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/page/FocusController.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameTree.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/platform/HashTools.h"
+#include "core/platform/KURL.h"
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLDocument::HTMLDocument(Frame* frame, const KURL& url)
+    : Document(frame, url, false, true)
+{
+    ScriptWrappable::init(this);
+    clearXMLVersion();
+}
+
+HTMLDocument::~HTMLDocument()
+{
+}
+
+int HTMLDocument::width()
+{
+    updateLayoutIgnorePendingStylesheets();
+    FrameView* frameView = view();
+    return frameView ? frameView->contentsWidth() : 0;
+}
+
+int HTMLDocument::height()
+{
+    updateLayoutIgnorePendingStylesheets();
+    FrameView* frameView = view();
+    return frameView ? frameView->contentsHeight() : 0;
+}
+
+String HTMLDocument::dir()
+{
+    HTMLElement* b = body();
+    if (!b)
+        return String();
+    return b->getAttribute(dirAttr);
+}
+
+void HTMLDocument::setDir(const String& value)
+{
+    HTMLElement* b = body();
+    if (b)
+        b->setAttribute(dirAttr, value);
+}
+
+String HTMLDocument::designMode() const
+{
+    return inDesignMode() ? "on" : "off";
+}
+
+void HTMLDocument::setDesignMode(const String& value)
+{
+    InheritedBool mode;
+    if (equalIgnoringCase(value, "on"))
+        mode = on;
+    else if (equalIgnoringCase(value, "off"))
+        mode = off;
+    else
+        mode = inherit;
+    Document::setDesignMode(mode);
+}
+
+Element* HTMLDocument::activeElement()
+{
+    if (Node* node = treeScope()->focusedNode())
+        return node->isElementNode() ? toElement(node) : body();
+    return body();
+}
+
+bool HTMLDocument::hasFocus()
+{
+    Page* page = this->page();
+    if (!page)
+        return false;
+    if (!page->focusController()->isActive())
+        return false;
+    if (Frame* focusedFrame = page->focusController()->focusedFrame()) {
+        if (focusedFrame->tree()->isDescendantOf(frame()))
+            return true;
+    }
+    return false;
+}
+
+String HTMLDocument::bgColor()
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (!bodyElement)
+        return String();
+    return bodyElement->bgColor();
+}
+
+void HTMLDocument::setBgColor(const String& value)
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (bodyElement)
+        bodyElement->setBgColor(value);
+}
+
+String HTMLDocument::fgColor()
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (!bodyElement)
+        return String();
+    return bodyElement->text();
+}
+
+void HTMLDocument::setFgColor(const String& value)
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (bodyElement)
+        bodyElement->setText(value);
+}
+
+String HTMLDocument::alinkColor()
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (!bodyElement)
+        return String();
+    return bodyElement->aLink();
+}
+
+void HTMLDocument::setAlinkColor(const String& value)
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (bodyElement) {
+        // This check is a bit silly, but some benchmarks like to set the
+        // document's link colors over and over to the same value and we
+        // don't want to incur a style update each time.
+        if (bodyElement->aLink() != value)
+            bodyElement->setALink(value);
+    }
+}
+
+String HTMLDocument::linkColor()
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (!bodyElement)
+        return String();
+    return bodyElement->link();
+}
+
+void HTMLDocument::setLinkColor(const String& value)
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (bodyElement) {
+        // This check is a bit silly, but some benchmarks like to set the
+        // document's link colors over and over to the same value and we
+        // don't want to incur a style update each time.
+        if (bodyElement->link() != value)
+            bodyElement->setLink(value);
+    }
+}
+
+String HTMLDocument::vlinkColor()
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (!bodyElement)
+        return String();
+    return bodyElement->vLink();
+}
+
+void HTMLDocument::setVlinkColor(const String& value)
+{
+    HTMLElement* b = body();
+    HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0;
+
+    if (bodyElement) {
+        // This check is a bit silly, but some benchmarks like to set the
+        // document's link colors over and over to the same value and we
+        // don't want to incur a style update each time.
+        if (bodyElement->vLink() != value)
+            bodyElement->setVLink(value);
+    }
+}
+
+void HTMLDocument::captureEvents()
+{
+}
+
+void HTMLDocument::releaseEvents()
+{
+}
+
+PassRefPtr<DocumentParser> HTMLDocument::createParser()
+{
+    bool reportErrors = InspectorInstrumentation::collectingHTMLParseErrors(this->page());
+    return HTMLDocumentParser::create(this, reportErrors);
+}
+
+// --------------------------------------------------------------------------
+// not part of the DOM
+// --------------------------------------------------------------------------
+
+PassRefPtr<Element> HTMLDocument::createElement(const AtomicString& name, ExceptionCode& ec)
+{
+    if (!isValidName(name)) {
+        ec = INVALID_CHARACTER_ERR;
+        return 0;
+    }
+    return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name.lower(), xhtmlNamespaceURI), this, 0, false);
+}
+
+void HTMLDocument::addItemToMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name)
+{
+    if (name.isEmpty())
+        return;
+    map.add(name.impl());
+    if (Frame* f = frame())
+        f->script()->namedItemAdded(this, name);
+}
+
+void HTMLDocument::removeItemFromMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name)
+{
+    if (name.isEmpty())
+        return;
+    map.remove(name.impl());
+    if (Frame* f = frame())
+        f->script()->namedItemRemoved(this, name);
+}
+
+void HTMLDocument::addNamedItem(const AtomicString& name)
+{
+    addItemToMap(m_namedItemCounts, name);
+}
+
+void HTMLDocument::removeNamedItem(const AtomicString& name)
+{ 
+    removeItemFromMap(m_namedItemCounts, name);
+}
+
+void HTMLDocument::addExtraNamedItem(const AtomicString& name)
+{
+    addItemToMap(m_extraNamedItemCounts, name);
+}
+
+void HTMLDocument::removeExtraNamedItem(const AtomicString& name)
+{ 
+    removeItemFromMap(m_extraNamedItemCounts, name);
+}
+
+static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName)
+{
+    set->add(qName.localName().impl());
+}
+
+static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet()
+{
+    // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive
+    // Mozilla treats all other values as case-sensitive, thus so do we.
+    HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>;
+
+    addLocalNameToSet(attrSet, accept_charsetAttr);
+    addLocalNameToSet(attrSet, acceptAttr);
+    addLocalNameToSet(attrSet, alignAttr);
+    addLocalNameToSet(attrSet, alinkAttr);
+    addLocalNameToSet(attrSet, axisAttr);
+    addLocalNameToSet(attrSet, bgcolorAttr);
+    addLocalNameToSet(attrSet, charsetAttr);
+    addLocalNameToSet(attrSet, checkedAttr);
+    addLocalNameToSet(attrSet, clearAttr);
+    addLocalNameToSet(attrSet, codetypeAttr);
+    addLocalNameToSet(attrSet, colorAttr);
+    addLocalNameToSet(attrSet, compactAttr);
+    addLocalNameToSet(attrSet, declareAttr);
+    addLocalNameToSet(attrSet, deferAttr);
+    addLocalNameToSet(attrSet, dirAttr);
+    addLocalNameToSet(attrSet, disabledAttr);
+    addLocalNameToSet(attrSet, enctypeAttr);
+    addLocalNameToSet(attrSet, faceAttr);
+    addLocalNameToSet(attrSet, frameAttr);
+    addLocalNameToSet(attrSet, hreflangAttr);
+    addLocalNameToSet(attrSet, http_equivAttr);
+    addLocalNameToSet(attrSet, langAttr);
+    addLocalNameToSet(attrSet, languageAttr);
+    addLocalNameToSet(attrSet, linkAttr);
+    addLocalNameToSet(attrSet, mediaAttr);
+    addLocalNameToSet(attrSet, methodAttr);
+    addLocalNameToSet(attrSet, multipleAttr);
+    addLocalNameToSet(attrSet, nohrefAttr);
+    addLocalNameToSet(attrSet, noresizeAttr);
+    addLocalNameToSet(attrSet, noshadeAttr);
+    addLocalNameToSet(attrSet, nowrapAttr);
+    addLocalNameToSet(attrSet, readonlyAttr);
+    addLocalNameToSet(attrSet, relAttr);
+    addLocalNameToSet(attrSet, revAttr);
+    addLocalNameToSet(attrSet, rulesAttr);
+    addLocalNameToSet(attrSet, scopeAttr);
+    addLocalNameToSet(attrSet, scrollingAttr);
+    addLocalNameToSet(attrSet, selectedAttr);
+    addLocalNameToSet(attrSet, shapeAttr);
+    addLocalNameToSet(attrSet, targetAttr);
+    addLocalNameToSet(attrSet, textAttr);
+    addLocalNameToSet(attrSet, typeAttr);
+    addLocalNameToSet(attrSet, valignAttr);
+    addLocalNameToSet(attrSet, valuetypeAttr);
+    addLocalNameToSet(attrSet, vlinkAttr);
+
+    return attrSet;
+}
+
+bool HTMLDocument::isCaseSensitiveAttribute(const QualifiedName& attributeName)
+{
+    static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet();
+    bool isPossibleHTMLAttr = !attributeName.hasPrefix() && (attributeName.namespaceURI() == nullAtom);
+    return !isPossibleHTMLAttr || !htmlCaseInsensitiveAttributesSet->contains(attributeName.localName().impl());
+}
+
+void HTMLDocument::clear()
+{
+    // FIXME: This does nothing, and that seems unlikely to be correct.
+    // We've long had a comment saying that IE doesn't support this.
+    // But I do see it in the documentation for Mozilla.
+}
+
+bool HTMLDocument::isFrameSet() const
+{
+    HTMLElement* bodyElement = body();
+    return bodyElement && bodyElement->hasTagName(framesetTag);
+}
+
+}
diff --git a/Source/core/html/HTMLDocument.h b/Source/core/html/HTMLDocument.h
new file mode 100644
index 0000000..09d750c
--- /dev/null
+++ b/Source/core/html/HTMLDocument.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2006, 2007, 2008, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLDocument_h
+#define HTMLDocument_h
+
+#include "core/dom/Document.h"
+#include "core/loader/cache/CachedResourceClient.h"
+#include <wtf/HashCountedSet.h>
+#include <wtf/text/AtomicStringHash.h>
+
+namespace WebCore {
+
+class FrameView;
+class HTMLElement;
+
+class HTMLDocument : public Document, public CachedResourceClient {
+public:
+    static PassRefPtr<HTMLDocument> create(Frame* frame, const KURL& url)
+    {
+        return adoptRef(new HTMLDocument(frame, url));
+    }
+    virtual ~HTMLDocument();
+
+    int width();
+    int height();
+
+    String dir();
+    void setDir(const String&);
+
+    String designMode() const;
+    void setDesignMode(const String&);
+
+    Element* activeElement();
+    bool hasFocus();
+
+    String bgColor();
+    void setBgColor(const String&);
+    String fgColor();
+    void setFgColor(const String&);
+    String alinkColor();
+    void setAlinkColor(const String&);
+    String linkColor();
+    void setLinkColor(const String&);
+    String vlinkColor();
+    void setVlinkColor(const String&);
+
+    void clear();
+
+    void captureEvents();
+    void releaseEvents();
+
+    void addNamedItem(const AtomicString& name);
+    void removeNamedItem(const AtomicString& name);
+    bool hasNamedItem(AtomicStringImpl* name);
+
+    void addExtraNamedItem(const AtomicString& name);
+    void removeExtraNamedItem(const AtomicString& name);
+    bool hasExtraNamedItem(AtomicStringImpl* name);
+
+    static bool isCaseSensitiveAttribute(const QualifiedName&);
+
+protected:
+    HTMLDocument(Frame*, const KURL&);
+
+private:
+    virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
+
+    virtual bool isFrameSet() const;
+    virtual PassRefPtr<DocumentParser> createParser();
+
+    void addItemToMap(HashCountedSet<AtomicStringImpl*>&, const AtomicString&);
+    void removeItemFromMap(HashCountedSet<AtomicStringImpl*>&, const AtomicString&);
+
+    HashCountedSet<AtomicStringImpl*> m_namedItemCounts;
+    HashCountedSet<AtomicStringImpl*> m_extraNamedItemCounts;
+};
+
+inline bool HTMLDocument::hasNamedItem(AtomicStringImpl* name)
+{
+    ASSERT(name);
+    return m_namedItemCounts.contains(name);
+}
+
+inline bool HTMLDocument::hasExtraNamedItem(AtomicStringImpl* name)
+{
+    ASSERT(name);
+    return m_extraNamedItemCounts.contains(name);
+}
+
+inline HTMLDocument* toHTMLDocument(Document* document)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!document || document->isHTMLDocument());
+    return static_cast<HTMLDocument*>(document);
+}
+
+inline const HTMLDocument* toHTMLDocument(const Document* document)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!document || document->isHTMLDocument());
+    return static_cast<const HTMLDocument*>(document);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toHTMLDocument(const HTMLDocument*);
+
+} // namespace WebCore
+
+#endif // HTMLDocument_h
diff --git a/Source/core/html/HTMLDocument.idl b/Source/core/html/HTMLDocument.idl
new file mode 100644
index 0000000..91f2905
--- /dev/null
+++ b/Source/core/html/HTMLDocument.idl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomToV8,
+    SkipVTableValidation
+] interface HTMLDocument : Document {
+    [Custom] void open();
+    void close();
+    [Custom, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds] void write([Default=Undefined] optional DOMString text);
+    [Custom, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds] void writeln([Default=Undefined] optional DOMString text);
+
+    readonly attribute HTMLCollection embeds;
+    readonly attribute HTMLCollection plugins;
+    readonly attribute HTMLCollection scripts;
+
+    // Extensions
+
+    [Replaceable] attribute HTMLAllCollection all;
+
+    void clear();
+
+    void captureEvents();
+    void releaseEvents();
+
+    readonly attribute long width;
+    readonly attribute long height;
+             [TreatNullAs=NullString] attribute DOMString dir;
+             [TreatNullAs=NullString] attribute DOMString designMode;
+    readonly attribute DOMString compatMode;
+
+    readonly attribute Element activeElement;
+    boolean hasFocus();
+
+    // Deprecated attributes
+             [TreatNullAs=NullString] attribute DOMString bgColor;
+             [TreatNullAs=NullString] attribute DOMString fgColor;
+             [TreatNullAs=NullString] attribute DOMString alinkColor;
+             [TreatNullAs=NullString] attribute DOMString linkColor;
+             [TreatNullAs=NullString] attribute DOMString vlinkColor;
+};
+
diff --git a/Source/core/html/HTMLElement.cpp b/Source/core/html/HTMLElement.cpp
new file mode 100644
index 0000000..374db34
--- /dev/null
+++ b/Source/core/html/HTMLElement.cpp
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2011 Motorola Mobility. 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLElementFactory.h"
+#include "HTMLNames.h"
+#include "XMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/css/CSSParser.h"
+#include "core/css/CSSValuePool.h"
+#include "core/css/StylePropertySet.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventListener.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/Text.h"
+#include "core/editing/TextIterator.h"
+#include "core/editing/markup.h"
+#include "core/html/DOMSettableTokenList.h"
+#include "core/html/HTMLBRElement.h"
+#include "core/html/HTMLCollection.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLTemplateElement.h"
+#include "core/html/HTMLTextFormControlElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/FrameLoader.h"
+#include "core/page/Frame.h"
+#include "core/page/Settings.h"
+#include "core/rendering/RenderWordBreak.h"
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace WTF;
+
+using std::min;
+using std::max;
+
+PassRefPtr<HTMLElement> HTMLElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLElement(tagName, document));
+}
+
+String HTMLElement::nodeName() const
+{
+    // FIXME: Would be nice to have an atomicstring lookup based off uppercase
+    // chars that does not have to copy the string on a hit in the hash.
+    // FIXME: We should have a way to detect XHTML elements and replace the hasPrefix() check with it.
+    if (document()->isHTMLDocument() && !tagQName().hasPrefix())
+        return tagQName().localNameUpper();
+    return Element::nodeName();
+}
+
+bool HTMLElement::ieForbidsInsertHTML() const
+{
+    // FIXME: Supposedly IE disallows settting innerHTML, outerHTML
+    // and createContextualFragment on these tags.  We have no tests to
+    // verify this however, so this list could be totally wrong.
+    // This list was moved from the previous endTagRequirement() implementation.
+    // This is also called from editing and assumed to be the list of tags
+    // for which no end tag should be serialized. It's unclear if the list for
+    // IE compat and the list for serialization sanity are the same.
+    if (hasLocalName(areaTag)
+        || hasLocalName(baseTag)
+        || hasLocalName(basefontTag)
+        || hasLocalName(brTag)
+        || hasLocalName(colTag)
+        || hasLocalName(embedTag)
+        || hasLocalName(frameTag)
+        || hasLocalName(hrTag)
+        || hasLocalName(imageTag)
+        || hasLocalName(imgTag)
+        || hasLocalName(inputTag)
+        || hasLocalName(isindexTag)
+        || hasLocalName(linkTag)
+        || hasLocalName(metaTag)
+        || hasLocalName(paramTag)
+        || hasLocalName(sourceTag)
+        || hasLocalName(wbrTag))
+        return true;
+    return false;
+}
+
+static inline int unicodeBidiAttributeForDirAuto(HTMLElement* element)
+{
+    if (element->hasLocalName(preTag) || element->hasLocalName(textareaTag))
+        return CSSValueWebkitPlaintext;
+    // FIXME: For bdo element, dir="auto" should result in "bidi-override isolate" but we don't support having multiple values in unicode-bidi yet.
+    // See https://bugs.webkit.org/show_bug.cgi?id=73164.
+    return CSSValueWebkitIsolate;
+}
+
+unsigned HTMLElement::parseBorderWidthAttribute(const AtomicString& value) const
+{
+    unsigned borderWidth = 0;
+    if (value.isEmpty() || !parseHTMLNonNegativeInteger(value, borderWidth))
+        return hasLocalName(tableTag) ? 1 : borderWidth;
+    return borderWidth;
+}
+
+void HTMLElement::applyBorderAttributeToStyle(const AtomicString& value, MutableStylePropertySet* style)
+{
+    addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderWidth, parseBorderWidthAttribute(value), CSSPrimitiveValue::CSS_PX);
+    addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderStyle, CSSValueSolid);
+}
+
+void HTMLElement::mapLanguageAttributeToLocale(const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (!value.isEmpty()) {
+        // Have to quote so the locale id is treated as a string instead of as a CSS keyword.
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitLocale, quoteCSSString(value));
+    } else {
+        // The empty string means the language is explicitly unknown.
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitLocale, CSSValueAuto);
+    }
+}
+
+bool HTMLElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == alignAttr || name == contenteditableAttr || name == hiddenAttr || name == langAttr || name.matches(XMLNames::langAttr) || name == draggableAttr || name == dirAttr)
+        return true;
+    return StyledElement::isPresentationAttribute(name);
+}
+
+void HTMLElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == alignAttr) {
+        if (equalIgnoringCase(value, "middle"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueCenter);
+        else
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, value);
+    } else if (name == contenteditableAttr) {
+        if (value.isEmpty() || equalIgnoringCase(value, "true")) {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserModify, CSSValueReadWrite);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWordWrap, CSSValueBreakWord);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitLineBreak, CSSValueAfterWhiteSpace);
+        } else if (equalIgnoringCase(value, "plaintext-only")) {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserModify, CSSValueReadWritePlaintextOnly);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWordWrap, CSSValueBreakWord);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitLineBreak, CSSValueAfterWhiteSpace);
+        } else if (equalIgnoringCase(value, "false"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserModify, CSSValueReadOnly);
+    } else if (name == hiddenAttr) {
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyDisplay, CSSValueNone);
+    } else if (name == draggableAttr) {
+        if (equalIgnoringCase(value, "true")) {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserDrag, CSSValueElement);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserSelect, CSSValueNone);
+        } else if (equalIgnoringCase(value, "false"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitUserDrag, CSSValueNone);
+    } else if (name == dirAttr) {
+        if (equalIgnoringCase(value, "auto"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyUnicodeBidi, unicodeBidiAttributeForDirAuto(this));
+        else {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyDirection, value);
+            if (!hasTagName(bdiTag) && !hasTagName(bdoTag) && !hasTagName(outputTag))
+                addPropertyToPresentationAttributeStyle(style, CSSPropertyUnicodeBidi, CSSValueEmbed);
+        }
+    } else if (name.matches(XMLNames::langAttr))
+        mapLanguageAttributeToLocale(value, style);
+    else if (name == langAttr) {
+        // xml:lang has a higher priority than lang.
+        if (!fastHasAttribute(XMLNames::langAttr))
+            mapLanguageAttributeToLocale(value, style);
+    } else
+        StyledElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+AtomicString HTMLElement::eventNameForAttributeName(const QualifiedName& attrName) const
+{
+    if (!attrName.namespaceURI().isNull())
+        return AtomicString();
+    
+    typedef HashMap<AtomicString, AtomicString> StringToStringMap;
+    DEFINE_STATIC_LOCAL(StringToStringMap, attributeNameToEventNameMap, ());
+    if (!attributeNameToEventNameMap.size()) {
+        attributeNameToEventNameMap.set(onclickAttr.localName(), eventNames().clickEvent);
+        attributeNameToEventNameMap.set(oncontextmenuAttr.localName(), eventNames().contextmenuEvent);
+        attributeNameToEventNameMap.set(ondblclickAttr.localName(), eventNames().dblclickEvent);
+        attributeNameToEventNameMap.set(onmousedownAttr.localName(), eventNames().mousedownEvent);
+        attributeNameToEventNameMap.set(onmousemoveAttr.localName(), eventNames().mousemoveEvent);
+        attributeNameToEventNameMap.set(onmouseoutAttr.localName(), eventNames().mouseoutEvent);
+        attributeNameToEventNameMap.set(onmouseoverAttr.localName(), eventNames().mouseoverEvent);
+        attributeNameToEventNameMap.set(onmouseupAttr.localName(), eventNames().mouseupEvent);
+        attributeNameToEventNameMap.set(onmousewheelAttr.localName(), eventNames().mousewheelEvent);
+        attributeNameToEventNameMap.set(onfocusAttr.localName(), eventNames().focusEvent);
+        attributeNameToEventNameMap.set(onfocusinAttr.localName(), eventNames().focusinEvent);
+        attributeNameToEventNameMap.set(onfocusoutAttr.localName(), eventNames().focusoutEvent);
+        attributeNameToEventNameMap.set(onblurAttr.localName(), eventNames().blurEvent);
+        attributeNameToEventNameMap.set(onkeydownAttr.localName(), eventNames().keydownEvent);
+        attributeNameToEventNameMap.set(onkeypressAttr.localName(), eventNames().keypressEvent);
+        attributeNameToEventNameMap.set(onkeyupAttr.localName(), eventNames().keyupEvent);
+        attributeNameToEventNameMap.set(onscrollAttr.localName(), eventNames().scrollEvent);
+        attributeNameToEventNameMap.set(onbeforecutAttr.localName(), eventNames().beforecutEvent);
+        attributeNameToEventNameMap.set(oncutAttr.localName(), eventNames().cutEvent);
+        attributeNameToEventNameMap.set(onbeforecopyAttr.localName(), eventNames().beforecopyEvent);
+        attributeNameToEventNameMap.set(oncopyAttr.localName(), eventNames().copyEvent);
+        attributeNameToEventNameMap.set(onbeforepasteAttr.localName(), eventNames().beforepasteEvent);
+        attributeNameToEventNameMap.set(onpasteAttr.localName(), eventNames().pasteEvent);
+        attributeNameToEventNameMap.set(ondragenterAttr.localName(), eventNames().dragenterEvent);
+        attributeNameToEventNameMap.set(ondragoverAttr.localName(), eventNames().dragoverEvent);
+        attributeNameToEventNameMap.set(ondragleaveAttr.localName(), eventNames().dragleaveEvent);
+        attributeNameToEventNameMap.set(ondropAttr.localName(), eventNames().dropEvent);
+        attributeNameToEventNameMap.set(ondragstartAttr.localName(), eventNames().dragstartEvent);
+        attributeNameToEventNameMap.set(ondragAttr.localName(), eventNames().dragEvent);
+        attributeNameToEventNameMap.set(ondragendAttr.localName(), eventNames().dragendEvent);
+        attributeNameToEventNameMap.set(onselectstartAttr.localName(), eventNames().selectstartEvent);
+        attributeNameToEventNameMap.set(onsubmitAttr.localName(), eventNames().submitEvent);
+        attributeNameToEventNameMap.set(onerrorAttr.localName(), eventNames().errorEvent);
+        attributeNameToEventNameMap.set(onwebkitanimationstartAttr.localName(), eventNames().webkitAnimationStartEvent);
+        attributeNameToEventNameMap.set(onwebkitanimationiterationAttr.localName(), eventNames().webkitAnimationIterationEvent);
+        attributeNameToEventNameMap.set(onwebkitanimationendAttr.localName(), eventNames().webkitAnimationEndEvent);
+        attributeNameToEventNameMap.set(onwebkittransitionendAttr.localName(), eventNames().webkitTransitionEndEvent);
+        attributeNameToEventNameMap.set(ontransitionendAttr.localName(), eventNames().webkitTransitionEndEvent);
+        attributeNameToEventNameMap.set(oninputAttr.localName(), eventNames().inputEvent);
+        attributeNameToEventNameMap.set(oninvalidAttr.localName(), eventNames().invalidEvent);
+        attributeNameToEventNameMap.set(ontouchstartAttr.localName(), eventNames().touchstartEvent);
+        attributeNameToEventNameMap.set(ontouchmoveAttr.localName(), eventNames().touchmoveEvent);
+        attributeNameToEventNameMap.set(ontouchendAttr.localName(), eventNames().touchendEvent);
+        attributeNameToEventNameMap.set(ontouchcancelAttr.localName(), eventNames().touchcancelEvent);
+        attributeNameToEventNameMap.set(onwebkitfullscreenchangeAttr.localName(), eventNames().webkitfullscreenchangeEvent);
+        attributeNameToEventNameMap.set(onwebkitfullscreenerrorAttr.localName(), eventNames().webkitfullscreenerrorEvent);
+        attributeNameToEventNameMap.set(onabortAttr.localName(), eventNames().abortEvent);
+        attributeNameToEventNameMap.set(oncanplayAttr.localName(), eventNames().canplayEvent);
+        attributeNameToEventNameMap.set(oncanplaythroughAttr.localName(), eventNames().canplaythroughEvent);
+        attributeNameToEventNameMap.set(onchangeAttr.localName(), eventNames().changeEvent);
+        attributeNameToEventNameMap.set(ondurationchangeAttr.localName(), eventNames().durationchangeEvent);
+        attributeNameToEventNameMap.set(onemptiedAttr.localName(), eventNames().emptiedEvent);
+        attributeNameToEventNameMap.set(onendedAttr.localName(), eventNames().endedEvent);
+        attributeNameToEventNameMap.set(onloadeddataAttr.localName(), eventNames().loadeddataEvent);
+        attributeNameToEventNameMap.set(onloadedmetadataAttr.localName(), eventNames().loadedmetadataEvent);
+        attributeNameToEventNameMap.set(onloadstartAttr.localName(), eventNames().loadstartEvent);
+        attributeNameToEventNameMap.set(onpauseAttr.localName(), eventNames().pauseEvent);
+        attributeNameToEventNameMap.set(onplayAttr.localName(), eventNames().playEvent);
+        attributeNameToEventNameMap.set(onplayingAttr.localName(), eventNames().playingEvent);
+        attributeNameToEventNameMap.set(onprogressAttr.localName(), eventNames().progressEvent);
+        attributeNameToEventNameMap.set(onratechangeAttr.localName(), eventNames().ratechangeEvent);
+        attributeNameToEventNameMap.set(onresetAttr.localName(), eventNames().resetEvent);
+        attributeNameToEventNameMap.set(onseekedAttr.localName(), eventNames().seekedEvent);
+        attributeNameToEventNameMap.set(onseekingAttr.localName(), eventNames().seekingEvent);
+        attributeNameToEventNameMap.set(onselectAttr.localName(), eventNames().selectEvent);
+        attributeNameToEventNameMap.set(onstalledAttr.localName(), eventNames().stalledEvent);
+        attributeNameToEventNameMap.set(onsuspendAttr.localName(), eventNames().suspendEvent);
+        attributeNameToEventNameMap.set(ontimeupdateAttr.localName(), eventNames().timeupdateEvent);
+        attributeNameToEventNameMap.set(onvolumechangeAttr.localName(), eventNames().volumechangeEvent);
+        attributeNameToEventNameMap.set(onwaitingAttr.localName(), eventNames().waitingEvent);
+        attributeNameToEventNameMap.set(onloadAttr.localName(), eventNames().loadEvent);
+    }
+
+    return attributeNameToEventNameMap.get(attrName.localName());
+}
+
+void HTMLElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (isIdAttributeName(name) || name == classAttr || name == styleAttr)
+        return StyledElement::parseAttribute(name, value);
+
+    if (name == dirAttr)
+        dirAttributeChanged(value);
+    else if (name == tabindexAttr) {
+        int tabindex = 0;
+        if (value.isEmpty())
+            clearTabIndexExplicitlyIfNeeded();
+        else if (parseHTMLInteger(value, 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 {
+        AtomicString eventName = eventNameForAttributeName(name);
+        if (!eventName.isNull())
+            setAttributeEventListener(eventName, createAttributeEventListener(this, name, value));
+    }
+}
+
+String HTMLElement::innerHTML() const
+{
+    return createMarkup(this, ChildrenOnly);
+}
+
+String HTMLElement::outerHTML() const
+{
+    return createMarkup(this);
+}
+
+void HTMLElement::setInnerHTML(const String& html, ExceptionCode& ec)
+{
+    if (RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, this, AllowScriptingContent, ec)) {
+        ContainerNode* container = this;
+        if (hasLocalName(templateTag))
+            container = toHTMLTemplateElement(this)->content();
+        replaceChildrenWithFragment(container, fragment.release(), ec);
+    }
+}
+
+static void mergeWithNextTextNode(PassRefPtr<Node> node, ExceptionCode& ec)
+{
+    ASSERT(node && node->isTextNode());
+    Node* next = node->nextSibling();
+    if (!next || !next->isTextNode())
+        return;
+    
+    RefPtr<Text> textNode = toText(node.get());
+    RefPtr<Text> textNext = toText(next);
+    textNode->appendData(textNext->data(), ec);
+    if (ec)
+        return;
+    if (textNext->parentNode()) // Might have been removed by mutation event.
+        textNext->remove(ec);
+}
+
+void HTMLElement::setOuterHTML(const String& html, ExceptionCode& ec)
+{
+    Node* p = parentNode();
+    if (!p || !p->isHTMLElement()) {
+        ec = NO_MODIFICATION_ALLOWED_ERR;
+        return;
+    }
+    RefPtr<HTMLElement> parent = toHTMLElement(p);
+    RefPtr<Node> prev = previousSibling();
+    RefPtr<Node> next = nextSibling();
+
+    RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, parent.get(), AllowScriptingContent, ec);
+    if (ec)
+        return;
+      
+    parent->replaceChild(fragment.release(), this, ec);
+    RefPtr<Node> node = next ? next->previousSibling() : 0;
+    if (!ec && node && node->isTextNode())
+        mergeWithNextTextNode(node.release(), ec);
+
+    if (!ec && prev && prev->isTextNode())
+        mergeWithNextTextNode(prev.release(), ec);
+}
+
+PassRefPtr<DocumentFragment> HTMLElement::textToFragment(const String& text, ExceptionCode& ec)
+{
+    RefPtr<DocumentFragment> fragment = DocumentFragment::create(document());
+    unsigned int i, length = text.length();
+    UChar c = 0;
+    for (unsigned int start = 0; start < length; ) {
+
+        // Find next line break.
+        for (i = start; i < length; i++) {
+          c = text[i];
+          if (c == '\r' || c == '\n')
+              break;
+        }
+
+        fragment->appendChild(Text::create(document(), text.substring(start, i - start)), ec);
+        if (ec)
+            return 0;
+
+        if (c == '\r' || c == '\n') {
+            fragment->appendChild(HTMLBRElement::create(document()), ec);
+            if (ec)
+                return 0;
+            // Make sure \r\n doesn't result in two line breaks.
+            if (c == '\r' && i + 1 < length && text[i + 1] == '\n')
+                i++;
+        }
+
+        start = i + 1; // Character after line break.
+    }
+
+    return fragment;
+}
+
+void HTMLElement::setInnerText(const String& text, ExceptionCode& ec)
+{
+    if (ieForbidsInsertHTML()) {
+        ec = NO_MODIFICATION_ALLOWED_ERR;
+        return;
+    }
+    if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) ||
+        hasLocalName(headTag) || hasLocalName(htmlTag) || hasLocalName(tableTag) || 
+        hasLocalName(tbodyTag) || hasLocalName(tfootTag) || hasLocalName(theadTag) ||
+        hasLocalName(trTag)) {
+        ec = NO_MODIFICATION_ALLOWED_ERR;
+        return;
+    }
+
+    // FIXME: This doesn't take whitespace collapsing into account at all.
+
+    if (!text.contains('\n') && !text.contains('\r')) {
+        if (text.isEmpty()) {
+            removeChildren();
+            return;
+        }
+        replaceChildrenWithText(this, text, ec);
+        return;
+    }
+
+    // FIXME: Do we need to be able to detect preserveNewline style even when there's no renderer?
+    // FIXME: Can the renderer be out of date here? Do we need to call updateStyleIfNeeded?
+    // For example, for the contents of textarea elements that are display:none?
+    RenderObject* r = renderer();
+    if (r && r->style()->preserveNewline()) {
+        if (!text.contains('\r')) {
+            replaceChildrenWithText(this, text, ec);
+            return;
+        }
+        String textWithConsistentLineBreaks = text;
+        textWithConsistentLineBreaks.replace("\r\n", "\n");
+        textWithConsistentLineBreaks.replace('\r', '\n');
+        replaceChildrenWithText(this, textWithConsistentLineBreaks, ec);
+        return;
+    }
+
+    // Add text nodes and <br> elements.
+    ec = 0;
+    RefPtr<DocumentFragment> fragment = textToFragment(text, ec);
+    if (!ec)
+        replaceChildrenWithFragment(this, fragment.release(), ec);
+}
+
+void HTMLElement::setOuterText(const String &text, ExceptionCode& ec)
+{
+    if (ieForbidsInsertHTML()) {
+        ec = NO_MODIFICATION_ALLOWED_ERR;
+        return;
+    }
+    if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) ||
+        hasLocalName(headTag) || hasLocalName(htmlTag) || hasLocalName(tableTag) || 
+        hasLocalName(tbodyTag) || hasLocalName(tfootTag) || hasLocalName(theadTag) ||
+        hasLocalName(trTag)) {
+        ec = NO_MODIFICATION_ALLOWED_ERR;
+        return;
+    }
+
+    ContainerNode* parent = parentNode();
+    if (!parent) {
+        ec = NO_MODIFICATION_ALLOWED_ERR;
+        return;
+    }
+
+    RefPtr<Node> prev = previousSibling();
+    RefPtr<Node> next = nextSibling();
+    RefPtr<Node> newChild;
+    ec = 0;
+    
+    // Convert text to fragment with <br> tags instead of linebreaks if needed.
+    if (text.contains('\r') || text.contains('\n'))
+        newChild = textToFragment(text, ec);
+    else
+        newChild = Text::create(document(), text);
+
+    if (!this || !parentNode())
+        ec = HIERARCHY_REQUEST_ERR;
+    if (ec)
+        return;
+    parent->replaceChild(newChild.release(), this, ec);
+
+    RefPtr<Node> node = next ? next->previousSibling() : 0;
+    if (!ec && node && node->isTextNode())
+        mergeWithNextTextNode(node.release(), ec);
+
+    if (!ec && prev && prev->isTextNode())
+        mergeWithNextTextNode(prev.release(), ec);
+}
+
+Node* HTMLElement::insertAdjacent(const String& where, Node* newChild, ExceptionCode& ec)
+{
+    // In Internet Explorer if the element has no parent and where is "beforeBegin" or "afterEnd",
+    // a document fragment is created and the elements appended in the correct order. This document
+    // fragment isn't returned anywhere.
+    //
+    // This is impossible for us to implement as the DOM tree does not allow for such structures,
+    // Opera also appears to disallow such usage.
+
+    if (equalIgnoringCase(where, "beforeBegin")) {
+        ContainerNode* parent = this->parentNode();
+        return (parent && parent->insertBefore(newChild, this, ec)) ? newChild : 0;
+    }
+
+    if (equalIgnoringCase(where, "afterBegin"))
+        return insertBefore(newChild, firstChild(), ec) ? newChild : 0;
+
+    if (equalIgnoringCase(where, "beforeEnd"))
+        return appendChild(newChild, ec) ? newChild : 0;
+
+    if (equalIgnoringCase(where, "afterEnd")) {
+        ContainerNode* parent = this->parentNode();
+        return (parent && parent->insertBefore(newChild, nextSibling(), ec)) ? newChild : 0;
+    }
+    
+    // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative.
+    ec = NOT_SUPPORTED_ERR;
+    return 0;
+}
+
+Element* HTMLElement::insertAdjacentElement(const String& where, Element* newChild, ExceptionCode& ec)
+{
+    if (!newChild) {
+        // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative.
+        ec = TYPE_MISMATCH_ERR;
+        return 0;
+    }
+
+    Node* returnValue = insertAdjacent(where, newChild, ec);
+    ASSERT_WITH_SECURITY_IMPLICATION(!returnValue || returnValue->isElementNode());
+    return toElement(returnValue); 
+}
+
+// Step 3 of http://www.whatwg.org/specs/web-apps/current-work/multipage/apis-in-html-documents.html#insertadjacenthtml()
+static Element* contextElementForInsertion(const String& where, Element* element, ExceptionCode& ec)
+{
+    if (equalIgnoringCase(where, "beforeBegin") || equalIgnoringCase(where, "afterEnd")) {
+        ContainerNode* parent = element->parentNode();
+        if (parent && !parent->isElementNode()) {
+            ec = NO_MODIFICATION_ALLOWED_ERR;
+            return 0;
+        }
+        ASSERT_WITH_SECURITY_IMPLICATION(!parent || parent->isElementNode());
+        return toElement(parent);
+    }
+    if (equalIgnoringCase(where, "afterBegin") || equalIgnoringCase(where, "beforeEnd"))
+        return element;
+    ec =  SYNTAX_ERR;
+    return 0;
+}
+
+void HTMLElement::insertAdjacentHTML(const String& where, const String& markup, ExceptionCode& ec)
+{
+    Element* contextElement = contextElementForInsertion(where, this, ec);
+    if (!contextElement)
+        return;
+    RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, contextElement, AllowScriptingContent, ec);
+    if (!fragment)
+        return;
+    insertAdjacent(where, fragment.get(), ec);
+}
+
+void HTMLElement::insertAdjacentText(const String& where, const String& text, ExceptionCode& ec)
+{
+    RefPtr<Text> textNode = document()->createTextNode(text);
+    insertAdjacent(where, textNode.get(), ec);
+}
+
+void HTMLElement::applyAlignmentAttributeToStyle(const AtomicString& alignment, MutableStylePropertySet* style)
+{
+    // Vertical alignment with respect to the current baseline of the text
+    // right or left means floating images.
+    int floatValue = CSSValueInvalid;
+    int verticalAlignValue = CSSValueInvalid;
+
+    if (equalIgnoringCase(alignment, "absmiddle"))
+        verticalAlignValue = CSSValueMiddle;
+    else if (equalIgnoringCase(alignment, "absbottom"))
+        verticalAlignValue = CSSValueBottom;
+    else if (equalIgnoringCase(alignment, "left")) {
+        floatValue = CSSValueLeft;
+        verticalAlignValue = CSSValueTop;
+    } else if (equalIgnoringCase(alignment, "right")) {
+        floatValue = CSSValueRight;
+        verticalAlignValue = CSSValueTop;
+    } else if (equalIgnoringCase(alignment, "top"))
+        verticalAlignValue = CSSValueTop;
+    else if (equalIgnoringCase(alignment, "middle"))
+        verticalAlignValue = CSSValueWebkitBaselineMiddle;
+    else if (equalIgnoringCase(alignment, "center"))
+        verticalAlignValue = CSSValueMiddle;
+    else if (equalIgnoringCase(alignment, "bottom"))
+        verticalAlignValue = CSSValueBaseline;
+    else if (equalIgnoringCase(alignment, "texttop"))
+        verticalAlignValue = CSSValueTextTop;
+
+    if (floatValue != CSSValueInvalid)
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyFloat, floatValue);
+
+    if (verticalAlignValue != CSSValueInvalid)
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, verticalAlignValue);
+}
+
+bool HTMLElement::hasCustomFocusLogic() const
+{
+    return false;
+}
+
+bool HTMLElement::supportsFocus() const
+{
+    return Element::supportsFocus() || (rendererIsEditable() && parentNode() && !parentNode()->rendererIsEditable());
+}
+
+String HTMLElement::contentEditable() const
+{
+    const AtomicString& value = fastGetAttribute(contenteditableAttr);
+
+    if (value.isNull())
+        return "inherit";
+    if (value.isEmpty() || equalIgnoringCase(value, "true"))
+        return "true";
+    if (equalIgnoringCase(value, "false"))
+         return "false";
+    if (equalIgnoringCase(value, "plaintext-only"))
+        return "plaintext-only";
+
+    return "inherit";
+}
+
+void HTMLElement::setContentEditable(const String& enabled, ExceptionCode& ec)
+{
+    if (equalIgnoringCase(enabled, "true"))
+        setAttribute(contenteditableAttr, "true");
+    else if (equalIgnoringCase(enabled, "false"))
+        setAttribute(contenteditableAttr, "false");
+    else if (equalIgnoringCase(enabled, "plaintext-only"))
+        setAttribute(contenteditableAttr, "plaintext-only");
+    else if (equalIgnoringCase(enabled, "inherit"))
+        removeAttribute(contenteditableAttr);
+    else
+        ec = SYNTAX_ERR;
+}
+
+bool HTMLElement::draggable() const
+{
+    return equalIgnoringCase(getAttribute(draggableAttr), "true");
+}
+
+void HTMLElement::setDraggable(bool value)
+{
+    setAttribute(draggableAttr, value ? "true" : "false");
+}
+
+bool HTMLElement::spellcheck() const
+{
+    return isSpellCheckingEnabled();
+}
+
+void HTMLElement::setSpellcheck(bool enable)
+{
+    setAttribute(spellcheckAttr, enable ? "true" : "false");
+}
+
+
+void HTMLElement::click()
+{
+    dispatchSimulatedClick(0, SendNoEvents, DoNotShowPressedLook);
+}
+
+void HTMLElement::accessKeyAction(bool sendMouseEvents)
+{
+    dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
+}
+
+String HTMLElement::title() const
+{
+    return getAttribute(titleAttr);
+}
+
+short HTMLElement::tabIndex() const
+{
+    if (supportsFocus())
+        return Element::tabIndex();
+    return -1;
+}
+
+void HTMLElement::setTabIndex(int value)
+{
+    setAttribute(tabindexAttr, String::number(value));
+}
+
+TranslateAttributeMode HTMLElement::translateAttributeMode() const
+{
+    const AtomicString& value = getAttribute(translateAttr);
+
+    if (value == nullAtom)
+        return TranslateAttributeInherit;
+    if (equalIgnoringCase(value, "yes") || equalIgnoringCase(value, ""))
+        return TranslateAttributeYes;
+    if (equalIgnoringCase(value, "no"))
+        return TranslateAttributeNo;
+
+    return TranslateAttributeInherit;
+}
+
+bool HTMLElement::translate() const
+{
+    for (const Node* n = this; n; n = n->parentNode()) {
+        if (n->isHTMLElement()) {
+            TranslateAttributeMode mode = static_cast<const HTMLElement*>(n)->translateAttributeMode();
+            if (mode != TranslateAttributeInherit) {
+                ASSERT(mode == TranslateAttributeYes || mode == TranslateAttributeNo);
+                return mode == TranslateAttributeYes;
+            }
+        }
+    }
+
+    // Default on the root element is translate=yes.
+    return true;
+}
+
+void HTMLElement::setTranslate(bool enable)
+{
+    setAttribute(translateAttr, enable ? "yes" : "no");
+}
+
+
+PassRefPtr<HTMLCollection> HTMLElement::children()
+{
+    return ensureCachedHTMLCollection(NodeChildren);
+}
+
+bool HTMLElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    if (hasLocalName(noscriptTag)) {
+        Frame* frame = document()->frame();
+        if (frame && frame->script()->canExecuteScripts(NotAboutToExecuteScript))
+            return false;
+    } else if (hasLocalName(noembedTag)) {
+        Frame* frame = document()->frame();
+        if (frame && frame->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
+            return false;
+    }
+    return StyledElement::rendererIsNeeded(context);
+}
+
+RenderObject* HTMLElement::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+    if (hasLocalName(wbrTag))
+        return new (arena) RenderWordBreak(this);
+    return RenderObject::createObject(this, style);
+}
+
+HTMLFormElement* HTMLElement::findFormAncestor() const
+{
+    for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
+        if (ancestor->hasTagName(formTag))
+            return static_cast<HTMLFormElement*>(ancestor);
+    }
+    return 0;
+}
+
+HTMLFormElement* HTMLElement::virtualForm() const
+{
+    return findFormAncestor();
+}
+
+static inline bool elementAffectsDirectionality(const Node* node)
+{
+    return node->isHTMLElement() && (node->hasTagName(bdiTag) || toHTMLElement(node)->hasAttribute(dirAttr));
+}
+
+static void setHasDirAutoFlagRecursively(Node* firstNode, bool flag, Node* lastNode = 0)
+{
+    firstNode->setSelfOrAncestorHasDirAutoAttribute(flag);
+
+    Node* node = firstNode->firstChild();
+
+    while (node) {
+        if (node->selfOrAncestorHasDirAutoAttribute() == flag)
+            return;
+
+        if (elementAffectsDirectionality(node)) {
+            if (node == lastNode)
+                return;
+            node = NodeTraversal::nextSkippingChildren(node, firstNode);
+            continue;
+        }
+        node->setSelfOrAncestorHasDirAutoAttribute(flag);
+        if (node == lastNode)
+            return;
+        node = NodeTraversal::next(node, firstNode);
+    }
+}
+
+void HTMLElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    StyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+
+    if (!selfOrAncestorHasDirAutoAttribute())
+        return;
+
+    for (Element* ancestor = this; ancestor; ancestor = ancestor->parentElement()) {
+        if (!elementAffectsDirectionality(ancestor))
+            continue;
+        toHTMLElement(ancestor)->calculateAndAdjustDirectionality();
+        return;
+    }
+}
+
+void HTMLElement::removedFrom(ContainerNode* insertionPoint)
+{
+    StyledElement::removedFrom(insertionPoint);
+    if (!parentNode() && selfOrAncestorHasDirAutoAttribute())
+        setHasDirAutoFlagRecursively(this, false);
+}
+
+Node::InsertionNotificationRequest HTMLElement::insertedInto(ContainerNode* insertionPoint)
+{
+    StyledElement::insertedInto(insertionPoint);
+    if (parentNode()->selfOrAncestorHasDirAutoAttribute() && !selfOrAncestorHasDirAutoAttribute())
+        setHasDirAutoFlagRecursively(this, true);
+
+    return InsertionDone;
+}
+
+bool HTMLElement::hasDirectionAuto() const
+{
+    const AtomicString& direction = fastGetAttribute(dirAttr);
+    return (hasTagName(bdiTag) && direction == nullAtom) || equalIgnoringCase(direction, "auto");
+}
+
+TextDirection HTMLElement::directionalityIfhasDirAutoAttribute(bool& isAuto) const
+{
+    if (!(selfOrAncestorHasDirAutoAttribute() && hasDirectionAuto())) {
+        isAuto = false;
+        return LTR;
+    }
+
+    isAuto = true;
+    return directionality();
+}
+
+TextDirection HTMLElement::directionality(Node** strongDirectionalityTextNode) const
+{
+    if (isHTMLTextFormControlElement(this)) {
+        HTMLTextFormControlElement* textElement = toHTMLTextFormControlElement(const_cast<HTMLElement*>(this));
+        bool hasStrongDirectionality;
+        Unicode::Direction textDirection = textElement->value().defaultWritingDirection(&hasStrongDirectionality);
+        if (strongDirectionalityTextNode)
+            *strongDirectionalityTextNode = hasStrongDirectionality ? textElement : 0;
+        return (textDirection == Unicode::LeftToRight) ? LTR : RTL;
+    }
+
+    Node* node = firstChild();
+    while (node) {
+        // Skip bdi, script, style and text form controls.
+        if (equalIgnoringCase(node->nodeName(), "bdi") || node->hasTagName(scriptTag) || node->hasTagName(styleTag) 
+            || (node->isElementNode() && toElement(node)->isTextFormControl())) {
+            node = NodeTraversal::nextSkippingChildren(node, this);
+            continue;
+        }
+
+        // Skip elements with valid dir attribute
+        if (node->isElementNode()) {
+            AtomicString dirAttributeValue = toElement(node)->fastGetAttribute(dirAttr);
+            if (equalIgnoringCase(dirAttributeValue, "rtl") || equalIgnoringCase(dirAttributeValue, "ltr") || equalIgnoringCase(dirAttributeValue, "auto")) {
+                node = NodeTraversal::nextSkippingChildren(node, this);
+                continue;
+            }
+        }
+
+        if (node->isTextNode()) {
+            bool hasStrongDirectionality;
+            WTF::Unicode::Direction textDirection = node->textContent(true).defaultWritingDirection(&hasStrongDirectionality);
+            if (hasStrongDirectionality) {
+                if (strongDirectionalityTextNode)
+                    *strongDirectionalityTextNode = node;
+                return (textDirection == WTF::Unicode::LeftToRight) ? LTR : RTL;
+            }
+        }
+        node = NodeTraversal::next(node, this);
+    }
+    if (strongDirectionalityTextNode)
+        *strongDirectionalityTextNode = 0;
+    return LTR;
+}
+
+void HTMLElement::dirAttributeChanged(const AtomicString& value)
+{
+    Element* parent = parentElement();
+
+    if (parent && parent->isHTMLElement() && parent->selfOrAncestorHasDirAutoAttribute())
+        toHTMLElement(parent)->adjustDirectionalityIfNeededAfterChildAttributeChanged(this);
+
+    if (equalIgnoringCase(value, "auto"))
+        calculateAndAdjustDirectionality();
+}
+
+void HTMLElement::adjustDirectionalityIfNeededAfterChildAttributeChanged(Element* child)
+{
+    ASSERT(selfOrAncestorHasDirAutoAttribute());
+    Node* strongDirectionalityTextNode;
+    TextDirection textDirection = directionality(&strongDirectionalityTextNode);
+    setHasDirAutoFlagRecursively(child, false);
+    if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection) {
+        Element* elementToAdjust = this;
+        for (; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) {
+            if (elementAffectsDirectionality(elementToAdjust)) {
+                elementToAdjust->setNeedsStyleRecalc();
+                return;
+            }
+        }
+    }
+}
+
+void HTMLElement::calculateAndAdjustDirectionality()
+{
+    Node* strongDirectionalityTextNode;
+    TextDirection textDirection = directionality(&strongDirectionalityTextNode);
+    setHasDirAutoFlagRecursively(this, true, strongDirectionalityTextNode);
+    if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection)
+        setNeedsStyleRecalc();
+}
+
+void HTMLElement::addHTMLLengthToStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
+{
+    // FIXME: This function should not spin up the CSS parser, but should instead just figure out the correct
+    // length unit and make the appropriate parsed value.
+
+    // strip attribute garbage..
+    StringImpl* v = value.impl();
+    if (v) {
+        unsigned int l = 0;
+
+        while (l < v->length() && (*v)[l] <= ' ')
+            l++;
+
+        for (; l < v->length(); l++) {
+            UChar cc = (*v)[l];
+            if (cc > '9')
+                break;
+            if (cc < '0') {
+                if (cc == '%' || cc == '*')
+                    l++;
+                if (cc != '.')
+                    break;
+            }
+        }
+
+        if (l != v->length()) {
+            addPropertyToPresentationAttributeStyle(style, propertyID, v->substring(0, l));
+            return;
+        }
+    }
+
+    addPropertyToPresentationAttributeStyle(style, propertyID, value);
+}
+
+static RGBA32 parseColorStringWithCrazyLegacyRules(const String& colorString)
+{
+    // Per spec, only look at the first 128 digits of the string.
+    const size_t maxColorLength = 128;
+    // We'll pad the buffer with two extra 0s later, so reserve two more than the max.
+    Vector<char, maxColorLength+2> digitBuffer;
+
+    size_t i = 0;
+    // Skip a leading #.
+    if (colorString[0] == '#')
+        i = 1;
+
+    // Grab the first 128 characters, replacing non-hex characters with 0.
+    // Non-BMP characters are replaced with "00" due to them appearing as two "characters" in the String.
+    for (; i < colorString.length() && digitBuffer.size() < maxColorLength; i++) {
+        if (!isASCIIHexDigit(colorString[i]))
+            digitBuffer.append('0');
+        else
+            digitBuffer.append(colorString[i]);
+    }
+
+    if (!digitBuffer.size())
+        return Color::black;
+
+    // Pad the buffer out to at least the next multiple of three in size.
+    digitBuffer.append('0');
+    digitBuffer.append('0');
+
+    if (digitBuffer.size() < 6)
+        return makeRGB(toASCIIHexValue(digitBuffer[0]), toASCIIHexValue(digitBuffer[1]), toASCIIHexValue(digitBuffer[2]));
+
+    // Split the digits into three components, then search the last 8 digits of each component.
+    ASSERT(digitBuffer.size() >= 6);
+    size_t componentLength = digitBuffer.size() / 3;
+    size_t componentSearchWindowLength = min<size_t>(componentLength, 8);
+    size_t redIndex = componentLength - componentSearchWindowLength;
+    size_t greenIndex = componentLength * 2 - componentSearchWindowLength;
+    size_t blueIndex = componentLength * 3 - componentSearchWindowLength;
+    // Skip digits until one of them is non-zero, or we've only got two digits left in the component.
+    while (digitBuffer[redIndex] == '0' && digitBuffer[greenIndex] == '0' && digitBuffer[blueIndex] == '0' && (componentLength - redIndex) > 2) {
+        redIndex++;
+        greenIndex++;
+        blueIndex++;
+    }
+    ASSERT(redIndex + 1 < componentLength);
+    ASSERT(greenIndex >= componentLength);
+    ASSERT(greenIndex + 1 < componentLength * 2);
+    ASSERT(blueIndex >= componentLength * 2);
+    ASSERT_WITH_SECURITY_IMPLICATION(blueIndex + 1 < digitBuffer.size());
+
+    int redValue = toASCIIHexValue(digitBuffer[redIndex], digitBuffer[redIndex + 1]);
+    int greenValue = toASCIIHexValue(digitBuffer[greenIndex], digitBuffer[greenIndex + 1]);
+    int blueValue = toASCIIHexValue(digitBuffer[blueIndex], digitBuffer[blueIndex + 1]);
+    return makeRGB(redValue, greenValue, blueValue);
+}
+
+// Color parsing that matches HTML's "rules for parsing a legacy color value"
+void HTMLElement::addHTMLColorToStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& attributeValue)
+{
+    // An empty string doesn't apply a color. (One containing only whitespace does, which is why this check occurs before stripping.)
+    if (attributeValue.isEmpty())
+        return;
+
+    String colorString = attributeValue.stripWhiteSpace();
+
+    // "transparent" doesn't apply a color either.
+    if (equalIgnoringCase(colorString, "transparent"))
+        return;
+
+    // If the string is a named CSS color or a 3/6-digit hex color, use that.
+    Color parsedColor(colorString);
+    if (!parsedColor.isValid())
+        parsedColor.setRGB(parseColorStringWithCrazyLegacyRules(colorString));
+
+    style->setProperty(propertyID, cssValuePool().createColorValue(parsedColor.rgb()));
+}
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+
+// For use in the debugger
+void dumpInnerHTML(WebCore::HTMLElement*);
+
+void dumpInnerHTML(WebCore::HTMLElement* element)
+{
+    printf("%s\n", element->innerHTML().ascii().data());
+}
+#endif
diff --git a/Source/core/html/HTMLElement.h b/Source/core/html/HTMLElement.h
new file mode 100644
index 0000000..6564127
--- /dev/null
+++ b/Source/core/html/HTMLElement.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLElement_h
+#define HTMLElement_h
+
+#include "core/dom/StyledElement.h"
+
+namespace WebCore {
+
+class DocumentFragment;
+class HTMLCollection;
+class HTMLFormElement;
+
+enum TranslateAttributeMode {
+    TranslateAttributeYes,
+    TranslateAttributeNo,
+    TranslateAttributeInherit
+};
+
+class HTMLElement : public StyledElement {
+public:
+    static PassRefPtr<HTMLElement> create(const QualifiedName& tagName, Document*);
+
+    PassRefPtr<HTMLCollection> children();
+
+    virtual String title() const OVERRIDE FINAL;
+
+    virtual short tabIndex() const;
+    void setTabIndex(int);
+
+    String innerHTML() const;
+    String outerHTML() const;
+    void setInnerHTML(const String&, ExceptionCode&);
+    void setOuterHTML(const String&, ExceptionCode&);
+    void setInnerText(const String&, ExceptionCode&);
+    void setOuterText(const String&, ExceptionCode&);
+
+    Element* insertAdjacentElement(const String& where, Element* newChild, ExceptionCode&);
+    void insertAdjacentHTML(const String& where, const String& html, ExceptionCode&);
+    void insertAdjacentText(const String& where, const String& text, ExceptionCode&);
+
+    virtual bool hasCustomFocusLogic() const;
+    virtual bool supportsFocus() const;
+
+    String contentEditable() const;
+    void setContentEditable(const String&, ExceptionCode&);
+
+    virtual bool draggable() const;
+    void setDraggable(bool);
+
+    bool spellcheck() const;
+    void setSpellcheck(bool);
+
+    bool translate() const;
+    void setTranslate(bool);
+
+    void click();
+
+    virtual void accessKeyAction(bool sendMouseEvents);
+
+    bool ieForbidsInsertHTML() const;
+
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+
+    HTMLFormElement* form() const { return virtualForm(); }
+
+    HTMLFormElement* findFormAncestor() const;
+
+    bool hasDirectionAuto() const;
+    TextDirection directionalityIfhasDirAutoAttribute(bool& isAuto) const;
+
+    virtual bool isHTMLUnknownElement() const { return false; }
+
+    virtual bool isLabelable() const { return false; }
+
+protected:
+    HTMLElement(const QualifiedName& tagName, Document*, ConstructionType);
+
+    void addHTMLLengthToStyle(MutableStylePropertySet*, CSSPropertyID, const String& value);
+    void addHTMLColorToStyle(MutableStylePropertySet*, CSSPropertyID, const String& color);
+
+    void applyAlignmentAttributeToStyle(const AtomicString&, MutableStylePropertySet*);
+    void applyBorderAttributeToStyle(const AtomicString&, MutableStylePropertySet*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+    unsigned parseBorderWidthAttribute(const AtomicString&) const;
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+    void calculateAndAdjustDirectionality();
+
+private:
+    virtual String nodeName() const OVERRIDE FINAL;
+
+    void mapLanguageAttributeToLocale(const AtomicString&, MutableStylePropertySet*);
+
+    virtual HTMLFormElement* virtualForm() const;
+
+    Node* insertAdjacent(const String& where, Node* newChild, ExceptionCode&);
+    PassRefPtr<DocumentFragment> textToFragment(const String&, ExceptionCode&);
+
+    void dirAttributeChanged(const AtomicString&);
+    void adjustDirectionalityIfNeededAfterChildAttributeChanged(Element* child);
+    TextDirection directionality(Node** strongDirectionalityTextNode= 0) const;
+
+    TranslateAttributeMode translateAttributeMode() const;
+
+    AtomicString eventNameForAttributeName(const QualifiedName& attrName) const;
+};
+
+inline HTMLElement* toHTMLElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isHTMLElement());
+    return static_cast<HTMLElement*>(node);
+}
+
+inline const HTMLElement* toHTMLElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isHTMLElement());
+    return static_cast<const HTMLElement*>(node);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toHTMLElement(const HTMLElement*);
+
+inline HTMLElement::HTMLElement(const QualifiedName& tagName, Document* document, ConstructionType type = CreateHTMLElement)
+    : StyledElement(tagName, document, type)
+{
+    ASSERT(tagName.localName().impl());
+    ScriptWrappable::init(this);
+}
+
+} // namespace WebCore
+
+#endif // HTMLElement_h
diff --git a/Source/core/html/HTMLElement.idl b/Source/core/html/HTMLElement.idl
new file mode 100644
index 0000000..78e4a5e
--- /dev/null
+++ b/Source/core/html/HTMLElement.idl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomToV8,
+    SkipVTableValidation
+] interface HTMLElement : Element {
+             // iht.com relies on id returning the empty string when no id is present. 
+             // Other browsers do this as well. So we don't convert null to JS null.
+             [Reflect] attribute DOMString id;
+             [Reflect] attribute DOMString title;
+             [Reflect] attribute DOMString lang;
+             attribute boolean             translate;
+             [Reflect] attribute DOMString dir;
+
+             attribute long              tabIndex;
+             attribute boolean           draggable;
+             [Reflect] attribute DOMString webkitdropzone;
+             [Reflect] attribute boolean hidden;
+             [Reflect] attribute DOMString accessKey;
+
+    // Extensions
+             [TreatNullAs=NullString, DeliverCustomElementCallbacks, SetterRaisesException] attribute DOMString innerHTML;
+             [TreatNullAs=NullString, SetterRaisesException] attribute DOMString innerText;
+             [TreatNullAs=NullString, DeliverCustomElementCallbacks, SetterRaisesException] attribute DOMString outerHTML;
+             [TreatNullAs=NullString, SetterRaisesException] attribute DOMString outerText;
+
+    [RaisesException] Element insertAdjacentElement([Default=Undefined] optional DOMString where,
+                                  [Default=Undefined] optional Element element);
+    [DeliverCustomElementCallbacks, RaisesException] void insertAdjacentHTML([Default=Undefined] optional DOMString where,
+                            [Default=Undefined] optional DOMString html);
+    [RaisesException] void insertAdjacentText([Default=Undefined] optional DOMString where,
+                            [Default=Undefined] optional DOMString text);
+
+    readonly attribute HTMLCollection children;
+
+             [TreatNullAs=NullString, SetterRaisesException] attribute DOMString contentEditable;
+    readonly attribute boolean isContentEditable;
+
+             attribute boolean spellcheck;
+
+    void click();
+};
+
diff --git a/Source/core/html/HTMLEmbedElement.cpp b/Source/core/html/HTMLEmbedElement.cpp
new file mode 100644
index 0000000..909f822
--- /dev/null
+++ b/Source/core/html/HTMLEmbedElement.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
+ * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLEmbedElement.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLImageLoader.h"
+#include "core/html/HTMLObjectElement.h"
+#include "core/html/PluginDocument.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/page/Frame.h"
+#include "core/page/Settings.h"
+#include "core/rendering/RenderEmbeddedObject.h"
+#include "core/rendering/RenderImage.h"
+#include "core/rendering/RenderWidget.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLEmbedElement::HTMLEmbedElement(const QualifiedName& tagName, Document* document, bool createdByParser)
+    : HTMLPlugInImageElement(tagName, document, createdByParser, ShouldPreferPlugInsForImages)
+{
+    ASSERT(hasTagName(embedTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLEmbedElement> HTMLEmbedElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
+{
+    return adoptRef(new HTMLEmbedElement(tagName, document, createdByParser));
+}
+
+static inline RenderWidget* findWidgetRenderer(const Node* n) 
+{
+    if (!n->renderer())
+        do
+            n = n->parentNode();
+        while (n && !n->hasTagName(objectTag));
+
+    if (n && n->renderer() && n->renderer()->isWidget())
+        return toRenderWidget(n->renderer());
+
+    return 0;
+}
+
+RenderWidget* HTMLEmbedElement::renderWidgetForJSBindings() const
+{
+    document()->updateLayoutIgnorePendingStylesheets();
+    return findWidgetRenderer(this);
+}
+
+bool HTMLEmbedElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == hiddenAttr)
+        return true;
+    return HTMLPlugInImageElement::isPresentationAttribute(name);
+}
+
+void HTMLEmbedElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == hiddenAttr) {
+        if (equalIgnoringCase(value, "yes") || equalIgnoringCase(value, "true")) {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWidth, 0, CSSPrimitiveValue::CSS_PX);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyHeight, 0, CSSPrimitiveValue::CSS_PX);
+        }
+    } else
+        HTMLPlugInImageElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLEmbedElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == typeAttr) {
+        m_serviceType = value.string().lower();
+        size_t pos = m_serviceType.find(";");
+        if (pos != notFound)
+            m_serviceType = m_serviceType.left(pos);
+    } else if (name == codeAttr)
+        m_url = stripLeadingAndTrailingHTMLSpaces(value);
+    else if (name == srcAttr) {
+        m_url = stripLeadingAndTrailingHTMLSpaces(value);
+        if (renderer() && isImageType()) {
+            if (!m_imageLoader)
+                m_imageLoader = adoptPtr(new HTMLImageLoader(this));
+            m_imageLoader->updateFromElementIgnoringPreviousError();
+        }
+    } else
+        HTMLPlugInImageElement::parseAttribute(name, value);
+}
+
+void HTMLEmbedElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues)
+{
+    if (!hasAttributes())
+        return;
+
+    for (unsigned i = 0; i < attributeCount(); ++i) {
+        const Attribute* attribute = attributeItem(i);
+        paramNames.append(attribute->localName().string());
+        paramValues.append(attribute->value().string());
+    }
+}
+
+// FIXME: This should be unified with HTMLObjectElement::updateWidget and
+// moved down into HTMLPluginImageElement.cpp
+void HTMLEmbedElement::updateWidget(PluginCreationOption pluginCreationOption)
+{
+    ASSERT(!renderEmbeddedObject()->showsUnavailablePluginIndicator());
+    ASSERT(needsWidgetUpdate());
+    setNeedsWidgetUpdate(false);
+
+    if (m_url.isEmpty() && m_serviceType.isEmpty())
+        return;
+
+    // Note these pass m_url and m_serviceType to allow better code sharing with
+    // <object> which modifies url and serviceType before calling these.
+    if (!allowedToLoadFrameURL(m_url))
+        return;
+
+    // FIXME: It's sadness that we have this special case here.
+    //        See http://trac.webkit.org/changeset/25128 and
+    //        plugins/netscape-plugin-setwindow-size.html
+    if (pluginCreationOption == CreateOnlyNonNetscapePlugins && wouldLoadAsNetscapePlugin(m_url, m_serviceType)) {
+        // Ensure updateWidget() is called again during layout to create the Netscape plug-in.
+        setNeedsWidgetUpdate(true);
+        return;
+    }
+
+    // FIXME: These should be joined into a PluginParameters class.
+    Vector<String> paramNames;
+    Vector<String> paramValues;
+    parametersForPlugin(paramNames, paramValues);
+
+    RefPtr<HTMLEmbedElement> protect(this); // Loading the plugin might remove us from the document.
+    bool beforeLoadAllowedLoad = dispatchBeforeLoadEvent(m_url);
+    if (!beforeLoadAllowedLoad) {
+        if (document()->isPluginDocument()) {
+            // Plugins inside plugin documents load differently than other plugins. By the time
+            // we are here in a plugin document, the load of the plugin (which is the plugin document's
+            // main resource) has already started. We need to explicitly cancel the main resource load here.
+            toPluginDocument(document())->cancelManualPluginLoad();
+        }
+        return;
+    }
+    if (!renderer()) // Do not load the plugin if beforeload removed this element or its renderer.
+        return;
+
+    SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
+    // FIXME: beforeLoad could have detached the renderer!  Just like in the <object> case above.
+    loader->requestObject(this, m_url, getNameAttribute(), m_serviceType, paramNames, paramValues);
+}
+
+bool HTMLEmbedElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    if (isImageType())
+        return HTMLPlugInImageElement::rendererIsNeeded(context);
+
+    Frame* frame = document()->frame();
+    if (!frame)
+        return false;
+
+    // If my parent is an <object> and is not set to use fallback content, I
+    // should be ignored and not get a renderer.
+    ContainerNode* p = parentNode();
+    if (p && p->hasTagName(objectTag)) {
+        ASSERT(p->renderer());
+        if (!static_cast<HTMLObjectElement*>(p)->useFallbackContent()) {
+            ASSERT(!p->renderer()->isEmbeddedObject());
+            return false;
+        }
+    }
+    return HTMLPlugInImageElement::rendererIsNeeded(context);
+}
+
+bool HTMLEmbedElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == srcAttr || HTMLPlugInImageElement::isURLAttribute(attribute);
+}
+
+const AtomicString& HTMLEmbedElement::imageSourceURL() const
+{
+    return getAttribute(srcAttr);
+}
+
+void HTMLEmbedElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
+
+    addSubresourceURL(urls, document()->completeURL(getAttribute(srcAttr)));
+}
+
+}
diff --git a/Source/core/html/HTMLEmbedElement.h b/Source/core/html/HTMLEmbedElement.h
new file mode 100644
index 0000000..a5acdc8
--- /dev/null
+++ b/Source/core/html/HTMLEmbedElement.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2006, 2008, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLEmbedElement_h
+#define HTMLEmbedElement_h
+
+#include "core/html/HTMLPlugInImageElement.h"
+
+namespace WebCore {
+
+class HTMLEmbedElement FINAL : public HTMLPlugInImageElement {
+public:
+    static PassRefPtr<HTMLEmbedElement> create(const QualifiedName&, Document*, bool createdByParser);
+
+private:
+    HTMLEmbedElement(const QualifiedName&, Document*, bool createdByParser);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+    virtual const AtomicString& imageSourceURL() const OVERRIDE;
+
+    virtual RenderWidget* renderWidgetForJSBindings() const;
+
+    virtual void updateWidget(PluginCreationOption);
+
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+
+    void parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues);
+
+    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return true; }
+};
+
+}
+
+#endif
diff --git a/Source/core/html/HTMLEmbedElement.idl b/Source/core/html/HTMLEmbedElement.idl
new file mode 100644
index 0000000..b702089
--- /dev/null
+++ b/Source/core/html/HTMLEmbedElement.idl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomNamedGetter,
+    CustomNamedSetter,
+    CustomCall,
+    CustomIndexedGetter,
+    CustomIndexedSetter,
+    SkipVTableValidation
+] interface HTMLEmbedElement : HTMLElement {
+[Reflect] attribute DOMString align;
+[Reflect] attribute DOMString height;
+[Reflect] attribute DOMString name;
+[Reflect, URL] attribute DOMString src;
+[Reflect] attribute DOMString type;
+[Reflect] attribute DOMString width;
+
+#if defined(ENABLE_SVG) && ENABLE_SVG
+[CheckSecurityForNode, RaisesException] SVGDocument getSVGDocument();
+#endif
+};
+
diff --git a/Source/core/html/HTMLFieldSetElement.cpp b/Source/core/html/HTMLFieldSetElement.cpp
new file mode 100644
index 0000000..d441041
--- /dev/null
+++ b/Source/core/html/HTMLFieldSetElement.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLFieldSetElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/html/HTMLCollection.h"
+#include "core/html/HTMLLegendElement.h"
+#include "core/html/HTMLObjectElement.h"
+#include "core/rendering/RenderFieldset.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLFieldSetElement::HTMLFieldSetElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+    : HTMLFormControlElement(tagName, document, form)
+    , m_documentVersion(0)
+{
+    ASSERT(hasTagName(fieldsetTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLFieldSetElement> HTMLFieldSetElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+{
+    return adoptRef(new HTMLFieldSetElement(tagName, document, form));
+}
+
+void HTMLFieldSetElement::invalidateDisabledStateUnder(Element* base)
+{
+    for (Element* element = ElementTraversal::firstWithin(base); element; element = ElementTraversal::next(element, base)) {
+        if (element->isFormControlElement())
+            static_cast<HTMLFormControlElement*>(element)->ancestorDisabledStateWasChanged();
+    }
+}
+
+void HTMLFieldSetElement::disabledAttributeChanged()
+{
+    // This element must be updated before the style of nodes in its subtree gets recalculated.
+    HTMLFormControlElement::disabledAttributeChanged();
+    invalidateDisabledStateUnder(this);
+}
+
+void HTMLFieldSetElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    HTMLFormControlElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+    for (Element* element = ElementTraversal::firstWithin(this); element; element = ElementTraversal::nextSkippingChildren(element, this)) {
+        if (element->hasTagName(legendTag))
+            invalidateDisabledStateUnder(element);
+    }
+}
+
+bool HTMLFieldSetElement::supportsFocus() const
+{
+    return HTMLElement::supportsFocus();
+}
+
+const AtomicString& HTMLFieldSetElement::formControlType() const
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, fieldset, ("fieldset", AtomicString::ConstructFromLiteral));
+    return fieldset;
+}
+
+RenderObject* HTMLFieldSetElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderFieldset(this);
+}
+
+HTMLLegendElement* HTMLFieldSetElement::legend() const
+{
+    for (Element* child = ElementTraversal::firstWithin(this); child; child = ElementTraversal::nextSkippingChildren(child, this)) {
+        if (child->hasTagName(legendTag))
+            return static_cast<HTMLLegendElement*>(child);
+    }
+    return 0;
+}
+
+PassRefPtr<HTMLCollection> HTMLFieldSetElement::elements()
+{
+    return ensureCachedHTMLCollection(FormControls);
+}
+
+void HTMLFieldSetElement::refreshElementsIfNeeded() const
+{
+    uint64_t docVersion = document()->domTreeVersion();
+    if (m_documentVersion == docVersion)
+        return;
+
+    m_documentVersion = docVersion;
+
+    m_associatedElements.clear();
+
+    for (Element* element = ElementTraversal::firstWithin(this); element; element = ElementTraversal::next(element, this)) {
+        if (element->hasTagName(objectTag)) {
+            m_associatedElements.append(static_cast<HTMLObjectElement*>(element));
+            continue;
+        }
+
+        if (!element->isFormControlElement())
+            continue;
+
+        m_associatedElements.append(static_cast<HTMLFormControlElement*>(element));
+    }
+}
+
+const Vector<FormAssociatedElement*>& HTMLFieldSetElement::associatedElements() const
+{
+    refreshElementsIfNeeded();
+    return m_associatedElements;
+}
+
+unsigned HTMLFieldSetElement::length() const
+{
+    refreshElementsIfNeeded();
+    unsigned len = 0;
+    for (unsigned i = 0; i < m_associatedElements.size(); ++i)
+        if (m_associatedElements[i]->isEnumeratable())
+            ++len;
+    return len;
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLFieldSetElement.h b/Source/core/html/HTMLFieldSetElement.h
new file mode 100644
index 0000000..587f2fe
--- /dev/null
+++ b/Source/core/html/HTMLFieldSetElement.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFieldSetElement_h
+#define HTMLFieldSetElement_h
+
+#include "core/html/HTMLFormControlElement.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class FormAssociatedElement;
+class HTMLCollection;
+
+class HTMLFieldSetElement FINAL : public HTMLFormControlElement {
+public:
+    static PassRefPtr<HTMLFieldSetElement> create(const QualifiedName&, Document*, HTMLFormElement*);
+    HTMLLegendElement* legend() const;
+
+    PassRefPtr<HTMLCollection> elements();
+
+    const Vector<FormAssociatedElement*>& associatedElements() const;
+    unsigned length() const;
+
+protected:
+    virtual void disabledAttributeChanged() OVERRIDE;
+
+private:
+    HTMLFieldSetElement(const QualifiedName&, Document*, HTMLFormElement*);
+
+    virtual bool isEnumeratable() const { return true; }
+    virtual bool supportsFocus() const;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual const AtomicString& formControlType() const;
+    virtual bool recalcWillValidate() const { return false; }
+    virtual void childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) OVERRIDE;
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+
+    static void invalidateDisabledStateUnder(Element*);
+    void refreshElementsIfNeeded() const;
+
+    mutable Vector<FormAssociatedElement*> m_associatedElements;
+    // When dom tree is modified, we have to refresh the m_associatedElements array.
+    mutable uint64_t m_documentVersion;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLFieldSetElement.idl b/Source/core/html/HTMLFieldSetElement.idl
new file mode 100644
index 0000000..4e77da9
--- /dev/null
+++ b/Source/core/html/HTMLFieldSetElement.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLFieldSetElement : HTMLElement {
+    [Reflect] attribute boolean disabled;
+    readonly attribute HTMLFormElement form;
+    [Reflect] attribute DOMString name;
+
+    readonly attribute DOMString type;
+
+    readonly attribute HTMLCollection elements;
+
+    readonly attribute boolean         willValidate;
+    readonly attribute ValidityState   validity;
+    readonly attribute DOMString       validationMessage;
+    boolean  checkValidity();
+    void     setCustomValidity([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString error);
+};
diff --git a/Source/core/html/HTMLFontElement.cpp b/Source/core/html/HTMLFontElement.cpp
new file mode 100644
index 0000000..f15a943
--- /dev/null
+++ b/Source/core/html/HTMLFontElement.cpp
@@ -0,0 +1,205 @@
+/*
+ * 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, 2008, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLFontElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/css/CSSStyleSheet.h"
+#include "core/css/CSSValueList.h"
+#include "core/css/CSSValuePool.h"
+#include "core/css/StylePropertySet.h"
+#include "core/dom/Attribute.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include <wtf/text/StringBuilder.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLFontElement::HTMLFontElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(fontTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLFontElement> HTMLFontElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLFontElement(tagName, document));
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#fonts-and-colors
+template <typename CharacterType>
+static bool parseFontSize(const CharacterType* characters, unsigned length, int& size)
+{
+
+    // Step 1
+    // Step 2
+    const CharacterType* position = characters;
+    const CharacterType* end = characters + length;
+
+    // Step 3
+    while (position < end) {
+        if (!isHTMLSpace(*position))
+            break;
+        ++position;
+    }
+
+    // Step 4
+    if (position == end)
+        return false;
+    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;
+    }
+
+    // Step 6
+    StringBuilder digits;
+    digits.reserveCapacity(16);
+    while (position < end) {
+        if (!isASCIIDigit(*position))
+            break;
+        digits.append(*position++);
+    }
+
+    // Step 7
+    if (digits.isEmpty())
+        return false;
+
+    // Step 8
+    int value;
+
+    if (digits.is8Bit())
+        value = charactersToIntStrict(digits.characters8(), digits.length());
+    else
+        value = charactersToIntStrict(digits.characters16(), digits.length());
+
+    // 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;
+}
+
+static bool parseFontSize(const String& input, int& size)
+{
+    if (input.isEmpty())
+        return false;
+
+    if (input.is8Bit())
+        return parseFontSize(input.characters8(), input.length(), size);
+
+    return parseFontSize(input.characters16(), input.length(), size);
+}
+
+bool HTMLFontElement::cssValueFromFontSizeNumber(const String& s, int& size)
+{
+    int num = 0;
+    if (!parseFontSize(s, num))
+        return false;
+
+    switch (num) {
+    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;
+}
+
+bool HTMLFontElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == sizeAttr || name == colorAttr || name == faceAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLFontElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == sizeAttr) {
+        int size = 0;
+        if (cssValueFromFontSizeNumber(value, size))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyFontSize, size);
+    } else if (name == colorAttr)
+        addHTMLColorToStyle(style, CSSPropertyColor, value);
+    else if (name == faceAttr) {
+        if (RefPtr<CSSValueList> fontFaceValue = cssValuePool().createFontFaceValue(value))
+            style->setProperty(CSSProperty(CSSPropertyFontFamily, fontFaceValue.release()));
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+}
diff --git a/Source/core/html/HTMLFontElement.h b/Source/core/html/HTMLFontElement.h
new file mode 100644
index 0000000..12ddc99
--- /dev/null
+++ b/Source/core/html/HTMLFontElement.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFontElement_h
+#define HTMLFontElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLFontElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLFontElement> create(const QualifiedName&, Document*);
+    
+    static bool cssValueFromFontSizeNumber(const String&, int&);
+
+private:
+    HTMLFontElement(const QualifiedName&, Document*);
+
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLFontElement.idl b/Source/core/html/HTMLFontElement.idl
new file mode 100644
index 0000000..d2da3a9
--- /dev/null
+++ b/Source/core/html/HTMLFontElement.idl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLFontElement : HTMLElement {
+    [Reflect] attribute DOMString color;
+    [Reflect] attribute DOMString face;
+    [Reflect] attribute DOMString size;
+};
+
diff --git a/Source/core/html/HTMLFormControlElement.cpp b/Source/core/html/HTMLFormControlElement.cpp
new file mode 100644
index 0000000..b121575
--- /dev/null
+++ b/Source/core/html/HTMLFormControlElement.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLFormControlElement.h"
+
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/html/HTMLFieldSetElement.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLLegendElement.h"
+#include "core/html/ValidationMessage.h"
+#include "core/html/ValidityState.h"
+#include "core/page/EventHandler.h"
+#include "core/page/Frame.h"
+#include "core/page/UseCounter.h"
+#include "core/rendering/RenderBox.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace std;
+
+HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+    : LabelableElement(tagName, document)
+    , m_disabled(false)
+    , m_isReadOnly(false)
+    , m_isRequired(false)
+    , m_valueMatchesRenderer(false)
+    , m_ancestorDisabledState(AncestorDisabledStateUnknown)
+    , m_dataListAncestorState(Unknown)
+    , m_willValidateInitialized(false)
+    , m_willValidate(true)
+    , m_isValid(true)
+    , m_wasChangedSinceLastFormControlChangeEvent(false)
+    , m_hasAutofocused(false)
+{
+    setForm(form ? form : findFormAncestor());
+    setHasCustomStyleCallbacks();
+}
+
+HTMLFormControlElement::~HTMLFormControlElement()
+{
+}
+
+String HTMLFormControlElement::formEnctype() const
+{
+    const AtomicString& formEnctypeAttr = fastGetAttribute(formenctypeAttr);
+    if (formEnctypeAttr.isNull())
+        return emptyString();
+    return FormSubmission::Attributes::parseEncodingType(formEnctypeAttr);
+}
+
+void HTMLFormControlElement::setFormEnctype(const String& value)
+{
+    setAttribute(formenctypeAttr, value);
+}
+
+String HTMLFormControlElement::formMethod() const
+{
+    const AtomicString& formMethodAttr = fastGetAttribute(formmethodAttr);
+    if (formMethodAttr.isNull())
+        return emptyString();
+    return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(formMethodAttr));
+}
+
+void HTMLFormControlElement::setFormMethod(const String& value)
+{
+    setAttribute(formmethodAttr, value);
+}
+
+bool HTMLFormControlElement::formNoValidate() const
+{
+    return fastHasAttribute(formnovalidateAttr);
+}
+
+void HTMLFormControlElement::updateAncestorDisabledState() const
+{
+    HTMLFieldSetElement* fieldSetAncestor = 0;
+    ContainerNode* legendAncestor = 0;
+    for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
+        if (!legendAncestor && ancestor->hasTagName(legendTag))
+            legendAncestor = ancestor;
+        if (ancestor->hasTagName(fieldsetTag)) {
+            fieldSetAncestor = static_cast<HTMLFieldSetElement*>(ancestor);
+            break;
+        }
+    }
+    m_ancestorDisabledState = (fieldSetAncestor && fieldSetAncestor->isDisabledFormControl() && !(legendAncestor && legendAncestor == fieldSetAncestor->legend())) ? AncestorDisabledStateDisabled : AncestorDisabledStateEnabled;
+}
+
+void HTMLFormControlElement::ancestorDisabledStateWasChanged()
+{
+    m_ancestorDisabledState = AncestorDisabledStateUnknown;
+    disabledAttributeChanged();
+}
+
+void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == formAttr) {
+        formAttributeChanged();
+        UseCounter::count(document(), UseCounter::FormAttribute);
+    } else if (name == disabledAttr) {
+        bool oldDisabled = m_disabled;
+        m_disabled = !value.isNull();
+        if (oldDisabled != m_disabled)
+            disabledAttributeChanged();
+    } else if (name == readonlyAttr) {
+        bool wasReadOnly = m_isReadOnly;
+        m_isReadOnly = !value.isNull();
+        if (wasReadOnly != m_isReadOnly) {
+            setNeedsWillValidateCheck();
+            setNeedsStyleRecalc();
+            if (renderer() && renderer()->style()->hasAppearance())
+                renderer()->theme()->stateChanged(renderer(), ReadOnlyState);
+        }
+    } else if (name == requiredAttr) {
+        bool wasRequired = m_isRequired;
+        m_isRequired = !value.isNull();
+        if (wasRequired != m_isRequired)
+            requiredAttributeChanged();
+        UseCounter::count(document(), UseCounter::RequiredAttribute);
+    } else if (name == autofocusAttr) {
+        HTMLElement::parseAttribute(name, value);
+        UseCounter::count(document(), UseCounter::AutoFocusAttribute);
+    } else
+        HTMLElement::parseAttribute(name, value);
+}
+
+void HTMLFormControlElement::disabledAttributeChanged()
+{
+    setNeedsWillValidateCheck();
+    didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled);
+    if (renderer() && renderer()->style()->hasAppearance())
+        renderer()->theme()->stateChanged(renderer(), EnabledState);
+}
+
+void HTMLFormControlElement::requiredAttributeChanged()
+{
+    setNeedsValidityCheck();
+    // Style recalculation is needed because style selectors may include
+    // :required and :optional pseudo-classes.
+    setNeedsStyleRecalc();
+}
+
+static bool shouldAutofocus(HTMLFormControlElement* element)
+{
+    if (!element->fastHasAttribute(autofocusAttr))
+        return false;
+    if (!element->renderer())
+        return false;
+    if (element->document()->ignoreAutofocus())
+        return false;
+    if (element->document()->isSandboxed(SandboxAutomaticFeatures)) {
+        // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
+        element->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked autofocusing on a form control because the form's frame is sandboxed and the 'allow-scripts' permission is not set.");
+        return false;
+    }
+    if (element->hasAutofocused())
+        return false;
+
+    // FIXME: Should this set of hasTagName checks be replaced by a
+    // virtual member function?
+    if (element->hasTagName(inputTag))
+        return !static_cast<HTMLInputElement*>(element)->isInputTypeHidden();
+    if (element->hasTagName(selectTag))
+        return true;
+    if (element->hasTagName(keygenTag))
+        return true;
+    if (element->hasTagName(buttonTag))
+        return true;
+    if (element->hasTagName(textareaTag))
+        return true;
+
+    return false;
+}
+
+static void focusPostAttach(Node* element, unsigned)
+{ 
+    toElement(element)->focus(); 
+    element->deref(); 
+}
+
+void HTMLFormControlElement::attach()
+{
+    PostAttachCallbackDisabler disabler(this);
+
+    HTMLElement::attach();
+
+    // The call to updateFromElement() needs to go after the call through
+    // to the base class's attach() because that can sometimes do a close
+    // on the renderer.
+    if (renderer())
+        renderer()->updateFromElement();
+
+    if (shouldAutofocus(this)) {
+        setAutofocused();
+        ref();
+        queuePostAttachCallback(focusPostAttach, this);
+    }
+}
+
+void HTMLFormControlElement::didMoveToNewDocument(Document* oldDocument)
+{
+    FormAssociatedElement::didMoveToNewDocument(oldDocument);
+    HTMLElement::didMoveToNewDocument(oldDocument);
+}
+
+Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode* insertionPoint)
+{
+    m_ancestorDisabledState = AncestorDisabledStateUnknown;
+    m_dataListAncestorState = Unknown;
+    setNeedsWillValidateCheck();
+    HTMLElement::insertedInto(insertionPoint);
+    FormAssociatedElement::insertedInto(insertionPoint);
+    return InsertionDone;
+}
+
+void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint)
+{
+    m_validationMessage = nullptr;
+    m_ancestorDisabledState = AncestorDisabledStateUnknown;
+    m_dataListAncestorState = Unknown;
+    HTMLElement::removedFrom(insertionPoint);
+    FormAssociatedElement::removedFrom(insertionPoint);
+}
+
+bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
+{
+    return m_wasChangedSinceLastFormControlChangeEvent;
+}
+
+void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
+{
+    m_wasChangedSinceLastFormControlChangeEvent = changed;
+}
+
+void HTMLFormControlElement::dispatchFormControlChangeEvent()
+{
+    HTMLElement::dispatchChangeEvent();
+    setChangedSinceLastFormControlChangeEvent(false);
+}
+
+void HTMLFormControlElement::dispatchFormControlInputEvent()
+{
+    setChangedSinceLastFormControlChangeEvent(true);
+    HTMLElement::dispatchInputEvent();
+}
+
+bool HTMLFormControlElement::isDisabledFormControl() const
+{
+    if (m_disabled)
+        return true;
+
+    if (m_ancestorDisabledState == AncestorDisabledStateUnknown)
+        updateAncestorDisabledState();
+    if (m_ancestorDisabledState == AncestorDisabledStateDisabled)
+        return true;
+    return HTMLElement::isDisabledFormControl();
+}
+
+bool HTMLFormControlElement::isRequired() const
+{
+    return m_isRequired;
+}
+
+static void updateFromElementCallback(Node* node, unsigned)
+{
+    ASSERT_ARG(node, node->isElementNode());
+    ASSERT_ARG(node, toElement(node)->isFormControlElement());
+    if (RenderObject* renderer = node->renderer())
+        renderer->updateFromElement();
+}
+
+void HTMLFormControlElement::didRecalcStyle(StyleChange)
+{
+    // updateFromElement() can cause the selection to change, and in turn
+    // trigger synchronous layout, so it must not be called during style recalc.
+    if (renderer())
+        queuePostAttachCallback(updateFromElementCallback, this);
+}
+
+bool HTMLFormControlElement::supportsFocus() const
+{
+    return !isDisabledFormControl();
+}
+
+bool HTMLFormControlElement::isFocusable() const
+{
+    // If there's a renderer, make sure the size isn't empty, but if there's no renderer,
+    // it might still be focusable if it's in a canvas subtree (handled in Node::isFocusable).
+    if (renderer() && (!renderer()->isBox() || toRenderBox(renderer())->size().isEmpty()))
+        return false;
+    // HTMLElement::isFocusable handles visibility and calls suportsFocus which
+    // will cover the disabled case.
+    return HTMLElement::isFocusable();
+}
+
+bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent*) const
+{
+    return isFocusable() && document()->frame();
+}
+
+bool HTMLFormControlElement::isMouseFocusable() const
+{
+    return false;
+}
+
+short HTMLFormControlElement::tabIndex() const
+{
+    // Skip the supportsFocus check in HTMLElement.
+    return Element::tabIndex();
+}
+
+bool HTMLFormControlElement::recalcWillValidate() const
+{
+    if (m_dataListAncestorState == Unknown) {
+        for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
+            if (ancestor->hasTagName(datalistTag)) {
+                m_dataListAncestorState = InsideDataList;
+                break;
+            }
+        }
+        if (m_dataListAncestorState == Unknown)
+            m_dataListAncestorState = NotInsideDataList;
+    }
+    return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly();
+}
+
+bool HTMLFormControlElement::willValidate() const
+{
+    if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) {
+        m_willValidateInitialized = true;
+        bool newWillValidate = recalcWillValidate();
+        if (m_willValidate != newWillValidate) {
+            m_willValidate = newWillValidate;
+            const_cast<HTMLFormControlElement*>(this)->setNeedsValidityCheck();
+        }
+    } else {
+        // If the following assertion fails, setNeedsWillValidateCheck() is not
+        // called correctly when something which changes recalcWillValidate() result
+        // is updated.
+        ASSERT(m_willValidate == recalcWillValidate());
+    }
+    return m_willValidate;
+}
+
+void HTMLFormControlElement::setNeedsWillValidateCheck()
+{
+    // We need to recalculate willValidate immediately because willValidate change can causes style change.
+    bool newWillValidate = recalcWillValidate();
+    if (m_willValidateInitialized && m_willValidate == newWillValidate)
+        return;
+    m_willValidateInitialized = true;
+    m_willValidate = newWillValidate;
+    setNeedsValidityCheck();
+    setNeedsStyleRecalc();
+    if (!m_willValidate)
+        hideVisibleValidationMessage();
+}
+
+void HTMLFormControlElement::updateVisibleValidationMessage()
+{
+    Page* page = document()->page();
+    if (!page)
+        return;
+    String message;
+    if (renderer() && willValidate())
+        message = validationMessage().stripWhiteSpace();
+    if (!m_validationMessage)
+        m_validationMessage = ValidationMessage::create(this);
+    m_validationMessage->updateValidationMessage(message);
+}
+
+void HTMLFormControlElement::hideVisibleValidationMessage()
+{
+    if (m_validationMessage)
+        m_validationMessage->requestToHideMessage();
+}
+
+bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls)
+{
+    if (!willValidate() || isValidFormControlElement())
+        return true;
+    // An event handler can deref this object.
+    RefPtr<HTMLFormControlElement> protector(this);
+    RefPtr<Document> originalDocument(document());
+    bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
+    if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
+        unhandledInvalidControls->append(this);
+    return false;
+}
+
+bool HTMLFormControlElement::isValidFormControlElement()
+{
+    // If the following assertion fails, setNeedsValidityCheck() is not called
+    // correctly when something which changes validity is updated.
+    ASSERT(m_isValid == validity()->valid());
+    return m_isValid;
+}
+
+void HTMLFormControlElement::setNeedsValidityCheck()
+{
+    bool newIsValid = validity()->valid();
+    if (willValidate() && newIsValid != m_isValid) {
+        // Update style for pseudo classes such as :valid :invalid.
+        setNeedsStyleRecalc();
+    }
+    m_isValid = newIsValid;
+
+    // Updates only if this control already has a validtion message.
+    if (m_validationMessage && m_validationMessage->isVisible()) {
+        // Calls updateVisibleValidationMessage() even if m_isValid is not
+        // changed because a validation message can be chagned.
+        updateVisibleValidationMessage();
+    }
+}
+
+void HTMLFormControlElement::setCustomValidity(const String& error)
+{
+    FormAssociatedElement::setCustomValidity(error);
+    setNeedsValidityCheck();
+}
+
+bool HTMLFormControlElement::validationMessageShadowTreeContains(Node* node) const
+{
+    return m_validationMessage && m_validationMessage->shadowTreeContains(node);
+}
+
+void HTMLFormControlElement::dispatchBlurEvent(PassRefPtr<Node> newFocusedNode)
+{
+    HTMLElement::dispatchBlurEvent(newFocusedNode);
+    hideVisibleValidationMessage();
+}
+
+HTMLFormElement* HTMLFormControlElement::virtualForm() const
+{
+    return FormAssociatedElement::form();
+}
+
+bool HTMLFormControlElement::isDefaultButtonForForm() const
+{
+    return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
+}
+
+HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
+{
+    for (; node; node = node->parentNode()) {
+        if (node->isElementNode() && toElement(node)->isFormControlElement())
+            return static_cast<HTMLFormControlElement*>(node);
+    }
+    return 0;
+}
+
+void HTMLFormControlElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
+    LabelableElement::reportMemoryUsage(memoryObjectInfo);
+    info.addMember(m_validationMessage, "validationMessage");
+}
+
+} // namespace Webcore
diff --git a/Source/core/html/HTMLFormControlElement.h b/Source/core/html/HTMLFormControlElement.h
new file mode 100644
index 0000000..b9886d7
--- /dev/null
+++ b/Source/core/html/HTMLFormControlElement.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFormControlElement_h
+#define HTMLFormControlElement_h
+
+#include "core/html/FormAssociatedElement.h"
+#include "core/html/LabelableElement.h"
+
+namespace WebCore {
+
+class FormDataList;
+class HTMLFieldSetElement;
+class HTMLFormElement;
+class HTMLLegendElement;
+class ValidationMessage;
+class ValidityState;
+
+// HTMLFormControlElement is the default implementation of FormAssociatedElement,
+// and form-associated element implementations should use HTMLFormControlElement
+// unless there is a special reason.
+class HTMLFormControlElement : public LabelableElement, public FormAssociatedElement {
+public:
+    virtual ~HTMLFormControlElement();
+
+    HTMLFormElement* form() const { return FormAssociatedElement::form(); }
+
+    String formEnctype() const;
+    void setFormEnctype(const String&);
+    String formMethod() const;
+    void setFormMethod(const String&);
+    bool formNoValidate() const;
+
+    void ancestorDisabledStateWasChanged();
+
+    virtual void reset() { }
+
+    virtual bool formControlValueMatchesRenderer() const { return m_valueMatchesRenderer; }
+    virtual void setFormControlValueMatchesRenderer(bool b) { m_valueMatchesRenderer = b; }
+
+    virtual bool wasChangedSinceLastFormControlChangeEvent() const;
+    virtual void setChangedSinceLastFormControlChangeEvent(bool);
+
+    virtual void dispatchFormControlChangeEvent();
+    virtual void dispatchFormControlInputEvent();
+
+    virtual bool isDisabledFormControl() const OVERRIDE;
+
+    virtual bool isFocusable() const;
+    virtual bool isEnumeratable() const { return false; }
+
+    bool isRequired() const;
+
+    const AtomicString& type() const { return formControlType(); }
+
+    virtual const AtomicString& formControlType() const OVERRIDE = 0;
+
+    virtual bool canTriggerImplicitSubmission() const { return false; }
+
+    // Override in derived classes to get the encoded name=value pair for submitting.
+    // Return true for a successful control (see HTML4-17.13.2).
+    virtual bool appendFormData(FormDataList&, bool) { return false; }
+
+    virtual bool isSuccessfulSubmitButton() const { return false; }
+    virtual bool isActivatedSubmit() const { return false; }
+    virtual void setActivatedSubmit(bool) { }
+
+    virtual bool willValidate() const;
+    void updateVisibleValidationMessage();
+    void hideVisibleValidationMessage();
+    bool checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls = 0);
+    // This must be called when a validation constraint or control value is changed.
+    void setNeedsValidityCheck();
+    virtual void setCustomValidity(const String&) OVERRIDE;
+
+    bool isReadOnly() const { return m_isReadOnly; }
+    bool isDisabledOrReadOnly() const { return isDisabledFormControl() || m_isReadOnly; }
+
+    bool hasAutofocused() { return m_hasAutofocused; }
+    void setAutofocused() { m_hasAutofocused = true; }
+
+    static HTMLFormControlElement* enclosingFormControlElement(Node*);
+
+    using Node::ref;
+    using Node::deref;
+
+    virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+
+protected:
+    HTMLFormControlElement(const QualifiedName& tagName, Document*, HTMLFormElement*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual void requiredAttributeChanged();
+    virtual void disabledAttributeChanged();
+    virtual void attach();
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+
+    virtual bool supportsFocus() const;
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual bool isMouseFocusable() const;
+
+    virtual void didRecalcStyle(StyleChange) OVERRIDE;
+
+    virtual void dispatchBlurEvent(PassRefPtr<Node> newFocusedNode);
+
+    // This must be called any time the result of willValidate() has changed.
+    void setNeedsWillValidateCheck();
+    virtual bool recalcWillValidate() const;
+
+    bool validationMessageShadowTreeContains(Node*) const;
+
+private:
+    virtual void refFormAssociatedElement() { ref(); }
+    virtual void derefFormAssociatedElement() { deref(); }
+
+    virtual bool isFormControlElement() const { return true; }
+    virtual bool alwaysCreateUserAgentShadowRoot() const OVERRIDE { return true; }
+
+    virtual short tabIndex() const;
+
+    virtual HTMLFormElement* virtualForm() const;
+    virtual bool isDefaultButtonForForm() const;
+    virtual bool isValidFormControlElement();
+    void updateAncestorDisabledState() const;
+
+    OwnPtr<ValidationMessage> m_validationMessage;
+    bool m_disabled : 1;
+    bool m_isReadOnly : 1;
+    bool m_isRequired : 1;
+    bool m_valueMatchesRenderer : 1;
+
+    enum AncestorDisabledState { AncestorDisabledStateUnknown, AncestorDisabledStateEnabled, AncestorDisabledStateDisabled };
+    mutable AncestorDisabledState m_ancestorDisabledState;
+    enum DataListAncestorState { Unknown, InsideDataList, NotInsideDataList };
+    mutable enum DataListAncestorState m_dataListAncestorState;
+
+    // The initial value of m_willValidate depends on the derived class. We can't
+    // initialize it with a virtual function in the constructor. m_willValidate
+    // is not deterministic as long as m_willValidateInitialized is false.
+    mutable bool m_willValidateInitialized: 1;
+    mutable bool m_willValidate : 1;
+
+    // Cache of validity()->valid().
+    // But "candidate for constraint validation" doesn't affect m_isValid.
+    bool m_isValid : 1;
+
+    bool m_wasChangedSinceLastFormControlChangeEvent : 1;
+
+    bool m_hasAutofocused : 1;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLFormControlElementWithState.cpp b/Source/core/html/HTMLFormControlElementWithState.cpp
new file mode 100644
index 0000000..78707c9
--- /dev/null
+++ b/Source/core/html/HTMLFormControlElementWithState.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLFormControlElementWithState.h"
+
+#include "core/html/FormController.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/page/Chrome.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+
+namespace WebCore {
+
+HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
+    : HTMLFormControlElement(tagName, doc, f)
+{
+    document()->formController()->registerFormElementWithState(this);
+}
+
+HTMLFormControlElementWithState::~HTMLFormControlElementWithState()
+{
+    document()->formController()->unregisterFormElementWithState(this);
+}
+
+void HTMLFormControlElementWithState::didMoveToNewDocument(Document* oldDocument)
+{
+    if (oldDocument)
+        oldDocument->formController()->unregisterFormElementWithState(this);
+    document()->formController()->registerFormElementWithState(this);
+    HTMLFormControlElement::didMoveToNewDocument(oldDocument);
+}
+
+bool HTMLFormControlElementWithState::shouldAutocomplete() const
+{
+    if (!form())
+        return true;
+    return form()->shouldAutocomplete();
+}
+
+void HTMLFormControlElementWithState::notifyFormStateChanged()
+{
+    Frame* frame = document()->frame();
+    if (!frame)
+        return;
+
+    if (Page* page = frame->page())
+        page->chrome()->client()->formStateDidChange(this);
+}
+
+bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() const
+{
+    // We don't save/restore control state in a form with autocomplete=off.
+    return attached() && shouldAutocomplete();
+}
+
+FormControlState HTMLFormControlElementWithState::saveFormControlState() const
+{
+    return FormControlState();
+}
+
+void HTMLFormControlElementWithState::finishParsingChildren()
+{
+    HTMLFormControlElement::finishParsingChildren();
+    document()->formController()->restoreControlStateFor(*this);
+}
+
+bool HTMLFormControlElementWithState::isFormControlElementWithState() const
+{
+    return true;
+}
+
+} // namespace Webcore
diff --git a/Source/core/html/HTMLFormControlElementWithState.h b/Source/core/html/HTMLFormControlElementWithState.h
new file mode 100644
index 0000000..f54646d
--- /dev/null
+++ b/Source/core/html/HTMLFormControlElementWithState.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFormControlElementWithState_h
+#define HTMLFormControlElementWithState_h
+
+#include "core/html/HTMLFormControlElement.h"
+
+namespace WebCore {
+
+class FormControlState;
+
+class HTMLFormControlElementWithState : public HTMLFormControlElement {
+public:
+    virtual ~HTMLFormControlElementWithState();
+
+    virtual bool canContainRangeEndPoint() const { return false; }
+
+    virtual bool shouldSaveAndRestoreFormControlState() const;
+    virtual FormControlState saveFormControlState() const;
+    // The specified FormControlState must have at least one string value.
+    virtual void restoreFormControlState(const FormControlState&) { }
+    void notifyFormStateChanged();
+
+protected:
+    HTMLFormControlElementWithState(const QualifiedName& tagName, Document*, HTMLFormElement*);
+
+    virtual bool shouldAutocomplete() const;
+    virtual void finishParsingChildren();
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+    virtual bool isFormControlElementWithState() const OVERRIDE;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLFormControlsCollection.cpp b/Source/core/html/HTMLFormControlsCollection.cpp
new file mode 100644
index 0000000..e4d0793
--- /dev/null
+++ b/Source/core/html/HTMLFormControlsCollection.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010, 2011, 2012 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLFormControlsCollection.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLFieldSetElement.h"
+#include "core/html/HTMLFormControlElement.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLImageElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// Since the collections are to be "live", we have to do the
+// calculation every time if anything has changed.
+
+HTMLFormControlsCollection::HTMLFormControlsCollection(Node* ownerNode)
+    : HTMLCollection(ownerNode, FormControls, OverridesItemAfter)
+{
+    ASSERT(ownerNode->hasTagName(formTag) || ownerNode->hasTagName(fieldsetTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLFormControlsCollection> HTMLFormControlsCollection::create(Node* ownerNode, CollectionType)
+{
+    return adoptRef(new HTMLFormControlsCollection(ownerNode));
+}
+
+HTMLFormControlsCollection::~HTMLFormControlsCollection()
+{
+}
+
+const Vector<FormAssociatedElement*>& HTMLFormControlsCollection::formControlElements() const
+{
+    ASSERT(ownerNode());
+    ASSERT(ownerNode()->hasTagName(formTag) || ownerNode()->hasTagName(fieldsetTag));
+    if (ownerNode()->hasTagName(formTag))
+        return static_cast<HTMLFormElement*>(ownerNode())->associatedElements();
+    return static_cast<HTMLFieldSetElement*>(ownerNode())->associatedElements();
+}
+
+const Vector<HTMLImageElement*>& HTMLFormControlsCollection::formImageElements() const
+{
+    ASSERT(ownerNode());
+    ASSERT(ownerNode()->hasTagName(formTag));
+    return static_cast<HTMLFormElement*>(ownerNode())->imageElements();
+}
+
+Element* HTMLFormControlsCollection::virtualItemAfter(unsigned& offset, Element* previousItem) const
+{
+    const Vector<FormAssociatedElement*>& elementsArray = formControlElements();
+    if (previousItem)
+        offset++;
+    while (offset < elementsArray.size()) {
+        FormAssociatedElement* element = elementsArray[offset];
+        if (element->isEnumeratable())
+            return toHTMLElement(element);
+        offset++;
+    }
+    return 0;
+}
+
+static HTMLElement* firstNamedItem(const Vector<FormAssociatedElement*>& elementsArray,
+    const Vector<HTMLImageElement*>* imageElementsArray, const QualifiedName& attrName, const String& name)
+{
+    ASSERT(attrName == idAttr || attrName == nameAttr);
+
+    for (unsigned i = 0; i < elementsArray.size(); ++i) {
+        HTMLElement* element = toHTMLElement(elementsArray[i]);
+        if (elementsArray[i]->isEnumeratable() && element->fastGetAttribute(attrName) == name)
+            return element;
+    }
+
+    if (!imageElementsArray)
+        return 0;
+
+    for (unsigned i = 0; i < imageElementsArray->size(); ++i) {
+        HTMLImageElement* element = (*imageElementsArray)[i];
+        if (element->fastGetAttribute(attrName) == name)
+            return element;
+    }
+
+    return 0;
+}
+
+Node* HTMLFormControlsCollection::namedItem(const AtomicString& name) const
+{
+    // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp
+    // This method first searches for an object with a matching id
+    // attribute. If a match is not found, the method then searches for an
+    // object with a matching name attribute, but only on those elements
+    // that are allowed a name attribute.
+    const Vector<HTMLImageElement*>* imagesElements = ownerNode()->hasTagName(fieldsetTag) ? 0 : &formImageElements();
+    if (HTMLElement* item = firstNamedItem(formControlElements(), imagesElements, idAttr, name))
+        return item;
+
+    return firstNamedItem(formControlElements(), imagesElements, nameAttr, name);
+}
+
+void HTMLFormControlsCollection::updateNameCache() const
+{
+    if (hasNameCache())
+        return;
+
+    HashSet<AtomicStringImpl*> foundInputElements;
+
+    const Vector<FormAssociatedElement*>& elementsArray = formControlElements();
+
+    for (unsigned i = 0; i < elementsArray.size(); ++i) {
+        FormAssociatedElement* associatedElement = elementsArray[i];
+        if (associatedElement->isEnumeratable()) {
+            HTMLElement* element = toHTMLElement(associatedElement);
+            const AtomicString& idAttrVal = element->getIdAttribute();
+            const AtomicString& nameAttrVal = element->getNameAttribute();
+            if (!idAttrVal.isEmpty()) {
+                appendIdCache(idAttrVal, element);
+                foundInputElements.add(idAttrVal.impl());
+            }
+            if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal) {
+                appendNameCache(nameAttrVal, element);
+                foundInputElements.add(nameAttrVal.impl());
+            }
+        }
+    }
+
+    if (ownerNode()->hasTagName(formTag)) {
+        const Vector<HTMLImageElement*>& imageElementsArray = formImageElements();
+        for (unsigned i = 0; i < imageElementsArray.size(); ++i) {
+            HTMLImageElement* element = imageElementsArray[i];
+            const AtomicString& idAttrVal = element->getIdAttribute();
+            const AtomicString& nameAttrVal = element->getNameAttribute();
+            if (!idAttrVal.isEmpty() && !foundInputElements.contains(idAttrVal.impl()))
+                appendIdCache(idAttrVal, element);
+            if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && !foundInputElements.contains(nameAttrVal.impl()))
+                appendNameCache(nameAttrVal, element);
+        }
+    }
+
+    setHasNameCache();
+}
+
+}
diff --git a/Source/core/html/HTMLFormControlsCollection.h b/Source/core/html/HTMLFormControlsCollection.h
new file mode 100644
index 0000000..022b0eb
--- /dev/null
+++ b/Source/core/html/HTMLFormControlsCollection.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFormControlsCollection_h
+#define HTMLFormControlsCollection_h
+
+#include "core/html/HTMLCollection.h"
+
+namespace WebCore {
+
+class FormAssociatedElement;
+class HTMLElement;
+class HTMLImageElement;
+class QualifiedName;
+
+// This class is just a big hack to find form elements even in malformed HTML elements.
+// The famous <table><tr><form><td> problem.
+
+class HTMLFormControlsCollection : public HTMLCollection {
+public:
+    static PassRefPtr<HTMLFormControlsCollection> create(Node*, CollectionType);
+
+    virtual ~HTMLFormControlsCollection();
+
+    virtual Node* namedItem(const AtomicString& name) const;
+
+private:
+    HTMLFormControlsCollection(Node*);
+
+    virtual void updateNameCache() const;
+
+    const Vector<FormAssociatedElement*>& formControlElements() const;
+    const Vector<HTMLImageElement*>& formImageElements() const;
+    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLFormControlsCollection.idl b/Source/core/html/HTMLFormControlsCollection.idl
new file mode 100644
index 0000000..e590abf
--- /dev/null
+++ b/Source/core/html/HTMLFormControlsCollection.idl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2006, 2007, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomNamedGetter,
+    GenerateIsReachable=ImplOwnerNodeRoot,
+    DependentLifetime,
+] interface HTMLFormControlsCollection : HTMLCollection {
+    [Custom] Node namedItem([Default=Undefined] optional DOMString name);
+};
diff --git a/Source/core/html/HTMLFormElement.cpp b/Source/core/html/HTMLFormElement.cpp
new file mode 100644
index 0000000..f4b7a3f
--- /dev/null
+++ b/Source/core/html/HTMLFormElement.cpp
@@ -0,0 +1,711 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLFormElement.h"
+
+#include <limits>
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/AutocompleteErrorEvent.h"
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/fileapi/FileList.h"
+#include "core/html/DOMFormData.h"
+#include "core/html/FormController.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLCollection.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLImageElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/ValidityState.h"
+#include "core/loader/FormState.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/platform/FileSystem.h"
+#include "core/platform/MIMETypeRegistry.h"
+#include "core/platform/network/FormData.h"
+#include "core/rendering/RenderTextControl.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_associatedElementsBeforeIndex(0)
+    , m_associatedElementsAfterIndex(0)
+    , m_wasUserSubmitted(false)
+    , m_isSubmittingOrPreparingForSubmission(false)
+    , m_shouldSubmit(false)
+    , m_isInResetFunction(false)
+    , m_wasDemoted(false)
+    , m_requestAutocompleteTimer(this, &HTMLFormElement::requestAutocompleteTimerFired)
+{
+    ASSERT(hasTagName(formTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document)
+{
+    return adoptRef(new HTMLFormElement(formTag, document));
+}
+
+PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLFormElement(tagName, document));
+}
+
+HTMLFormElement::~HTMLFormElement()
+{
+    document()->formController()->willDeleteForm(this);
+
+    for (unsigned i = 0; i < m_associatedElements.size(); ++i)
+        m_associatedElements[i]->formWillBeDestroyed();
+    for (unsigned i = 0; i < m_imageElements.size(); ++i)
+        m_imageElements[i]->m_form = 0;
+}
+
+bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
+{
+    return document()->completeURL(url).protocolIs("https");
+}
+
+bool HTMLFormElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    if (!m_wasDemoted)
+        return HTMLElement::rendererIsNeeded(context);
+
+    ContainerNode* node = parentNode();
+    RenderObject* parentRenderer = node->renderer();
+    // FIXME: Shouldn't we also check for table caption (see |formIsTablePart| below).
+    bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag))
+        || (parentRenderer->isTableRow() && node->hasTagName(trTag))
+        || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
+        || (parentRenderer->isRenderTableCol() && node->hasTagName(colTag))
+        || (parentRenderer->isTableCell() && node->hasTagName(trTag));
+
+    if (!parentIsTableElementPart)
+        return true;
+
+    EDisplay display = context.style()->display();
+    bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
+        || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
+        || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
+        || display == TABLE_CAPTION;
+
+    return formIsTablePart;
+}
+
+Node::InsertionNotificationRequest HTMLFormElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+    if (insertionPoint->inDocument())
+        this->document()->didAssociateFormControl(this);
+    return InsertionDone;
+}
+
+static inline Node* findRoot(Node* n)
+{
+    Node* root = n;
+    for (; n; n = n->parentNode())
+        root = n;
+    return root;
+}
+
+void HTMLFormElement::removedFrom(ContainerNode* insertionPoint)
+{
+    Node* root = findRoot(this);
+    Vector<FormAssociatedElement*> associatedElements(m_associatedElements);
+    for (unsigned i = 0; i < associatedElements.size(); ++i)
+        associatedElements[i]->formRemovedFromTree(root);
+    HTMLElement::removedFrom(insertionPoint);
+}
+
+void HTMLFormElement::handleLocalEvents(Event* event)
+{
+    Node* targetNode = event->target()->toNode();
+    if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
+        event->stopPropagation();
+        return;
+    }
+    HTMLElement::handleLocalEvents(event);
+}
+
+unsigned HTMLFormElement::length() const
+{
+    unsigned len = 0;
+    for (unsigned i = 0; i < m_associatedElements.size(); ++i)
+        if (m_associatedElements[i]->isEnumeratable())
+            ++len;
+    return len;
+}
+
+Node* HTMLFormElement::item(unsigned index)
+{
+    return elements()->item(index);
+}
+
+void HTMLFormElement::submitImplicitly(Event* event, bool fromImplicitSubmissionTrigger)
+{
+    int submissionTriggerCount = 0;
+    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
+        FormAssociatedElement* formAssociatedElement = m_associatedElements[i];
+        if (!formAssociatedElement->isFormControlElement())
+            continue;
+        HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(formAssociatedElement);
+        if (formElement->isSuccessfulSubmitButton()) {
+            if (formElement->renderer()) {
+                formElement->dispatchSimulatedClick(event);
+                return;
+            }
+        } else if (formElement->canTriggerImplicitSubmission())
+            ++submissionTriggerCount;
+    }
+    if (fromImplicitSubmissionTrigger && submissionTriggerCount == 1)
+        prepareForSubmission(event);
+}
+
+static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
+{
+    for (Node* node = event->target()->toNode(); node; node = node->parentNode()) {
+        if (node->isElementNode() && toElement(node)->isFormControlElement())
+            return static_cast<HTMLFormControlElement*>(node);
+    }
+    return 0;
+}
+
+bool HTMLFormElement::validateInteractively(Event* event)
+{
+    ASSERT(event);
+    if (!document()->page() || !document()->page()->settings()->interactiveFormValidationEnabled() || noValidate())
+        return true;
+
+    HTMLFormControlElement* submitElement = submitElementFromEvent(event);
+    if (submitElement && submitElement->formNoValidate())
+        return true;
+
+    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
+        if (m_associatedElements[i]->isFormControlElement())
+            static_cast<HTMLFormControlElement*>(m_associatedElements[i])->hideVisibleValidationMessage();
+    }
+
+    Vector<RefPtr<FormAssociatedElement> > unhandledInvalidControls;
+    if (!checkInvalidControlsAndCollectUnhandled(unhandledInvalidControls))
+        return true;
+    // Because the form has invalid controls, we abort the form submission and
+    // show a validation message on a focusable form control.
+
+    // Needs to update layout now because we'd like to call isFocusable(), which
+    // has !renderer()->needsLayout() assertion.
+    document()->updateLayoutIgnorePendingStylesheets();
+
+    RefPtr<HTMLFormElement> protector(this);
+    // Focus on the first focusable control and show a validation message.
+    for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
+        FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
+        HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
+        if (unhandled->isFocusable() && unhandled->inDocument()) {
+            unhandled->scrollIntoViewIfNeeded(false);
+            unhandled->focus();
+            if (unhandled->isFormControlElement())
+                static_cast<HTMLFormControlElement*>(unhandled)->updateVisibleValidationMessage();
+            break;
+        }
+    }
+    // Warn about all of unfocusable controls.
+    if (document()->frame()) {
+        for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
+            FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
+            HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
+            if (unhandled->isFocusable() && unhandled->inDocument())
+                continue;
+            String message("An invalid form control with name='%name' is not focusable.");
+            message.replace("%name", unhandledAssociatedElement->name());
+            document()->addConsoleMessage(RenderingMessageSource, ErrorMessageLevel, message);
+        }
+    }
+    return false;
+}
+
+bool HTMLFormElement::prepareForSubmission(Event* event)
+{
+    Frame* frame = document()->frame();
+    if (m_isSubmittingOrPreparingForSubmission || !frame)
+        return m_isSubmittingOrPreparingForSubmission;
+
+    m_isSubmittingOrPreparingForSubmission = true;
+    m_shouldSubmit = false;
+
+    // Interactive validation must be done before dispatching the submit event.
+    if (!validateInteractively(event)) {
+        m_isSubmittingOrPreparingForSubmission = false;
+        return false;
+    }
+
+    StringPairVector controlNamesAndValues;
+    getTextFieldValues(controlNamesAndValues);
+    RefPtr<FormState> formState = FormState::create(this, controlNamesAndValues, document(), NotSubmittedByJavaScript);
+    frame->loader()->client()->dispatchWillSendSubmitEvent(formState.release());
+
+    if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)))
+        m_shouldSubmit = true;
+
+    m_isSubmittingOrPreparingForSubmission = false;
+
+    if (m_shouldSubmit)
+        submit(event, true, true, NotSubmittedByJavaScript);
+
+    return m_shouldSubmit;
+}
+
+void HTMLFormElement::submit()
+{
+    submit(0, false, true, NotSubmittedByJavaScript);
+}
+
+void HTMLFormElement::submitFromJavaScript()
+{
+    submit(0, false, ScriptController::processingUserGesture(), SubmittedByJavaScript);
+}
+
+void HTMLFormElement::getTextFieldValues(StringPairVector& fieldNamesAndValues) const
+{
+    ASSERT_ARG(fieldNamesAndValues, fieldNamesAndValues.isEmpty());
+
+    fieldNamesAndValues.reserveCapacity(m_associatedElements.size());
+    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
+        FormAssociatedElement* control = m_associatedElements[i];
+        HTMLElement* element = toHTMLElement(control);
+        if (!element->hasLocalName(inputTag))
+            continue;
+
+        HTMLInputElement* input = static_cast<HTMLInputElement*>(control);
+        if (!input->isTextField())
+            continue;
+
+        fieldNamesAndValues.append(make_pair(input->name().string(), input->value()));
+    }
+}
+
+void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
+{
+    FrameView* view = document()->view();
+    Frame* frame = document()->frame();
+    if (!view || !frame)
+        return;
+
+    if (m_isSubmittingOrPreparingForSubmission) {
+        m_shouldSubmit = true;
+        return;
+    }
+
+    m_isSubmittingOrPreparingForSubmission = true;
+    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) {
+        FormAssociatedElement* associatedElement = m_associatedElements[i];
+        if (!associatedElement->isFormControlElement())
+            continue;
+        if (needButtonActivation) {
+            HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(associatedElement);
+            if (control->isActivatedSubmit())
+                needButtonActivation = false;
+            else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
+                firstSuccessfulSubmitButton = control;
+        }
+    }
+
+    if (needButtonActivation && firstSuccessfulSubmitButton)
+        firstSuccessfulSubmitButton->setActivatedSubmit(true);
+
+    bool lockHistory = !processingUserGesture;
+    frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, lockHistory, formSubmissionTrigger));
+
+    if (needButtonActivation && firstSuccessfulSubmitButton)
+        firstSuccessfulSubmitButton->setActivatedSubmit(false);
+
+    m_shouldSubmit = false;
+    m_isSubmittingOrPreparingForSubmission = false;
+}
+
+void HTMLFormElement::reset()
+{
+    Frame* frame = document()->frame();
+    if (m_isInResetFunction || !frame)
+        return;
+
+    m_isInResetFunction = true;
+
+    if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
+        m_isInResetFunction = false;
+        return;
+    }
+
+    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
+        if (m_associatedElements[i]->isFormControlElement())
+            static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
+    }
+
+    m_isInResetFunction = false;
+}
+
+void HTMLFormElement::requestAutocomplete()
+{
+    Frame* frame = document()->frame();
+    if (!frame)
+        return;
+
+    if (!shouldAutocomplete() || !ScriptController::processingUserGesture()) {
+        finishRequestAutocomplete(AutocompleteResultErrorDisabled);
+        return;
+    }
+
+    StringPairVector controlNamesAndValues;
+    getTextFieldValues(controlNamesAndValues);
+    RefPtr<FormState> formState = FormState::create(this, controlNamesAndValues, document(), SubmittedByJavaScript);
+    frame->loader()->client()->didRequestAutocomplete(formState.release());
+}
+
+void HTMLFormElement::finishRequestAutocomplete(AutocompleteResult result)
+{
+    RefPtr<Event> event;
+    if (result == AutocompleteResultSuccess)
+        event = Event::create(eventNames().autocompleteEvent, false, false);
+    else if (result == AutocompleteResultErrorDisabled)
+        event = AutocompleteErrorEvent::create("disabled");
+    else if (result == AutocompleteResultErrorCancel)
+        event = AutocompleteErrorEvent::create("cancel");
+    else if (result == AutocompleteResultErrorInvalid)
+        event = AutocompleteErrorEvent::create("invalid");
+
+    event->setTarget(this);
+    m_pendingAutocompleteEvents.append(event.release());
+
+    // Dispatch events later as this API is meant to work asynchronously in all situations and implementations.
+    if (!m_requestAutocompleteTimer.isActive())
+        m_requestAutocompleteTimer.startOneShot(0);
+}
+
+void HTMLFormElement::requestAutocompleteTimerFired(Timer<HTMLFormElement>*)
+{
+    Vector<RefPtr<Event> > pendingEvents;
+    m_pendingAutocompleteEvents.swap(pendingEvents);
+    for (size_t i = 0; i < pendingEvents.size(); ++i)
+        dispatchEvent(pendingEvents[i].release());
+}
+
+void HTMLFormElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == actionAttr)
+        m_attributes.parseAction(value);
+    else if (name == targetAttr)
+        m_attributes.setTarget(value);
+    else if (name == methodAttr)
+        m_attributes.updateMethodType(value);
+    else if (name == enctypeAttr)
+        m_attributes.updateEncodingType(value);
+    else if (name == accept_charsetAttr)
+        m_attributes.setAcceptCharset(value);
+    else if (name == onautocompleteAttr)
+        setAttributeEventListener(eventNames().autocompleteEvent, createAttributeEventListener(this, name, value));
+    else if (name == onautocompleteerrorAttr)
+        setAttributeEventListener(eventNames().autocompleteerrorEvent, createAttributeEventListener(this, name, value));
+    else
+        HTMLElement::parseAttribute(name, value);
+}
+
+template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
+{
+    size_t size = vec.size();
+    for (size_t i = 0; i != size; ++i)
+        if (vec[i] == item) {
+            vec.remove(i);
+            break;
+        }
+}
+
+unsigned HTMLFormElement::formElementIndexWithFormAttribute(Element* element, unsigned rangeStart, unsigned rangeEnd)
+{
+    if (m_associatedElements.isEmpty())
+        return 0;
+
+    ASSERT(rangeStart <= rangeEnd);
+
+    if (rangeStart == rangeEnd)
+        return rangeStart;
+
+    unsigned left = rangeStart;
+    unsigned right = rangeEnd - 1;
+    unsigned short position;
+
+    // Does binary search on m_associatedElements in order to find the index
+    // to be inserted.
+    while (left != right) {
+        unsigned middle = left + ((right - left) / 2);
+        ASSERT(middle < m_associatedElementsBeforeIndex || middle >= m_associatedElementsAfterIndex);
+        position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[middle]));
+        if (position & DOCUMENT_POSITION_FOLLOWING)
+            right = middle;
+        else
+            left = middle + 1;
+    }
+    
+    ASSERT(left < m_associatedElementsBeforeIndex || left >= m_associatedElementsAfterIndex);
+    position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[left]));
+    if (position & DOCUMENT_POSITION_FOLLOWING)
+        return left;
+    return left + 1;
+}
+
+unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElement)
+{
+    HTMLElement* associatedHTMLElement = toHTMLElement(associatedElement);
+    // Treats separately the case where this element has the form attribute
+    // for performance consideration.
+    if (associatedHTMLElement->fastHasAttribute(formAttr)) {
+        unsigned short position = compareDocumentPosition(associatedHTMLElement);
+        if (position & DOCUMENT_POSITION_PRECEDING) {
+            ++m_associatedElementsBeforeIndex;
+            ++m_associatedElementsAfterIndex;
+            return HTMLFormElement::formElementIndexWithFormAttribute(associatedHTMLElement, 0, m_associatedElementsBeforeIndex - 1);
+        }
+        if (position & DOCUMENT_POSITION_FOLLOWING && !(position & DOCUMENT_POSITION_CONTAINED_BY))
+            return HTMLFormElement::formElementIndexWithFormAttribute(associatedHTMLElement, m_associatedElementsAfterIndex, m_associatedElements.size());
+    }
+
+    // Check for the special case where this element is the very last thing in
+    // the form's tree of children; we don't want to walk the entire tree in that
+    // common case that occurs during parsing; instead we'll just return a value
+    // that says "add this form element to the end of the array".
+    if (ElementTraversal::next(associatedHTMLElement, this)) {
+        unsigned i = m_associatedElementsBeforeIndex;
+        for (Element* element = this; element; element = ElementTraversal::next(element, this)) {
+            if (element == associatedHTMLElement) {
+                ++m_associatedElementsAfterIndex;
+                return i;
+            }
+            if (!element->isFormControlElement() && !element->hasTagName(objectTag))
+                continue;
+            if (!element->isHTMLElement() || toHTMLElement(element)->form() != this)
+                continue;
+            ++i;
+        }
+    }
+    return m_associatedElementsAfterIndex++;
+}
+
+void HTMLFormElement::registerFormElement(FormAssociatedElement* e)
+{
+    m_associatedElements.insert(formElementIndex(e), e);
+}
+
+void HTMLFormElement::removeFormElement(FormAssociatedElement* e)
+{
+    unsigned index;
+    for (index = 0; index < m_associatedElements.size(); ++index) {
+        if (m_associatedElements[index] == e)
+            break;
+    }
+    ASSERT_WITH_SECURITY_IMPLICATION(index < m_associatedElements.size());
+    if (index < m_associatedElementsBeforeIndex)
+        --m_associatedElementsBeforeIndex;
+    if (index < m_associatedElementsAfterIndex)
+        --m_associatedElementsAfterIndex;
+    removeFromVector(m_associatedElements, e);
+}
+
+bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+void HTMLFormElement::registerImgElement(HTMLImageElement* e)
+{
+    ASSERT(m_imageElements.find(e) == notFound);
+    m_imageElements.append(e);
+}
+
+void HTMLFormElement::removeImgElement(HTMLImageElement* e)
+{
+    ASSERT(m_imageElements.find(e) != notFound);
+    removeFromVector(m_imageElements, e);
+}
+
+PassRefPtr<HTMLCollection> HTMLFormElement::elements()
+{
+    return ensureCachedHTMLCollection(FormControls);
+}
+
+String HTMLFormElement::name() const
+{
+    return getNameAttribute();
+}
+
+bool HTMLFormElement::noValidate() const
+{
+    return fastHasAttribute(novalidateAttr);
+}
+
+// FIXME: This function should be removed because it does not do the same thing as the
+// JavaScript binding for action, which treats action as a URL attribute. Last time I
+// (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
+String HTMLFormElement::action() const
+{
+    return getAttribute(actionAttr);
+}
+
+void HTMLFormElement::setAction(const String &value)
+{
+    setAttribute(actionAttr, value);
+}
+
+void HTMLFormElement::setEnctype(const String &value)
+{
+    setAttribute(enctypeAttr, value);
+}
+
+String HTMLFormElement::method() const
+{
+    return FormSubmission::Attributes::methodString(m_attributes.method());
+}
+
+void HTMLFormElement::setMethod(const String &value)
+{
+    setAttribute(methodAttr, value);
+}
+
+String HTMLFormElement::target() const
+{
+    return getAttribute(targetAttr);
+}
+
+bool HTMLFormElement::wasUserSubmitted() const
+{
+    return m_wasUserSubmitted;
+}
+
+HTMLFormControlElement* HTMLFormElement::defaultButton() const
+{
+    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
+        if (!m_associatedElements[i]->isFormControlElement())
+            continue;
+        HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(m_associatedElements[i]);
+        if (control->isSuccessfulSubmitButton())
+            return control;
+    }
+
+    return 0;
+}
+
+bool HTMLFormElement::checkValidity()
+{
+    Vector<RefPtr<FormAssociatedElement> > controls;
+    return !checkInvalidControlsAndCollectUnhandled(controls);
+}
+
+bool HTMLFormElement::checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<FormAssociatedElement> >& unhandledInvalidControls)
+{
+    RefPtr<HTMLFormElement> protector(this);
+    // Copy m_associatedElements because event handlers called from
+    // HTMLFormControlElement::checkValidity() might change m_associatedElements.
+    Vector<RefPtr<FormAssociatedElement> > elements;
+    elements.reserveCapacity(m_associatedElements.size());
+    for (unsigned i = 0; i < m_associatedElements.size(); ++i)
+        elements.append(m_associatedElements[i]);
+    bool hasInvalidControls = false;
+    for (unsigned i = 0; i < elements.size(); ++i) {
+        if (elements[i]->form() == this && elements[i]->isFormControlElement()) {
+            HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(elements[i].get());
+            if (!control->checkValidity(&unhandledInvalidControls) && control->form() == this)
+                hasInvalidControls = true;
+        }
+    }
+    return hasInvalidControls;
+}
+
+HTMLFormControlElement* HTMLFormElement::elementForAlias(const AtomicString& alias)
+{
+    if (alias.isEmpty() || !m_elementAliases)
+        return 0;
+    return m_elementAliases->get(alias.impl()).get();
+}
+
+void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
+{
+    if (alias.isEmpty())
+        return;
+    if (!m_elementAliases)
+        m_elementAliases = adoptPtr(new AliasMap);
+    m_elementAliases->set(alias.impl(), element);
+}
+
+void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
+{
+    elements()->namedItems(name, namedItems);
+
+    HTMLFormControlElement* aliasElement = elementForAlias(name);
+    if (aliasElement) {
+        if (namedItems.find(aliasElement) == notFound) {
+            // We have seen it before but it is gone now. Still, we need to return it.
+            // FIXME: The above comment is not clear enough; it does not say why we need to do this.
+            namedItems.append(aliasElement);
+        }
+    }
+    if (namedItems.size() && namedItems.first() != aliasElement)
+        addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
+}
+
+bool HTMLFormElement::shouldAutocomplete() const
+{
+    return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off");
+}
+
+void HTMLFormElement::finishParsingChildren()
+{
+    HTMLElement::finishParsingChildren();
+    document()->formController()->restoreControlStateIn(*this);
+}
+
+void HTMLFormElement::copyNonAttributePropertiesFromElement(const Element& source)
+{
+    m_wasDemoted = static_cast<const HTMLFormElement&>(source).m_wasDemoted;
+    HTMLElement::copyNonAttributePropertiesFromElement(source);
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLFormElement.h b/Source/core/html/HTMLFormElement.h
new file mode 100644
index 0000000..e7b8597
--- /dev/null
+++ b/Source/core/html/HTMLFormElement.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFormElement_h
+#define HTMLFormElement_h
+
+#include "core/dom/CheckedRadioButtons.h"
+#include "core/html/HTMLElement.h"
+#include "core/loader/FormState.h"
+#include "core/loader/FormSubmission.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class Event;
+class FormAssociatedElement;
+class FormData;
+class HTMLFormControlElement;
+class HTMLImageElement;
+class HTMLInputElement;
+class TextEncoding;
+
+class HTMLFormElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLFormElement> create(Document*);
+    static PassRefPtr<HTMLFormElement> create(const QualifiedName&, Document*);
+    virtual ~HTMLFormElement();
+
+    PassRefPtr<HTMLCollection> elements();
+    void getNamedElements(const AtomicString&, Vector<RefPtr<Node> >&);
+
+    unsigned length() const;
+    Node* item(unsigned index);
+
+    String enctype() const { return m_attributes.encodingType(); }
+    void setEnctype(const String&);
+
+    String encoding() const { return m_attributes.encodingType(); }
+    void setEncoding(const String& value) { setEnctype(value); }
+
+    bool shouldAutocomplete() const;
+
+    // FIXME: Should rename these two functions to say "form control" or "form-associated element" instead of "form element".
+    void registerFormElement(FormAssociatedElement*);
+    void removeFormElement(FormAssociatedElement*);
+
+    void registerImgElement(HTMLImageElement*);
+    void removeImgElement(HTMLImageElement*);
+
+    bool prepareForSubmission(Event*);
+    void submit();
+    void submitFromJavaScript();
+    void reset();
+
+    void setDemoted(bool demoted) { m_wasDemoted = demoted; }
+
+    void submitImplicitly(Event*, bool fromImplicitSubmissionTrigger);
+    bool formWouldHaveSecureSubmission(const String& url);
+
+    String name() const;
+
+    bool noValidate() const;
+
+    String acceptCharset() const { return m_attributes.acceptCharset(); }
+    void setAcceptCharset(const String&);
+
+    String action() const;
+    void setAction(const String&);
+
+    String method() const;
+    void setMethod(const String&);
+
+    virtual String target() const;
+
+    bool wasUserSubmitted() const;
+
+    HTMLFormControlElement* defaultButton() const;
+
+    bool checkValidity();
+
+    enum AutocompleteResult {
+        AutocompleteResultSuccess,
+        AutocompleteResultErrorDisabled,
+        AutocompleteResultErrorCancel,
+        AutocompleteResultErrorInvalid,
+    };
+
+    void requestAutocomplete();
+    void finishRequestAutocomplete(AutocompleteResult);
+
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(autocomplete);
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(autocompleteerror);
+
+    HTMLFormControlElement* elementForAlias(const AtomicString&);
+    void addElementAlias(HTMLFormControlElement*, const AtomicString& alias);
+
+    CheckedRadioButtons& checkedRadioButtons() { return m_checkedRadioButtons; }
+
+    const Vector<FormAssociatedElement*>& associatedElements() const { return m_associatedElements; }
+    const Vector<HTMLImageElement*>& imageElements() const { return m_imageElements; }
+
+    void getTextFieldValues(StringPairVector& fieldNamesAndValues) const;
+
+private:
+    HTMLFormElement(const QualifiedName&, Document*);
+
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual void finishParsingChildren() OVERRIDE;
+
+    virtual void handleLocalEvents(Event*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return true; }
+
+    virtual void copyNonAttributePropertiesFromElement(const Element&) OVERRIDE;
+
+    void submit(Event*, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger);
+
+    unsigned formElementIndexWithFormAttribute(Element*, unsigned rangeStart, unsigned rangeEnd);
+    unsigned formElementIndex(FormAssociatedElement*);
+
+    // Returns true if the submission should proceed.
+    bool validateInteractively(Event*);
+
+    // Validates each of the controls, and stores controls of which 'invalid'
+    // event was not canceled to the specified vector. Returns true if there
+    // are any invalid controls in this form.
+    bool checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<FormAssociatedElement> >&);
+
+    typedef HashMap<RefPtr<AtomicStringImpl>, RefPtr<HTMLFormControlElement> > AliasMap;
+
+    FormSubmission::Attributes m_attributes;
+    OwnPtr<AliasMap> m_elementAliases;
+
+    CheckedRadioButtons m_checkedRadioButtons;
+
+    unsigned m_associatedElementsBeforeIndex;
+    unsigned m_associatedElementsAfterIndex;
+    Vector<FormAssociatedElement*> m_associatedElements;
+    Vector<HTMLImageElement*> m_imageElements;
+
+    bool m_wasUserSubmitted;
+    bool m_isSubmittingOrPreparingForSubmission;
+    bool m_shouldSubmit;
+
+    bool m_isInResetFunction;
+
+    bool m_wasDemoted;
+
+    void requestAutocompleteTimerFired(Timer<HTMLFormElement>*);
+
+    Vector<RefPtr<Event> > m_pendingAutocompleteEvents;
+    Timer<HTMLFormElement> m_requestAutocompleteTimer;
+};
+
+} // namespace WebCore
+
+#endif // HTMLFormElement_h
diff --git a/Source/core/html/HTMLFormElement.idl b/Source/core/html/HTMLFormElement.idl
new file mode 100644
index 0000000..fdb1468
--- /dev/null
+++ b/Source/core/html/HTMLFormElement.idl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomIndexedGetter,
+    CustomNamedGetter
+] interface HTMLFormElement : HTMLElement {
+    [Reflect=accept_charset] attribute DOMString acceptCharset;
+    [Reflect, URL] attribute DOMString action;
+    [Reflect] attribute DOMString autocomplete;
+    [TreatNullAs=NullString] attribute DOMString enctype;
+    [TreatNullAs=NullString] attribute DOMString encoding;
+    [TreatNullAs=NullString] attribute DOMString method;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute boolean noValidate;
+    [Reflect] attribute DOMString target;
+
+    readonly attribute HTMLCollection elements;
+    readonly attribute long length;
+
+    [ImplementedAs=submitFromJavaScript] void submit();
+    void reset();
+    boolean checkValidity();
+
+    [EnabledAtRuntime=requestAutocomplete] void requestAutocomplete();
+    [EnabledAtRuntime=requestAutocomplete,NotEnumerable] attribute EventListener onautocomplete;
+    [EnabledAtRuntime=requestAutocomplete,NotEnumerable] attribute EventListener onautocompleteerror;
+};
diff --git a/Source/core/html/HTMLFrameElement.cpp b/Source/core/html/HTMLFrameElement.cpp
new file mode 100644
index 0000000..da978ad
--- /dev/null
+++ b/Source/core/html/HTMLFrameElement.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann (hausmann@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLFrameElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/html/HTMLFrameSetElement.h"
+#include "core/page/Frame.h"
+#include "core/rendering/RenderFrame.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLFrameElement::HTMLFrameElement(const QualifiedName& tagName, Document* document)
+    : HTMLFrameElementBase(tagName, document)
+    , m_frameBorder(true)
+    , m_frameBorderSet(false)
+{
+    ASSERT(hasTagName(frameTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLFrameElement> HTMLFrameElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLFrameElement(tagName, document));
+}
+
+bool HTMLFrameElement::rendererIsNeeded(const NodeRenderingContext&)
+{
+    // For compatibility, frames render even when display: none is set.
+    return isURLAllowed();
+}
+
+RenderObject* HTMLFrameElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderFrame(this);
+}
+
+static inline HTMLFrameSetElement* containingFrameSetElement(Node* node)
+{
+    while ((node = node->parentNode())) {
+        if (node->hasTagName(framesetTag))
+            return static_cast<HTMLFrameSetElement*>(node);
+    }
+    return 0;
+}
+
+bool HTMLFrameElement::noResize() const
+{
+    return hasAttribute(noresizeAttr);
+}
+
+void HTMLFrameElement::attach()
+{
+    HTMLFrameElementBase::attach();
+    
+    if (HTMLFrameSetElement* frameSetElement = containingFrameSetElement(this)) {
+        if (!m_frameBorderSet)
+            m_frameBorder = frameSetElement->hasFrameBorder();
+    }
+}
+
+void HTMLFrameElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == frameborderAttr) {
+        m_frameBorder = value.toInt();
+        m_frameBorderSet = !value.isNull();
+        // FIXME: If we are already attached, this has no effect.
+    } else if (name == noresizeAttr) {
+        if (renderer())
+            renderer()->updateFromElement();
+    } else
+        HTMLFrameElementBase::parseAttribute(name, value);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLFrameElement.h b/Source/core/html/HTMLFrameElement.h
new file mode 100644
index 0000000..b9bf176
--- /dev/null
+++ b/Source/core/html/HTMLFrameElement.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2004, 2006, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFrameElement_h
+#define HTMLFrameElement_h
+
+#include "core/html/HTMLFrameElementBase.h"
+
+namespace WebCore {
+
+class HTMLFrameElement FINAL : public HTMLFrameElementBase {
+public:
+    static PassRefPtr<HTMLFrameElement> create(const QualifiedName&, Document*);
+
+    bool hasFrameBorder() const { return m_frameBorder; }
+
+    bool noResize() const;
+
+private:
+    HTMLFrameElement(const QualifiedName&, Document*);
+
+    virtual void attach();
+
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    virtual bool allowFullScreen() const { return false; }
+
+    bool m_frameBorder;
+    bool m_frameBorderSet;
+};
+
+} // namespace WebCore
+
+#endif // HTMLFrameElement_h
diff --git a/Source/core/html/HTMLFrameElement.idl b/Source/core/html/HTMLFrameElement.idl
new file mode 100644
index 0000000..4991428
--- /dev/null
+++ b/Source/core/html/HTMLFrameElement.idl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLFrameElement : HTMLElement {
+
+    [Reflect] attribute DOMString frameBorder;
+    [Reflect] attribute DOMString longDesc;
+    [Reflect] attribute DOMString marginHeight;
+    [Reflect] attribute DOMString marginWidth;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute boolean noResize;
+    [Reflect] attribute DOMString scrolling;
+    [Reflect, URL] attribute DOMString src;
+
+    // Introduced in DOM Level 2:
+    [CheckSecurityForNode] readonly attribute Document contentDocument;
+
+    // Extensions
+    readonly attribute DOMWindow contentWindow;
+
+#if defined(ENABLE_SVG) && ENABLE_SVG
+    [CheckSecurityForNode, RaisesException] SVGDocument getSVGDocument();
+#endif
+
+    [TreatNullAs=NullString, CustomSetter] attribute DOMString location;
+
+    readonly attribute long width;
+    readonly attribute long height;
+
+};
+
diff --git a/Source/core/html/HTMLFrameElementBase.cpp b/Source/core/html/HTMLFrameElementBase.cpp
new file mode 100644
index 0000000..48c540c
--- /dev/null
+++ b/Source/core/html/HTMLFrameElementBase.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann (hausmann@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 2008, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLFrameElementBase.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/EventNames.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/FrameLoader.h"
+#include "core/page/FocusController.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/platform/KURL.h"
+#include "core/rendering/RenderPart.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Document* document)
+    : HTMLFrameOwnerElement(tagName, document)
+    , m_scrolling(ScrollbarAuto)
+    , m_marginWidth(-1)
+    , m_marginHeight(-1)
+{
+}
+
+bool HTMLFrameElementBase::isURLAllowed() const
+{
+    if (m_URL.isEmpty())
+        return true;
+
+    const KURL& completeURL = document()->completeURL(m_URL);
+
+    if (protocolIsJavaScript(completeURL)) { 
+        Document* contentDoc = this->contentDocument();
+        if (contentDoc && !ScriptController::canAccessFromCurrentOrigin(contentDoc->frame()))
+            return false;
+    }
+
+    Frame* parentFrame = document()->frame();
+    if (parentFrame)
+        return parentFrame->isURLAllowed(completeURL);
+
+    return true;
+}
+
+void HTMLFrameElementBase::openURL(bool lockHistory, bool lockBackForwardList)
+{
+    if (!isURLAllowed())
+        return;
+
+    if (m_URL.isEmpty())
+        m_URL = blankURL().string();
+
+    Frame* parentFrame = document()->frame();
+    if (!parentFrame)
+        return;
+
+    parentFrame->loader()->subframeLoader()->requestFrame(this, m_URL, m_frameName, lockHistory, lockBackForwardList);
+}
+
+void HTMLFrameElementBase::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == srcdocAttr)
+        setLocation("about:srcdoc");
+    else if (name == srcAttr && !fastHasAttribute(srcdocAttr))
+        setLocation(stripLeadingAndTrailingHTMLSpaces(value));
+    else if (isIdAttributeName(name)) {
+        // Important to call through to base for the id attribute so the hasID bit gets set.
+        HTMLFrameOwnerElement::parseAttribute(name, value);
+        m_frameName = value;
+    } else if (name == nameAttr) {
+        m_frameName = value;
+        // FIXME: If we are already attached, this doesn't actually change the frame's name.
+        // FIXME: If we are already attached, this doesn't check for frame name
+        // conflicts and generate a unique frame name.
+    } else if (name == marginwidthAttr) {
+        m_marginWidth = value.toInt();
+        // FIXME: If we are already attached, this has no effect.
+    } else if (name == marginheightAttr) {
+        m_marginHeight = value.toInt();
+        // FIXME: If we are already attached, this has no effect.
+    } else if (name == scrollingAttr) {
+        // Auto and yes both simply mean "allow scrolling." No means "don't allow scrolling."
+        if (equalIgnoringCase(value, "auto") || equalIgnoringCase(value, "yes"))
+            m_scrolling = document()->frameElementsShouldIgnoreScrolling() ? ScrollbarAlwaysOff : ScrollbarAuto;
+        else if (equalIgnoringCase(value, "no"))
+            m_scrolling = ScrollbarAlwaysOff;
+        // FIXME: If we are already attached, this has no effect.
+    } else if (name == onbeforeloadAttr)
+        setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, name, value));
+    else if (name == onbeforeunloadAttr) {
+        // FIXME: should <frame> elements have beforeunload handlers?
+        setAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(this, name, value));
+    } else
+        HTMLFrameOwnerElement::parseAttribute(name, value);
+}
+
+void HTMLFrameElementBase::setNameAndOpenURL()
+{
+    m_frameName = getNameAttribute();
+    if (m_frameName.isNull())
+        m_frameName = getIdAttribute();
+    openURL();
+}
+
+Node::InsertionNotificationRequest HTMLFrameElementBase::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLFrameOwnerElement::insertedInto(insertionPoint);
+    if (insertionPoint->inDocument())
+        return InsertionShouldCallDidNotifySubtreeInsertions;
+    return InsertionDone;
+}
+
+void HTMLFrameElementBase::didNotifySubtreeInsertions(ContainerNode*)
+{
+    if (!inDocument())
+        return;
+
+    // DocumentFragments don't kick of any loads.
+    if (!document()->frame())
+        return;
+
+    if (!SubframeLoadingDisabler::canLoadFrame(this))
+        return;
+
+    // JavaScript in src=javascript: and beforeonload can access the renderer
+    // during attribute parsing *before* the normal parser machinery would
+    // attach the element. To support this, we lazyAttach here, but only
+    // if we don't already have a renderer (if we're inserted
+    // as part of a DocumentFragment, insertedInto from an earlier element
+    // could have forced a style resolve and already attached us).
+    if (!renderer())
+        lazyAttach(DoNotSetAttached);
+    setNameAndOpenURL();
+}
+
+void HTMLFrameElementBase::attach()
+{
+    HTMLFrameOwnerElement::attach();
+
+    if (RenderPart* part = renderPart()) {
+        if (Frame* frame = contentFrame())
+            part->setWidget(frame->view());
+    }
+}
+
+KURL HTMLFrameElementBase::location() const
+{
+    if (fastHasAttribute(srcdocAttr))
+        return KURL(ParsedURLString, "about:srcdoc");
+    return document()->completeURL(getAttribute(srcAttr));
+}
+
+void HTMLFrameElementBase::setLocation(const String& str)
+{
+    m_URL = AtomicString(str);
+
+    if (inDocument())
+        openURL(false, false);
+}
+
+bool HTMLFrameElementBase::supportsFocus() const
+{
+    return true;
+}
+
+void HTMLFrameElementBase::setFocus(bool received)
+{
+    HTMLFrameOwnerElement::setFocus(received);
+    if (Page* page = document()->page()) {
+        if (received)
+            page->focusController()->setFocusedFrame(contentFrame());
+        else if (page->focusController()->focusedFrame() == contentFrame()) // Focus may have already been given to another frame, don't take it away.
+            page->focusController()->setFocusedFrame(0);
+    }
+}
+
+bool HTMLFrameElementBase::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == srcAttr || HTMLFrameOwnerElement::isURLAttribute(attribute);
+}
+
+bool HTMLFrameElementBase::isHTMLContentAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == srcdocAttr || HTMLFrameOwnerElement::isHTMLContentAttribute(attribute);
+}
+
+int HTMLFrameElementBase::width()
+{
+    document()->updateLayoutIgnorePendingStylesheets();
+    if (!renderBox())
+        return 0;
+    return renderBox()->width();
+}
+
+int HTMLFrameElementBase::height()
+{
+    document()->updateLayoutIgnorePendingStylesheets();
+    if (!renderBox())
+        return 0;
+    return renderBox()->height();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLFrameElementBase.h b/Source/core/html/HTMLFrameElementBase.h
new file mode 100644
index 0000000..d8477e1
--- /dev/null
+++ b/Source/core/html/HTMLFrameElementBase.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2004, 2006, 2008, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFrameElementBase_h
+#define HTMLFrameElementBase_h
+
+#include "core/html/HTMLFrameOwnerElement.h"
+#include "core/platform/ScrollTypes.h"
+
+namespace WebCore {
+
+class HTMLFrameElementBase : public HTMLFrameOwnerElement {
+public:
+    KURL location() const;
+    void setLocation(const String&);
+
+    virtual ScrollbarMode scrollingMode() const { return m_scrolling; }
+    
+    int marginWidth() const { return m_marginWidth; }
+    int marginHeight() const { return m_marginHeight; }
+
+    int width();
+    int height();
+
+    virtual bool canContainRangeEndPoint() const { return false; }
+
+protected:
+    HTMLFrameElementBase(const QualifiedName&, Document*);
+
+    bool isURLAllowed() const;
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void didNotifySubtreeInsertions(ContainerNode*) OVERRIDE;
+    virtual void attach();
+
+private:
+    virtual bool supportsFocus() const;
+    virtual void setFocus(bool) OVERRIDE;
+    
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+    virtual bool isHTMLContentAttribute(const Attribute&) const OVERRIDE;
+
+    virtual bool isFrameElementBase() const { return true; }
+
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+
+    void setNameAndOpenURL();
+    void openURL(bool lockHistory = true, bool lockBackForwardList = true);
+
+    AtomicString m_URL;
+    AtomicString m_frameName;
+
+    ScrollbarMode m_scrolling;
+
+    int m_marginWidth;
+    int m_marginHeight;
+};
+
+} // namespace WebCore
+
+#endif // HTMLFrameElementBase_h
diff --git a/Source/core/html/HTMLFrameOwnerElement.cpp b/Source/core/html/HTMLFrameOwnerElement.cpp
new file mode 100644
index 0000000..fe653ef
--- /dev/null
+++ b/Source/core/html/HTMLFrameOwnerElement.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLFrameOwnerElement.h"
+
+#include "core/loader/FrameLoader.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/rendering/RenderPart.h"
+
+#if ENABLE(SVG)
+#include "core/dom/ExceptionCode.h"
+#include "core/svg/SVGDocument.h"
+#endif
+
+namespace WebCore {
+
+HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_contentFrame(0)
+    , m_sandboxFlags(SandboxNone)
+{
+}
+
+RenderPart* HTMLFrameOwnerElement::renderPart() const
+{
+    // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers
+    // when using fallback content.
+    if (!renderer() || !renderer()->isRenderPart())
+        return 0;
+    return toRenderPart(renderer());
+}
+
+void HTMLFrameOwnerElement::setContentFrame(Frame* frame)
+{
+    // Make sure we will not end up with two frames referencing the same owner element.
+    ASSERT(!m_contentFrame || m_contentFrame->ownerElement() != this);
+    ASSERT(frame);
+    // Disconnected frames should not be allowed to load.
+    ASSERT(inDocument());
+    m_contentFrame = frame;
+
+    for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
+        node->incrementConnectedSubframeCount();
+}
+
+void HTMLFrameOwnerElement::clearContentFrame()
+{
+    if (!m_contentFrame)
+        return;
+
+    m_contentFrame = 0;
+
+    for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
+        node->decrementConnectedSubframeCount();
+}
+
+void HTMLFrameOwnerElement::disconnectContentFrame()
+{
+    // FIXME: Currently we don't do this in removedFrom because this causes an
+    // unload event in the subframe which could execute script that could then
+    // reach up into this document and then attempt to look back down. We should
+    // see if this behavior is really needed as Gecko does not allow this.
+    if (Frame* frame = contentFrame()) {
+        RefPtr<Frame> protect(frame);
+        frame->loader()->frameDetached();
+        frame->disconnectOwnerElement();
+    }
+}
+
+HTMLFrameOwnerElement::~HTMLFrameOwnerElement()
+{
+    if (m_contentFrame)
+        m_contentFrame->disconnectOwnerElement();
+}
+
+Document* HTMLFrameOwnerElement::contentDocument() const
+{
+    return m_contentFrame ? m_contentFrame->document() : 0;
+}
+
+DOMWindow* HTMLFrameOwnerElement::contentWindow() const
+{
+    return m_contentFrame ? m_contentFrame->document()->domWindow() : 0;
+}
+
+void HTMLFrameOwnerElement::setSandboxFlags(SandboxFlags flags)
+{
+    m_sandboxFlags = flags;
+}
+
+bool HTMLFrameOwnerElement::isKeyboardFocusable(KeyboardEvent* event) const
+{
+    return m_contentFrame && HTMLElement::isKeyboardFocusable(event);
+}
+
+#if ENABLE(SVG)
+SVGDocument* HTMLFrameOwnerElement::getSVGDocument(ExceptionCode& ec) const
+{
+    Document* doc = contentDocument();
+    if (doc && doc->isSVGDocument())
+        return toSVGDocument(doc);
+    // Spec: http://www.w3.org/TR/SVG/struct.html#InterfaceGetSVGDocument
+    ec = NOT_SUPPORTED_ERR;
+    return 0;
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLFrameOwnerElement.h b/Source/core/html/HTMLFrameOwnerElement.h
new file mode 100644
index 0000000..984d493
--- /dev/null
+++ b/Source/core/html/HTMLFrameOwnerElement.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFrameOwnerElement_h
+#define HTMLFrameOwnerElement_h
+
+#include "core/html/HTMLElement.h"
+#include "core/loader/FrameLoaderTypes.h"
+
+namespace WebCore {
+
+class DOMWindow;
+class Frame;
+class RenderPart;
+
+#if ENABLE(SVG)
+class SVGDocument;
+#endif
+
+class HTMLFrameOwnerElement : public HTMLElement {
+public:
+    virtual ~HTMLFrameOwnerElement();
+
+    Frame* contentFrame() const { return m_contentFrame; }
+    DOMWindow* contentWindow() const;
+    Document* contentDocument() const;
+
+    void setContentFrame(Frame*);
+    void clearContentFrame();
+
+    void disconnectContentFrame();
+
+    // Most subclasses use RenderPart (either RenderEmbeddedObject or RenderIFrame)
+    // except for HTMLObjectElement and HTMLEmbedElement which may return any
+    // RenderObject when using fallback content.
+    RenderPart* renderPart() const;
+
+#if ENABLE(SVG)
+    SVGDocument* getSVGDocument(ExceptionCode&) const;
+#endif
+
+    virtual ScrollbarMode scrollingMode() const { return ScrollbarAuto; }
+
+    SandboxFlags sandboxFlags() const { return m_sandboxFlags; }
+
+protected:
+    HTMLFrameOwnerElement(const QualifiedName& tagName, Document*);
+    void setSandboxFlags(SandboxFlags);
+
+private:
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual bool isFrameOwnerElement() const OVERRIDE { return true; }
+
+    Frame* m_contentFrame;
+    SandboxFlags m_sandboxFlags;
+};
+
+inline HTMLFrameOwnerElement* toFrameOwnerElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isFrameOwnerElement());
+    return static_cast<HTMLFrameOwnerElement*>(node);
+}
+
+class SubframeLoadingDisabler {
+public:
+    explicit SubframeLoadingDisabler(Node* root)
+        : m_root(root)
+    {
+        disabledSubtreeRoots().add(m_root);
+    }
+
+    ~SubframeLoadingDisabler()
+    {
+        disabledSubtreeRoots().remove(m_root);
+    }
+
+    static bool canLoadFrame(HTMLFrameOwnerElement* owner)
+    {
+        for (Node* node = owner; node; node = node->parentOrShadowHostNode()) {
+            if (disabledSubtreeRoots().contains(node))
+                return false;
+        }
+        return true;
+    }
+
+private:
+    static HashSet<Node*>& disabledSubtreeRoots()
+    {
+        DEFINE_STATIC_LOCAL(HashSet<Node*>, nodes, ());
+        return nodes;
+    }
+
+    Node* m_root;
+};
+
+} // namespace WebCore
+
+#endif // HTMLFrameOwnerElement_h
diff --git a/Source/core/html/HTMLFrameSetElement.cpp b/Source/core/html/HTMLFrameSetElement.cpp
new file mode 100644
index 0000000..6699bc8
--- /dev/null
+++ b/Source/core/html/HTMLFrameSetElement.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann (hausmann@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLFrameSetElement.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/Text.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/page/Frame.h"
+#include "core/platform/Length.h"
+#include "core/rendering/RenderFrameSet.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLFrameSetElement::HTMLFrameSetElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_totalRows(1)
+    , m_totalCols(1)
+    , m_border(6)
+    , m_borderSet(false)
+    , m_borderColorSet(false)
+    , m_frameborder(true)
+    , m_frameborderSet(false)
+    , m_noresize(false)
+{
+    ASSERT(hasTagName(framesetTag));
+    ScriptWrappable::init(this);
+    setHasCustomStyleCallbacks();
+}
+
+PassRefPtr<HTMLFrameSetElement> HTMLFrameSetElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLFrameSetElement(tagName, document));
+}
+
+bool HTMLFrameSetElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == bordercolorAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLFrameSetElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == bordercolorAttr)
+        addHTMLColorToStyle(style, CSSPropertyBorderColor, value);
+    else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLFrameSetElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == rowsAttr) {
+        if (!value.isNull()) {
+            m_rowLengths = newLengthArray(value.string(), m_totalRows);
+            setNeedsStyleRecalc();
+        }
+    } else if (name == colsAttr) {
+        if (!value.isNull()) {
+            m_colLengths = newLengthArray(value.string(), m_totalCols);
+            setNeedsStyleRecalc();
+        }
+    } else if (name == frameborderAttr) {
+        if (!value.isNull()) {
+            if (equalIgnoringCase(value, "no") || equalIgnoringCase(value, "0")) {
+                m_frameborder = false;
+                m_frameborderSet = true;
+            } else if (equalIgnoringCase(value, "yes") || equalIgnoringCase(value, "1")) {
+                m_frameborderSet = true;
+            }
+        } else {
+            m_frameborder = false;
+            m_frameborderSet = false;
+        }
+    } else if (name == noresizeAttr) {
+        m_noresize = true;
+    } else if (name == borderAttr) {
+        if (!value.isNull()) {
+            m_border = value.toInt();
+            m_borderSet = true;
+        } else
+            m_borderSet = false;
+    } else if (name == bordercolorAttr)
+        m_borderColorSet = !value.isEmpty();
+    else if (name == onloadAttr)
+        document()->setWindowAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onbeforeunloadAttr)
+        document()->setWindowAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onunloadAttr)
+        document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onblurAttr)
+        document()->setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onfocusAttr)
+        document()->setWindowAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onfocusinAttr)
+        document()->setWindowAttributeEventListener(eventNames().focusinEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onfocusoutAttr)
+        document()->setWindowAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(document()->frame(), name, value));
+#if ENABLE(ORIENTATION_EVENTS)
+    else if (name == onorientationchangeAttr)
+        document()->setWindowAttributeEventListener(eventNames().orientationchangeEvent, createAttributeEventListener(document()->frame(), name, value));
+#endif
+    else if (name == onhashchangeAttr)
+        document()->setWindowAttributeEventListener(eventNames().hashchangeEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onresizeAttr)
+        document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onscrollAttr)
+        document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onstorageAttr)
+        document()->setWindowAttributeEventListener(eventNames().storageEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == ononlineAttr)
+        document()->setWindowAttributeEventListener(eventNames().onlineEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onofflineAttr)
+        document()->setWindowAttributeEventListener(eventNames().offlineEvent, createAttributeEventListener(document()->frame(), name, value));
+    else if (name == onpopstateAttr)
+        document()->setWindowAttributeEventListener(eventNames().popstateEvent, createAttributeEventListener(document()->frame(), name, value));
+    else
+        HTMLElement::parseAttribute(name, value);
+}
+
+bool HTMLFrameSetElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    // For compatibility, frames render even when display: none is set.
+    // However, we delay creating a renderer until stylesheets have loaded. 
+    return context.style()->isStyleAvailable();
+}
+
+RenderObject *HTMLFrameSetElement::createRenderer(RenderArena *arena, RenderStyle *style)
+{
+    if (style->hasContent())
+        return RenderObject::createObject(this, style);
+    
+    return new (arena) RenderFrameSet(this);
+}
+
+void HTMLFrameSetElement::attach()
+{
+    // Inherit default settings from parent frameset
+    // FIXME: This is not dynamic.
+    for (ContainerNode* node = parentNode(); node; node = node->parentNode()) {
+        if (node->hasTagName(framesetTag)) {
+            HTMLFrameSetElement* frameset = static_cast<HTMLFrameSetElement*>(node);
+            if (!m_frameborderSet)
+                m_frameborder = frameset->hasFrameBorder();
+            if (m_frameborder) {
+                if (!m_borderSet)
+                    m_border = frameset->border();
+                if (!m_borderColorSet)
+                    m_borderColorSet = frameset->hasBorderColor();
+            }
+            if (!m_noresize)
+                m_noresize = frameset->noResize();
+            break;
+        }
+    }
+
+    HTMLElement::attach();
+}
+
+void HTMLFrameSetElement::defaultEventHandler(Event* evt)
+{
+    if (evt->isMouseEvent() && !m_noresize && renderer() && renderer()->isFrameSet()) {
+        if (toRenderFrameSet(renderer())->userResize(static_cast<MouseEvent*>(evt))) {
+            evt->setDefaultHandled();
+            return;
+        }
+    }
+    HTMLElement::defaultEventHandler(evt);
+}
+
+void HTMLFrameSetElement::willRecalcStyle(StyleChange)
+{
+    if (needsStyleRecalc() && renderer()) {
+        renderer()->setNeedsLayout(true);
+        clearNeedsStyleRecalc();
+    }
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLFrameSetElement.h b/Source/core/html/HTMLFrameSetElement.h
new file mode 100644
index 0000000..2c7f181
--- /dev/null
+++ b/Source/core/html/HTMLFrameSetElement.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2004, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLFrameSetElement_h
+#define HTMLFrameSetElement_h
+
+#include "core/html/HTMLElement.h"
+#include <wtf/OwnArrayPtr.h>
+
+namespace WebCore {
+
+class HTMLFrameSetElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLFrameSetElement> create(const QualifiedName&, Document*);
+
+    bool hasFrameBorder() const { return m_frameborder; }
+    bool noResize() const { return m_noresize; }
+
+    int totalRows() const { return m_totalRows; }
+    int totalCols() const { return m_totalCols; }
+    int border() const { return hasFrameBorder() ? m_border : 0; }
+
+    bool hasBorderColor() const { return m_borderColorSet; }
+
+    const Length* rowLengths() const { return m_rowLengths.get(); }
+    const Length* colLengths() const { return m_colLengths.get(); }
+
+    // Declared virtual in Element
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(blur);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(error);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(focus);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(load);
+
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(beforeunload);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(hashchange);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(message);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(offline);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(online);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(popstate);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(resize);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(storage);
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(unload);
+#if ENABLE(ORIENTATION_EVENTS)
+    DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(orientationchange);
+#endif
+
+private:
+    HTMLFrameSetElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    virtual void attach();
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    
+    virtual void defaultEventHandler(Event*);
+
+    virtual void willRecalcStyle(StyleChange) OVERRIDE;
+
+    OwnArrayPtr<Length> m_rowLengths;
+    OwnArrayPtr<Length> m_colLengths;
+
+    int m_totalRows;
+    int m_totalCols;
+    
+    int m_border;
+    bool m_borderSet;
+    
+    bool m_borderColorSet;
+
+    bool m_frameborder;
+    bool m_frameborderSet;
+    bool m_noresize;
+};
+
+} // namespace WebCore
+
+#endif // HTMLFrameSetElement_h
diff --git a/Source/core/html/HTMLFrameSetElement.idl b/Source/core/html/HTMLFrameSetElement.idl
new file mode 100644
index 0000000..348251c
--- /dev/null
+++ b/Source/core/html/HTMLFrameSetElement.idl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006, 2007, 2009, 2010 Apple Inc. All rights reserve
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomNamedGetter
+] interface HTMLFrameSetElement : HTMLElement {
+    [Reflect] attribute DOMString cols;
+    [Reflect] attribute DOMString rows;
+
+    // Event handler attributes
+    [NotEnumerable] attribute EventListener onbeforeunload;
+    [NotEnumerable] attribute EventListener onhashchange;
+    [NotEnumerable] attribute EventListener onmessage;
+    [NotEnumerable] attribute EventListener onoffline;
+    [NotEnumerable] attribute EventListener ononline;
+    [NotEnumerable] attribute EventListener onpopstate;
+    [NotEnumerable] attribute EventListener onresize;
+    [NotEnumerable] attribute EventListener onstorage;
+    [NotEnumerable] attribute EventListener onunload;
+
+    [Conditional=ORIENTATION_EVENTS, NotEnumerable] attribute EventListener onorientationchange;
+
+    // Overrides of Element attributes (with different implementation in bindings).
+    [NotEnumerable] attribute EventListener onblur;
+    [NotEnumerable] attribute EventListener onerror;
+    [NotEnumerable] attribute EventListener onfocus;
+    [NotEnumerable] attribute EventListener onload;
+
+    // Not implemented yet.
+    // attribute [NotEnumerable] EventListener onafterprint;
+    // attribute [NotEnumerable] EventListener onbeforeprint;
+    // attribute [NotEnumerable] EventListener onredo;
+    // attribute [NotEnumerable] EventListener onundo;
+};
+
diff --git a/Source/core/html/HTMLHRElement.cpp b/Source/core/html/HTMLHRElement.cpp
new file mode 100644
index 0000000..e497de2
--- /dev/null
+++ b/Source/core/html/HTMLHRElement.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLHRElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/css/CSSValuePool.h"
+#include "core/css/StylePropertySet.h"
+#include "core/dom/Attribute.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLHRElement::HTMLHRElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(hrTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLHRElement> HTMLHRElement::create(Document* document)
+{
+    return adoptRef(new HTMLHRElement(hrTag, document));
+}
+
+PassRefPtr<HTMLHRElement> HTMLHRElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLHRElement(tagName, document));
+}
+
+bool HTMLHRElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == alignAttr || name == widthAttr || name == colorAttr || name == noshadeAttr || name == sizeAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLHRElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == alignAttr) {
+        if (equalIgnoringCase(value, "left")) {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyMarginLeft, 0, CSSPrimitiveValue::CSS_PX);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyMarginRight, CSSValueAuto);
+        } else if (equalIgnoringCase(value, "right")) {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyMarginLeft, CSSValueAuto);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyMarginRight, 0, CSSPrimitiveValue::CSS_PX);
+        } else {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyMarginLeft, CSSValueAuto);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyMarginRight, CSSValueAuto);
+        }
+    } else if (name == widthAttr) {
+        bool ok;
+        int v = value.toInt(&ok);
+        if (ok && !v)
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWidth, 1, CSSPrimitiveValue::CSS_PX);
+        else
+            addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+    } else if (name == colorAttr) {
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderStyle, CSSValueSolid);
+        addHTMLColorToStyle(style, CSSPropertyBorderColor, value);
+        addHTMLColorToStyle(style, CSSPropertyBackgroundColor, value);
+    } else if (name == noshadeAttr) {
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderStyle, CSSValueSolid);
+
+        RefPtr<CSSPrimitiveValue> darkGrayValue = cssValuePool().createColorValue(Color::darkGray);
+        style->setProperty(CSSPropertyBorderColor, darkGrayValue);
+        style->setProperty(CSSPropertyBackgroundColor, darkGrayValue);
+    } else if (name == sizeAttr) {
+        StringImpl* si = value.impl();
+        int size = si->toInt();
+        if (size <= 1)
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderBottomWidth, 0, CSSPrimitiveValue::CSS_PX);
+        else
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyHeight, size - 2, CSSPrimitiveValue::CSS_PX);
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+}
diff --git a/Source/core/html/HTMLHRElement.h b/Source/core/html/HTMLHRElement.h
new file mode 100644
index 0000000..b4498e7
--- /dev/null
+++ b/Source/core/html/HTMLHRElement.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLHRElement_h
+#define HTMLHRElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLHRElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLHRElement> create(Document*);
+    static PassRefPtr<HTMLHRElement> create(const QualifiedName&, Document*);
+
+    virtual bool canContainRangeEndPoint() const { return hasChildNodes(); }
+
+private:
+    HTMLHRElement(const QualifiedName&, Document*);
+
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // HTMLHRElement_h
diff --git a/Source/core/html/HTMLHRElement.idl b/Source/core/html/HTMLHRElement.idl
new file mode 100644
index 0000000..babe467
--- /dev/null
+++ b/Source/core/html/HTMLHRElement.idl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLHRElement : HTMLElement {
+    [Reflect] attribute DOMString align;
+    [Reflect] attribute boolean noShade;
+    [Reflect] attribute DOMString size;
+    [Reflect] attribute DOMString width;
+};
+
diff --git a/Source/core/html/HTMLHeadElement.cpp b/Source/core/html/HTMLHeadElement.cpp
new file mode 100644
index 0000000..db0eafa
--- /dev/null
+++ b/Source/core/html/HTMLHeadElement.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann (hausmann@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLHeadElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Text.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLHeadElement::HTMLHeadElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(headTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLHeadElement> HTMLHeadElement::create(Document* document)
+{
+    return adoptRef(new HTMLHeadElement(headTag, document));
+}
+
+PassRefPtr<HTMLHeadElement> HTMLHeadElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLHeadElement(tagName, document));
+}
+
+}
diff --git a/Source/core/html/HTMLHeadElement.h b/Source/core/html/HTMLHeadElement.h
new file mode 100644
index 0000000..54c7fe8
--- /dev/null
+++ b/Source/core/html/HTMLHeadElement.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2004, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLHeadElement_h
+#define HTMLHeadElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLHeadElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLHeadElement> create(Document*);
+    static PassRefPtr<HTMLHeadElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLHeadElement(const QualifiedName&, Document*);
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLHeadElement.idl b/Source/core/html/HTMLHeadElement.idl
new file mode 100644
index 0000000..6a784bd
--- /dev/null
+++ b/Source/core/html/HTMLHeadElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLHeadElement : HTMLElement {
+    [Reflect] attribute DOMString profile;
+};
+
diff --git a/Source/core/html/HTMLHeadingElement.cpp b/Source/core/html/HTMLHeadingElement.cpp
new file mode 100644
index 0000000..36f8a66
--- /dev/null
+++ b/Source/core/html/HTMLHeadingElement.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLHeadingElement.h"
+
+namespace WebCore {
+
+inline HTMLHeadingElement::HTMLHeadingElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLHeadingElement> HTMLHeadingElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLHeadingElement(tagName, document));
+}
+
+}
diff --git a/Source/core/html/HTMLHeadingElement.h b/Source/core/html/HTMLHeadingElement.h
new file mode 100644
index 0000000..c04bcfe
--- /dev/null
+++ b/Source/core/html/HTMLHeadingElement.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLHeadingElement_h
+#define HTMLHeadingElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLHeadingElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLHeadingElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLHeadingElement(const QualifiedName&, Document*);
+};
+
+} // namespace WebCore
+
+#endif // HTMLHeadingElement_h
diff --git a/Source/core/html/HTMLHeadingElement.idl b/Source/core/html/HTMLHeadingElement.idl
new file mode 100644
index 0000000..288f439
--- /dev/null
+++ b/Source/core/html/HTMLHeadingElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLHeadingElement : HTMLElement {
+    [Reflect] attribute DOMString align;
+};
+
diff --git a/Source/core/html/HTMLHtmlElement.cpp b/Source/core/html/HTMLHtmlElement.cpp
new file mode 100644
index 0000000..704dde1
--- /dev/null
+++ b/Source/core/html/HTMLHtmlElement.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann (hausmann@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLHtmlElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Document.h"
+#include "core/dom/DocumentParser.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/appcache/ApplicationCacheHost.h"
+#include "core/page/Frame.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLHtmlElement::HTMLHtmlElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(htmlTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLHtmlElement> HTMLHtmlElement::create(Document* document)
+{
+    return adoptRef(new HTMLHtmlElement(htmlTag, document));
+}
+
+PassRefPtr<HTMLHtmlElement> HTMLHtmlElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLHtmlElement(tagName, document));
+}
+
+bool HTMLHtmlElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == manifestAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+void HTMLHtmlElement::insertedByParser()
+{
+    // When parsing a fragment, its dummy document has a null parser.
+    if (!document()->parser() || !document()->parser()->documentWasLoadedAsPartOfNavigation())
+        return;
+
+    if (!document()->frame())
+        return;
+
+    DocumentLoader* documentLoader = document()->frame()->loader()->documentLoader();
+    if (!documentLoader)
+        return;
+
+    const AtomicString& manifest = getAttribute(manifestAttr);
+    if (manifest.isEmpty())
+        documentLoader->applicationCacheHost()->selectCacheWithoutManifest();
+    else
+        documentLoader->applicationCacheHost()->selectCacheWithManifest(document()->completeURL(manifest));
+}
+
+}
diff --git a/Source/core/html/HTMLHtmlElement.h b/Source/core/html/HTMLHtmlElement.h
new file mode 100644
index 0000000..6ac6ed4
--- /dev/null
+++ b/Source/core/html/HTMLHtmlElement.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2004, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLHtmlElement_h
+#define HTMLHtmlElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLHtmlElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLHtmlElement> create(Document*);
+    static PassRefPtr<HTMLHtmlElement> create(const QualifiedName&, Document*);
+
+    void insertedByParser();
+
+private:
+    HTMLHtmlElement(const QualifiedName&, Document*);
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLHtmlElement.idl b/Source/core/html/HTMLHtmlElement.idl
new file mode 100644
index 0000000..430cdc6
--- /dev/null
+++ b/Source/core/html/HTMLHtmlElement.idl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLHtmlElement : HTMLElement {
+    [Reflect] attribute DOMString version;
+    [Reflect, URL] attribute DOMString manifest;
+};
+
diff --git a/Source/core/html/HTMLIFrameElement.cpp b/Source/core/html/HTMLIFrameElement.cpp
new file mode 100644
index 0000000..6bb3b29
--- /dev/null
+++ b/Source/core/html/HTMLIFrameElement.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann (hausmann@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Ericsson AB. 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLIFrameElement.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/ScriptableDocumentParser.h"
+#include "core/html/HTMLDocument.h"
+#include "core/page/Frame.h"
+#include "core/rendering/RenderIFrame.h"
+#include <wtf/text/TextPosition.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLIFrameElement::HTMLIFrameElement(const QualifiedName& tagName, Document* document)
+    : HTMLFrameElementBase(tagName, document)
+{
+    ASSERT(hasTagName(iframeTag));
+    ScriptWrappable::init(this);
+    setHasCustomStyleCallbacks();
+}
+
+PassRefPtr<HTMLIFrameElement> HTMLIFrameElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLIFrameElement(tagName, document));
+}
+
+bool HTMLIFrameElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == widthAttr || name == heightAttr || name == alignAttr || name == frameborderAttr || name == seamlessAttr)
+        return true;
+    return HTMLFrameElementBase::isPresentationAttribute(name);
+}
+
+void HTMLIFrameElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == widthAttr)
+        addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+    else if (name == heightAttr)
+        addHTMLLengthToStyle(style, CSSPropertyHeight, value);
+    else if (name == alignAttr)
+        applyAlignmentAttributeToStyle(value, style);
+    else if (name == frameborderAttr) {
+        // Frame border doesn't really match the HTML4 spec definition for iframes. It simply adds
+        // a presentational hint that the border should be off if set to zero.
+        if (!value.toInt()) {
+            // Add a rule that nulls out our border width.
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderWidth, 0, CSSPrimitiveValue::CSS_PX);
+        }
+    } else
+        HTMLFrameElementBase::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLIFrameElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == nameAttr) {
+        if (inDocument() && document()->isHTMLDocument() && !isInShadowTree()) {
+            HTMLDocument* document = toHTMLDocument(this->document());
+            document->removeExtraNamedItem(m_name);
+            document->addExtraNamedItem(value);
+        }
+        m_name = value;
+    } else if (name == sandboxAttr) {
+        String invalidTokens;
+        setSandboxFlags(value.isNull() ? SandboxNone : SecurityContext::parseSandboxPolicy(value, invalidTokens));
+        if (!invalidTokens.isNull())
+            document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Error while parsing the 'sandbox' attribute: " + invalidTokens);
+    } else if (name == seamlessAttr) {
+        // If we're adding or removing the seamless attribute, we need to force the content document to recalculate its StyleResolver.
+        if (contentDocument())
+            contentDocument()->styleResolverChanged(DeferRecalcStyle);
+    } else
+        HTMLFrameElementBase::parseAttribute(name, value);
+}
+
+bool HTMLIFrameElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    return isURLAllowed() && context.style()->display() != NONE;
+}
+
+RenderObject* HTMLIFrameElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderIFrame(this);
+}
+
+Node::InsertionNotificationRequest HTMLIFrameElement::insertedInto(ContainerNode* insertionPoint)
+{
+    InsertionNotificationRequest result = HTMLFrameElementBase::insertedInto(insertionPoint);
+    if (insertionPoint->inDocument() && document()->isHTMLDocument() && !insertionPoint->isInShadowTree())
+        toHTMLDocument(document())->addExtraNamedItem(m_name);
+    return result;
+}
+
+void HTMLIFrameElement::removedFrom(ContainerNode* insertionPoint)
+{
+    HTMLFrameElementBase::removedFrom(insertionPoint);
+    if (insertionPoint->inDocument() && document()->isHTMLDocument() && !insertionPoint->isInShadowTree())
+        toHTMLDocument(document())->removeExtraNamedItem(m_name);
+}
+
+bool HTMLIFrameElement::shouldDisplaySeamlessly() const
+{
+    return contentDocument() && contentDocument()->shouldDisplaySeamlesslyWithParent();
+}
+
+void HTMLIFrameElement::didRecalcStyle(StyleChange styleChange)
+{
+    if (!shouldDisplaySeamlessly())
+        return;
+    Document* childDocument = contentDocument();
+    if (styleChange >= Inherit || childDocument->childNeedsStyleRecalc() || childDocument->needsStyleRecalc())
+        contentDocument()->recalcStyle(styleChange);
+}
+
+}
diff --git a/Source/core/html/HTMLIFrameElement.h b/Source/core/html/HTMLIFrameElement.h
new file mode 100644
index 0000000..b352894
--- /dev/null
+++ b/Source/core/html/HTMLIFrameElement.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2004, 2006, 2008, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLIFrameElement_h
+#define HTMLIFrameElement_h
+
+#include "core/html/HTMLFrameElementBase.h"
+
+namespace WebCore {
+
+class HTMLIFrameElement FINAL : public HTMLFrameElementBase {
+public:
+    static PassRefPtr<HTMLIFrameElement> create(const QualifiedName&, Document*);
+
+    bool shouldDisplaySeamlessly() const;
+
+private:
+    HTMLIFrameElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+
+    virtual void didRecalcStyle(StyleChange) OVERRIDE;
+
+    AtomicString m_name;
+};
+
+} // namespace WebCore
+
+#endif // HTMLIFrameElement_h
diff --git a/Source/core/html/HTMLIFrameElement.idl b/Source/core/html/HTMLIFrameElement.idl
new file mode 100644
index 0000000..aa54d7e
--- /dev/null
+++ b/Source/core/html/HTMLIFrameElement.idl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006, 2007, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLIFrameElement : HTMLElement {
+    [Reflect] attribute DOMString align;
+    [Reflect] attribute DOMString frameBorder;
+    [Reflect] attribute DOMString height;
+    [Reflect] attribute DOMString longDesc;
+    [Reflect] attribute DOMString marginHeight;
+    [Reflect] attribute DOMString marginWidth;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute DOMString sandbox;
+    [Reflect, EnabledAtRuntime=seamlessIFrames] attribute boolean seamless;
+    [Reflect] attribute DOMString scrolling;
+    [Reflect, URL] attribute DOMString src;
+    [Reflect] attribute DOMString srcdoc;
+    [Reflect] attribute DOMString width;
+
+    // Introduced in DOM Level 2:
+    [CheckSecurityForNode] readonly attribute Document contentDocument;
+
+    // Extensions
+    readonly attribute DOMWindow contentWindow;
+
+#if defined(ENABLE_SVG) && ENABLE_SVG
+    [CheckSecurityForNode, RaisesException] SVGDocument getSVGDocument();
+#endif
+};
+
diff --git a/Source/core/html/HTMLImageElement.cpp b/Source/core/html/HTMLImageElement.cpp
new file mode 100644
index 0000000..c8d1e22
--- /dev/null
+++ b/Source/core/html/HTMLImageElement.cpp
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLImageElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/EventNames.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/cache/CachedImage.h"
+#include "core/page/FrameView.h"
+#include "core/rendering/RenderImage.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+    : HTMLElement(tagName, document)
+    , m_imageLoader(this)
+    , m_form(form)
+    , m_compositeOperator(CompositeSourceOver)
+{
+    ASSERT(hasTagName(imgTag));
+    ScriptWrappable::init(this);
+    if (form)
+        form->registerImgElement(this);
+}
+
+PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document* document)
+{
+    return adoptRef(new HTMLImageElement(imgTag, document));
+}
+
+PassRefPtr<HTMLImageElement> HTMLImageElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+{
+    return adoptRef(new HTMLImageElement(tagName, document, form));
+}
+
+HTMLImageElement::~HTMLImageElement()
+{
+    if (m_form)
+        m_form->removeImgElement(this);
+}
+
+PassRefPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document* document, const int* optionalWidth, const int* optionalHeight)
+{
+    RefPtr<HTMLImageElement> image = adoptRef(new HTMLImageElement(imgTag, document));
+    if (optionalWidth)
+        image->setWidth(*optionalWidth);
+    if (optionalHeight)
+        image->setHeight(*optionalHeight);
+    return image.release();
+}
+
+bool HTMLImageElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == widthAttr || name == heightAttr || name == borderAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == valignAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLImageElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == widthAttr)
+        addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+    else if (name == heightAttr)
+        addHTMLLengthToStyle(style, CSSPropertyHeight, value);
+    else if (name == borderAttr)
+        applyBorderAttributeToStyle(value, style);
+    else if (name == vspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
+    } else if (name == hspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
+    } else if (name == alignAttr)
+        applyAlignmentAttributeToStyle(value, style);
+    else if (name == valignAttr)
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, value);
+    else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == altAttr) {
+        if (renderer() && renderer()->isImage())
+            toRenderImage(renderer())->updateAltText();
+    } else if (name == srcAttr)
+        m_imageLoader.updateFromElementIgnoringPreviousError();
+    else if (name == usemapAttr)
+        setIsLink(!value.isNull());
+    else if (name == onbeforeloadAttr)
+        setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, name, value));
+    else if (name == compositeAttr) {
+        // FIXME: images don't support blend modes in their compositing attribute.
+        BlendMode blendOp = BlendModeNormal;
+        if (!parseCompositeAndBlendOperator(value, m_compositeOperator, blendOp))
+            m_compositeOperator = CompositeSourceOver;
+    } else
+        HTMLElement::parseAttribute(name, value);
+}
+
+String HTMLImageElement::altText() const
+{
+    // lets figure out the alt text.. magic stuff
+    // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
+    // also heavily discussed by Hixie on bugzilla
+    String alt = getAttribute(altAttr);
+    // fall back to title attribute
+    if (alt.isNull())
+        alt = getAttribute(titleAttr);
+    return alt;
+}
+
+RenderObject* HTMLImageElement::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+    if (style->hasContent())
+        return RenderObject::createObject(this, style);
+
+    RenderImage* image = new (arena) RenderImage(this);
+    image->setImageResource(RenderImageResource::create());
+    return image;
+}
+
+bool HTMLImageElement::canStartSelection() const
+{
+    if (shadow())
+        return HTMLElement::canStartSelection();
+
+    return false;
+}
+
+void HTMLImageElement::attach()
+{
+    HTMLElement::attach();
+
+    if (renderer() && renderer()->isImage() && !m_imageLoader.hasPendingBeforeLoadEvent()) {
+        RenderImage* renderImage = toRenderImage(renderer());
+        RenderImageResource* renderImageResource = renderImage->imageResource();
+        if (renderImageResource->hasImage())
+            return;
+        renderImageResource->setCachedImage(m_imageLoader.image());
+
+        // If we have no image at all because we have no src attribute, set
+        // image height and width for the alt text instead.
+        if (!m_imageLoader.image() && !renderImageResource->cachedImage())
+            renderImage->setImageSizeForAltText();
+    }
+}
+
+Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint)
+{
+    if (!m_form) {
+        // m_form can be non-null if it was set in constructor.
+        for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
+            if (ancestor->hasTagName(formTag)) {
+                m_form = static_cast<HTMLFormElement*>(ancestor);
+                m_form->registerImgElement(this);
+                break;
+            }
+        }
+    }
+
+    // If we have been inserted from a renderer-less document,
+    // our loader may have not fetched the image, so do it now.
+    if (insertionPoint->inDocument() && !m_imageLoader.image())
+        m_imageLoader.updateFromElement();
+
+    return HTMLElement::insertedInto(insertionPoint);
+}
+
+void HTMLImageElement::removedFrom(ContainerNode* insertionPoint)
+{
+    if (m_form)
+        m_form->removeImgElement(this);
+    m_form = 0;
+    HTMLElement::removedFrom(insertionPoint);
+}
+
+int HTMLImageElement::width(bool ignorePendingStylesheets)
+{
+    if (!renderer()) {
+        // check the attribute first for an explicit pixel value
+        bool ok;
+        int width = getAttribute(widthAttr).toInt(&ok);
+        if (ok)
+            return width;
+
+        // if the image is available, use its width
+        if (m_imageLoader.image())
+            return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).width();
+    }
+
+    if (ignorePendingStylesheets)
+        document()->updateLayoutIgnorePendingStylesheets();
+    else
+        document()->updateLayout();
+
+    RenderBox* box = renderBox();
+    return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedWidth(), box) : 0;
+}
+
+int HTMLImageElement::height(bool ignorePendingStylesheets)
+{
+    if (!renderer()) {
+        // check the attribute first for an explicit pixel value
+        bool ok;
+        int height = getAttribute(heightAttr).toInt(&ok);
+        if (ok)
+            return height;
+
+        // if the image is available, use its height
+        if (m_imageLoader.image())
+            return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).height();
+    }
+
+    if (ignorePendingStylesheets)
+        document()->updateLayoutIgnorePendingStylesheets();
+    else
+        document()->updateLayout();
+
+    RenderBox* box = renderBox();
+    return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedHeight(), box) : 0;
+}
+
+int HTMLImageElement::naturalWidth() const
+{
+    if (!m_imageLoader.image())
+        return 0;
+
+    return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).width();
+}
+
+int HTMLImageElement::naturalHeight() const
+{
+    if (!m_imageLoader.image())
+        return 0;
+
+    return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).height();
+}
+
+bool HTMLImageElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == srcAttr
+        || attribute.name() == lowsrcAttr
+        || attribute.name() == longdescAttr
+        || (attribute.name() == usemapAttr && attribute.value().string()[0] != '#')
+        || HTMLElement::isURLAttribute(attribute);
+}
+
+const AtomicString& HTMLImageElement::alt() const
+{
+    return getAttribute(altAttr);
+}
+
+bool HTMLImageElement::draggable() const
+{
+    // Image elements are draggable by default.
+    return !equalIgnoringCase(getAttribute(draggableAttr), "false");
+}
+
+void HTMLImageElement::setHeight(int value)
+{
+    setAttribute(heightAttr, String::number(value));
+}
+
+KURL HTMLImageElement::src() const
+{
+    return document()->completeURL(getAttribute(srcAttr));
+}
+
+void HTMLImageElement::setSrc(const String& value)
+{
+    setAttribute(srcAttr, value);
+}
+
+void HTMLImageElement::setWidth(int value)
+{
+    setAttribute(widthAttr, String::number(value));
+}
+
+int HTMLImageElement::x() const
+{
+    RenderObject* r = renderer();
+    if (!r)
+        return 0;
+
+    // FIXME: This doesn't work correctly with transforms.
+    FloatPoint absPos = r->localToAbsolute();
+    return absPos.x();
+}
+
+int HTMLImageElement::y() const
+{
+    RenderObject* r = renderer();
+    if (!r)
+        return 0;
+
+    // FIXME: This doesn't work correctly with transforms.
+    FloatPoint absPos = r->localToAbsolute();
+    return absPos.y();
+}
+
+bool HTMLImageElement::complete() const
+{
+    return m_imageLoader.imageComplete();
+}
+
+void HTMLImageElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLElement::addSubresourceAttributeURLs(urls);
+
+    addSubresourceURL(urls, src());
+    // FIXME: What about when the usemap attribute begins with "#"?
+    addSubresourceURL(urls, document()->completeURL(getAttribute(usemapAttr)));
+}
+
+void HTMLImageElement::didMoveToNewDocument(Document* oldDocument)
+{
+    m_imageLoader.elementDidMoveToNewDocument();
+    HTMLElement::didMoveToNewDocument(oldDocument);
+}
+
+bool HTMLImageElement::isServerMap() const
+{
+    if (!fastHasAttribute(ismapAttr))
+        return false;
+
+    const AtomicString& usemap = fastGetAttribute(usemapAttr);
+    
+    // If the usemap attribute starts with '#', it refers to a map element in the document.
+    if (usemap.string()[0] == '#')
+        return false;
+
+    return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(usemap)).isEmpty();
+}
+
+void HTMLImageElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
+    HTMLElement::reportMemoryUsage(memoryObjectInfo);
+    info.addMember(m_imageLoader, "imageLoader");
+    info.addMember(m_form, "form");
+}
+
+}
diff --git a/Source/core/html/HTMLImageElement.h b/Source/core/html/HTMLImageElement.h
new file mode 100644
index 0000000..f510160
--- /dev/null
+++ b/Source/core/html/HTMLImageElement.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLImageElement_h
+#define HTMLImageElement_h
+
+#include "core/html/HTMLElement.h"
+#include "core/html/HTMLImageLoader.h"
+#include "core/platform/graphics/GraphicsTypes.h"
+
+namespace WebCore {
+
+class HTMLFormElement;
+
+class HTMLImageElement : public HTMLElement {
+    friend class HTMLFormElement;
+public:
+    static PassRefPtr<HTMLImageElement> create(Document*);
+    static PassRefPtr<HTMLImageElement> create(const QualifiedName&, Document*, HTMLFormElement*);
+    static PassRefPtr<HTMLImageElement> createForJSConstructor(Document*, const int* optionalWidth, const int* optionalHeight);
+
+    virtual ~HTMLImageElement();
+
+    int width(bool ignorePendingStylesheets = false);
+    int height(bool ignorePendingStylesheets = false);
+
+    int naturalWidth() const;
+    int naturalHeight() const;
+
+    bool isServerMap() const;
+
+    String altText() const;
+
+    CompositeOperator compositeOperator() const { return m_compositeOperator; }
+
+    CachedImage* cachedImage() const { return m_imageLoader.image(); }
+    void setCachedImage(CachedImage* i) { m_imageLoader.setImage(i); };
+
+    void setLoadManually(bool loadManually) { m_imageLoader.setLoadManually(loadManually); }
+
+    const AtomicString& alt() const;
+
+    void setHeight(int);
+
+    KURL src() const;
+    void setSrc(const String&);
+
+    void setWidth(int);
+
+    int x() const;
+    int y() const;
+
+    bool complete() const;
+
+    bool hasPendingActivity() const { return m_imageLoader.hasPendingActivity(); }
+
+    virtual bool canContainRangeEndPoint() const { return false; }
+
+    virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+
+protected:
+    HTMLImageElement(const QualifiedName&, Document*, HTMLFormElement* = 0);
+
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+
+private:
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    virtual void attach();
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+
+    virtual bool canStartSelection() const;
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+    virtual bool draggable() const;
+
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return true; }
+    virtual bool shouldRegisterAsExtraNamedItem() const OVERRIDE { return true; }
+
+    HTMLImageLoader m_imageLoader;
+    HTMLFormElement* m_form;
+    CompositeOperator m_compositeOperator;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLImageElement.idl b/Source/core/html/HTMLImageElement.idl
new file mode 100644
index 0000000..3287fd6
--- /dev/null
+++ b/Source/core/html/HTMLImageElement.idl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    SkipVTableValidation
+] interface HTMLImageElement : HTMLElement {
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute DOMString align;
+    [Reflect] attribute DOMString alt;
+    [Reflect] attribute DOMString border;
+    [Reflect] attribute DOMString crossOrigin;
+    attribute long height;
+    [Reflect] attribute long hspace;
+    [Reflect] attribute boolean isMap;
+    [Reflect, URL] attribute DOMString longDesc;
+    [Reflect, URL] attribute DOMString src;
+    [Reflect] attribute DOMString useMap;
+    [Reflect] attribute long vspace;
+    attribute long width;
+    
+    // Extensions
+    readonly attribute boolean complete;
+    [Reflect,URL] attribute DOMString lowsrc;
+    readonly attribute long naturalHeight;
+    readonly attribute long naturalWidth;
+    readonly attribute long x;
+    readonly attribute long y;
+};
+
diff --git a/Source/core/html/HTMLImageLoader.cpp b/Source/core/html/HTMLImageLoader.cpp
new file mode 100644
index 0000000..56d048a
--- /dev/null
+++ b/Source/core/html/HTMLImageLoader.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLImageLoader.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Element.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/html/HTMLObjectElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/cache/CachedImage.h"
+#include "core/page/Settings.h"
+
+namespace WebCore {
+
+HTMLImageLoader::HTMLImageLoader(Element* node)
+    : ImageLoader(node)
+{
+}
+
+HTMLImageLoader::~HTMLImageLoader()
+{
+}
+
+void HTMLImageLoader::dispatchLoadEvent()
+{
+    // HTMLVideoElement uses this class to load the poster image, but it should not fire events for loading or failure.
+    if (element()->hasTagName(HTMLNames::videoTag))
+        return;
+
+    bool errorOccurred = image()->errorOccurred();
+    if (!errorOccurred && image()->response().httpStatusCode() >= 400)
+        errorOccurred = element()->hasTagName(HTMLNames::objectTag); // An <object> considers a 404 to be an error and should fire onerror.
+    element()->dispatchEvent(Event::create(errorOccurred ? eventNames().errorEvent : eventNames().loadEvent, false, false));
+}
+
+String HTMLImageLoader::sourceURI(const AtomicString& attr) const
+{
+    return stripLeadingAndTrailingHTMLSpaces(attr);
+}
+
+void HTMLImageLoader::notifyFinished(CachedResource*)
+{
+    CachedImage* cachedImage = image();
+
+    RefPtr<Element> element = this->element();
+    ImageLoader::notifyFinished(cachedImage);
+
+    bool loadError = cachedImage->errorOccurred() || cachedImage->response().httpStatusCode() >= 400;
+
+    if (loadError && element->hasTagName(HTMLNames::objectTag))
+        static_cast<HTMLObjectElement*>(element.get())->renderFallbackContent();
+}
+
+}
diff --git a/Source/core/html/HTMLImageLoader.h b/Source/core/html/HTMLImageLoader.h
new file mode 100644
index 0000000..c55accb
--- /dev/null
+++ b/Source/core/html/HTMLImageLoader.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLImageLoader_h
+#define HTMLImageLoader_h
+
+#include "core/loader/ImageLoader.h"
+
+namespace WebCore {
+
+class HTMLImageLoader : public ImageLoader {
+public:
+    HTMLImageLoader(Element*);
+    virtual ~HTMLImageLoader();
+
+    virtual void dispatchLoadEvent();
+    virtual String sourceURI(const AtomicString&) const;
+
+    virtual void notifyFinished(CachedResource*);
+};
+
+}
+
+#endif
diff --git a/Source/core/html/HTMLInputElement.cpp b/Source/core/html/HTMLInputElement.cpp
new file mode 100644
index 0000000..7c6383b
--- /dev/null
+++ b/Source/core/html/HTMLInputElement.cpp
@@ -0,0 +1,1906 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2012 Samsung Electronics. 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLInputElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/accessibility/AXObjectCache.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/BeforeTextInsertedEvent.h"
+#include "core/dom/Document.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/IdTargetObserver.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/ScopedEventQueue.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/TouchEvent.h"
+#include "core/editing/Editor.h"
+#include "core/editing/FrameSelection.h"
+#include "core/fileapi/FileList.h"
+#include "core/html/FileInputType.h"
+#include "core/html/FormController.h"
+#include "core/html/HTMLCollection.h"
+#include "core/html/HTMLDataListElement.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLImageLoader.h"
+#include "core/html/HTMLOptionElement.h"
+#include "core/html/InputType.h"
+#include "core/html/SearchInputType.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/shadow/InsertionPoint.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "RuntimeEnabledFeatures.h"
+#include "core/page/UseCounter.h"
+#include "core/platform/DateTimeChooser.h"
+#include "core/platform/Language.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/PlatformMouseEvent.h"
+#include "core/platform/text/PlatformLocale.h"
+#include "core/rendering/RenderTextControlSingleLine.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
+
+#if ENABLE(INPUT_TYPE_COLOR)
+#include "core/html/ColorInputType.h"
+#endif
+
+#if ENABLE(INPUT_SPEECH)
+#include "RuntimeEnabledFeatures.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#if ENABLE(DATALIST_ELEMENT)
+class ListAttributeTargetObserver : IdTargetObserver {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<ListAttributeTargetObserver> create(const AtomicString& id, HTMLInputElement*);
+    virtual void idTargetChanged() OVERRIDE;
+
+private:
+    ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement*);
+
+    HTMLInputElement* m_element;
+};
+#endif
+
+// FIXME: According to HTML4, the length attribute's value can be arbitrarily
+// large. However, due to https://bugs.webkit.org/show_bug.cgi?id=14536 things
+// get rather sluggish when a text field has a larger number of characters than
+// this, even when just clicking in the text field.
+const int HTMLInputElement::maximumLength = 524288;
+const int defaultSize = 20;
+const int maxSavedResults = 256;
+
+HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
+    : HTMLTextFormControlElement(tagName, document, form)
+    , m_size(defaultSize)
+    , m_maxLength(maximumLength)
+    , m_maxResults(-1)
+    , m_isChecked(false)
+    , m_reflectsCheckedAttribute(true)
+    , m_isIndeterminate(false)
+    , m_hasType(false)
+    , m_isActivatedSubmit(false)
+    , m_autocomplete(Uninitialized)
+    , m_isAutofilled(false)
+#if ENABLE(DATALIST_ELEMENT)
+    , m_hasNonEmptyList(false)
+#endif
+    , m_stateRestored(false)
+    , m_parsingInProgress(createdByParser)
+    , m_valueAttributeWasUpdatedAfterParsing(false)
+    , m_wasModifiedByUser(false)
+    , m_canReceiveDroppedFiles(false)
+    , m_hasTouchEventHandler(false)
+    , m_inputType(InputType::createText(this))
+{
+    ASSERT(hasTagName(inputTag) || hasTagName(isindexTag));
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+    setHasCustomStyleCallbacks();
+#endif
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
+{
+    RefPtr<HTMLInputElement> inputElement = adoptRef(new HTMLInputElement(tagName, document, form, createdByParser));
+    inputElement->ensureUserAgentShadowRoot();
+    return inputElement.release();
+}
+
+HTMLImageLoader* HTMLInputElement::imageLoader()
+{
+    if (!m_imageLoader)
+        m_imageLoader = adoptPtr(new HTMLImageLoader(this));
+    return m_imageLoader.get();
+}
+
+void HTMLInputElement::didAddUserAgentShadowRoot(ShadowRoot*)
+{
+    m_inputType->createShadowSubtree();
+}
+
+HTMLInputElement::~HTMLInputElement()
+{
+    // Need to remove form association while this is still an HTMLInputElement
+    // so that virtual functions are called correctly.
+    setForm(0);
+    // setForm(0) may register this to a document-level radio button group.
+    // We should unregister it to avoid accessing a deleted object.
+    if (isRadioButton())
+        document()->formController()->checkedRadioButtons().removeButton(this);
+    if (m_hasTouchEventHandler)
+        document()->didRemoveEventTargetNode(this);
+}
+
+const AtomicString& HTMLInputElement::name() const
+{
+    return m_name.isNull() ? emptyAtom : m_name;
+}
+
+Vector<FileChooserFileInfo> HTMLInputElement::filesFromFileInputFormControlState(const FormControlState& state)
+{
+    return FileInputType::filesFromFormControlState(state);
+}
+
+HTMLElement* HTMLInputElement::containerElement() const
+{
+    return m_inputType->containerElement();
+}
+
+HTMLElement* HTMLInputElement::innerTextElement() const
+{
+    return m_inputType->innerTextElement();
+}
+
+HTMLElement* HTMLInputElement::innerBlockElement() const
+{
+    return m_inputType->innerBlockElement();
+}
+
+HTMLElement* HTMLInputElement::innerSpinButtonElement() const
+{
+    return m_inputType->innerSpinButtonElement();
+}
+
+HTMLElement* HTMLInputElement::resultsButtonElement() const
+{
+    return m_inputType->resultsButtonElement();
+}
+
+HTMLElement* HTMLInputElement::cancelButtonElement() const
+{
+    return m_inputType->cancelButtonElement();
+}
+
+#if ENABLE(INPUT_SPEECH)
+HTMLElement* HTMLInputElement::speechButtonElement() const
+{
+    return m_inputType->speechButtonElement();
+}
+#endif
+
+HTMLElement* HTMLInputElement::sliderThumbElement() const
+{
+    return m_inputType->sliderThumbElement();
+}
+
+HTMLElement* HTMLInputElement::sliderTrackElement() const
+{
+    return m_inputType->sliderTrackElement();
+}
+
+HTMLElement* HTMLInputElement::placeholderElement() const
+{
+    return m_inputType->placeholderElement();
+}
+
+bool HTMLInputElement::shouldAutocomplete() const
+{
+    if (m_autocomplete != Uninitialized)
+        return m_autocomplete == On;
+    return HTMLTextFormControlElement::shouldAutocomplete();
+}
+
+bool HTMLInputElement::isValidValue(const String& value) const
+{
+    if (!m_inputType->canSetStringValue()) {
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+    return !m_inputType->typeMismatchFor(value)
+        && !m_inputType->stepMismatch(value)
+        && !m_inputType->rangeUnderflow(value)
+        && !m_inputType->rangeOverflow(value)
+        && !tooLong(value, IgnoreDirtyFlag)
+        && !m_inputType->patternMismatch(value)
+        && !m_inputType->valueMissing(value);
+}
+
+bool HTMLInputElement::tooLong() const
+{
+    return willValidate() && tooLong(value(), CheckDirtyFlag);
+}
+
+bool HTMLInputElement::typeMismatch() const
+{
+    return willValidate() && m_inputType->typeMismatch();
+}
+
+bool HTMLInputElement::valueMissing() const
+{
+    return willValidate() && m_inputType->valueMissing(value());
+}
+
+bool HTMLInputElement::hasBadInput() const
+{
+    return willValidate() && m_inputType->hasBadInput();
+}
+
+bool HTMLInputElement::patternMismatch() const
+{
+    return willValidate() && m_inputType->patternMismatch(value());
+}
+
+bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const
+{
+    // We use isTextType() instead of supportsMaxLength() because of the
+    // 'virtual' overhead.
+    if (!isTextType())
+        return false;
+    int max = maxLength();
+    if (max < 0)
+        return false;
+    if (check == CheckDirtyFlag) {
+        // Return false for the default value or a value set by a script even if
+        // it is longer than maxLength.
+        if (!hasDirtyValue() || !m_wasModifiedByUser)
+            return false;
+    }
+    return numGraphemeClusters(value) > static_cast<unsigned>(max);
+}
+
+bool HTMLInputElement::rangeUnderflow() const
+{
+    return willValidate() && m_inputType->rangeUnderflow(value());
+}
+
+bool HTMLInputElement::rangeOverflow() const
+{
+    return willValidate() && m_inputType->rangeOverflow(value());
+}
+
+String HTMLInputElement::validationMessage() const
+{
+    if (!willValidate())
+        return String();
+
+    if (customError())
+        return customValidationMessage();
+
+    return m_inputType->validationMessage();
+}
+
+double HTMLInputElement::minimum() const
+{
+    return m_inputType->minimum();
+}
+
+double HTMLInputElement::maximum() const
+{
+    return m_inputType->maximum();
+}
+
+bool HTMLInputElement::stepMismatch() const
+{
+    return willValidate() && m_inputType->stepMismatch(value());
+}
+
+bool HTMLInputElement::getAllowedValueStep(Decimal* step) const
+{
+    return m_inputType->getAllowedValueStep(step);
+}
+
+StepRange HTMLInputElement::createStepRange(AnyStepHandling anyStepHandling) const
+{
+    return m_inputType->createStepRange(anyStepHandling);
+}
+
+#if ENABLE(DATALIST_ELEMENT)
+Decimal HTMLInputElement::findClosestTickMarkValue(const Decimal& value)
+{
+    return m_inputType->findClosestTickMarkValue(value);
+}
+#endif
+
+void HTMLInputElement::stepUp(int n, ExceptionCode& ec)
+{
+    m_inputType->stepUp(n, ec);
+}
+
+void HTMLInputElement::stepDown(int n, ExceptionCode& ec)
+{
+    m_inputType->stepUp(-n, ec);
+}
+
+void HTMLInputElement::blur()
+{
+    m_inputType->blur();
+}
+
+void HTMLInputElement::defaultBlur()
+{
+    HTMLTextFormControlElement::blur();
+}
+
+bool HTMLInputElement::hasCustomFocusLogic() const
+{
+    return m_inputType->hasCustomFocusLogic();
+}
+
+bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
+{
+    return m_inputType->isKeyboardFocusable(event);
+}
+
+bool HTMLInputElement::isMouseFocusable() const
+{
+    return m_inputType->isMouseFocusable();
+}
+
+bool HTMLInputElement::isTextFormControlKeyboardFocusable(KeyboardEvent* event) const
+{
+    return HTMLTextFormControlElement::isKeyboardFocusable(event);
+}
+
+bool HTMLInputElement::isTextFormControlMouseFocusable() const
+{
+    return HTMLTextFormControlElement::isMouseFocusable();
+}
+
+void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
+{
+    if (isTextField()) {
+        if (!restorePreviousSelection || !hasCachedSelection())
+            select();
+        else
+            restoreCachedSelection();
+        if (document()->frame())
+            document()->frame()->selection()->revealSelection();
+    } else
+        HTMLTextFormControlElement::updateFocusAppearance(restorePreviousSelection);
+}
+
+void HTMLInputElement::endEditing()
+{
+    if (!isTextField())
+        return;
+
+    if (Frame* frame = document()->frame())
+        frame->editor()->textFieldDidEndEditing(this);
+}
+
+bool HTMLInputElement::shouldUseInputMethod()
+{
+    return m_inputType->shouldUseInputMethod();
+}
+
+void HTMLInputElement::handleFocusEvent(Node* oldFocusedNode, FocusDirection direction)
+{
+    m_inputType->handleFocusEvent(oldFocusedNode, direction);
+}
+
+void HTMLInputElement::handleBlurEvent()
+{
+    m_inputType->handleBlurEvent();
+}
+
+void HTMLInputElement::setType(const String& type)
+{
+    // 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 (type.isEmpty())
+        removeAttribute(typeAttr);
+    else
+        setAttribute(typeAttr, type);
+}
+
+void HTMLInputElement::updateType()
+{
+    OwnPtr<InputType> newType = InputType::create(this, fastGetAttribute(typeAttr));
+    bool hadType = m_hasType;
+    m_hasType = true;
+    if (m_inputType->formControlType() == newType->formControlType())
+        return;
+
+    if (hadType && !newType->canChangeFromAnotherType()) {
+        // Set the attribute back to the old value.
+        // Useful in case we were called from inside parseAttribute.
+        setAttribute(typeAttr, type());
+        return;
+    }
+
+    removeFromRadioButtonGroup();
+
+    bool didStoreValue = m_inputType->storesValueSeparateFromAttribute();
+    bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes();
+
+    m_inputType->destroyShadowSubtree();
+
+    bool wasAttached = attached();
+    if (wasAttached)
+        detach();
+
+    m_inputType = newType.release();
+    m_inputType->createShadowSubtree();
+
+    bool hasTouchEventHandler = m_inputType->hasTouchEventHandler();
+    if (hasTouchEventHandler != m_hasTouchEventHandler) {
+        if (hasTouchEventHandler)
+            document()->didAddTouchEventHandler(this);
+        else
+            document()->didRemoveTouchEventHandler(this);
+        m_hasTouchEventHandler = hasTouchEventHandler;
+    }
+
+    setNeedsWillValidateCheck();
+
+    bool willStoreValue = m_inputType->storesValueSeparateFromAttribute();
+
+    if (didStoreValue && !willStoreValue && hasDirtyValue()) {
+        setAttribute(valueAttr, m_valueIfDirty);
+        m_valueIfDirty = String();
+    }
+    if (!didStoreValue && willStoreValue) {
+        AtomicString valueString = fastGetAttribute(valueAttr);
+        m_valueIfDirty = sanitizeValue(valueString);
+    } else
+        updateValueIfNeeded();
+
+    setFormControlValueMatchesRenderer(false);
+    m_inputType->updateInnerTextValue();
+
+    m_wasModifiedByUser = false;
+
+    if (didRespectHeightAndWidth != m_inputType->shouldRespectHeightAndWidthAttributes()) {
+        ASSERT(elementData());
+        if (const Attribute* height = getAttributeItem(heightAttr))
+            attributeChanged(heightAttr, height->value());
+        if (const Attribute* width = getAttributeItem(widthAttr))
+            attributeChanged(widthAttr, width->value());
+        if (const Attribute* align = getAttributeItem(alignAttr))
+            attributeChanged(alignAttr, align->value());
+    }
+
+    if (wasAttached) {
+        attach();
+        if (document()->focusedNode() == this)
+            updateFocusAppearance(true);
+    }
+
+    if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
+        elementShadow->invalidateDistribution();
+
+    setChangedSinceLastFormControlChangeEvent(false);
+
+    addToRadioButtonGroup();
+
+    setNeedsValidityCheck();
+    notifyFormStateChanged();
+}
+
+void HTMLInputElement::subtreeHasChanged()
+{
+    m_inputType->subtreeHasChanged();
+    // When typing in an input field, childrenChanged is not called, so we need to force the directionality check.
+    calculateAndAdjustDirectionality();
+}
+
+const AtomicString& HTMLInputElement::formControlType() const
+{
+    return m_inputType->formControlType();
+}
+
+bool HTMLInputElement::shouldSaveAndRestoreFormControlState() const
+{
+    if (!m_inputType->shouldSaveAndRestoreFormControlState())
+        return false;
+    return HTMLTextFormControlElement::shouldSaveAndRestoreFormControlState();
+}
+
+FormControlState HTMLInputElement::saveFormControlState() const
+{
+    return m_inputType->saveFormControlState();
+}
+
+void HTMLInputElement::restoreFormControlState(const FormControlState& state)
+{
+    m_inputType->restoreFormControlState(state);
+    m_stateRestored = true;
+}
+
+bool HTMLInputElement::canStartSelection() const
+{
+    if (!isTextField())
+        return false;
+    return HTMLTextFormControlElement::canStartSelection();
+}
+
+bool HTMLInputElement::canHaveSelection() const
+{
+    return isTextField();
+}
+
+void HTMLInputElement::accessKeyAction(bool sendMouseEvents)
+{
+    m_inputType->accessKeyAction(sendMouseEvents);
+}
+
+bool HTMLInputElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == widthAttr || name == heightAttr || (name == borderAttr && isImageButton()))
+        return true;
+    return HTMLTextFormControlElement::isPresentationAttribute(name);
+}
+
+void HTMLInputElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == vspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
+    } else if (name == hspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
+    } else if (name == alignAttr) {
+        if (m_inputType->shouldRespectAlignAttribute())
+            applyAlignmentAttributeToStyle(value, style);
+    } else if (name == widthAttr) {
+        if (m_inputType->shouldRespectHeightAndWidthAttributes())
+            addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+    } else if (name == heightAttr) {
+        if (m_inputType->shouldRespectHeightAndWidthAttributes())
+            addHTMLLengthToStyle(style, CSSPropertyHeight, value);
+    } else if (name == borderAttr && isImageButton())
+        applyBorderAttributeToStyle(value, style);
+    else
+        HTMLTextFormControlElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLInputElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == nameAttr) {
+        removeFromRadioButtonGroup();
+        m_name = value;
+        addToRadioButtonGroup();
+        HTMLTextFormControlElement::parseAttribute(name, value);
+    } else if (name == autocompleteAttr) {
+        if (equalIgnoringCase(value, "off"))
+            m_autocomplete = Off;
+        else {
+            if (value.isEmpty())
+                m_autocomplete = Uninitialized;
+            else
+                m_autocomplete = On;
+        }
+    } else if (name == typeAttr)
+        updateType();
+    else if (name == valueAttr) {
+        // We only need to setChanged if the form is looking at the default value right now.
+        if (!hasDirtyValue()) {
+            updatePlaceholderVisibility(false);
+            setNeedsStyleRecalc();
+        }
+        setFormControlValueMatchesRenderer(false);
+        setNeedsValidityCheck();
+        m_valueAttributeWasUpdatedAfterParsing = !m_parsingInProgress;
+        m_inputType->valueAttributeChanged();
+    } else if (name == checkedAttr) {
+        // Another radio button in the same group might be checked by state
+        // restore. We shouldn't call setChecked() even if this has the checked
+        // attribute. So, delay the setChecked() call until
+        // finishParsingChildren() is called if parsing is in progress.
+        if (!m_parsingInProgress && m_reflectsCheckedAttribute) {
+            setChecked(!value.isNull());
+            m_reflectsCheckedAttribute = true;
+        }
+    } else if (name == maxlengthAttr)
+        parseMaxLengthAttribute(value);
+    else if (name == sizeAttr) {
+        int oldSize = m_size;
+        int valueAsInteger = value.toInt();
+        m_size = valueAsInteger > 0 ? valueAsInteger : defaultSize;
+        if (m_size != oldSize && renderer())
+            renderer()->setNeedsLayoutAndPrefWidthsRecalc();
+    } else if (name == altAttr)
+        m_inputType->altAttributeChanged();
+    else if (name == srcAttr)
+        m_inputType->srcAttributeChanged();
+    else if (name == usemapAttr || name == accesskeyAttr) {
+        // FIXME: ignore for the moment
+    } else if (name == onsearchAttr) {
+        // Search field and slider attributes all just cause updateFromElement to be called through style recalcing.
+        setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, name, value));
+    } else if (name == resultsAttr) {
+        int oldResults = m_maxResults;
+        m_maxResults = !value.isNull() ? std::min(value.toInt(), maxSavedResults) : -1;
+        // FIXME: Detaching just for maxResults change is not ideal.  We should figure out the right
+        // time to relayout for this change.
+        if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0))
+            reattachIfAttached();
+        setNeedsStyleRecalc();
+        UseCounter::count(document(), UseCounter::ResultsAttribute);
+    } else if (name == autosaveAttr) {
+        setNeedsStyleRecalc();
+        UseCounter::count(document(), UseCounter::AutoSaveAttribute);
+    } else if (name == incrementalAttr) {
+        setNeedsStyleRecalc();
+        UseCounter::count(document(), UseCounter::IncrementalAttribute);
+    } else if (name == minAttr) {
+        m_inputType->minOrMaxAttributeChanged();
+        setNeedsValidityCheck();
+        UseCounter::count(document(), UseCounter::MinAttribute);
+    } else if (name == maxAttr) {
+        m_inputType->minOrMaxAttributeChanged();
+        setNeedsValidityCheck();
+        UseCounter::count(document(), UseCounter::MaxAttribute);
+    } else if (name == multipleAttr) {
+        m_inputType->multipleAttributeChanged();
+        setNeedsValidityCheck();
+    } else if (name == stepAttr) {
+        m_inputType->stepAttributeChanged();
+        setNeedsValidityCheck();
+        UseCounter::count(document(), UseCounter::StepAttribute);
+    } else if (name == patternAttr) {
+        setNeedsValidityCheck();
+        UseCounter::count(document(), UseCounter::PatternAttribute);
+    } else if (name == precisionAttr) {
+        setNeedsValidityCheck();
+        UseCounter::count(document(), UseCounter::PrecisionAttribute);
+    } else if (name == disabledAttr) {
+        HTMLTextFormControlElement::parseAttribute(name, value);
+        m_inputType->disabledAttributeChanged();
+    } else if (name == readonlyAttr) {
+        HTMLTextFormControlElement::parseAttribute(name, value);
+        m_inputType->readonlyAttributeChanged();
+    }
+#if ENABLE(DATALIST_ELEMENT)
+    else if (name == listAttr) {
+        m_hasNonEmptyList = !value.isEmpty();
+        if (m_hasNonEmptyList) {
+            resetListAttributeTargetObserver();
+            listAttributeTargetChanged();
+        }
+        UseCounter::count(document(), UseCounter::ListAttribute);
+    }
+#endif
+#if ENABLE(INPUT_SPEECH)
+    else if (name == webkitspeechAttr) {
+        if (renderer()) {
+            // This renderer and its children have quite different layouts and styles depending on
+            // whether the speech button is visible or not. So we reset the whole thing and recreate
+            // to get the right styles and layout.
+            detach();
+            m_inputType->destroyShadowSubtree();
+            m_inputType->createShadowSubtree();
+            if (!attached())
+                attach();
+        } else {
+            m_inputType->destroyShadowSubtree();
+            m_inputType->createShadowSubtree();
+        }
+        setFormControlValueMatchesRenderer(false);
+        setNeedsStyleRecalc();
+        UseCounter::count(document(), UseCounter::PrefixedSpeechAttribute);
+    } else if (name == onwebkitspeechchangeAttr)
+        setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, name, value));
+#endif
+    else if (name == webkitdirectoryAttr) {
+        HTMLTextFormControlElement::parseAttribute(name, value);
+        UseCounter::count(document(), UseCounter::PrefixedDirectoryAttribute);
+    }
+    else
+        HTMLTextFormControlElement::parseAttribute(name, value);
+    m_inputType->attributeChanged();
+}
+
+void HTMLInputElement::finishParsingChildren()
+{
+    m_parsingInProgress = false;
+    HTMLTextFormControlElement::finishParsingChildren();
+    if (!m_stateRestored) {
+        bool checked = hasAttribute(checkedAttr);
+        if (checked)
+            setChecked(checked);
+        m_reflectsCheckedAttribute = true;
+    }
+}
+
+bool HTMLInputElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    return m_inputType->rendererIsNeeded() && HTMLTextFormControlElement::rendererIsNeeded(context);
+}
+
+RenderObject* HTMLInputElement::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+    return m_inputType->createRenderer(arena, style);
+}
+
+void HTMLInputElement::attach()
+{
+    PostAttachCallbackDisabler disabler(this);
+
+    if (!m_hasType)
+        updateType();
+
+    HTMLTextFormControlElement::attach();
+
+    m_inputType->attach();
+
+    if (document()->focusedNode() == this)
+        document()->updateFocusAppearanceSoon(true /* restore selection */);
+}
+
+void HTMLInputElement::detach()
+{
+    HTMLTextFormControlElement::detach();
+    setFormControlValueMatchesRenderer(false);
+    m_inputType->detach();
+}
+
+String HTMLInputElement::altText() const
+{
+    // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
+    // also heavily discussed by Hixie on bugzilla
+    // note this is intentionally different to HTMLImageElement::altText()
+    String alt = fastGetAttribute(altAttr);
+    // fall back to title attribute
+    if (alt.isNull())
+        alt = getAttribute(titleAttr);
+    if (alt.isNull())
+        alt = getAttribute(valueAttr);
+    if (alt.isEmpty())
+        alt = inputElementAltText();
+    return alt;
+}
+
+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 not.
+    return !isDisabledFormControl() && m_inputType->canBeSuccessfulSubmitButton();
+}
+
+bool HTMLInputElement::isActivatedSubmit() const
+{
+    return m_isActivatedSubmit;
+}
+
+void HTMLInputElement::setActivatedSubmit(bool flag)
+{
+    m_isActivatedSubmit = flag;
+}
+
+bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart)
+{
+    return m_inputType->isFormDataAppendable() && m_inputType->appendFormData(encoding, multipart);
+}
+
+void HTMLInputElement::reset()
+{
+    if (m_inputType->storesValueSeparateFromAttribute())
+        setValue(String());
+
+    setAutofilled(false);
+    setChecked(hasAttribute(checkedAttr));
+    m_reflectsCheckedAttribute = true;
+}
+
+bool HTMLInputElement::isTextField() const
+{
+    return m_inputType->isTextField();
+}
+
+bool HTMLInputElement::isTextType() const
+{
+    return m_inputType->isTextType();
+}
+
+void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventBehavior)
+{
+    if (checked() == nowChecked)
+        return;
+
+    m_reflectsCheckedAttribute = false;
+    m_isChecked = nowChecked;
+    setNeedsStyleRecalc();
+
+    if (CheckedRadioButtons* buttons = checkedRadioButtons())
+            buttons->updateCheckedState(this);
+    if (renderer() && renderer()->style()->hasAppearance())
+        renderer()->theme()->stateChanged(renderer(), CheckedState);
+    setNeedsValidityCheck();
+
+    // Ideally we'd do this from the render tree (matching
+    // RenderTextView), but it's not possible to do it at the moment
+    // because of the way the code is structured.
+    if (renderer()) {
+        if (AXObjectCache* cache = renderer()->document()->existingAXObjectCache())
+            cache->checkedStateChanged(this);
+    }
+
+    // Only send a change event for items in the document (avoid firing during
+    // parsing) and don't send a change event for a radio button that's getting
+    // 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 (eventBehavior != DispatchNoEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) {
+        setTextAsOfLastFormControlChangeEvent(String());
+        dispatchFormControlChangeEvent();
+    }
+
+    didAffectSelector(AffectedSelectorChecked);
+}
+
+void HTMLInputElement::setIndeterminate(bool newValue)
+{
+    if (indeterminate() == newValue)
+        return;
+
+    m_isIndeterminate = newValue;
+
+    didAffectSelector(AffectedSelectorIndeterminate);
+
+    if (renderer() && renderer()->style()->hasAppearance())
+        renderer()->theme()->stateChanged(renderer(), CheckedState);
+}
+
+int HTMLInputElement::size() const
+{
+    return m_size;
+}
+
+bool HTMLInputElement::sizeShouldIncludeDecoration(int& preferredSize) const
+{
+    return m_inputType->sizeShouldIncludeDecoration(defaultSize, preferredSize);
+}
+
+void HTMLInputElement::copyNonAttributePropertiesFromElement(const Element& source)
+{
+    const HTMLInputElement& sourceElement = static_cast<const HTMLInputElement&>(source);
+
+    m_valueIfDirty = sourceElement.m_valueIfDirty;
+    m_wasModifiedByUser = false;
+    setChecked(sourceElement.m_isChecked);
+    m_reflectsCheckedAttribute = sourceElement.m_reflectsCheckedAttribute;
+    m_isIndeterminate = sourceElement.m_isIndeterminate;
+
+    HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source);
+
+    setFormControlValueMatchesRenderer(false);
+    m_inputType->updateInnerTextValue();
+}
+
+String HTMLInputElement::value() const
+{
+    String value;
+    if (m_inputType->getTypeSpecificValue(value))
+        return value;
+
+    value = m_valueIfDirty;
+    if (!value.isNull())
+        return value;
+
+    AtomicString valueString = fastGetAttribute(valueAttr);
+    value = sanitizeValue(valueString);
+    if (!value.isNull())
+        return value;
+
+    return m_inputType->fallbackValue();
+}
+
+String HTMLInputElement::valueWithDefault() const
+{
+    String value = this->value();
+    if (!value.isNull())
+        return value;
+
+    return m_inputType->defaultValue();
+}
+
+void HTMLInputElement::setValueForUser(const String& value)
+{
+    // Call setValue and make it send a change event.
+    setValue(value, DispatchChangeEvent);
+}
+
+const String& HTMLInputElement::suggestedValue() const
+{
+    return m_suggestedValue;
+}
+
+void HTMLInputElement::setSuggestedValue(const String& value)
+{
+    if (!m_inputType->canSetSuggestedValue())
+        return;
+    setFormControlValueMatchesRenderer(false);
+    m_suggestedValue = sanitizeValue(value);
+    setNeedsStyleRecalc();
+    m_inputType->updateInnerTextValue();
+}
+
+void HTMLInputElement::setEditingValue(const String& value)
+{
+    if (!renderer() || !isTextField())
+        return;
+    setInnerTextValue(value);
+    subtreeHasChanged();
+
+    unsigned max = value.length();
+    if (focused())
+        setSelectionRange(max, max);
+    else
+        cacheSelectionInResponseToSetValue(max);
+
+    dispatchInputEvent();
+}
+
+void HTMLInputElement::setValue(const String& value, ExceptionCode& ec, TextFieldEventBehavior eventBehavior)
+{
+    if (isFileUpload() && !value.isEmpty()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    setValue(value, eventBehavior);
+}
+
+void HTMLInputElement::setValue(const String& value, TextFieldEventBehavior eventBehavior)
+{
+    if (!m_inputType->canSetValue(value))
+        return;
+
+    RefPtr<HTMLInputElement> protector(this);
+    EventQueueScope scope;
+    String sanitizedValue = sanitizeValue(value);
+    bool valueChanged = sanitizedValue != this->value();
+
+    setLastChangeWasNotUserEdit();
+    setFormControlValueMatchesRenderer(false);
+    m_suggestedValue = String(); // Prevent TextFieldInputType::setValue from using the suggested value.
+    m_inputType->setValue(sanitizedValue, valueChanged, eventBehavior);
+
+    if (!valueChanged)
+        return;
+
+    notifyFormStateChanged();
+}
+
+void HTMLInputElement::setValueInternal(const String& sanitizedValue, TextFieldEventBehavior eventBehavior)
+{
+    m_valueIfDirty = sanitizedValue;
+    m_wasModifiedByUser = eventBehavior != DispatchNoEvent;
+    setNeedsValidityCheck();
+}
+
+double HTMLInputElement::valueAsDate() const
+{
+    return m_inputType->valueAsDate();
+}
+
+void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec)
+{
+    m_inputType->setValueAsDate(value, ec);
+}
+
+double HTMLInputElement::valueAsNumber() const
+{
+    return m_inputType->valueAsDouble();
+}
+
+void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec, TextFieldEventBehavior eventBehavior)
+{
+    if (!std::isfinite(newValue)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    m_inputType->setValueAsDouble(newValue, eventBehavior, ec);
+}
+
+void HTMLInputElement::setValueFromRenderer(const String& value)
+{
+    // File upload controls will never use this.
+    ASSERT(!isFileUpload());
+
+    m_suggestedValue = String();
+
+    // Renderer and our event handler are responsible for sanitizing values.
+    ASSERT(value == sanitizeValue(value) || sanitizeValue(value).isEmpty());
+
+    // Workaround for bug where trailing \n is included in the result of textContent.
+    // The assert macro above may also be simplified to: value == constrainValue(value)
+    // http://bugs.webkit.org/show_bug.cgi?id=9661
+    m_valueIfDirty = value == "\n" ? emptyString() : value;
+
+    setFormControlValueMatchesRenderer(true);
+    m_wasModifiedByUser = true;
+
+    // Input event is fired by the Node::defaultEventHandler for editable controls.
+    if (!isTextField())
+        dispatchInputEvent();
+    notifyFormStateChanged();
+
+    setNeedsValidityCheck();
+
+    // Clear autofill flag (and yellow background) on user edit.
+    setAutofilled(false);
+}
+
+void* HTMLInputElement::preDispatchEventHandler(Event* event)
+{
+    if (event->type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event)) {
+        event->stopPropagation();
+        return 0;
+    }
+    if (event->type() != eventNames().clickEvent)
+        return 0;
+    if (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button() != LeftButton)
+        return 0;
+    // FIXME: Check whether there are any cases where this actually ends up leaking.
+    return m_inputType->willDispatchClick().leakPtr();
+}
+
+void HTMLInputElement::postDispatchEventHandler(Event* event, void* dataFromPreDispatch)
+{
+    OwnPtr<ClickHandlingState> state = adoptPtr(static_cast<ClickHandlingState*>(dataFromPreDispatch));
+    if (!state)
+        return;
+    m_inputType->didDispatchClick(event, *state);
+}
+
+void HTMLInputElement::defaultEventHandler(Event* evt)
+{
+    if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
+        m_inputType->handleClickEvent(static_cast<MouseEvent*>(evt));
+        if (evt->defaultHandled())
+            return;
+    }
+
+    if (evt->isTouchEvent()) {
+        m_inputType->handleTouchEvent(static_cast<TouchEvent*>(evt));
+        if (evt->defaultHandled())
+            return;
+    }
+
+    if (evt->isKeyboardEvent() && evt->type() == eventNames().keydownEvent) {
+        m_inputType->handleKeydownEvent(static_cast<KeyboardEvent*>(evt));
+        if (evt->defaultHandled())
+            return;
+    }
+
+    // Call the base event handler before any of our own event handling for almost all events in text fields.
+    // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function.
+    bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
+    if (callBaseClassEarly) {
+        HTMLTextFormControlElement::defaultEventHandler(evt);
+        if (evt->defaultHandled())
+            return;
+    }
+
+    // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
+    // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
+    // 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) {
+        m_inputType->handleDOMActivateEvent(evt);
+        if (evt->defaultHandled())
+            return;
+    }
+
+    // Use key press event here since sending simulated mouse events
+    // on key down blocks the proper sending of the key press event.
+    if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent) {
+        m_inputType->handleKeypressEvent(static_cast<KeyboardEvent*>(evt));
+        if (evt->defaultHandled())
+            return;
+    }
+
+    if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent) {
+        m_inputType->handleKeyupEvent(static_cast<KeyboardEvent*>(evt));
+        if (evt->defaultHandled())
+            return;
+    }
+
+    if (m_inputType->shouldSubmitImplicitly(evt)) {
+        if (isSearchField()) {
+            addSearchResult();
+            onSearch();
+        }
+        // Form submission finishes editing, just as loss of focus does.
+        // If there was a change, send the event now.
+        if (wasChangedSinceLastFormControlChangeEvent())
+            dispatchFormControlChangeEvent();
+
+        RefPtr<HTMLFormElement> formForSubmission = m_inputType->formForSubmission();
+        // Form may never have been present, or may have been destroyed by code responding to the change event.
+        if (formForSubmission)
+            formForSubmission->submitImplicitly(evt, canTriggerImplicitSubmission());
+
+        evt->setDefaultHandled();
+        return;
+    }
+
+    if (evt->isBeforeTextInsertedEvent())
+        m_inputType->handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(evt));
+
+    if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent) {
+        m_inputType->handleMouseDownEvent(static_cast<MouseEvent*>(evt));
+        if (evt->defaultHandled())
+            return;
+    }
+
+    m_inputType->forwardEvent(evt);
+
+    if (!callBaseClassEarly && !evt->defaultHandled())
+        HTMLTextFormControlElement::defaultEventHandler(evt);
+}
+
+bool HTMLInputElement::willRespondToMouseClickEvents()
+{
+    // FIXME: Consider implementing willRespondToMouseClickEvents() in InputType if more accurate results are necessary.
+    if (!isDisabledFormControl())
+        return true;
+
+    return HTMLTextFormControlElement::willRespondToMouseClickEvents();
+}
+
+bool HTMLInputElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == srcAttr || attribute.name() == formactionAttr || HTMLTextFormControlElement::isURLAttribute(attribute);
+}
+
+String HTMLInputElement::defaultValue() const
+{
+    return fastGetAttribute(valueAttr);
+}
+
+void HTMLInputElement::setDefaultValue(const String &value)
+{
+    setAttribute(valueAttr, value);
+}
+
+static inline bool isRFC2616TokenCharacter(UChar ch)
+{
+    return isASCII(ch) && ch > ' ' && ch != '"' && ch != '(' && ch != ')' && ch != ',' && ch != '/' && (ch < ':' || ch > '@') && (ch < '[' || ch > ']') && ch != '{' && ch != '}' && ch != 0x7f;
+}
+
+static bool isValidMIMEType(const String& type)
+{
+    size_t slashPosition = type.find('/');
+    if (slashPosition == notFound || !slashPosition || slashPosition == type.length() - 1)
+        return false;
+    for (size_t i = 0; i < type.length(); ++i) {
+        if (!isRFC2616TokenCharacter(type[i]) && i != slashPosition)
+            return false;
+    }
+    return true;
+}
+
+static bool isValidFileExtension(const String& type)
+{
+    if (type.length() < 2)
+        return false;
+    return type[0] == '.';
+}
+
+static Vector<String> parseAcceptAttribute(const String& acceptString, bool (*predicate)(const String&))
+{
+    Vector<String> types;
+    if (acceptString.isEmpty())
+        return types;
+
+    Vector<String> splitTypes;
+    acceptString.split(',', false, splitTypes);
+    for (size_t i = 0; i < splitTypes.size(); ++i) {
+        String trimmedType = stripLeadingAndTrailingHTMLSpaces(splitTypes[i]);
+        if (trimmedType.isEmpty())
+            continue;
+        if (!predicate(trimmedType))
+            continue;
+        types.append(trimmedType.lower());
+    }
+
+    return types;
+}
+
+Vector<String> HTMLInputElement::acceptMIMETypes()
+{
+    return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidMIMEType);
+}
+
+Vector<String> HTMLInputElement::acceptFileExtensions()
+{
+    return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidFileExtension);
+}
+
+String HTMLInputElement::accept() const
+{
+    return fastGetAttribute(acceptAttr);
+}
+
+String HTMLInputElement::alt() const
+{
+    return fastGetAttribute(altAttr);
+}
+
+int HTMLInputElement::maxLength() const
+{
+    return m_maxLength;
+}
+
+void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec)
+{
+    if (maxLength < 0)
+        ec = INDEX_SIZE_ERR;
+    else
+        setAttribute(maxlengthAttr, String::number(maxLength));
+}
+
+bool HTMLInputElement::multiple() const
+{
+    return fastHasAttribute(multipleAttr);
+}
+
+void HTMLInputElement::setSize(unsigned size)
+{
+    setAttribute(sizeAttr, String::number(size));
+}
+
+void HTMLInputElement::setSize(unsigned size, ExceptionCode& ec)
+{
+    if (!size)
+        ec = INDEX_SIZE_ERR;
+    else
+        setSize(size);
+}
+
+KURL HTMLInputElement::src() const
+{
+    return document()->completeURL(fastGetAttribute(srcAttr));
+}
+
+void HTMLInputElement::setAutofilled(bool autofilled)
+{
+    if (autofilled == m_isAutofilled)
+        return;
+
+    m_isAutofilled = autofilled;
+    setNeedsStyleRecalc();
+}
+
+FileList* HTMLInputElement::files()
+{
+    return m_inputType->files();
+}
+
+void HTMLInputElement::setFiles(PassRefPtr<FileList> files)
+{
+    m_inputType->setFiles(files);
+}
+
+bool HTMLInputElement::receiveDroppedFiles(const DragData* dragData)
+{
+    return m_inputType->receiveDroppedFiles(dragData);
+}
+
+String HTMLInputElement::droppedFileSystemId()
+{
+    return m_inputType->droppedFileSystemId();
+}
+
+Icon* HTMLInputElement::icon() const
+{
+    return m_inputType->icon();
+}
+
+bool HTMLInputElement::canReceiveDroppedFiles() const
+{
+    return m_canReceiveDroppedFiles;
+}
+
+void HTMLInputElement::setCanReceiveDroppedFiles(bool canReceiveDroppedFiles)
+{
+    if (m_canReceiveDroppedFiles == canReceiveDroppedFiles)
+        return;
+    m_canReceiveDroppedFiles = canReceiveDroppedFiles;
+    if (renderer())
+        renderer()->updateFromElement();
+}
+
+String HTMLInputElement::visibleValue() const
+{
+    return m_inputType->visibleValue();
+}
+
+String HTMLInputElement::sanitizeValue(const String& proposedValue) const
+{
+    if (proposedValue.isNull())
+        return proposedValue;
+    return m_inputType->sanitizeValue(proposedValue);
+}
+
+String HTMLInputElement::localizeValue(const String& proposedValue) const
+{
+    if (proposedValue.isNull())
+        return proposedValue;
+    return m_inputType->localizeValue(proposedValue);
+}
+
+bool HTMLInputElement::isInRange() const
+{
+    return m_inputType->isInRange(value());
+}
+
+bool HTMLInputElement::isOutOfRange() const
+{
+    return m_inputType->isOutOfRange(value());
+}
+
+bool HTMLInputElement::isRequiredFormControl() const
+{
+    return m_inputType->supportsRequired() && isRequired();
+}
+
+bool HTMLInputElement::matchesReadOnlyPseudoClass() const
+{
+    return m_inputType->supportsReadOnly() && isReadOnly();
+}
+
+bool HTMLInputElement::matchesReadWritePseudoClass() const
+{
+    return m_inputType->supportsReadOnly() && !isReadOnly();
+}
+
+void HTMLInputElement::addSearchResult()
+{
+    m_inputType->addSearchResult();
+}
+
+void HTMLInputElement::onSearch()
+{
+    ASSERT(isSearchField());
+    if (m_inputType)
+        static_cast<SearchInputType*>(m_inputType.get())->stopSearchEventTimer();
+    dispatchEvent(Event::create(eventNames().searchEvent, true, false));
+}
+
+void HTMLInputElement::updateClearButtonVisibility()
+{
+    m_inputType->updateClearButtonVisibility();
+}
+
+void HTMLInputElement::willChangeForm()
+{
+    removeFromRadioButtonGroup();
+    HTMLTextFormControlElement::willChangeForm();
+}
+
+void HTMLInputElement::didChangeForm()
+{
+    HTMLTextFormControlElement::didChangeForm();
+    addToRadioButtonGroup();
+}
+
+Node::InsertionNotificationRequest HTMLInputElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLTextFormControlElement::insertedInto(insertionPoint);
+    if (insertionPoint->inDocument() && !form())
+        addToRadioButtonGroup();
+#if ENABLE(DATALIST_ELEMENT)
+    resetListAttributeTargetObserver();
+#endif
+    return InsertionDone;
+}
+
+void HTMLInputElement::removedFrom(ContainerNode* insertionPoint)
+{
+    if (insertionPoint->inDocument() && !form())
+        removeFromRadioButtonGroup();
+    HTMLTextFormControlElement::removedFrom(insertionPoint);
+    ASSERT(!inDocument());
+#if ENABLE(DATALIST_ELEMENT)
+    resetListAttributeTargetObserver();
+#endif
+}
+
+void HTMLInputElement::didMoveToNewDocument(Document* oldDocument)
+{
+    if (hasImageLoader())
+        imageLoader()->elementDidMoveToNewDocument();
+
+    if (oldDocument) {
+        if (isRadioButton())
+            oldDocument->formController()->checkedRadioButtons().removeButton(this);
+        if (m_hasTouchEventHandler)
+            oldDocument->didRemoveEventTargetNode(this);
+    }
+
+    if (m_hasTouchEventHandler)
+        document()->didAddTouchEventHandler(this);
+
+    HTMLTextFormControlElement::didMoveToNewDocument(oldDocument);
+}
+
+void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLTextFormControlElement::addSubresourceAttributeURLs(urls);
+
+    addSubresourceURL(urls, src());
+}
+
+bool HTMLInputElement::recalcWillValidate() const
+{
+    return m_inputType->supportsValidation() && HTMLTextFormControlElement::recalcWillValidate();
+}
+
+void HTMLInputElement::requiredAttributeChanged()
+{
+    HTMLTextFormControlElement::requiredAttributeChanged();
+    if (CheckedRadioButtons* buttons = checkedRadioButtons())
+        buttons->requiredAttributeChanged(this);
+    m_inputType->requiredAttributeChanged();
+}
+
+#if ENABLE(INPUT_TYPE_COLOR)
+void HTMLInputElement::selectColorInColorChooser(const Color& color)
+{
+    if (!m_inputType->isColorControl())
+        return;
+    static_cast<ColorInputType*>(m_inputType.get())->didChooseColor(color);
+}
+#endif
+
+#if ENABLE(DATALIST_ELEMENT)
+HTMLElement* HTMLInputElement::list() const
+{
+    return dataList();
+}
+
+HTMLDataListElement* HTMLInputElement::dataList() const
+{
+    if (!m_hasNonEmptyList)
+        return 0;
+
+    if (!m_inputType->shouldRespectListAttribute())
+        return 0;
+
+    Element* element = treeScope()->getElementById(fastGetAttribute(listAttr));
+    if (!element)
+        return 0;
+    if (!element->hasTagName(datalistTag))
+        return 0;
+
+    return static_cast<HTMLDataListElement*>(element);
+}
+
+void HTMLInputElement::resetListAttributeTargetObserver()
+{
+    if (inDocument())
+        m_listAttributeTargetObserver = ListAttributeTargetObserver::create(fastGetAttribute(listAttr), this);
+    else
+        m_listAttributeTargetObserver = nullptr;
+}
+
+void HTMLInputElement::listAttributeTargetChanged()
+{
+    m_inputType->listAttributeTargetChanged();
+}
+#endif // ENABLE(DATALIST_ELEMENT)
+
+bool HTMLInputElement::isSteppable() const
+{
+    return m_inputType->isSteppable();
+}
+
+#if ENABLE(INPUT_SPEECH)
+
+bool HTMLInputElement::isSpeechEnabled() const
+{
+    // FIXME: Add support for RANGE, EMAIL, URL, COLOR and DATE/TIME input types.
+    return m_inputType->shouldRespectSpeechAttribute() && RuntimeEnabledFeatures::speechInputEnabled() && hasAttribute(webkitspeechAttr);
+}
+
+#endif
+
+bool HTMLInputElement::isTextButton() const
+{
+    return m_inputType->isTextButton();
+}
+
+bool HTMLInputElement::isRadioButton() const
+{
+    return m_inputType->isRadioButton();
+}
+
+bool HTMLInputElement::isSearchField() const
+{
+    return m_inputType->isSearchField();
+}
+
+bool HTMLInputElement::isInputTypeHidden() const
+{
+    return m_inputType->isHiddenType();
+}
+
+bool HTMLInputElement::isPasswordField() const
+{
+    return m_inputType->isPasswordField();
+}
+
+bool HTMLInputElement::isCheckbox() const
+{
+    return m_inputType->isCheckbox();
+}
+
+bool HTMLInputElement::isRangeControl() const
+{
+    return m_inputType->isRangeControl();
+}
+
+#if ENABLE(INPUT_TYPE_COLOR)
+bool HTMLInputElement::isColorControl() const
+{
+    return m_inputType->isColorControl();
+}
+#endif
+
+bool HTMLInputElement::isText() const
+{
+    return m_inputType->isTextType();
+}
+
+bool HTMLInputElement::isEmailField() const
+{
+    return m_inputType->isEmailField();
+}
+
+bool HTMLInputElement::isFileUpload() const
+{
+    return m_inputType->isFileUpload();
+}
+
+bool HTMLInputElement::isImageButton() const
+{
+    return m_inputType->isImageButton();
+}
+
+bool HTMLInputElement::isNumberField() const
+{
+    return m_inputType->isNumberField();
+}
+
+bool HTMLInputElement::isSubmitButton() const
+{
+    return m_inputType->isSubmitButton();
+}
+
+bool HTMLInputElement::isTelephoneField() const
+{
+    return m_inputType->isTelephoneField();
+}
+
+bool HTMLInputElement::isURLField() const
+{
+    return m_inputType->isURLField();
+}
+
+bool HTMLInputElement::isDateField() const
+{
+    return m_inputType->isDateField();
+}
+
+bool HTMLInputElement::isDateTimeField() const
+{
+    return m_inputType->isDateTimeField();
+}
+
+bool HTMLInputElement::isDateTimeLocalField() const
+{
+    return m_inputType->isDateTimeLocalField();
+}
+
+bool HTMLInputElement::isMonthField() const
+{
+    return m_inputType->isMonthField();
+}
+
+bool HTMLInputElement::isTimeField() const
+{
+    return m_inputType->isTimeField();
+}
+
+bool HTMLInputElement::isWeekField() const
+{
+    return m_inputType->isWeekField();
+}
+
+bool HTMLInputElement::isEnumeratable() const
+{
+    return m_inputType->isEnumeratable();
+}
+
+bool HTMLInputElement::supportLabels() const
+{
+    return m_inputType->supportLabels();
+}
+
+bool HTMLInputElement::shouldAppearChecked() const
+{
+    return checked() && m_inputType->isCheckable();
+}
+
+bool HTMLInputElement::supportsPlaceholder() const
+{
+    return m_inputType->supportsPlaceholder();
+}
+
+void HTMLInputElement::updatePlaceholderText()
+{
+    return m_inputType->updatePlaceholderText();
+}
+
+void HTMLInputElement::parseMaxLengthAttribute(const AtomicString& value)
+{
+    int maxLength;
+    if (!parseHTMLInteger(value, maxLength))
+        maxLength = maximumLength;
+    if (maxLength < 0 || maxLength > maximumLength)
+        maxLength = maximumLength;
+    int oldMaxLength = m_maxLength;
+    m_maxLength = maxLength;
+    if (oldMaxLength != maxLength)
+        updateValueIfNeeded();
+    setNeedsStyleRecalc();
+    setNeedsValidityCheck();
+}
+
+void HTMLInputElement::updateValueIfNeeded()
+{
+    String newValue = sanitizeValue(m_valueIfDirty);
+    ASSERT(!m_valueIfDirty.isNull() || newValue.isNull());
+    if (newValue != m_valueIfDirty)
+        setValue(newValue);
+}
+
+String HTMLInputElement::defaultToolTip() const
+{
+    return m_inputType->defaultToolTip();
+}
+
+bool HTMLInputElement::shouldAppearIndeterminate() const
+{
+    return m_inputType->supportsIndeterminateAppearance() && indeterminate();
+}
+
+#if ENABLE(MEDIA_CAPTURE)
+String HTMLInputElement::capture() const
+{
+    if (!isFileUpload())
+        return String();
+
+    String capture = fastGetAttribute(captureAttr).lower();
+    if (capture == "camera"
+        || capture == "camcorder"
+        || capture == "microphone"
+        || capture == "filesystem")
+        return capture;
+
+    return "filesystem";
+}
+
+void HTMLInputElement::setCapture(const String& value)
+{
+    setAttribute(captureAttr, value);
+}
+
+#endif
+
+bool HTMLInputElement::isInRequiredRadioButtonGroup()
+{
+    ASSERT(isRadioButton());
+    if (CheckedRadioButtons* buttons = checkedRadioButtons())
+        return buttons->isInRequiredGroup(this);
+    return false;
+}
+
+HTMLInputElement* HTMLInputElement::checkedRadioButtonForGroup() const
+{
+    if (CheckedRadioButtons* buttons = checkedRadioButtons())
+        return buttons->checkedButtonForGroup(name());
+    return 0;
+}
+
+CheckedRadioButtons* HTMLInputElement::checkedRadioButtons() const
+{
+    if (!isRadioButton())
+        return 0;
+    if (HTMLFormElement* formElement = form())
+        return &formElement->checkedRadioButtons();
+    if (inDocument())
+        return &document()->formController()->checkedRadioButtons();
+    return 0;
+}
+
+inline void HTMLInputElement::addToRadioButtonGroup()
+{
+    if (CheckedRadioButtons* buttons = checkedRadioButtons())
+        buttons->addButton(this);
+}
+
+inline void HTMLInputElement::removeFromRadioButtonGroup()
+{
+    if (CheckedRadioButtons* buttons = checkedRadioButtons())
+        buttons->removeButton(this);
+}
+
+unsigned HTMLInputElement::height() const
+{
+    return m_inputType->height();
+}
+
+unsigned HTMLInputElement::width() const
+{
+    return m_inputType->width();
+}
+
+void HTMLInputElement::setHeight(unsigned height)
+{
+    setAttribute(heightAttr, String::number(height));
+}
+
+void HTMLInputElement::setWidth(unsigned width)
+{
+    setAttribute(widthAttr, String::number(width));
+}
+
+#if ENABLE(DATALIST_ELEMENT)
+PassOwnPtr<ListAttributeTargetObserver> ListAttributeTargetObserver::create(const AtomicString& id, HTMLInputElement* element)
+{
+    return adoptPtr(new ListAttributeTargetObserver(id, element));
+}
+
+ListAttributeTargetObserver::ListAttributeTargetObserver(const AtomicString& id, HTMLInputElement* element)
+    : IdTargetObserver(element->treeScope()->idTargetObserverRegistry(), id)
+    , m_element(element)
+{
+}
+
+void ListAttributeTargetObserver::idTargetChanged()
+{
+    m_element->listAttributeTargetChanged();
+}
+#endif
+
+void HTMLInputElement::setRangeText(const String& replacement, ExceptionCode& ec)
+{
+    if (!m_inputType->supportsSelectionAPI()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    HTMLTextFormControlElement::setRangeText(replacement, ec);
+}
+
+void HTMLInputElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionCode& ec)
+{
+    if (!m_inputType->supportsSelectionAPI()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    HTMLTextFormControlElement::setRangeText(replacement, start, end, selectionMode, ec);
+}
+
+bool HTMLInputElement::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
+{
+    if (!document()->view())
+        return false;
+
+    parameters.type = type();
+    parameters.minimum = minimum();
+    parameters.maximum = maximum();
+    parameters.required = isRequired();
+    if (!RuntimeEnabledFeatures::langAttributeAwareFormControlUIEnabled())
+        parameters.locale = defaultLanguage();
+    else {
+        AtomicString computedLocale = computeInheritedLanguage();
+        parameters.locale = computedLocale.isEmpty() ? AtomicString(defaultLanguage()) : computedLocale;
+    }
+
+    StepRange stepRange = createStepRange(RejectAny);
+    if (stepRange.hasStep()) {
+        parameters.step = stepRange.step().toDouble();
+        parameters.stepBase = stepRange.stepBase().toDouble();
+    } else {
+        parameters.step = 1.0;
+        parameters.stepBase = 0;
+    }
+
+    parameters.anchorRectInRootView = document()->view()->contentsToRootView(pixelSnappedBoundingBox());
+    parameters.currentValue = value();
+    parameters.isAnchorElementRTL = computedStyle()->direction() == RTL;
+#if ENABLE(DATALIST_ELEMENT)
+    if (HTMLDataListElement* dataList = this->dataList()) {
+        RefPtr<HTMLCollection> options = dataList->options();
+        for (unsigned i = 0; HTMLOptionElement* option = toHTMLOptionElement(options->item(i)); ++i) {
+            if (!isValidValue(option->value()))
+                continue;
+            parameters.suggestionValues.append(sanitizeValue(option->value()));
+            parameters.localizedSuggestionValues.append(localizeValue(option->value()));
+            parameters.suggestionLabels.append(option->value() == option->label() ? String() : option->label());
+        }
+    }
+#endif
+    return true;
+}
+
+void HTMLInputElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
+    HTMLTextFormControlElement::reportMemoryUsage(memoryObjectInfo);
+    info.addMember(m_name, "name");
+    info.addMember(m_valueIfDirty, "valueIfDirty");
+    info.addMember(m_suggestedValue, "suggestedValue");
+    info.addMember(m_inputType, "inputType");
+#if ENABLE(DATALIST_ELEMENT)
+    info.addMember(m_listAttributeTargetObserver, "listAttributeTargetObserver");
+#endif
+}
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+PassRefPtr<RenderStyle> HTMLInputElement::customStyleForRenderer()
+{
+    return m_inputType->customStyleForRenderer(document()->styleResolver()->styleForElement(this));
+}
+#endif
+
+} // namespace
diff --git a/Source/core/html/HTMLInputElement.h b/Source/core/html/HTMLInputElement.h
new file mode 100644
index 0000000..0cb7988
--- /dev/null
+++ b/Source/core/html/HTMLInputElement.h
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Samsung Electronics. 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLInputElement_h
+#define HTMLInputElement_h
+
+#include "core/html/HTMLTextFormControlElement.h"
+#include "core/html/StepRange.h"
+#include "core/platform/FileChooser.h"
+
+namespace WebCore {
+
+class CheckedRadioButtons;
+class DragData;
+class FileList;
+class HTMLDataListElement;
+class HTMLImageLoader;
+class HTMLOptionElement;
+class Icon;
+class InputType;
+class KURL;
+class ListAttributeTargetObserver;
+struct DateTimeChooserParameters;
+
+class HTMLInputElement : public HTMLTextFormControlElement {
+public:
+    static PassRefPtr<HTMLInputElement> create(const QualifiedName&, Document*, HTMLFormElement*, bool createdByParser);
+    virtual ~HTMLInputElement();
+
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitspeechchange);
+
+    virtual HTMLInputElement* toInputElement() { return this; }
+
+    virtual bool shouldAutocomplete() const;
+
+    // For ValidityState
+    virtual bool hasBadInput() const OVERRIDE;
+    virtual bool patternMismatch() const OVERRIDE;
+    virtual bool rangeUnderflow() const OVERRIDE;
+    virtual bool rangeOverflow() const;
+    virtual bool stepMismatch() const OVERRIDE;
+    virtual bool tooLong() const OVERRIDE;
+    virtual bool typeMismatch() const OVERRIDE;
+    virtual bool valueMissing() const OVERRIDE;
+    virtual String validationMessage() const OVERRIDE;
+
+    // Returns the minimum value for type=date, number, or range.  Don't call this for other types.
+    double minimum() const;
+    // Returns the maximum value for type=date, number, or range.  Don't call this for other types.
+    // This always returns a value which is >= minimum().
+    double maximum() const;
+    // Sets the "allowed value step" defined in the HTML spec to the specified double pointer.
+    // Returns false if there is no "allowed value step."
+    bool getAllowedValueStep(Decimal*) const;
+    StepRange createStepRange(AnyStepHandling) const;
+
+#if ENABLE(DATALIST_ELEMENT)
+    Decimal findClosestTickMarkValue(const Decimal&);
+#endif
+
+    // Implementations of HTMLInputElement::stepUp() and stepDown().
+    void stepUp(int, ExceptionCode&);
+    void stepDown(int, ExceptionCode&);
+    void stepUp(ExceptionCode& ec) { stepUp(1, ec); }
+    void stepDown(ExceptionCode& ec) { stepDown(1, ec); }
+    // stepUp()/stepDown() for user-interaction.
+    bool isSteppable() const;
+
+    bool isTextButton() const;
+
+    bool isRadioButton() const;
+    bool isTextField() const;
+    bool isSearchField() const;
+    bool isInputTypeHidden() const;
+    bool isPasswordField() const;
+    bool isCheckbox() const;
+    bool isRangeControl() const;
+
+#if ENABLE(INPUT_TYPE_COLOR)
+    bool isColorControl() const;
+#endif
+
+    // 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;
+
+    bool isEmailField() const;
+    bool isFileUpload() const;
+    bool isImageButton() const;
+    bool isNumberField() const;
+    bool isSubmitButton() const;
+    bool isTelephoneField() const;
+    bool isURLField() const;
+    bool isDateField() const;
+    bool isDateTimeField() const;
+    bool isDateTimeLocalField() const;
+    bool isMonthField() const;
+    bool isTimeField() const;
+    bool isWeekField() const;
+
+#if ENABLE(INPUT_SPEECH)
+    bool isSpeechEnabled() const;
+#endif
+
+    HTMLElement* containerElement() const;
+    virtual HTMLElement* innerTextElement() const;
+    HTMLElement* innerBlockElement() const;
+    HTMLElement* innerSpinButtonElement() const;
+    HTMLElement* resultsButtonElement() const;
+    HTMLElement* cancelButtonElement() const;
+#if ENABLE(INPUT_SPEECH)
+    HTMLElement* speechButtonElement() const;
+#endif
+    HTMLElement* sliderThumbElement() const;
+    HTMLElement* sliderTrackElement() const;
+    virtual HTMLElement* placeholderElement() const;
+
+    bool checked() const { return m_isChecked; }
+    void setChecked(bool, TextFieldEventBehavior = DispatchNoEvent);
+
+    // 'indeterminate' is a state independent of the checked state that causes the control to draw in a way that hides the actual state.
+    bool indeterminate() const { return m_isIndeterminate; }
+    void setIndeterminate(bool);
+    // shouldAppearChecked is used by the rendering tree/CSS while checked() is used by JS to determine checked state
+    bool shouldAppearChecked() const;
+    virtual bool shouldAppearIndeterminate() const OVERRIDE;
+
+    int size() const;
+    bool sizeShouldIncludeDecoration(int& preferredSize) const;
+
+    void setType(const String&);
+
+    String value() const;
+    void setValue(const String&, ExceptionCode&, TextFieldEventBehavior = DispatchNoEvent);
+    void setValue(const String&, TextFieldEventBehavior = DispatchNoEvent);
+    void setValueForUser(const String&);
+    // Checks if the specified string would be a valid value.
+    // We should not call this for types with no string value such as CHECKBOX and RADIO.
+    bool isValidValue(const String&) const;
+    bool hasDirtyValue() const { return !m_valueIfDirty.isNull(); };
+
+    String sanitizeValue(const String&) const;
+
+    String localizeValue(const String&) const;
+
+    // The value which is drawn by a renderer.
+    String visibleValue() const;
+
+    const String& suggestedValue() const;
+    void setSuggestedValue(const String&);
+
+    void setEditingValue(const String&);
+
+    double valueAsDate() const;
+    void setValueAsDate(double, ExceptionCode&);
+
+    double valueAsNumber() const;
+    void setValueAsNumber(double, ExceptionCode&, TextFieldEventBehavior = DispatchNoEvent);
+
+    String valueWithDefault() const;
+
+    void setValueFromRenderer(const String&);
+
+    bool canHaveSelection() const;
+
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual void detach();
+
+    // FIXME: For isActivatedSubmit and setActivatedSubmit, we should use the NVI-idiom here by making
+    // it private virtual in all classes and expose a public method in HTMLFormControlElement to call
+    // the private virtual method.
+    virtual bool isActivatedSubmit() const;
+    virtual void setActivatedSubmit(bool flag);
+
+    String altText() const;
+
+    int maxResults() const { return m_maxResults; }
+
+    String defaultValue() const;
+    void setDefaultValue(const String&);
+
+    Vector<String> acceptMIMETypes();
+    Vector<String> acceptFileExtensions();
+    String accept() const;
+    String alt() const;
+
+    void setSize(unsigned);
+    void setSize(unsigned, ExceptionCode&);
+
+    KURL src() const;
+
+    virtual int maxLength() const;
+    void setMaxLength(int, ExceptionCode&);
+
+    bool multiple() const;
+
+    bool isAutofilled() const { return m_isAutofilled; }
+    void setAutofilled(bool = true);
+
+    FileList* files();
+    void setFiles(PassRefPtr<FileList>);
+
+    // Returns true if the given DragData has more than one dropped files.
+    bool receiveDroppedFiles(const DragData*);
+
+    String droppedFileSystemId();
+
+    Icon* icon() const;
+    // These functions are used for rendering the input active during a
+    // drag-and-drop operation.
+    bool canReceiveDroppedFiles() const;
+    void setCanReceiveDroppedFiles(bool);
+
+    void addSearchResult();
+    void onSearch();
+
+    void updateClearButtonVisibility();
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+#if ENABLE(DATALIST_ELEMENT)
+    HTMLElement* list() const;
+    HTMLDataListElement* dataList() const;
+    void listAttributeTargetChanged();
+#endif
+
+    HTMLInputElement* checkedRadioButtonForGroup() const;
+    bool isInRequiredRadioButtonGroup();
+
+    // Functions for InputType classes.
+    void setValueInternal(const String&, TextFieldEventBehavior);
+    bool isTextFormControlKeyboardFocusable(KeyboardEvent*) const;
+    bool isTextFormControlMouseFocusable() const;
+    bool valueAttributeWasUpdatedAfterParsing() const { return m_valueAttributeWasUpdatedAfterParsing; }
+
+    void cacheSelectionInResponseToSetValue(int caretOffset) { cacheSelection(caretOffset, caretOffset, SelectionHasNoDirection); }
+
+#if ENABLE(INPUT_TYPE_COLOR)
+    // For test purposes.
+    void selectColorInColorChooser(const Color&);
+#endif
+
+    String defaultToolTip() const;
+
+#if ENABLE(MEDIA_CAPTURE)
+    String capture() const;
+    void setCapture(const String& value);
+#endif
+
+    static const int maximumLength;
+
+    unsigned height() const;
+    unsigned width() const;
+    void setHeight(unsigned);
+    void setWidth(unsigned);
+
+    virtual void blur() OVERRIDE;
+    void defaultBlur();
+
+    virtual const AtomicString& name() const OVERRIDE;
+
+    void endEditing();
+
+    static Vector<FileChooserFileInfo> filesFromFileInputFormControlState(const FormControlState&);
+
+    virtual bool matchesReadOnlyPseudoClass() const OVERRIDE;
+    virtual bool matchesReadWritePseudoClass() const OVERRIDE;
+    virtual void setRangeText(const String& replacement, ExceptionCode&) OVERRIDE;
+    virtual void setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionCode&) OVERRIDE;
+
+    bool hasImageLoader() const { return m_imageLoader; }
+    HTMLImageLoader* imageLoader();
+
+    bool setupDateTimeChooserParameters(DateTimeChooserParameters&);
+    virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+
+protected:
+    HTMLInputElement(const QualifiedName&, Document*, HTMLFormElement*, bool createdByParser);
+
+    virtual void defaultEventHandler(Event*);
+
+private:
+    enum AutoCompleteSetting { Uninitialized, On, Off };
+
+    // FIXME: Author shadows should be allowed
+    // https://bugs.webkit.org/show_bug.cgi?id=92608
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+
+    virtual void didAddUserAgentShadowRoot(ShadowRoot*) OVERRIDE;
+
+    virtual void willChangeForm() OVERRIDE;
+    virtual void didChangeForm() OVERRIDE;
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+
+    virtual bool hasCustomFocusLogic() const OVERRIDE;
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual bool isMouseFocusable() const;
+    virtual bool isEnumeratable() const;
+    virtual bool supportLabels() const OVERRIDE;
+    virtual void updateFocusAppearance(bool restorePreviousSelection);
+    virtual bool shouldUseInputMethod();
+
+    virtual bool isTextFormControl() const { return isTextField(); }
+
+    virtual bool canTriggerImplicitSubmission() const { return isTextField(); }
+
+    virtual const AtomicString& formControlType() const;
+
+    virtual bool shouldSaveAndRestoreFormControlState() const OVERRIDE;
+    virtual FormControlState saveFormControlState() const OVERRIDE;
+    virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
+
+    virtual bool canStartSelection() const;
+
+    virtual void accessKeyAction(bool sendMouseEvents);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+    virtual void finishParsingChildren();
+
+    virtual void copyNonAttributePropertiesFromElement(const Element&);
+
+    virtual void attach();
+
+    virtual bool appendFormData(FormDataList&, bool);
+
+    virtual bool isSuccessfulSubmitButton() const;
+
+    virtual void reset();
+
+    virtual void* preDispatchEventHandler(Event*);
+    virtual void postDispatchEventHandler(Event*, void* dataFromPreDispatch);
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+    virtual bool isInRange() const;
+    virtual bool isOutOfRange() const;
+
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+
+    bool supportsMaxLength() const { return isTextType(); }
+    bool isTextType() const;
+    bool tooLong(const String&, NeedsToCheckDirtyFlag) const;
+
+    virtual bool supportsPlaceholder() const;
+    virtual void updatePlaceholderText();
+    virtual bool isEmptyValue() const OVERRIDE { return innerTextValue().isEmpty(); }
+    virtual bool isEmptySuggestedValue() const { return suggestedValue().isEmpty(); }
+    virtual void handleFocusEvent(Node* oldFocusedNode, FocusDirection) OVERRIDE;
+    virtual void handleBlurEvent();
+
+    virtual bool isOptionalFormControl() const { return !isRequiredFormControl(); }
+    virtual bool isRequiredFormControl() const;
+    virtual bool recalcWillValidate() const;
+    virtual void requiredAttributeChanged() OVERRIDE;
+
+    void updateType();
+    
+    virtual void subtreeHasChanged();
+
+#if ENABLE(DATALIST_ELEMENT)
+    void resetListAttributeTargetObserver();
+#endif
+    void parseMaxLengthAttribute(const AtomicString&);
+    void updateValueIfNeeded();
+
+    // Returns null if this isn't associated with any radio button group.
+    CheckedRadioButtons* checkedRadioButtons() const;
+    void addToRadioButtonGroup();
+    void removeFromRadioButtonGroup();
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+#endif
+
+    AtomicString m_name;
+    String m_valueIfDirty;
+    String m_suggestedValue;
+    int m_size;
+    int m_maxLength;
+    short m_maxResults;
+    bool m_isChecked : 1;
+    bool m_reflectsCheckedAttribute : 1;
+    bool m_isIndeterminate : 1;
+    bool m_hasType : 1;
+    bool m_isActivatedSubmit : 1;
+    unsigned m_autocomplete : 2; // AutoCompleteSetting
+    bool m_isAutofilled : 1;
+#if ENABLE(DATALIST_ELEMENT)
+    bool m_hasNonEmptyList : 1;
+#endif
+    bool m_stateRestored : 1;
+    bool m_parsingInProgress : 1;
+    bool m_valueAttributeWasUpdatedAfterParsing : 1;
+    bool m_wasModifiedByUser : 1;
+    bool m_canReceiveDroppedFiles : 1;
+    bool m_hasTouchEventHandler : 1;
+    OwnPtr<InputType> m_inputType;
+    // The ImageLoader must be owned by this element because the loader code assumes
+    // that it lives as long as its owning element lives. If we move the loader into
+    // the ImageInput object we may delete the loader while this element lives on.
+    OwnPtr<HTMLImageLoader> m_imageLoader;
+#if ENABLE(DATALIST_ELEMENT)
+    OwnPtr<ListAttributeTargetObserver> m_listAttributeTargetObserver;
+#endif
+};
+
+} //namespace
+#endif
diff --git a/Source/core/html/HTMLInputElement.idl b/Source/core/html/HTMLInputElement.idl
new file mode 100644
index 0000000..2a4184c
--- /dev/null
+++ b/Source/core/html/HTMLInputElement.idl
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ * Copyright (C) 2012 Samsung Electronics. 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    SkipVTableValidation
+] interface HTMLInputElement : HTMLElement {
+    [Reflect] attribute DOMString accept;
+    [Reflect] attribute DOMString alt;
+    [Reflect] attribute DOMString autocomplete;
+    [Reflect] attribute boolean autofocus;
+    [Reflect=checked] attribute boolean defaultChecked;
+    attribute boolean checked;
+    [Reflect] attribute DOMString dirName;
+    [Reflect] attribute boolean disabled;
+    readonly attribute HTMLFormElement form;
+    attribute FileList files;
+    [Reflect, URL] attribute DOMString formAction;
+    [TreatNullAs=NullString] attribute DOMString formEnctype;
+    [TreatNullAs=NullString] attribute DOMString formMethod;
+    [Reflect] attribute boolean formNoValidate;
+    [Reflect] attribute DOMString formTarget;
+    attribute unsigned long height;
+    attribute boolean indeterminate;
+    [Conditional=DATALIST_ELEMENT] readonly attribute HTMLElement list;
+    [Reflect] attribute DOMString max;
+    [SetterRaisesException] attribute long maxLength;
+    [Reflect] attribute DOMString min;
+    [Reflect] attribute boolean multiple;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute DOMString pattern;
+    [Reflect] attribute DOMString placeholder;
+    [Reflect] attribute boolean readOnly;
+    [Reflect] attribute boolean required;
+    [SetterRaisesException] attribute unsigned long size; // Changed string -> long -> unsigned long
+    [Reflect, URL] attribute DOMString src;
+    [Reflect] attribute DOMString step;
+    [TreatNullAs=NullString] attribute DOMString type; // readonly dropped as part of DOM level 2
+    [TreatNullAs=NullString] attribute DOMString defaultValue;
+    // See the discussion in https://bugs.webkit.org/show_bug.cgi?id=100085
+    [TreatNullAs=NullString, SetterRaisesException] attribute DOMString value;
+    [SetterRaisesException] attribute Date valueAsDate;
+    [SetterRaisesException] attribute double valueAsNumber;
+
+    [RaisesException] void stepUp(optional long n);
+    [RaisesException] void stepDown(optional long n);
+
+    attribute unsigned long width;
+    readonly attribute boolean willValidate;
+    readonly attribute ValidityState validity;
+    readonly attribute DOMString validationMessage;
+    boolean checkValidity();
+    void setCustomValidity([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString error);
+
+    readonly attribute NodeList labels;
+
+    void select();
+    [Custom] attribute long selectionStart;
+    [Custom] attribute long selectionEnd;
+    [Custom] attribute DOMString selectionDirection;
+
+    [RaisesException] void setRangeText(DOMString replacement);
+    [RaisesException] void setRangeText(DOMString replacement,
+                        unsigned long start,
+                        unsigned long end,
+                        [Default=NullString] optional DOMString selectionMode);
+
+    [Custom] void setSelectionRange([Default=Undefined] optional long start,
+                                    [Default=Undefined] optional long end,
+                                    optional DOMString direction);
+
+    // Non-standard attributes
+    [Reflect] attribute DOMString align;
+    [Reflect, EnabledAtRuntime=directoryUpload] attribute boolean webkitdirectory;
+    [Reflect] attribute DOMString useMap;
+    [Reflect] attribute boolean incremental;
+    [Conditional=INPUT_SPEECH, Reflect, EnabledAtRuntime=speechInput] attribute boolean webkitSpeech;
+    [Conditional=INPUT_SPEECH, Reflect, EnabledAtRuntime=speechInput] attribute boolean webkitGrammar;
+    [Conditional=INPUT_SPEECH, NotEnumerable] attribute EventListener onwebkitspeechchange;
+
+    // See http://www.w3.org/TR/html-media-capture/
+    [Conditional=MEDIA_CAPTURE] attribute DOMString capture;
+};
diff --git a/Source/core/html/HTMLKeygenElement.cpp b/Source/core/html/HTMLKeygenElement.cpp
new file mode 100644
index 0000000..8ffd99f
--- /dev/null
+++ b/Source/core/html/HTMLKeygenElement.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLKeygenElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/Text.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLOptionElement.h"
+#include "core/html/HTMLSelectElement.h"
+#include "core/platform/SSLKeyGenerator.h"
+#include <wtf/StdLibExtras.h>
+
+using namespace WebCore;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+class KeygenSelectElement FINAL : public HTMLSelectElement {
+public:
+    static PassRefPtr<KeygenSelectElement> create(Document* document)
+    {
+        return adoptRef(new KeygenSelectElement(document));
+    }
+
+protected:
+    KeygenSelectElement(Document* document)
+        : HTMLSelectElement(selectTag, document, 0, false)
+    {
+        DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-keygen-select", AtomicString::ConstructFromLiteral));
+        setPseudo(pseudoId);
+    }
+
+private:
+    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren()
+    {
+        return create(document());
+    }
+};
+
+inline HTMLKeygenElement::HTMLKeygenElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+    : HTMLFormControlElementWithState(tagName, document, form)
+{
+    ASSERT(hasTagName(keygenTag));
+    ScriptWrappable::init(this);
+
+    // Create a select element with one option element for each key size.
+    Vector<String> keys;
+    getSupportedKeySizes(keys);
+
+    RefPtr<HTMLSelectElement> select = KeygenSelectElement::create(document);
+    for (size_t i = 0; i < keys.size(); ++i) {
+        RefPtr<HTMLOptionElement> option = HTMLOptionElement::create(document);
+        select->appendChild(option, IGNORE_EXCEPTION);
+        option->appendChild(Text::create(document, keys[i]), IGNORE_EXCEPTION);
+    }
+
+    ensureUserAgentShadowRoot()->appendChild(select, IGNORE_EXCEPTION);
+}
+
+PassRefPtr<HTMLKeygenElement> HTMLKeygenElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+{
+    return adoptRef(new HTMLKeygenElement(tagName, document, form));
+}
+
+void HTMLKeygenElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    // Reflect disabled attribute on the shadow select element
+    if (name == disabledAttr)
+        shadowSelect()->setAttribute(name, value);
+
+    HTMLFormControlElement::parseAttribute(name, value);
+}
+
+bool HTMLKeygenElement::appendFormData(FormDataList& encoded_values, bool)
+{
+    // Only RSA is supported at this time.
+    const AtomicString& keyType = fastGetAttribute(keytypeAttr);
+    if (!keyType.isNull() && !equalIgnoringCase(keyType, "rsa"))
+        return false;
+    String value = signedPublicKeyAndChallengeString(shadowSelect()->selectedIndex(), fastGetAttribute(challengeAttr), document()->baseURL());
+    if (value.isNull())
+        return false;
+    encoded_values.appendData(name(), value.utf8());
+    return true;
+}
+
+const AtomicString& HTMLKeygenElement::formControlType() const
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, keygen, ("keygen", AtomicString::ConstructFromLiteral));
+    return keygen;
+}
+
+void HTMLKeygenElement::reset()
+{
+    static_cast<HTMLFormControlElement*>(shadowSelect())->reset();
+}
+
+bool HTMLKeygenElement::shouldSaveAndRestoreFormControlState() const
+{
+    return false;
+}
+
+HTMLSelectElement* HTMLKeygenElement::shadowSelect() const
+{
+    ShadowRoot* root = userAgentShadowRoot();
+    return root ? toHTMLSelectElement(root->firstChild()) : 0;
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLKeygenElement.h b/Source/core/html/HTMLKeygenElement.h
new file mode 100644
index 0000000..2af5860
--- /dev/null
+++ b/Source/core/html/HTMLKeygenElement.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLKeygenElement_h
+#define HTMLKeygenElement_h
+
+#include "core/html/HTMLFormControlElementWithState.h"
+
+namespace WebCore {
+
+class HTMLSelectElement;
+
+class HTMLKeygenElement FINAL : public HTMLFormControlElementWithState {
+public:
+    static PassRefPtr<HTMLKeygenElement> create(const QualifiedName&, Document*, HTMLFormElement*);
+
+    virtual bool willValidate() const { return false; }
+
+private:
+    HTMLKeygenElement(const QualifiedName&, Document*, HTMLFormElement*);
+
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+
+    virtual bool canStartSelection() const { return false; }
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    virtual bool appendFormData(FormDataList&, bool);
+    virtual const AtomicString& formControlType() const;
+    virtual bool isOptionalFormControl() const { return false; }
+
+    virtual bool isEnumeratable() const { return true; }
+    virtual bool supportLabels() const OVERRIDE { return true; }
+
+    virtual void reset();
+    virtual bool shouldSaveAndRestoreFormControlState() const OVERRIDE;
+
+    HTMLSelectElement* shadowSelect() const;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLKeygenElement.idl b/Source/core/html/HTMLKeygenElement.idl
new file mode 100644
index 0000000..c8361d8
--- /dev/null
+++ b/Source/core/html/HTMLKeygenElement.idl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+interface HTMLKeygenElement : HTMLElement {
+    [Reflect] attribute boolean autofocus;
+    [Reflect] attribute DOMString challenge;
+    [Reflect] attribute boolean disabled;
+    readonly attribute HTMLFormElement form;
+    [Reflect] attribute DOMString keytype;
+    [Reflect] attribute DOMString name;
+
+    readonly attribute DOMString type;
+
+    readonly attribute boolean willValidate;
+    readonly attribute ValidityState validity;
+    readonly attribute DOMString validationMessage;
+    boolean checkValidity();
+    void setCustomValidity([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString error);
+
+    readonly attribute NodeList labels;
+};
+
diff --git a/Source/core/html/HTMLLIElement.cpp b/Source/core/html/HTMLLIElement.cpp
new file mode 100644
index 0000000..176485e
--- /dev/null
+++ b/Source/core/html/HTMLLIElement.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2006, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLLIElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/EventPathWalker.h"
+#include "core/rendering/RenderListItem.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLLIElement::HTMLLIElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(liTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLLIElement> HTMLLIElement::create(Document* document)
+{
+    return adoptRef(new HTMLLIElement(liTag, document));
+}
+
+PassRefPtr<HTMLLIElement> HTMLLIElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLLIElement(tagName, document));
+}
+
+bool HTMLLIElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == typeAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLLIElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == typeAttr) {
+        if (value == "a")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueLowerAlpha);
+        else if (value == "A")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueUpperAlpha);
+        else if (value == "i")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueLowerRoman);
+        else if (value == "I")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueUpperRoman);
+        else if (value == "1")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueDecimal);
+        else
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, value);
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLLIElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == valueAttr) {
+        if (renderer() && renderer()->isListItem())
+            parseValue(value);
+    } else
+        HTMLElement::parseAttribute(name, value);
+}
+
+void HTMLLIElement::attach()
+{
+    ASSERT(!attached());
+
+    HTMLElement::attach();
+
+    if (renderer() && renderer()->isListItem()) {
+        RenderListItem* listItemRenderer = toRenderListItem(renderer());
+
+        // Find the enclosing list node.
+        Element* listNode = 0;
+        Element* current = this;
+        while (!listNode) {
+            current = current->parentElement();
+            if (!current)
+                break;
+            if (current->hasTagName(ulTag) || current->hasTagName(olTag))
+                listNode = current;
+        }
+
+        // If we are not in a list, tell the renderer so it can position us inside.
+        // We don't want to change our style to say "inside" since that would affect nested nodes.
+        if (!listNode)
+            listItemRenderer->setNotInList(true);
+
+        parseValue(fastGetAttribute(valueAttr));
+    }
+}
+
+inline void HTMLLIElement::parseValue(const AtomicString& value)
+{
+    ASSERT(renderer() && renderer()->isListItem());
+
+    bool valueOK;
+    int requestedValue = value.toInt(&valueOK);
+    if (valueOK)
+        toRenderListItem(renderer())->setExplicitValue(requestedValue);
+    else
+        toRenderListItem(renderer())->clearExplicitValue();
+}
+
+}
diff --git a/Source/core/html/HTMLLIElement.h b/Source/core/html/HTMLLIElement.h
new file mode 100644
index 0000000..0c02ebb
--- /dev/null
+++ b/Source/core/html/HTMLLIElement.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLLIElement_h
+#define HTMLLIElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLLIElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLLIElement> create(Document*);
+    static PassRefPtr<HTMLLIElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLLIElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    virtual void attach();
+
+    void parseValue(const AtomicString&);
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLLIElement.idl b/Source/core/html/HTMLLIElement.idl
new file mode 100644
index 0000000..ba3eaae
--- /dev/null
+++ b/Source/core/html/HTMLLIElement.idl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLLIElement : HTMLElement {
+    [Reflect] attribute DOMString type;
+    [Reflect] attribute long value;    
+};
+
diff --git a/Source/core/html/HTMLLabelElement.cpp b/Source/core/html/HTMLLabelElement.cpp
new file mode 100644
index 0000000..5f69302
--- /dev/null
+++ b/Source/core/html/HTMLLabelElement.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLLabelElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/html/FormAssociatedElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static LabelableElement* nodeAsLabelableElement(Node* node)
+{
+    if (!node || !node->isHTMLElement())
+        return 0;
+    
+    HTMLElement* element = static_cast<HTMLElement*>(node);
+    if (!element->isLabelable())
+        return 0;
+
+    LabelableElement* labelableElement = static_cast<LabelableElement*>(element);
+    if (!labelableElement->supportLabels())
+        return 0;
+
+    return labelableElement;
+}
+
+inline HTMLLabelElement::HTMLLabelElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(labelTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLLabelElement> HTMLLabelElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLLabelElement(tagName, document));
+}
+
+bool HTMLLabelElement::isFocusable() const
+{
+    return false;
+}
+
+LabelableElement* HTMLLabelElement::control()
+{
+    const AtomicString& controlId = getAttribute(forAttr);
+    if (controlId.isNull()) {
+        // Search the children and descendants of the label element for a form element.
+        // per http://dev.w3.org/html5/spec/Overview.html#the-label-element
+        // the form element must be "labelable form-associated element".
+        Element* element = this;
+        while ((element = ElementTraversal::next(element, this))) {
+            if (LabelableElement* labelableElement = nodeAsLabelableElement(element))
+                return labelableElement;
+        }
+        return 0;
+    }
+    
+    // Find the first element whose id is controlId. If it is found and it is a labelable form control,
+    // return it, otherwise return 0.
+    return nodeAsLabelableElement(treeScope()->getElementById(controlId));
+}
+
+HTMLFormElement* HTMLLabelElement::form() const
+{
+    return FormAssociatedElement::findAssociatedForm(this, 0);
+}
+
+void HTMLLabelElement::setActive(bool down, bool pause)
+{
+    if (down == active())
+        return;
+
+    // Update our status first.
+    HTMLElement::setActive(down, pause);
+
+    // Also update our corresponding control.
+    if (HTMLElement* element = control())
+        element->setActive(down, pause);
+}
+
+void HTMLLabelElement::setHovered(bool over)
+{
+    if (over == hovered())
+        return;
+        
+    // Update our status first.
+    HTMLElement::setHovered(over);
+
+    // Also update our corresponding control.
+    if (HTMLElement* element = control())
+        element->setHovered(over);
+}
+
+void HTMLLabelElement::defaultEventHandler(Event* evt)
+{
+    static bool processingClick = false;
+
+    if (evt->type() == eventNames().clickEvent && !processingClick) {
+        RefPtr<HTMLElement> element = control();
+
+        // If we can't find a control or if the control received the click
+        // event, then there's no need for us to do anything.
+        if (!element || (evt->target() && element->containsIncludingShadowDOM(evt->target()->toNode())))
+            return;
+
+        processingClick = true;
+
+        // Click the corresponding control.
+        element->dispatchSimulatedClick(evt);
+
+        if (element->isMouseFocusable())
+            element->focus();
+
+        processingClick = false;
+        
+        evt->setDefaultHandled();
+    }
+    
+    HTMLElement::defaultEventHandler(evt);
+}
+
+bool HTMLLabelElement::willRespondToMouseClickEvents()
+{
+    if (control() && control()->willRespondToMouseClickEvents())
+        return true;
+
+    return HTMLElement::willRespondToMouseClickEvents();
+}
+
+void HTMLLabelElement::focus(bool, FocusDirection direction)
+{
+    // to match other browsers, always restore previous selection
+    if (HTMLElement* element = control())
+        element->focus(true, direction);
+}
+
+void HTMLLabelElement::accessKeyAction(bool sendMouseEvents)
+{
+    if (HTMLElement* element = control())
+        element->accessKeyAction(sendMouseEvents);
+    else
+        HTMLElement::accessKeyAction(sendMouseEvents);
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLLabelElement.h b/Source/core/html/HTMLLabelElement.h
new file mode 100644
index 0000000..29532a8
--- /dev/null
+++ b/Source/core/html/HTMLLabelElement.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLLabelElement_h
+#define HTMLLabelElement_h
+
+#include "core/html/HTMLElement.h"
+#include "core/html/LabelableElement.h"
+
+namespace WebCore {
+
+class HTMLLabelElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLLabelElement> create(const QualifiedName&, Document*);
+
+    LabelableElement* control();
+    HTMLFormElement* form() const;
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+private:
+    HTMLLabelElement(const QualifiedName&, Document*);
+
+    virtual bool isFocusable() const;
+
+    virtual void accessKeyAction(bool sendMouseEvents);
+
+    // Overridden to update the hover/active state of the corresponding control.
+    virtual void setActive(bool = true, bool pause = false);
+    virtual void setHovered(bool = true);
+
+    // Overridden to either click() or focus() the corresponding control.
+    virtual void defaultEventHandler(Event*);
+
+    virtual void focus(bool restorePreviousSelection, FocusDirection) OVERRIDE;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLLabelElement.idl b/Source/core/html/HTMLLabelElement.idl
new file mode 100644
index 0000000..fa37360
--- /dev/null
+++ b/Source/core/html/HTMLLabelElement.idl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLLabelElement : HTMLElement {
+    readonly attribute HTMLFormElement form;
+    [Reflect=for] attribute DOMString htmlFor;
+    readonly attribute HTMLElement control;
+};
+
diff --git a/Source/core/html/HTMLLegendElement.cpp b/Source/core/html/HTMLLegendElement.cpp
new file mode 100644
index 0000000..15e8b1d
--- /dev/null
+++ b/Source/core/html/HTMLLegendElement.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLLegendElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/html/HTMLFieldSetElement.h"
+#include "core/html/HTMLFormControlElement.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+
+inline HTMLLegendElement::HTMLLegendElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(legendTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLLegendElement> HTMLLegendElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLLegendElement(tagName, document));
+}
+
+HTMLFormControlElement* HTMLLegendElement::associatedControl()
+{
+    // Check if there's a fieldset belonging to this legend.
+    Element* fieldset = parentElement();
+    while (fieldset && !fieldset->hasTagName(fieldsetTag))
+        fieldset = fieldset->parentElement();
+    if (!fieldset)
+        return 0;
+
+    // Find first form element inside the fieldset that is not a legend element.
+    // FIXME: Should we consider tabindex?
+    Element* element = fieldset;
+    while ((element = ElementTraversal::next(element, fieldset))) {
+        if (element->isFormControlElement())
+            return static_cast<HTMLFormControlElement*>(element);
+    }
+
+    return 0;
+}
+
+void HTMLLegendElement::focus(bool, FocusDirection direction)
+{
+    if (isFocusable())
+        Element::focus(true, direction);
+        
+    // To match other browsers' behavior, never restore previous selection.
+    if (HTMLFormControlElement* control = associatedControl())
+        control->focus(false, direction);
+}
+
+void HTMLLegendElement::accessKeyAction(bool sendMouseEvents)
+{
+    if (HTMLFormControlElement* control = associatedControl())
+        control->accessKeyAction(sendMouseEvents);
+}
+
+HTMLFormElement* HTMLLegendElement::virtualForm() const
+{
+    // According to the specification, If the legend has a fieldset element as
+    // its parent, then the form attribute must return the same value as the
+    // form attribute on that fieldset element. Otherwise, it must return null.
+    ContainerNode* fieldset = parentNode();
+    if (!fieldset || !fieldset->hasTagName(fieldsetTag))
+        return 0;
+
+    return static_cast<HTMLFieldSetElement*>(fieldset)->form();
+}
+    
+} // namespace
diff --git a/Source/core/html/HTMLLegendElement.h b/Source/core/html/HTMLLegendElement.h
new file mode 100644
index 0000000..0917175
--- /dev/null
+++ b/Source/core/html/HTMLLegendElement.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLLegendElement_h
+#define HTMLLegendElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLFormControlElement;
+
+class HTMLLegendElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLLegendElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLLegendElement(const QualifiedName&, Document*);
+
+    // Control in the legend's fieldset that gets focus and access key.
+    HTMLFormControlElement* associatedControl();
+
+    virtual void accessKeyAction(bool sendMouseEvents);
+    virtual void focus(bool restorePreviousSelection, FocusDirection) OVERRIDE;
+    virtual HTMLFormElement* virtualForm() const OVERRIDE;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLLegendElement.idl b/Source/core/html/HTMLLegendElement.idl
new file mode 100644
index 0000000..e8e8871
--- /dev/null
+++ b/Source/core/html/HTMLLegendElement.idl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLLegendElement : HTMLElement {
+    readonly attribute HTMLFormElement form;
+    [Reflect] attribute DOMString align;
+};
+
diff --git a/Source/core/html/HTMLLinkElement.cpp b/Source/core/html/HTMLLinkElement.cpp
new file mode 100644
index 0000000..6f143fe
--- /dev/null
+++ b/Source/core/html/HTMLLinkElement.cpp
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Rob Buis (rwlbuis@gmail.com)
+ * Copyright (C) 2011 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLLinkElement.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/css/MediaList.h"
+#include "core/css/MediaQueryEvaluator.h"
+#include "core/css/StyleResolver.h"
+#include "core/css/StyleSheetContents.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/DocumentStyleSheetCollection.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventSender.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/loader/cache/CachedCSSStyleSheet.h"
+#include "core/loader/cache/CachedResource.h"
+#include "core/loader/cache/CachedResourceLoader.h"
+#include "core/loader/cache/CachedResourceRequest.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameTree.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/page/Settings.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static LinkEventSender& linkLoadEventSender()
+{
+    DEFINE_STATIC_LOCAL(LinkEventSender, sharedLoadEventSender, (eventNames().loadEvent));
+    return sharedLoadEventSender;
+}
+
+inline HTMLLinkElement::HTMLLinkElement(const QualifiedName& tagName, Document* document, bool createdByParser)
+    : HTMLElement(tagName, document)
+    , m_linkLoader(this)
+    , m_sizes(DOMSettableTokenList::create())
+    , m_disabledState(Unset)
+    , m_loading(false)
+    , m_createdByParser(createdByParser)
+    , m_isInShadowTree(false)
+    , m_firedLoad(false)
+    , m_loadedSheet(false)
+    , m_pendingSheetType(None)
+    , m_beforeLoadRecurseCount(0)
+{
+    ASSERT(hasTagName(linkTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLLinkElement> HTMLLinkElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
+{
+    return adoptRef(new HTMLLinkElement(tagName, document, createdByParser));
+}
+
+HTMLLinkElement::~HTMLLinkElement()
+{
+    if (m_sheet)
+        m_sheet->clearOwnerNode();
+
+    if (m_cachedSheet)
+        m_cachedSheet->removeClient(this);
+
+    if (inDocument())
+        document()->styleSheetCollection()->removeStyleSheetCandidateNode(this);
+
+    linkLoadEventSender().cancelEvent(this);
+}
+
+void HTMLLinkElement::setDisabledState(bool disabled)
+{
+    DisabledState oldDisabledState = m_disabledState;
+    m_disabledState = disabled ? Disabled : EnabledViaScript;
+    if (oldDisabledState != m_disabledState) {
+        // If we change the disabled state while the sheet is still loading, then we have to
+        // perform three checks:
+        if (styleSheetIsLoading()) {
+            // Check #1: The sheet becomes disabled while loading.
+            if (m_disabledState == Disabled)
+                removePendingSheet();
+
+            // Check #2: An alternate sheet becomes enabled while it is still loading.
+            if (m_relAttribute.isAlternate() && m_disabledState == EnabledViaScript)
+                addPendingSheet(Blocking);
+
+            // Check #3: A main sheet becomes enabled while it was still loading and
+            // after it was disabled via script. It takes really terrible code to make this
+            // happen (a double toggle for no reason essentially). This happens on
+            // virtualplastic.net, which manages to do about 12 enable/disables on only 3
+            // sheets. :)
+            if (!m_relAttribute.isAlternate() && m_disabledState == EnabledViaScript && oldDisabledState == Disabled)
+                addPendingSheet(Blocking);
+
+            // If the sheet is already loading just bail.
+            return;
+        }
+
+        // Load the sheet, since it's never been loaded before.
+        if (!m_sheet && m_disabledState == EnabledViaScript)
+            process();
+        else
+            document()->styleResolverChanged(DeferRecalcStyle); // Update the style selector.
+    }
+}
+
+void HTMLLinkElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == relAttr) {
+        m_relAttribute = LinkRelAttribute(value);
+        process();
+    } else if (name == hrefAttr) {
+        process();
+    } else if (name == typeAttr) {
+        m_type = value;
+        process();
+    } else if (name == sizesAttr) {
+        setSizes(value);
+        process();
+    } else if (name == mediaAttr) {
+        m_media = value.string().lower();
+        process();
+    } else if (name == disabledAttr)
+        setDisabledState(!value.isNull());
+    else if (name == onbeforeloadAttr)
+        setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, name, value));
+    else {
+        if (name == titleAttr && m_sheet)
+            m_sheet->setTitle(value);
+        HTMLElement::parseAttribute(name, value);
+    }
+}
+
+bool HTMLLinkElement::shouldLoadLink()
+{
+    bool continueLoad = true;
+    RefPtr<Document> originalDocument = document();
+    int recursionRank = ++m_beforeLoadRecurseCount;
+    if (!dispatchBeforeLoadEvent(getNonEmptyURLAttribute(hrefAttr)))
+        continueLoad = false;
+
+    // A beforeload handler might have removed us from the document or changed the document.
+    if (continueLoad && (!inDocument() || document() != originalDocument))
+        continueLoad = false;
+
+    // If the beforeload handler recurses into the link element by mutating it, we should only
+    // let the latest (innermost) mutation occur.
+    if (recursionRank != m_beforeLoadRecurseCount)
+        continueLoad = false;
+
+    if (recursionRank == 1)
+        m_beforeLoadRecurseCount = 0;
+
+    return continueLoad;
+}
+
+void HTMLLinkElement::process()
+{
+    if (!inDocument() || m_isInShadowTree) {
+        ASSERT(!m_sheet);
+        return;
+    }
+
+    String type = m_type.lower();
+    KURL url = getNonEmptyURLAttribute(hrefAttr);
+
+    if (!m_linkLoader.loadLink(m_relAttribute, type, m_sizes->toString(), url, document()))
+        return;
+
+    if ((m_disabledState != Disabled) && m_relAttribute.isStyleSheet()
+        && document()->frame() && url.isValid()) {
+        
+        String charset = getAttribute(charsetAttr);
+        if (charset.isEmpty() && document()->frame())
+            charset = document()->charset();
+        
+        if (m_cachedSheet) {
+            removePendingSheet();
+            m_cachedSheet->removeClient(this);
+            m_cachedSheet = 0;
+        }
+
+        if (!shouldLoadLink())
+            return;
+
+        m_loading = true;
+
+        bool mediaQueryMatches = true;
+        if (!m_media.isEmpty()) {
+            RefPtr<RenderStyle> documentStyle = StyleResolver::styleForDocument(document());
+            RefPtr<MediaQuerySet> media = MediaQuerySet::createAllowingDescriptionSyntax(m_media);
+            MediaQueryEvaluator evaluator(document()->frame()->view()->mediaType(), document()->frame(), documentStyle.get());
+            mediaQueryMatches = evaluator.eval(media.get());
+        }
+
+        // Don't hold up render tree construction and script execution on stylesheets
+        // that are not needed for the rendering at the moment.
+        bool blocking = mediaQueryMatches && !isAlternate();
+        addPendingSheet(blocking ? Blocking : NonBlocking);
+
+        // Load stylesheets that are not needed for the rendering immediately with low priority.
+        ResourceLoadPriority priority = blocking ? ResourceLoadPriorityUnresolved : ResourceLoadPriorityVeryLow;
+        CachedResourceRequest request(ResourceRequest(document()->completeURL(url)), charset, priority);
+        request.setInitiator(this);
+        m_cachedSheet = document()->cachedResourceLoader()->requestCSSStyleSheet(request);
+        
+        if (m_cachedSheet)
+            m_cachedSheet->addClient(this);
+        else {
+            // The request may have been denied if (for example) the stylesheet is local and the document is remote.
+            m_loading = false;
+            removePendingSheet();
+        }
+    } else if (m_sheet) {
+        // we no longer contain a stylesheet, e.g. perhaps rel or type was changed
+        clearSheet();
+        document()->styleResolverChanged(DeferRecalcStyle);
+    }
+}
+
+void HTMLLinkElement::clearSheet()
+{
+    ASSERT(m_sheet);
+    ASSERT(m_sheet->ownerNode() == this);
+    m_sheet->clearOwnerNode();
+    m_sheet = 0;
+}
+
+Node::InsertionNotificationRequest HTMLLinkElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+    if (!insertionPoint->inDocument())
+        return InsertionDone;
+
+    m_isInShadowTree = isInShadowTree();
+    if (m_isInShadowTree)
+        return InsertionDone;
+
+    document()->styleSheetCollection()->addStyleSheetCandidateNode(this, m_createdByParser);
+
+    process();
+    return InsertionDone;
+}
+
+void HTMLLinkElement::removedFrom(ContainerNode* insertionPoint)
+{
+    HTMLElement::removedFrom(insertionPoint);
+    if (!insertionPoint->inDocument())
+        return;
+
+    m_linkLoader.released();
+
+    if (m_isInShadowTree) {
+        ASSERT(!m_sheet);
+        return;
+    }
+    document()->styleSheetCollection()->removeStyleSheetCandidateNode(this);
+
+    if (m_sheet)
+        clearSheet();
+
+    if (styleSheetIsLoading())
+        removePendingSheet(RemovePendingSheetNotifyLater);
+
+    if (document()->renderer())
+        document()->styleResolverChanged(DeferRecalcStyle);
+}
+
+void HTMLLinkElement::finishParsingChildren()
+{
+    m_createdByParser = false;
+    HTMLElement::finishParsingChildren();
+}
+
+void HTMLLinkElement::setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* cachedStyleSheet)
+{
+    if (!inDocument()) {
+        ASSERT(!m_sheet);
+        return;
+    }
+    // Completing the sheet load may cause scripts to execute.
+    RefPtr<Node> protector(this);
+
+    CSSParserContext parserContext(document(), baseURL, charset);
+
+    if (RefPtr<StyleSheetContents> restoredSheet = const_cast<CachedCSSStyleSheet*>(cachedStyleSheet)->restoreParsedStyleSheet(parserContext)) {
+        ASSERT(restoredSheet->isCacheable());
+        ASSERT(!restoredSheet->isLoading());
+
+        m_sheet = CSSStyleSheet::create(restoredSheet, this);
+        m_sheet->setMediaQueries(MediaQuerySet::createAllowingDescriptionSyntax(m_media));
+        m_sheet->setTitle(title());
+
+        m_loading = false;
+        sheetLoaded();
+        notifyLoadedSheetAndAllCriticalSubresources(false);
+        return;
+    }
+
+    RefPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(href, parserContext);
+
+    m_sheet = CSSStyleSheet::create(styleSheet, this);
+    m_sheet->setMediaQueries(MediaQuerySet::createAllowingDescriptionSyntax(m_media));
+    m_sheet->setTitle(title());
+
+    styleSheet->parseAuthorStyleSheet(cachedStyleSheet, document()->securityOrigin());
+
+    m_loading = false;
+    styleSheet->notifyLoadedSheet(cachedStyleSheet);
+    styleSheet->checkLoaded();
+
+    if (styleSheet->isCacheable())
+        const_cast<CachedCSSStyleSheet*>(cachedStyleSheet)->saveParsedStyleSheet(styleSheet);
+}
+
+bool HTMLLinkElement::styleSheetIsLoading() const
+{
+    if (m_loading)
+        return true;
+    if (!m_sheet)
+        return false;
+    return m_sheet->contents()->isLoading();
+}
+
+void HTMLLinkElement::linkLoaded()
+{
+    dispatchEvent(Event::create(eventNames().loadEvent, false, false));
+}
+
+void HTMLLinkElement::linkLoadingErrored()
+{
+    dispatchEvent(Event::create(eventNames().errorEvent, false, false));
+}
+
+void HTMLLinkElement::didStartLinkPrerender()
+{
+    dispatchEvent(Event::create(eventNames().webkitprerenderstartEvent, false, false));
+}
+
+void HTMLLinkElement::didStopLinkPrerender()
+{
+    dispatchEvent(Event::create(eventNames().webkitprerenderstopEvent, false, false));
+}
+
+void HTMLLinkElement::didSendLoadForLinkPrerender()
+{
+    dispatchEvent(Event::create(eventNames().webkitprerenderloadEvent, false, false));
+}
+
+void HTMLLinkElement::didSendDOMContentLoadedForLinkPrerender()
+{
+    dispatchEvent(Event::create(eventNames().webkitprerenderdomcontentloadedEvent, false, false));
+}
+
+bool HTMLLinkElement::sheetLoaded()
+{
+    if (!styleSheetIsLoading()) {
+        removePendingSheet();
+        return true;
+    }
+    return false;
+}
+
+void HTMLLinkElement::dispatchPendingLoadEvents()
+{
+    linkLoadEventSender().dispatchPendingEvents();
+}
+
+void HTMLLinkElement::dispatchPendingEvent(LinkEventSender* eventSender)
+{
+    ASSERT_UNUSED(eventSender, eventSender == &linkLoadEventSender());
+    if (m_loadedSheet)
+        linkLoaded();
+    else
+        linkLoadingErrored();
+}
+
+void HTMLLinkElement::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)
+{
+    if (m_firedLoad)
+        return;
+    m_loadedSheet = !errorOccurred;
+    linkLoadEventSender().dispatchEventSoon(this);
+    m_firedLoad = true;
+}
+
+void HTMLLinkElement::startLoadingDynamicSheet()
+{
+    // We don't support multiple blocking sheets.
+    ASSERT(m_pendingSheetType < Blocking);
+    addPendingSheet(Blocking);
+}
+
+bool HTMLLinkElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+KURL HTMLLinkElement::href() const
+{
+    return document()->completeURL(getAttribute(hrefAttr));
+}
+
+String HTMLLinkElement::rel() const
+{
+    return getAttribute(relAttr);
+}
+
+String HTMLLinkElement::target() const
+{
+    return getAttribute(targetAttr);
+}
+
+String HTMLLinkElement::type() const
+{
+    return getAttribute(typeAttr);
+}
+
+IconType HTMLLinkElement::iconType() const
+{
+    return m_relAttribute.iconType();
+}
+
+String HTMLLinkElement::iconSizes() const
+{
+    return m_sizes->toString();
+}
+
+void HTMLLinkElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLElement::addSubresourceAttributeURLs(urls);
+
+    // Favicons are handled by a special case in LegacyWebArchive::create()
+    if (m_relAttribute.iconType() != InvalidIcon)
+        return;
+
+    if (!m_relAttribute.isStyleSheet())
+        return;
+    
+    // Append the URL of this link element.
+    addSubresourceURL(urls, href());
+    
+    // Walk the URLs linked by the linked-to stylesheet.
+    if (CSSStyleSheet* styleSheet = const_cast<HTMLLinkElement*>(this)->sheet())
+        styleSheet->contents()->addSubresourceStyleURLs(urls);
+}
+
+void HTMLLinkElement::addPendingSheet(PendingSheetType type)
+{
+    if (type <= m_pendingSheetType)
+        return;
+    m_pendingSheetType = type;
+
+    if (m_pendingSheetType == NonBlocking)
+        return;
+    document()->styleSheetCollection()->addPendingSheet();
+}
+
+void HTMLLinkElement::removePendingSheet(RemovePendingSheetNotificationType notification)
+{
+    PendingSheetType type = m_pendingSheetType;
+    m_pendingSheetType = None;
+
+    if (type == None)
+        return;
+    if (type == NonBlocking) {
+        // Document::removePendingSheet() triggers the style selector recalc for blocking sheets.
+        document()->styleResolverChanged(RecalcStyleImmediately);
+        return;
+    }
+
+    document()->styleSheetCollection()->removePendingSheet(
+        notification == RemovePendingSheetNotifyImmediately
+        ? DocumentStyleSheetCollection::RemovePendingSheetNotifyImmediately
+        : DocumentStyleSheetCollection::RemovePendingSheetNotifyLater);
+}
+
+DOMSettableTokenList* HTMLLinkElement::sizes() const
+{
+    return m_sizes.get();
+}
+
+void HTMLLinkElement::setSizes(const String& value)
+{
+    m_sizes->setValue(value);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLLinkElement.h b/Source/core/html/HTMLLinkElement.h
new file mode 100644
index 0000000..d099bc2
--- /dev/null
+++ b/Source/core/html/HTMLLinkElement.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLLinkElement_h
+#define HTMLLinkElement_h
+
+#include "core/css/CSSStyleSheet.h"
+#include "core/dom/IconURL.h"
+#include "core/html/DOMSettableTokenList.h"
+#include "core/html/HTMLElement.h"
+#include "core/html/LinkRelAttribute.h"
+#include "core/loader/LinkLoader.h"
+#include "core/loader/LinkLoaderClient.h"
+#include "core/loader/cache/CachedResourceHandle.h"
+#include "core/loader/cache/CachedStyleSheetClient.h"
+#include "core/platform/Timer.h"
+
+namespace WebCore {
+
+class HTMLLinkElement;
+class KURL;
+
+template<typename T> class EventSender;
+typedef EventSender<HTMLLinkElement> LinkEventSender;
+
+class HTMLLinkElement FINAL : public HTMLElement, public CachedStyleSheetClient, public LinkLoaderClient {
+public:
+    static PassRefPtr<HTMLLinkElement> create(const QualifiedName&, Document*, bool createdByParser);
+    virtual ~HTMLLinkElement();
+
+    KURL href() const;
+    String rel() const;
+
+    virtual String target() const;
+
+    String type() const;
+
+    IconType iconType() const;
+
+    // the icon size string as parsed from the HTML attribute
+    String iconSizes() const;
+
+    CSSStyleSheet* sheet() const { return m_sheet.get(); }
+
+    bool styleSheetIsLoading() const;
+
+    bool isDisabled() const { return m_disabledState == Disabled; }
+    bool isEnabledViaScript() const { return m_disabledState == EnabledViaScript; }
+    void setSizes(const String&);
+    DOMSettableTokenList* sizes() const;
+
+    void dispatchPendingEvent(LinkEventSender*);
+    static void dispatchPendingLoadEvents();
+
+private:
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    virtual bool shouldLoadLink();
+    void process();
+    static void processCallback(Node*);
+    void clearSheet();
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+
+    // from CachedResourceClient
+    virtual void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet);
+    virtual bool sheetLoaded();
+    virtual void notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred);
+    virtual void startLoadingDynamicSheet();
+
+    virtual void linkLoaded() OVERRIDE;
+    virtual void linkLoadingErrored() OVERRIDE;
+    virtual void didStartLinkPrerender() OVERRIDE;
+    virtual void didStopLinkPrerender() OVERRIDE;
+    virtual void didSendLoadForLinkPrerender() OVERRIDE;
+    virtual void didSendDOMContentLoadedForLinkPrerender() OVERRIDE;
+
+    bool isAlternate() const { return m_disabledState == Unset && m_relAttribute.isAlternate(); }
+    
+    void setDisabledState(bool);
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+private:
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+
+    virtual void finishParsingChildren();
+    
+    enum PendingSheetType { None, NonBlocking, Blocking };
+    void addPendingSheet(PendingSheetType);
+
+    enum RemovePendingSheetNotificationType {
+        RemovePendingSheetNotifyImmediately,
+        RemovePendingSheetNotifyLater
+    };
+
+    void removePendingSheet(RemovePendingSheetNotificationType = RemovePendingSheetNotifyImmediately);
+
+private:
+    HTMLLinkElement(const QualifiedName&, Document*, bool createdByParser);
+
+    LinkLoader m_linkLoader;
+    CachedResourceHandle<CachedCSSStyleSheet> m_cachedSheet;
+    RefPtr<CSSStyleSheet> m_sheet;
+    enum DisabledState {
+        Unset,
+        EnabledViaScript,
+        Disabled
+    };
+
+    String m_type;
+    String m_media;
+    RefPtr<DOMSettableTokenList> m_sizes;
+    DisabledState m_disabledState;
+    LinkRelAttribute m_relAttribute;
+    bool m_loading;
+    bool m_createdByParser;
+    bool m_isInShadowTree;
+    bool m_firedLoad;
+    bool m_loadedSheet;
+
+    PendingSheetType m_pendingSheetType;
+
+    int m_beforeLoadRecurseCount;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLLinkElement.idl b/Source/core/html/HTMLLinkElement.idl
new file mode 100644
index 0000000..35f1e31
--- /dev/null
+++ b/Source/core/html/HTMLLinkElement.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ * Copyright (C) 2011 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLLinkElement : HTMLElement {
+    [Reflect] attribute boolean disabled;
+    [Reflect] attribute DOMString charset;
+    [Reflect, URL] attribute DOMString href;
+    [Reflect] attribute DOMString hreflang;
+    [Reflect] attribute DOMString media;
+    [Reflect] attribute DOMString rel;
+    [Reflect] attribute DOMString rev;
+    [Custom] attribute DOMSettableTokenList sizes;
+    [Reflect] attribute DOMString target;
+    [Reflect] attribute DOMString type;
+
+    // DOM Level 2 Style
+    readonly attribute StyleSheet sheet;
+};
+
diff --git a/Source/core/html/HTMLMapElement.cpp b/Source/core/html/HTMLMapElement.cpp
new file mode 100644
index 0000000..2a139c0
--- /dev/null
+++ b/Source/core/html/HTMLMapElement.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLMapElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/html/HTMLAreaElement.h"
+#include "core/html/HTMLCollection.h"
+#include "core/html/HTMLImageElement.h"
+#include "core/platform/graphics/IntSize.h"
+#include "core/rendering/HitTestResult.h"
+#include "core/rendering/RenderObject.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLMapElement::HTMLMapElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(mapTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLMapElement> HTMLMapElement::create(Document* document)
+{
+    return adoptRef(new HTMLMapElement(mapTag, document));
+}
+
+PassRefPtr<HTMLMapElement> HTMLMapElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLMapElement(tagName, document));
+}
+
+HTMLMapElement::~HTMLMapElement()
+{
+}
+
+bool HTMLMapElement::mapMouseEvent(LayoutPoint location, const LayoutSize& size, HitTestResult& result)
+{
+    HTMLAreaElement* defaultArea = 0;
+    Element* element = this;
+    while ((element = ElementTraversal::next(element, this))) {
+        if (element->hasTagName(areaTag)) {
+            HTMLAreaElement* areaElt = static_cast<HTMLAreaElement*>(element);
+            if (areaElt->isDefault()) {
+                if (!defaultArea)
+                    defaultArea = areaElt;
+            } else if (areaElt->mapMouseEvent(location, size, result))
+                return true;
+        }
+    }
+    
+    if (defaultArea) {
+        result.setInnerNode(defaultArea);
+        result.setURLElement(defaultArea);
+    }
+    return defaultArea;
+}
+
+HTMLImageElement* HTMLMapElement::imageElement()
+{
+    RefPtr<HTMLCollection> images = document()->images();
+    for (unsigned i = 0; Node* curr = images->item(i); i++) {
+        if (!curr->hasTagName(imgTag))
+            continue;
+        
+        // The HTMLImageElement's useMap() value includes the '#' symbol at the beginning,
+        // which has to be stripped off.
+        HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(curr);
+        String useMapName = imageElement->getAttribute(usemapAttr).string().substring(1);
+        if (equalIgnoringCase(useMapName, m_name))
+            return imageElement;
+    }
+    
+    return 0;    
+}
+
+void HTMLMapElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    // FIXME: This logic seems wrong for XML documents.
+    // Either the id or name will be used depending on the order the attributes are parsed.
+
+    if (isIdAttributeName(name) || name == nameAttr) {
+        if (isIdAttributeName(name)) {
+            // Call base class so that hasID bit gets set.
+            HTMLElement::parseAttribute(name, value);
+            if (document()->isHTMLDocument())
+                return;
+        }
+        if (inDocument())
+            treeScope()->removeImageMap(this);
+        String mapName = value;
+        if (mapName[0] == '#')
+            mapName = mapName.substring(1);
+        m_name = document()->isHTMLDocument() ? mapName.lower() : mapName;
+        if (inDocument())
+            treeScope()->addImageMap(this);
+
+        return;
+    }
+
+    HTMLElement::parseAttribute(name, value);
+}
+
+PassRefPtr<HTMLCollection> HTMLMapElement::areas()
+{
+    return ensureCachedHTMLCollection(MapAreas);
+}
+
+Node::InsertionNotificationRequest HTMLMapElement::insertedInto(ContainerNode* insertionPoint)
+{
+    if (insertionPoint->inDocument())
+        treeScope()->addImageMap(this);
+    return HTMLElement::insertedInto(insertionPoint);
+}
+
+void HTMLMapElement::removedFrom(ContainerNode* insertionPoint)
+{
+    if (insertionPoint->inDocument())
+        treeScope()->removeImageMap(this);
+    HTMLElement::removedFrom(insertionPoint);
+}
+
+}
diff --git a/Source/core/html/HTMLMapElement.h b/Source/core/html/HTMLMapElement.h
new file mode 100644
index 0000000..7843179
--- /dev/null
+++ b/Source/core/html/HTMLMapElement.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLMapElement_h
+#define HTMLMapElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HitTestResult;
+class HTMLImageElement;
+    
+class HTMLMapElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLMapElement> create(Document*);
+    static PassRefPtr<HTMLMapElement> create(const QualifiedName&, Document*);
+    virtual ~HTMLMapElement();
+
+    const AtomicString& getName() const { return m_name; }
+
+    bool mapMouseEvent(LayoutPoint location, const LayoutSize&, HitTestResult&);
+    
+    HTMLImageElement* imageElement();
+    PassRefPtr<HTMLCollection> areas();
+
+private:
+    HTMLMapElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+
+    AtomicString m_name;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLMapElement.idl b/Source/core/html/HTMLMapElement.idl
new file mode 100644
index 0000000..01dcae0
--- /dev/null
+++ b/Source/core/html/HTMLMapElement.idl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLMapElement : HTMLElement {
+    readonly attribute HTMLCollection areas;
+    [Reflect] attribute DOMString name;
+};
+
diff --git a/Source/core/html/HTMLMarqueeElement.cpp b/Source/core/html/HTMLMarqueeElement.cpp
new file mode 100644
index 0000000..b17dfb2
--- /dev/null
+++ b/Source/core/html/HTMLMarqueeElement.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLMarqueeElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/rendering/RenderLayer.h"
+#include "core/rendering/RenderMarquee.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLMarqueeElement::HTMLMarqueeElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , ActiveDOMObject(document)
+{
+    ASSERT(hasTagName(marqueeTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLMarqueeElement> HTMLMarqueeElement::create(const QualifiedName& tagName, Document* document)
+{
+    RefPtr<HTMLMarqueeElement> marqueeElement(adoptRef(new HTMLMarqueeElement(tagName, document)));
+    marqueeElement->suspendIfNeeded();
+    return marqueeElement.release();
+}
+
+int HTMLMarqueeElement::minimumDelay() const
+{
+    if (fastGetAttribute(truespeedAttr).isEmpty()) {
+        // WinIE uses 60ms as the minimum delay by default.
+        return 60;
+    }
+    return 0;
+}
+
+bool HTMLMarqueeElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == widthAttr || name == heightAttr || name == bgcolorAttr || name == vspaceAttr || name == hspaceAttr || name == scrollamountAttr || name == scrolldelayAttr || name == loopAttr || name == behaviorAttr || name == directionAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLMarqueeElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == widthAttr) {
+        if (!value.isEmpty())
+            addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+    } else if (name == heightAttr) {
+        if (!value.isEmpty())
+            addHTMLLengthToStyle(style, CSSPropertyHeight, value);
+    } else if (name == bgcolorAttr) {
+        if (!value.isEmpty())
+            addHTMLColorToStyle(style, CSSPropertyBackgroundColor, value);
+    } else if (name == vspaceAttr) {
+        if (!value.isEmpty()) {
+            addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
+            addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
+        }
+    } else if (name == hspaceAttr) {
+        if (!value.isEmpty()) {
+            addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
+            addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
+        }
+    } else if (name == scrollamountAttr) {
+        if (!value.isEmpty())
+            addHTMLLengthToStyle(style, CSSPropertyWebkitMarqueeIncrement, value);
+    } else if (name == scrolldelayAttr) {
+        if (!value.isEmpty())
+            addHTMLLengthToStyle(style, CSSPropertyWebkitMarqueeSpeed, value);
+    } else if (name == loopAttr) {
+        if (!value.isEmpty()) {
+            if (value == "-1" || equalIgnoringCase(value, "infinite"))
+                addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitMarqueeRepetition, CSSValueInfinite);
+            else
+                addHTMLLengthToStyle(style, CSSPropertyWebkitMarqueeRepetition, value);
+        }
+    } else if (name == behaviorAttr) {
+        if (!value.isEmpty())
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitMarqueeStyle, value);
+    } else if (name == directionAttr) {
+        if (!value.isEmpty())
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitMarqueeDirection, value);
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLMarqueeElement::start()
+{
+    if (RenderMarquee* marqueeRenderer = renderMarquee())
+        marqueeRenderer->start();
+}
+
+void HTMLMarqueeElement::stop()
+{
+    if (RenderMarquee* marqueeRenderer = renderMarquee())
+        marqueeRenderer->stop();
+}
+
+int HTMLMarqueeElement::scrollAmount() const
+{
+    bool ok;
+    int scrollAmount = fastGetAttribute(scrollamountAttr).toInt(&ok);
+    return ok && scrollAmount >= 0 ? scrollAmount : RenderStyle::initialMarqueeIncrement().intValue();
+}
+    
+void HTMLMarqueeElement::setScrollAmount(int scrollAmount, ExceptionCode& ec)
+{
+    if (scrollAmount < 0)
+        ec = INDEX_SIZE_ERR;
+    else
+        setIntegralAttribute(scrollamountAttr, scrollAmount);
+}
+    
+int HTMLMarqueeElement::scrollDelay() const
+{
+    bool ok;
+    int scrollDelay = fastGetAttribute(scrolldelayAttr).toInt(&ok);
+    return ok && scrollDelay >= 0 ? scrollDelay : RenderStyle::initialMarqueeSpeed();
+}
+
+void HTMLMarqueeElement::setScrollDelay(int scrollDelay, ExceptionCode& ec)
+{
+    if (scrollDelay < 0)
+        ec = INDEX_SIZE_ERR;
+    else
+        setIntegralAttribute(scrolldelayAttr, scrollDelay);
+}
+    
+int HTMLMarqueeElement::loop() const
+{
+    bool ok;
+    int loopValue = fastGetAttribute(loopAttr).toInt(&ok);
+    return ok && loopValue > 0 ? loopValue : -1;
+}
+    
+void HTMLMarqueeElement::setLoop(int loop, ExceptionCode& ec)
+{
+    if (loop <= 0 && loop != -1)
+        ec = INDEX_SIZE_ERR;
+    else
+        setIntegralAttribute(loopAttr, loop);
+}
+
+bool HTMLMarqueeElement::canSuspend() const
+{
+    return true;
+}
+
+void HTMLMarqueeElement::suspend(ReasonForSuspension)
+{
+    if (RenderMarquee* marqueeRenderer = renderMarquee())
+        marqueeRenderer->suspend();
+}
+
+void HTMLMarqueeElement::resume()
+{
+    if (RenderMarquee* marqueeRenderer = renderMarquee())
+        marqueeRenderer->updateMarqueePosition();
+}
+
+RenderMarquee* HTMLMarqueeElement::renderMarquee() const
+{
+    if (renderer() && renderer()->hasLayer())
+        return renderBoxModelObject()->layer()->marquee();
+    return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLMarqueeElement.h b/Source/core/html/HTMLMarqueeElement.h
new file mode 100644
index 0000000..a4fcee3
--- /dev/null
+++ b/Source/core/html/HTMLMarqueeElement.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLMarqueeElement_h
+#define HTMLMarqueeElement_h
+
+#include "core/dom/ActiveDOMObject.h"
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class RenderMarquee;
+
+class HTMLMarqueeElement FINAL : public HTMLElement, private ActiveDOMObject {
+public:
+    static PassRefPtr<HTMLMarqueeElement> create(const QualifiedName&, Document*);
+
+    int minimumDelay() const;
+
+    // DOM Functions
+
+    void start();
+    void stop();
+    
+    int scrollAmount() const;
+    void setScrollAmount(int, ExceptionCode&);
+    
+    int scrollDelay() const;
+    void setScrollDelay(int, ExceptionCode&);
+    
+    int loop() const;
+    void setLoop(int, ExceptionCode&);
+    
+private:
+    HTMLMarqueeElement(const QualifiedName&, Document*);
+
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    // ActiveDOMObject
+    virtual bool canSuspend() const;
+    virtual void suspend(ReasonForSuspension);
+    virtual void resume();
+
+    RenderMarquee* renderMarquee() const;
+};
+
+} // namespace WebCore
+
+#endif // HTMLMarqueeElement_h
diff --git a/Source/core/html/HTMLMarqueeElement.idl b/Source/core/html/HTMLMarqueeElement.idl
new file mode 100644
index 0000000..5b8e3a9
--- /dev/null
+++ b/Source/core/html/HTMLMarqueeElement.idl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLMarqueeElement : HTMLElement {
+    void start();
+    void stop();
+    
+    [Reflect] attribute DOMString behavior;
+    [Reflect] attribute DOMString bgColor;
+    [Reflect] attribute DOMString direction;
+    [Reflect] attribute DOMString height;
+    [Reflect] attribute unsigned long hspace;
+    [SetterRaisesException] attribute long loop;
+    [SetterRaisesException] attribute long scrollAmount;
+    [SetterRaisesException] attribute long scrollDelay;
+    [Reflect] attribute boolean trueSpeed;
+    [Reflect] attribute unsigned long vspace;
+    [Reflect] attribute DOMString width;
+
+    // FIXME: Implement the following event handler attributes
+    // https://bugs.webkit.org/show_bug.cgi?id=49788
+    // attribute EventListener onbounce;
+    // attribute EventListener onfinish;
+    // attribute EventListener onstart;
+};
diff --git a/Source/core/html/HTMLMediaElement.cpp b/Source/core/html/HTMLMediaElement.cpp
new file mode 100644
index 0000000..334d719
--- /dev/null
+++ b/Source/core/html/HTMLMediaElement.cpp
@@ -0,0 +1,4359 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+#include "core/html/HTMLMediaElement.h"
+
+#include <limits>
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/css/MediaList.h"
+#include "core/css/MediaQueryEvaluator.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/ClientRect.h"
+#include "core/dom/ClientRectList.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLSourceElement.h"
+#include "core/html/HTMLVideoElement.h"
+#include "core/html/MediaController.h"
+#include "core/html/MediaDocument.h"
+#include "core/html/MediaError.h"
+#include "core/html/MediaFragmentURIParser.h"
+#include "core/html/MediaKeyError.h"
+#include "core/html/MediaKeyEvent.h"
+#include "core/html/TimeRanges.h"
+#include "core/html/shadow/MediaControls.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/loader/appcache/ApplicationCacheHost.h"
+#include "core/page/Chrome.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/ContentSecurityPolicy.h"
+#include "core/page/DiagnosticLoggingKeys.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/PageGroup.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/page/SecurityPolicy.h"
+#include "core/page/Settings.h"
+#include "core/platform/ContentType.h"
+#include "core/platform/Language.h"
+#include "core/platform/Logging.h"
+#include "core/platform/MIMETypeRegistry.h"
+#include "core/platform/graphics/MediaPlayer.h"
+#include "core/rendering/RenderLayerCompositor.h"
+#include "core/rendering/RenderVideo.h"
+#include "core/rendering/RenderView.h"
+#include "modules/mediastream/MediaStreamRegistry.h"
+#include "modules/mediasource/MediaSource.h"
+#include "modules/mediasource/MediaSourceRegistry.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/MathExtras.h>
+#include <wtf/MemoryInstrumentationVector.h>
+#include <wtf/NonCopyingSort.h>
+#include <wtf/text/CString.h>
+#include <wtf/Uint8Array.h>
+
+#include "core/html/HTMLTrackElement.h"
+#include "core/html/track/InbandTextTrack.h"
+#include "core/html/track/TextTrackCueList.h"
+#include "core/html/track/TextTrackList.h"
+#include "core/page/CaptionUserPreferences.h"
+#include "RuntimeEnabledFeatures.h"
+#include "core/platform/graphics/InbandTextTrackPrivate.h"
+
+#if ENABLE(WEB_AUDIO)
+#include "core/platform/audio/AudioSourceProvider.h"
+#include "modules/webaudio/MediaElementAudioSourceNode.h"
+#endif
+
+#if ENABLE(ENCRYPTED_MEDIA_V2)
+#include "MediaKeyNeededEvent.h"
+#include "MediaKeys.h"
+#endif
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+#include "core/platform/graphics/PlatformTextTrack.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+#if !LOG_DISABLED
+static String urlForLoggingMedia(const KURL& url)
+{
+    static const unsigned maximumURLLengthForLogging = 128;
+
+    if (url.string().length() < maximumURLLengthForLogging)
+        return url.string();
+    return url.string().substring(0, maximumURLLengthForLogging) + "...";
+}
+
+static const char* boolString(bool val)
+{
+    return val ? "true" : "false";
+}
+#endif
+
+#ifndef LOG_MEDIA_EVENTS
+// Default to not logging events because so many are generated they can overwhelm the rest of
+// the logging.
+#define LOG_MEDIA_EVENTS 0
+#endif
+
+#ifndef LOG_CACHED_TIME_WARNINGS
+// Default to not logging warnings about excessive drift in the cached media time because it adds a
+// fair amount of overhead and logging.
+#define LOG_CACHED_TIME_WARNINGS 0
+#endif
+
+// URL protocol used to signal that the media source API is being used.
+static const char* mediaSourceBlobProtocol = "blob";
+
+using namespace HTMLNames;
+using namespace std;
+
+typedef HashMap<Document*, HashSet<HTMLMediaElement*> > DocumentElementSetMap;
+static DocumentElementSetMap& documentToElementSetMap()
+{
+    DEFINE_STATIC_LOCAL(DocumentElementSetMap, map, ());
+    return map;
+}
+
+static void addElementToDocumentMap(HTMLMediaElement* element, Document* document)
+{
+    DocumentElementSetMap& map = documentToElementSetMap();
+    HashSet<HTMLMediaElement*> set = map.take(document);
+    set.add(element);
+    map.add(document, set);
+}
+
+static void removeElementFromDocumentMap(HTMLMediaElement* element, Document* document)
+{
+    DocumentElementSetMap& map = documentToElementSetMap();
+    HashSet<HTMLMediaElement*> set = map.take(document);
+    set.remove(element);
+    if (!set.isEmpty())
+        map.add(document, set);
+}
+
+#if ENABLE(ENCRYPTED_MEDIA)
+static ExceptionCode exceptionCodeForMediaKeyException(MediaPlayer::MediaKeyException exception)
+{
+    switch (exception) {
+    case MediaPlayer::NoError:
+        return 0;
+    case MediaPlayer::InvalidPlayerState:
+        return INVALID_STATE_ERR;
+    case MediaPlayer::KeySystemNotSupported:
+        return NOT_SUPPORTED_ERR;
+    }
+
+    ASSERT_NOT_REACHED();
+    return INVALID_STATE_ERR;
+}
+#endif
+
+class TrackDisplayUpdateScope {
+public:
+    TrackDisplayUpdateScope(HTMLMediaElement* mediaElement)
+    {
+        m_mediaElement = mediaElement;
+        m_mediaElement->beginIgnoringTrackDisplayUpdateRequests();
+    }
+    ~TrackDisplayUpdateScope()
+    {
+        ASSERT(m_mediaElement);
+        m_mediaElement->endIgnoringTrackDisplayUpdateRequests();
+    }
+
+private:
+    HTMLMediaElement* m_mediaElement;
+};
+
+HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* document, bool createdByParser)
+    : HTMLElement(tagName, document)
+    , ActiveDOMObject(document)
+    , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
+    , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
+    , m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
+    , m_playedTimeRanges()
+    , m_asyncEventQueue(GenericEventQueue::create(this))
+    , m_playbackRate(1.0f)
+    , m_defaultPlaybackRate(1.0f)
+    , m_webkitPreservesPitch(true)
+    , m_networkState(NETWORK_EMPTY)
+    , m_readyState(HAVE_NOTHING)
+    , m_readyStateMaximum(HAVE_NOTHING)
+    , m_volume(1.0f)
+    , m_lastSeekTime(0)
+    , m_previousProgressTime(numeric_limits<double>::max())
+    , m_lastTimeUpdateEventWallTime(0)
+    , m_lastTimeUpdateEventMovieTime(numeric_limits<double>::max())
+    , m_loadState(WaitingForSource)
+    , m_restrictions(RequireUserGestureForFullscreenRestriction | RequirePageConsentToLoadMediaRestriction)
+    , m_preload(MediaPlayer::Auto)
+    , m_displayMode(Unknown)
+    , m_processingMediaPlayerCallback(0)
+    , m_cachedTime(MediaPlayer::invalidTime())
+    , m_cachedTimeWallClockUpdateTime(0)
+    , m_minimumWallClockTimeToCacheMediaTime(0)
+    , m_fragmentStartTime(MediaPlayer::invalidTime())
+    , m_fragmentEndTime(MediaPlayer::invalidTime())
+    , m_pendingActionFlags(0)
+    , m_playing(false)
+    , m_shouldDelayLoadEvent(false)
+    , m_haveFiredLoadedData(false)
+    , m_inActiveDocument(true)
+    , m_autoplaying(true)
+    , m_muted(false)
+    , m_paused(true)
+    , m_seeking(false)
+    , m_sentStalledEvent(false)
+    , m_sentEndEvent(false)
+    , m_pausedInternal(false)
+    , m_sendProgressEvents(true)
+    , m_closedCaptionsVisible(false)
+    , m_dispatchingCanPlayEvent(false)
+    , m_loadInitiatedByUserGesture(false)
+    , m_completelyLoaded(false)
+    , m_havePreparedToPlay(false)
+    , m_parsingInProgress(createdByParser)
+    , m_tracksAreReady(true)
+    , m_haveVisibleTextTrack(false)
+    , m_processingPreferenceChange(false)
+    , m_lastTextTrackUpdateTime(-1)
+    , m_textTracks(0)
+    , m_ignoreTrackDisplayUpdate(0)
+#if ENABLE(WEB_AUDIO)
+    , m_audioSourceNode(0)
+#endif
+{
+    LOG(Media, "HTMLMediaElement::HTMLMediaElement");
+    ScriptWrappable::init(this);
+
+    if (document->settings() && document->settings()->mediaPlaybackRequiresUserGesture()) {
+        addBehaviorRestriction(RequireUserGestureForRateChangeRestriction);
+        addBehaviorRestriction(RequireUserGestureForLoadRestriction);
+    }
+
+    setHasCustomStyleCallbacks();
+    addElementToDocumentMap(this, document);
+
+    document->registerForCaptionPreferencesChangedCallbacks(this);
+}
+
+HTMLMediaElement::~HTMLMediaElement()
+{
+    LOG(Media, "HTMLMediaElement::~HTMLMediaElement");
+    setShouldDelayLoadEvent(false);
+    document()->unregisterForCaptionPreferencesChangedCallbacks(this);
+    if (m_textTracks)
+        m_textTracks->clearOwner();
+    if (m_textTracks) {
+        for (unsigned i = 0; i < m_textTracks->length(); ++i)
+            m_textTracks->item(i)->clearClient();
+    }
+
+    if (m_mediaController)
+        m_mediaController->removeMediaElement(this);
+
+    setSourceState(MediaSource::closedKeyword());
+
+#if ENABLE(ENCRYPTED_MEDIA_V2)
+    setMediaKeys(0);
+#endif
+
+    removeElementFromDocumentMap(this, document());
+
+    m_completelyLoaded = true;
+    m_player.clear();
+}
+
+void HTMLMediaElement::didMoveToNewDocument(Document* oldDocument)
+{
+    if (m_shouldDelayLoadEvent) {
+        if (oldDocument)
+            oldDocument->decrementLoadEventDelayCount();
+        document()->incrementLoadEventDelayCount();
+    }
+
+    if (oldDocument)
+        removeElementFromDocumentMap(this, oldDocument);
+
+    addElementToDocumentMap(this, document());
+
+    HTMLElement::didMoveToNewDocument(oldDocument);
+}
+
+bool HTMLMediaElement::hasCustomFocusLogic() const
+{
+    return true;
+}
+
+bool HTMLMediaElement::supportsFocus() const
+{
+    if (ownerDocument()->isMediaDocument())
+        return false;
+
+    // If no controls specified, we should still be able to focus the element if it has tabIndex.
+    return controls() ||  HTMLElement::supportsFocus();
+}
+
+bool HTMLMediaElement::isMouseFocusable() const
+{
+    return false;
+}
+
+void HTMLMediaElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == srcAttr) {
+        // Trigger a reload, as long as the 'src' attribute is present.
+        if (!value.isNull()) {
+            clearMediaPlayer(LoadMediaResource);
+            scheduleDelayedAction(LoadMediaResource);
+        }
+    } else if (name == controlsAttr)
+        configureMediaControls();
+    else if (name == preloadAttr) {
+        if (equalIgnoringCase(value, "none"))
+            m_preload = MediaPlayer::None;
+        else if (equalIgnoringCase(value, "metadata"))
+            m_preload = MediaPlayer::MetaData;
+        else {
+            // The spec does not define an "invalid value default" but "auto" is suggested as the
+            // "missing value default", so use it for everything except "none" and "metadata"
+            m_preload = MediaPlayer::Auto;
+        }
+
+        // The attribute must be ignored if the autoplay attribute is present
+        if (!autoplay() && m_player)
+            m_player->setPreload(m_preload);
+
+    } else if (name == mediagroupAttr)
+        setMediaGroup(value);
+    else if (name == onabortAttr)
+        setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, name, value));
+    else if (name == onbeforeloadAttr)
+        setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, name, value));
+    else if (name == oncanplayAttr)
+        setAttributeEventListener(eventNames().canplayEvent, createAttributeEventListener(this, name, value));
+    else if (name == oncanplaythroughAttr)
+        setAttributeEventListener(eventNames().canplaythroughEvent, createAttributeEventListener(this, name, value));
+    else if (name == ondurationchangeAttr)
+        setAttributeEventListener(eventNames().durationchangeEvent, createAttributeEventListener(this, name, value));
+    else if (name == onemptiedAttr)
+        setAttributeEventListener(eventNames().emptiedEvent, createAttributeEventListener(this, name, value));
+    else if (name == onendedAttr)
+        setAttributeEventListener(eventNames().endedEvent, createAttributeEventListener(this, name, value));
+    else if (name == onerrorAttr)
+        setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, name, value));
+    else if (name == onloadeddataAttr)
+        setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, name, value));
+    else if (name == onloadedmetadataAttr)
+        setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, name, value));
+    else if (name == onloadstartAttr)
+        setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, name, value));
+    else if (name == onpauseAttr)
+        setAttributeEventListener(eventNames().pauseEvent, createAttributeEventListener(this, name, value));
+    else if (name == onplayAttr)
+        setAttributeEventListener(eventNames().playEvent, createAttributeEventListener(this, name, value));
+    else if (name == onplayingAttr)
+        setAttributeEventListener(eventNames().playingEvent, createAttributeEventListener(this, name, value));
+    else if (name == onprogressAttr)
+        setAttributeEventListener(eventNames().progressEvent, createAttributeEventListener(this, name, value));
+    else if (name == onratechangeAttr)
+        setAttributeEventListener(eventNames().ratechangeEvent, createAttributeEventListener(this, name, value));
+    else if (name == onseekedAttr)
+        setAttributeEventListener(eventNames().seekedEvent, createAttributeEventListener(this, name, value));
+    else if (name == onseekingAttr)
+        setAttributeEventListener(eventNames().seekingEvent, createAttributeEventListener(this, name, value));
+    else if (name == onstalledAttr)
+        setAttributeEventListener(eventNames().stalledEvent, createAttributeEventListener(this, name, value));
+    else if (name == onsuspendAttr)
+        setAttributeEventListener(eventNames().suspendEvent, createAttributeEventListener(this, name, value));
+    else if (name == ontimeupdateAttr)
+        setAttributeEventListener(eventNames().timeupdateEvent, createAttributeEventListener(this, name, value));
+    else if (name == onvolumechangeAttr)
+        setAttributeEventListener(eventNames().volumechangeEvent, createAttributeEventListener(this, name, value));
+    else if (name == onwaitingAttr)
+        setAttributeEventListener(eventNames().waitingEvent, createAttributeEventListener(this, name, value));
+    else
+        HTMLElement::parseAttribute(name, value);
+}
+
+void HTMLMediaElement::finishParsingChildren()
+{
+    HTMLElement::finishParsingChildren();
+    m_parsingInProgress = false;
+
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return;
+
+    for (Node* node = firstChild(); node; node = node->nextSibling()) {
+        if (node->hasTagName(trackTag)) {
+            scheduleDelayedAction(LoadTextTrackResource);
+            break;
+        }
+    }
+}
+
+bool HTMLMediaElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    return controls() ? HTMLElement::rendererIsNeeded(context) : false;
+}
+
+RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderMedia(this);
+}
+
+bool HTMLMediaElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
+{
+    if (!hasMediaControls())
+        return false;
+    // <media> doesn't allow its content, including shadow subtree, to
+    // be rendered. So this should return false for most of the children.
+    // One exception is a shadow tree built for rendering controls which should be visible.
+    // So we let them go here by comparing its subtree root with one of the controls.
+    return (mediaControls()->treeScope() == childContext.node()->treeScope()
+            && childContext.isOnUpperEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext));
+}
+
+Node::InsertionNotificationRequest HTMLMediaElement::insertedInto(ContainerNode* insertionPoint)
+{
+    LOG(Media, "HTMLMediaElement::insertedInto");
+    HTMLElement::insertedInto(insertionPoint);
+    if (insertionPoint->inDocument() && !getAttribute(srcAttr).isEmpty() && m_networkState == NETWORK_EMPTY)
+        scheduleDelayedAction(LoadMediaResource);
+    configureMediaControls();
+    return InsertionDone;
+}
+
+void HTMLMediaElement::removedFrom(ContainerNode* insertionPoint)
+{
+    m_inActiveDocument = false;
+
+    if (insertionPoint->inDocument()) {
+        LOG(Media, "HTMLMediaElement::removedFromDocument");
+        configureMediaControls();
+        if (m_networkState > NETWORK_EMPTY)
+            pause();
+    }
+
+    HTMLElement::removedFrom(insertionPoint);
+}
+
+void HTMLMediaElement::attach()
+{
+    ASSERT(!attached());
+
+    HTMLElement::attach();
+
+    if (renderer())
+        renderer()->updateFromElement();
+}
+
+void HTMLMediaElement::didRecalcStyle(StyleChange)
+{
+    if (renderer())
+        renderer()->updateFromElement();
+}
+
+void HTMLMediaElement::scheduleDelayedAction(DelayedActionType actionType)
+{
+    LOG(Media, "HTMLMediaElement::scheduleLoad");
+
+    if ((actionType & LoadMediaResource) && !(m_pendingActionFlags & LoadMediaResource)) {
+        prepareForLoad();
+        m_pendingActionFlags |= LoadMediaResource;
+    }
+
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled() && (actionType & LoadTextTrackResource))
+        m_pendingActionFlags |= LoadTextTrackResource;
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    if (actionType & TextTrackChangesNotification)
+        m_pendingActionFlags |= TextTrackChangesNotification;
+#endif
+
+    if (!m_loadTimer.isActive())
+        m_loadTimer.startOneShot(0);
+}
+
+void HTMLMediaElement::scheduleNextSourceChild()
+{
+    // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
+    m_pendingActionFlags |= LoadMediaResource;
+    m_loadTimer.startOneShot(0);
+}
+
+void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
+{
+#if LOG_MEDIA_EVENTS
+    LOG(Media, "HTMLMediaElement::scheduleEvent - scheduling '%s'", eventName.string().ascii().data());
+#endif
+    RefPtr<Event> event = Event::create(eventName, false, true);
+    event->setTarget(this);
+
+    m_asyncEventQueue->enqueueEvent(event.release());
+}
+
+void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
+{
+    RefPtr<HTMLMediaElement> protect(this); // loadNextSourceChild may fire 'beforeload', which can make arbitrary DOM mutations.
+
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled() && (m_pendingActionFlags & LoadTextTrackResource))
+        configureTextTracks();
+
+    if (m_pendingActionFlags & LoadMediaResource) {
+        if (m_loadState == LoadingFromSourceElement)
+            loadNextSourceChild();
+        else
+            loadInternal();
+    }
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled() && (m_pendingActionFlags & TextTrackChangesNotification))
+        notifyMediaPlayerOfTextTrackChanges();
+#endif
+
+    m_pendingActionFlags = 0;
+}
+
+PassRefPtr<MediaError> HTMLMediaElement::error() const
+{
+    return m_error;
+}
+
+void HTMLMediaElement::setSrc(const String& url)
+{
+    setAttribute(srcAttr, url);
+}
+
+HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
+{
+    return m_networkState;
+}
+
+String HTMLMediaElement::canPlayType(const String& mimeType, const String& keySystem, const KURL& url) const
+{
+    MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType), keySystem, url, this);
+    String canPlay;
+
+    // 4.8.10.3
+    switch (support)
+    {
+        case MediaPlayer::IsNotSupported:
+            canPlay = emptyString();
+            break;
+        case MediaPlayer::MayBeSupported:
+            canPlay = ASCIILiteral("maybe");
+            break;
+        case MediaPlayer::IsSupported:
+            canPlay = ASCIILiteral("probably");
+            break;
+    }
+
+    LOG(Media, "HTMLMediaElement::canPlayType(%s, %s, %s) -> %s", mimeType.utf8().data(), keySystem.utf8().data(), url.elidedString().utf8().data(), canPlay.utf8().data());
+
+    return canPlay;
+}
+
+void HTMLMediaElement::load()
+{
+    RefPtr<HTMLMediaElement> protect(this); // loadInternal may result in a 'beforeload' event, which can make arbitrary DOM mutations.
+
+    LOG(Media, "HTMLMediaElement::load()");
+
+    if (userGestureRequiredForLoad() && !ScriptController::processingUserGesture())
+        return;
+
+    m_loadInitiatedByUserGesture = ScriptController::processingUserGesture();
+    if (m_loadInitiatedByUserGesture)
+        removeBehaviorsRestrictionsAfterFirstUserGesture();
+    prepareForLoad();
+    loadInternal();
+    prepareToPlay();
+}
+
+void HTMLMediaElement::prepareForLoad()
+{
+    LOG(Media, "HTMLMediaElement::prepareForLoad");
+
+    // Perform the cleanup required for the resource load algorithm to run.
+    stopPeriodicTimers();
+    m_loadTimer.stop();
+    m_sentEndEvent = false;
+    m_sentStalledEvent = false;
+    m_haveFiredLoadedData = false;
+    m_completelyLoaded = false;
+    m_havePreparedToPlay = false;
+    m_displayMode = Unknown;
+
+    // 1 - Abort any already-running instance of the resource selection algorithm for this element.
+    m_loadState = WaitingForSource;
+    m_currentSourceNode = 0;
+
+    // 2 - If there are any tasks from the media element's media element event task source in
+    // one of the task queues, then remove those tasks.
+    cancelPendingEventsAndCallbacks();
+
+    // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
+    // a task to fire a simple event named abort at the media element.
+    if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE)
+        scheduleEvent(eventNames().abortEvent);
+
+    setSourceState(MediaSource::closedKeyword());
+
+    createMediaPlayer();
+
+    // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
+    if (m_networkState != NETWORK_EMPTY) {
+        m_networkState = NETWORK_EMPTY;
+        m_readyState = HAVE_NOTHING;
+        m_readyStateMaximum = HAVE_NOTHING;
+        refreshCachedTime();
+        m_paused = true;
+        m_seeking = false;
+        invalidateCachedTime();
+        scheduleEvent(eventNames().emptiedEvent);
+        updateMediaController();
+        if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+            updateActiveTextTrackCues(0);
+    }
+
+    // 5 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
+    setPlaybackRate(defaultPlaybackRate());
+
+    // 6 - Set the error attribute to null and the autoplaying flag to true.
+    m_error = 0;
+    m_autoplaying = true;
+
+    // 7 - Invoke the media element's resource selection algorithm.
+
+    // 8 - Note: Playback of any previously playing media resource for this element stops.
+
+    // The resource selection algorithm
+    // 1 - Set the networkState to NETWORK_NO_SOURCE
+    m_networkState = NETWORK_NO_SOURCE;
+
+    // 2 - Asynchronously await a stable state.
+
+    m_playedTimeRanges = TimeRanges::create();
+    m_lastSeekTime = 0;
+
+    // The spec doesn't say to block the load event until we actually run the asynchronous section
+    // algorithm, but do it now because we won't start that until after the timer fires and the
+    // event may have already fired by then.
+    setShouldDelayLoadEvent(true);
+
+    configureMediaControls();
+}
+
+void HTMLMediaElement::loadInternal()
+{
+    // Some of the code paths below this function dispatch the BeforeLoad event. This ASSERT helps
+    // us catch those bugs more quickly without needing all the branches to align to actually
+    // trigger the event.
+    ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
+
+    // Once the page has allowed an element to load media, it is free to load at will. This allows a
+    // playlist that starts in a foreground tab to continue automatically if the tab is subsequently
+    // put in the the background.
+    removeBehaviorRestriction(RequirePageConsentToLoadMediaRestriction);
+
+    // HTMLMediaElement::textTracksAreReady will need "... the text tracks whose mode was not in the
+    // disabled state when the element's resource selection algorithm last started".
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled()) {
+        m_textTracksWhenResourceSelectionBegan.clear();
+        if (m_textTracks) {
+            for (unsigned i = 0; i < m_textTracks->length(); ++i) {
+                TextTrack* track = m_textTracks->item(i);
+                if (track->mode() != TextTrack::disabledKeyword())
+                    m_textTracksWhenResourceSelectionBegan.append(track);
+            }
+        }
+    }
+
+    selectMediaResource();
+}
+
+void HTMLMediaElement::selectMediaResource()
+{
+    LOG(Media, "HTMLMediaElement::selectMediaResource");
+
+    enum Mode { attribute, children };
+
+    // 3 - If the media element has a src attribute, then let mode be attribute.
+    Mode mode = attribute;
+    if (!fastHasAttribute(srcAttr)) {
+        Node* node;
+        for (node = firstChild(); node; node = node->nextSibling()) {
+            if (node->hasTagName(sourceTag))
+                break;
+        }
+
+        // Otherwise, if the media element does not have a src attribute but has a source
+        // element child, then let mode be children and let candidate be the first such
+        // source element child in tree order.
+        if (node) {
+            mode = children;
+            m_nextChildNodeToConsider = node;
+            m_currentSourceNode = 0;
+        } else {
+            // Otherwise the media element has neither a src attribute nor a source element
+            // child: set the networkState to NETWORK_EMPTY, and abort these steps; the
+            // synchronous section ends.
+            m_loadState = WaitingForSource;
+            setShouldDelayLoadEvent(false);
+            m_networkState = NETWORK_EMPTY;
+
+            LOG(Media, "HTMLMediaElement::selectMediaResource, nothing to load");
+            return;
+        }
+    }
+
+    // 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event),
+    // and set its networkState to NETWORK_LOADING.
+    setShouldDelayLoadEvent(true);
+    m_networkState = NETWORK_LOADING;
+
+    // 5 - Queue a task to fire a simple event named loadstart at the media element.
+    scheduleEvent(eventNames().loadstartEvent);
+
+    // 6 - If mode is attribute, then run these substeps
+    if (mode == attribute) {
+        m_loadState = LoadingFromSrcAttr;
+
+        // If the src attribute's value is the empty string ... jump down to the failed step below
+        KURL mediaURL = getNonEmptyURLAttribute(srcAttr);
+        if (mediaURL.isEmpty()) {
+            mediaLoadingFailed(MediaPlayer::FormatError);
+            LOG(Media, "HTMLMediaElement::selectMediaResource, empty 'src'");
+            return;
+        }
+
+        if (!isSafeToLoadURL(mediaURL, Complain) || !dispatchBeforeLoadEvent(mediaURL.string())) {
+            mediaLoadingFailed(MediaPlayer::FormatError);
+            return;
+        }
+
+        // No type or key system information is available when the url comes
+        // from the 'src' attribute so MediaPlayer
+        // will have to pick a media engine based on the file extension.
+        ContentType contentType((String()));
+        loadResource(mediaURL, contentType, String());
+        LOG(Media, "HTMLMediaElement::selectMediaResource, using 'src' attribute url");
+        return;
+    }
+
+    // Otherwise, the source elements will be used
+    loadNextSourceChild();
+}
+
+void HTMLMediaElement::loadNextSourceChild()
+{
+    ContentType contentType((String()));
+    String keySystem;
+    KURL mediaURL = selectNextSourceChild(&contentType, &keySystem, Complain);
+    if (!mediaURL.isValid()) {
+        waitForSourceChange();
+        return;
+    }
+
+    // Recreate the media player for the new url
+    createMediaPlayer();
+
+    m_loadState = LoadingFromSourceElement;
+    loadResource(mediaURL, contentType, keySystem);
+}
+
+void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& contentType, const String& keySystem)
+{
+    ASSERT(isSafeToLoadURL(initialURL, Complain));
+
+    LOG(Media, "HTMLMediaElement::loadResource(%s, %s, %s)", urlForLoggingMedia(initialURL).utf8().data(), contentType.raw().utf8().data(), keySystem.utf8().data());
+
+    Frame* frame = document()->frame();
+    if (!frame) {
+        mediaLoadingFailed(MediaPlayer::FormatError);
+        return;
+    }
+
+    KURL url = initialURL;
+    if (!frame->loader()->willLoadMediaElementURL(url)) {
+        mediaLoadingFailed(MediaPlayer::FormatError);
+        return;
+    }
+
+    // The resource fetch algorithm
+    m_networkState = NETWORK_LOADING;
+
+    // Set m_currentSrc *before* changing to the cache url, the fact that we are loading from the app
+    // cache is an internal detail not exposed through the media element API.
+    m_currentSrc = url;
+
+    LOG(Media, "HTMLMediaElement::loadResource - m_currentSrc -> %s", urlForLoggingMedia(m_currentSrc).utf8().data());
+
+    if (MediaStreamRegistry::registry().lookupMediaStreamDescriptor(url.string()))
+      removeBehaviorRestriction(RequireUserGestureForRateChangeRestriction);
+
+    if (m_sendProgressEvents)
+        startProgressEventTimer();
+
+    // Reset display mode to force a recalculation of what to show because we are resetting the player.
+    setDisplayMode(Unknown);
+
+    if (!autoplay())
+        m_player->setPreload(m_preload);
+    m_player->setPreservesPitch(m_webkitPreservesPitch);
+
+    if (fastHasAttribute(mutedAttr))
+        m_muted = true;
+    updateVolume();
+
+    ASSERT(!m_mediaSource);
+
+    if (url.protocolIs(mediaSourceBlobProtocol))
+        m_mediaSource = MediaSourceRegistry::registry().lookupMediaSource(url.string());
+
+    if (m_mediaSource) {
+        if (!m_player->load(url, m_mediaSource))
+            mediaLoadingFailed(MediaPlayer::FormatError);
+    } else if (!m_player->load(url, contentType, keySystem)) {
+        mediaLoadingFailed(MediaPlayer::FormatError);
+    }
+
+    // If there is no poster to display, allow the media engine to render video frames as soon as
+    // they are available.
+    updateDisplayState();
+
+    if (renderer())
+        renderer()->updateFromElement();
+}
+
+static bool trackIndexCompare(TextTrack* a,
+                              TextTrack* b)
+{
+    return a->trackIndex() - b->trackIndex() < 0;
+}
+
+static bool eventTimeCueCompare(const std::pair<double, TextTrackCue*>& a,
+                                const std::pair<double, TextTrackCue*>& b)
+{
+    // 12 - Sort the tasks in events in ascending time order (tasks with earlier
+    // times first).
+    if (a.first != b.first)
+        return a.first - b.first < 0;
+
+    // If the cues belong to different text tracks, it doesn't make sense to
+    // compare the two tracks by the relative cue order, so return the relative
+    // track order.
+    if (a.second->track() != b.second->track())
+        return trackIndexCompare(a.second->track(), b.second->track());
+
+    // 12 - Further sort tasks in events that have the same time by the
+    // relative text track cue order of the text track cues associated
+    // with these tasks.
+    return a.second->cueIndex() - b.second->cueIndex() < 0;
+}
+
+
+void HTMLMediaElement::updateActiveTextTrackCues(double movieTime)
+{
+    LOG(Media, "HTMLMediaElement::updateActiveTextTrackCues");
+
+    // 4.8.10.8 Playing the media resource
+
+    //  If the current playback position changes while the steps are running,
+    //  then the user agent must wait for the steps to complete, and then must
+    //  immediately rerun the steps.
+    if (ignoreTrackDisplayUpdateRequests())
+        return;
+
+    // 1 - Let current cues be a list of cues, initialized to contain all the
+    // cues of all the hidden, showing, or showing by default text tracks of the
+    // media element (not the disabled ones) whose start times are less than or
+    // equal to the current playback position and whose end times are greater
+    // than the current playback position.
+    CueList currentCues;
+
+    // The user agent must synchronously unset [the text track cue active] flag
+    // whenever ... the media element's readyState is changed back to HAVE_NOTHING.
+    if (m_readyState != HAVE_NOTHING && m_player)
+        currentCues = m_cueTree.allOverlaps(m_cueTree.createInterval(movieTime, movieTime));
+
+    CueList previousCues;
+    CueList missedCues;
+
+    // 2 - Let other cues be a list of cues, initialized to contain all the cues
+    // of hidden, showing, and showing by default text tracks of the media
+    // element that are not present in current cues.
+    previousCues = m_currentlyActiveCues;
+
+    // 3 - Let last time be the current playback position at the time this
+    // algorithm was last run for this media element, if this is not the first
+    // time it has run.
+    double lastTime = m_lastTextTrackUpdateTime;
+
+    // 4 - If the current playback position has, since the last time this
+    // algorithm was run, only changed through its usual monotonic increase
+    // during normal playback, then let missed cues be the list of cues in other
+    // cues whose start times are greater than or equal to last time and whose
+    // end times are less than or equal to the current playback position.
+    // Otherwise, let missed cues be an empty list.
+    if (lastTime >= 0 && m_lastSeekTime < movieTime) {
+        CueList potentiallySkippedCues =
+            m_cueTree.allOverlaps(m_cueTree.createInterval(lastTime, movieTime));
+
+        for (size_t i = 0; i < potentiallySkippedCues.size(); ++i) {
+            double cueStartTime = potentiallySkippedCues[i].low();
+            double cueEndTime = potentiallySkippedCues[i].high();
+
+            // Consider cues that may have been missed since the last seek time.
+            if (cueStartTime > max(m_lastSeekTime, lastTime) && cueEndTime < movieTime)
+                missedCues.append(potentiallySkippedCues[i]);
+        }
+    }
+
+    m_lastTextTrackUpdateTime = movieTime;
+
+    // 5 - If the time was reached through the usual monotonic increase of the
+    // current playback position during normal playback, and if the user agent
+    // has not fired a timeupdate event at the element in the past 15 to 250ms
+    // and is not still running event handlers for such an event, then the user
+    // agent must queue a task to fire a simple event named timeupdate at the
+    // element. (In the other cases, such as explicit seeks, relevant events get
+    // fired as part of the overall process of changing the current playback
+    // position.)
+    if (m_lastSeekTime <= lastTime)
+        scheduleTimeupdateEvent(false);
+
+    // Explicitly cache vector sizes, as their content is constant from here.
+    size_t currentCuesSize = currentCues.size();
+    size_t missedCuesSize = missedCues.size();
+    size_t previousCuesSize = previousCues.size();
+
+    // 6 - If all of the cues in current cues have their text track cue active
+    // flag set, none of the cues in other cues have their text track cue active
+    // flag set, and missed cues is empty, then abort these steps.
+    bool activeSetChanged = missedCuesSize;
+
+    for (size_t i = 0; !activeSetChanged && i < previousCuesSize; ++i)
+        if (!currentCues.contains(previousCues[i]) && previousCues[i].data()->isActive())
+            activeSetChanged = true;
+
+    for (size_t i = 0; i < currentCuesSize; ++i) {
+        currentCues[i].data()->updateDisplayTree(movieTime);
+
+        if (!currentCues[i].data()->isActive())
+            activeSetChanged = true;
+    }
+
+    if (!activeSetChanged) {
+        // Even though the active set has not changed, it is possible that the
+        // the mode of a track has changed from 'hidden' to 'showing' and the
+        // cues have not yet been rendered.
+        // Note: don't call updateTextTrackDisplay() unless we have controls because it will
+        // create them.
+        if (hasMediaControls())
+            updateTextTrackDisplay();
+        return;
+    }
+
+    // 7 - If the time was reached through the usual monotonic increase of the
+    // current playback position during normal playback, and there are cues in
+    // other cues that have their text track cue pause-on-exi flag set and that
+    // either have their text track cue active flag set or are also in missed
+    // cues, then immediately pause the media element.
+    for (size_t i = 0; !m_paused && i < previousCuesSize; ++i) {
+        if (previousCues[i].data()->pauseOnExit()
+            && previousCues[i].data()->isActive()
+            && !currentCues.contains(previousCues[i]))
+            pause();
+    }
+
+    for (size_t i = 0; !m_paused && i < missedCuesSize; ++i) {
+        if (missedCues[i].data()->pauseOnExit())
+            pause();
+    }
+
+    // 8 - Let events be a list of tasks, initially empty. Each task in this
+    // list will be associated with a text track, a text track cue, and a time,
+    // which are used to sort the list before the tasks are queued.
+    Vector<std::pair<double, TextTrackCue*> > eventTasks;
+
+    // 8 - Let affected tracks be a list of text tracks, initially empty.
+    Vector<TextTrack*> affectedTracks;
+
+    for (size_t i = 0; i < missedCuesSize; ++i) {
+        // 9 - For each text track cue in missed cues, prepare an event named enter
+        // for the TextTrackCue object with the text track cue start time.
+        eventTasks.append(std::make_pair(missedCues[i].data()->startTime(),
+                                         missedCues[i].data()));
+
+        // 10 - For each text track [...] in missed cues, prepare an event
+        // named exit for the TextTrackCue object with the  with the later of
+        // the text track cue end time and the text track cue start time.
+
+        // Note: An explicit task is added only if the cue is NOT a zero or
+        // negative length cue. Otherwise, the need for an exit event is
+        // checked when these tasks are actually queued below. This doesn't
+        // affect sorting events before dispatch either, because the exit
+        // event has the same time as the enter event.
+        if (missedCues[i].data()->startTime() < missedCues[i].data()->endTime())
+            eventTasks.append(std::make_pair(missedCues[i].data()->endTime(),
+                                             missedCues[i].data()));
+    }
+
+    for (size_t i = 0; i < previousCuesSize; ++i) {
+        // 10 - For each text track cue in other cues that has its text
+        // track cue active flag set prepare an event named exit for the
+        // TextTrackCue object with the text track cue end time.
+        if (!currentCues.contains(previousCues[i]))
+            eventTasks.append(std::make_pair(previousCues[i].data()->endTime(),
+                                             previousCues[i].data()));
+    }
+
+    for (size_t i = 0; i < currentCuesSize; ++i) {
+        // 11 - For each text track cue in current cues that does not have its
+        // text track cue active flag set, prepare an event named enter for the
+        // TextTrackCue object with the text track cue start time.
+        if (!previousCues.contains(currentCues[i]))
+            eventTasks.append(std::make_pair(currentCues[i].data()->startTime(),
+                                             currentCues[i].data()));
+    }
+
+    // 12 - Sort the tasks in events in ascending time order (tasks with earlier
+    // times first).
+    nonCopyingSort(eventTasks.begin(), eventTasks.end(), eventTimeCueCompare);
+
+    for (size_t i = 0; i < eventTasks.size(); ++i) {
+        if (!affectedTracks.contains(eventTasks[i].second->track()))
+            affectedTracks.append(eventTasks[i].second->track());
+
+        // 13 - Queue each task in events, in list order.
+        RefPtr<Event> event;
+
+        // Each event in eventTasks may be either an enterEvent or an exitEvent,
+        // depending on the time that is associated with the event. This
+        // correctly identifies the type of the event, if the startTime is
+        // less than the endTime in the cue.
+        if (eventTasks[i].second->startTime() >= eventTasks[i].second->endTime()) {
+            event = Event::create(eventNames().enterEvent, false, false);
+            event->setTarget(eventTasks[i].second);
+            m_asyncEventQueue->enqueueEvent(event.release());
+
+            event = Event::create(eventNames().exitEvent, false, false);
+            event->setTarget(eventTasks[i].second);
+            m_asyncEventQueue->enqueueEvent(event.release());
+        } else {
+            if (eventTasks[i].first == eventTasks[i].second->startTime())
+                event = Event::create(eventNames().enterEvent, false, false);
+            else
+                event = Event::create(eventNames().exitEvent, false, false);
+
+            event->setTarget(eventTasks[i].second);
+            m_asyncEventQueue->enqueueEvent(event.release());
+        }
+    }
+
+    // 14 - Sort affected tracks in the same order as the text tracks appear in
+    // the media element's list of text tracks, and remove duplicates.
+    nonCopyingSort(affectedTracks.begin(), affectedTracks.end(), trackIndexCompare);
+
+    // 15 - For each text track in affected tracks, in the list order, queue a
+    // task to fire a simple event named cuechange at the TextTrack object, and, ...
+    for (size_t i = 0; i < affectedTracks.size(); ++i) {
+        RefPtr<Event> event = Event::create(eventNames().cuechangeEvent, false, false);
+        event->setTarget(affectedTracks[i]);
+
+        m_asyncEventQueue->enqueueEvent(event.release());
+
+        // ... if the text track has a corresponding track element, to then fire a
+        // simple event named cuechange at the track element as well.
+        if (affectedTracks[i]->trackType() == TextTrack::TrackElement) {
+            RefPtr<Event> event = Event::create(eventNames().cuechangeEvent, false, false);
+            HTMLTrackElement* trackElement = static_cast<LoadableTextTrack*>(affectedTracks[i])->trackElement();
+            ASSERT(trackElement);
+            event->setTarget(trackElement);
+
+            m_asyncEventQueue->enqueueEvent(event.release());
+        }
+    }
+
+    // 16 - Set the text track cue active flag of all the cues in the current
+    // cues, and unset the text track cue active flag of all the cues in the
+    // other cues.
+    for (size_t i = 0; i < currentCuesSize; ++i)
+        currentCues[i].data()->setIsActive(true);
+
+    for (size_t i = 0; i < previousCuesSize; ++i)
+        if (!currentCues.contains(previousCues[i]))
+            previousCues[i].data()->setIsActive(false);
+
+    // Update the current active cues.
+    m_currentlyActiveCues = currentCues;
+
+    if (activeSetChanged)
+        updateTextTrackDisplay();
+}
+
+bool HTMLMediaElement::textTracksAreReady() const
+{
+    // 4.8.10.12.1 Text track model
+    // ...
+    // The text tracks of a media element are ready if all the text tracks whose mode was not
+    // in the disabled state when the element's resource selection algorithm last started now
+    // have a text track readiness state of loaded or failed to load.
+    for (unsigned i = 0; i < m_textTracksWhenResourceSelectionBegan.size(); ++i) {
+        if (m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::Loading
+            || m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::NotLoaded)
+            return false;
+    }
+
+    return true;
+}
+
+void HTMLMediaElement::textTrackReadyStateChanged(TextTrack* track)
+{
+    if (m_player && m_textTracksWhenResourceSelectionBegan.contains(track)) {
+        if (track->readinessState() != TextTrack::Loading)
+            setReadyState(m_player->readyState());
+    } else {
+        // The track readiness state might have changed as a result of the user
+        // clicking the captions button. In this case, a check whether all the
+        // resources have failed loading should be done in order to hide the CC button.
+        if (hasMediaControls() && track->readinessState() == TextTrack::FailedToLoad)
+            mediaControls()->refreshClosedCaptionsButtonVisibility();
+    }
+}
+
+void HTMLMediaElement::textTrackModeChanged(TextTrack* track)
+{
+    if (track->trackType() == TextTrack::TrackElement) {
+        // 4.8.10.12.3 Sourcing out-of-band text tracks
+        // ... when a text track corresponding to a track element is created with text track
+        // mode set to disabled and subsequently changes its text track mode to hidden, showing,
+        // or showing by default for the first time, the user agent must immediately and synchronously
+        // run the following algorithm ...
+
+        for (Node* node = firstChild(); node; node = node->nextSibling()) {
+            if (!node->hasTagName(trackTag))
+                continue;
+            HTMLTrackElement* trackElement = static_cast<HTMLTrackElement*>(node);
+            if (trackElement->track() != track)
+                continue;
+
+            // Mark this track as "configured" so configureTextTracks won't change the mode again.
+            track->setHasBeenConfigured(true);
+            if (track->mode() != TextTrack::disabledKeyword()) {
+                if (trackElement->readyState() == HTMLTrackElement::LOADED)
+                    textTrackAddCues(track, track->cues());
+
+                // If this is the first added track, create the list of text tracks.
+                if (!m_textTracks)
+                  m_textTracks = TextTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
+            }
+            break;
+        }
+    } else if (track->trackType() == TextTrack::AddTrack && track->mode() != TextTrack::disabledKeyword())
+        textTrackAddCues(track, track->cues());
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    if (platformTextTrackMenu())
+        platformTextTrackMenu()->trackWasSelected(track->platformTextTrack());
+#endif
+
+    configureTextTrackDisplay();
+    updateActiveTextTrackCues(currentTime());
+}
+
+void HTMLMediaElement::textTrackKindChanged(TextTrack* track)
+{
+    if (track->kind() != TextTrack::captionsKeyword() && track->kind() != TextTrack::subtitlesKeyword() && track->mode() == TextTrack::showingKeyword())
+        track->setMode(TextTrack::hiddenKeyword());
+}
+
+void HTMLMediaElement::beginIgnoringTrackDisplayUpdateRequests()
+{
+    ++m_ignoreTrackDisplayUpdate;
+}
+
+void HTMLMediaElement::endIgnoringTrackDisplayUpdateRequests()
+{
+    ASSERT(m_ignoreTrackDisplayUpdate);
+    --m_ignoreTrackDisplayUpdate;
+    if (!m_ignoreTrackDisplayUpdate && m_inActiveDocument)
+        updateActiveTextTrackCues(currentTime());
+}
+
+void HTMLMediaElement::textTrackAddCues(TextTrack*, const TextTrackCueList* cues)
+{
+    LOG(Media, "HTMLMediaElement::textTrackAddCues");
+
+    TrackDisplayUpdateScope scope(this);
+    for (size_t i = 0; i < cues->length(); ++i)
+        textTrackAddCue(cues->item(i)->track(), cues->item(i));
+}
+
+void HTMLMediaElement::textTrackRemoveCues(TextTrack*, const TextTrackCueList* cues)
+{
+    LOG(Media, "HTMLMediaElement::textTrackRemoveCues");
+
+    TrackDisplayUpdateScope scope(this);
+    for (size_t i = 0; i < cues->length(); ++i)
+        textTrackRemoveCue(cues->item(i)->track(), cues->item(i));
+}
+
+void HTMLMediaElement::textTrackAddCue(TextTrack*, PassRefPtr<TextTrackCue> cue)
+{
+    // Negative duration cues need be treated in the interval tree as
+    // zero-length cues.
+    double endTime = max(cue->startTime(), cue->endTime());
+
+    CueInterval interval = m_cueTree.createInterval(cue->startTime(), endTime, cue.get());
+    if (!m_cueTree.contains(interval))
+        m_cueTree.add(interval);
+    updateActiveTextTrackCues(currentTime());
+}
+
+void HTMLMediaElement::textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue> cue)
+{
+    // Negative duration cues need to be treated in the interval tree as
+    // zero-length cues.
+    double endTime = max(cue->startTime(), cue->endTime());
+
+    CueInterval interval = m_cueTree.createInterval(cue->startTime(), endTime, cue.get());
+    m_cueTree.remove(interval);
+
+    size_t index = m_currentlyActiveCues.find(interval);
+    if (index != notFound) {
+        m_currentlyActiveCues.remove(index);
+        cue->setIsActive(false);
+    }
+
+    cue->removeDisplayTree();
+    updateActiveTextTrackCues(currentTime());
+}
+
+
+bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidURLAction actionIfInvalid)
+{
+    if (!url.isValid()) {
+        LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE because url is invalid", urlForLoggingMedia(url).utf8().data());
+        return false;
+    }
+
+    Frame* frame = document()->frame();
+    if (!frame || !document()->securityOrigin()->canDisplay(url)) {
+        if (actionIfInvalid == Complain)
+            FrameLoader::reportLocalLoadFailed(frame, url.elidedString());
+        LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE rejected by SecurityOrigin", urlForLoggingMedia(url).utf8().data());
+        return false;
+    }
+
+    if (!document()->contentSecurityPolicy()->allowMediaFromSource(url)) {
+        LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> rejected by Content Security Policy", urlForLoggingMedia(url).utf8().data());
+        return false;
+    }
+
+    return true;
+}
+
+void HTMLMediaElement::startProgressEventTimer()
+{
+    if (m_progressEventTimer.isActive())
+        return;
+
+    m_previousProgressTime = WTF::currentTime();
+    // 350ms is not magic, it is in the spec!
+    m_progressEventTimer.startRepeating(0.350);
+}
+
+void HTMLMediaElement::waitForSourceChange()
+{
+    LOG(Media, "HTMLMediaElement::waitForSourceChange");
+
+    stopPeriodicTimers();
+    m_loadState = WaitingForSource;
+
+    // 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
+    m_networkState = NETWORK_NO_SOURCE;
+
+    // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
+    setShouldDelayLoadEvent(false);
+
+    updateDisplayState();
+
+    if (renderer())
+        renderer()->updateFromElement();
+}
+
+void HTMLMediaElement::noneSupported()
+{
+    LOG(Media, "HTMLMediaElement::noneSupported");
+
+    stopPeriodicTimers();
+    m_loadState = WaitingForSource;
+    m_currentSourceNode = 0;
+
+    // 4.8.10.5
+    // 6 - Reaching this step indicates that the media resource failed to load or that the given
+    // URL could not be resolved. In one atomic operation, run the following steps:
+
+    // 6.1 - Set the error attribute to a new MediaError object whose code attribute is set to
+    // MEDIA_ERR_SRC_NOT_SUPPORTED.
+    m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
+
+    // 6.2 - Forget the media element's media-resource-specific text tracks.
+
+    // 6.3 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
+    m_networkState = NETWORK_NO_SOURCE;
+
+    // 7 - Queue a task to fire a simple event named error at the media element.
+    scheduleEvent(eventNames().errorEvent);
+
+    setSourceState(MediaSource::closedKeyword());
+
+    // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
+    setShouldDelayLoadEvent(false);
+
+    // 9 - Abort these steps. Until the load() method is invoked or the src attribute is changed,
+    // the element won't attempt to load another resource.
+
+    updateDisplayState();
+
+    if (renderer())
+        renderer()->updateFromElement();
+}
+
+void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
+{
+    LOG(Media, "HTMLMediaElement::mediaEngineError(%d)", static_cast<int>(err->code()));
+
+    // 1 - The user agent should cancel the fetching process.
+    stopPeriodicTimers();
+    m_loadState = WaitingForSource;
+
+    // 2 - Set the error attribute to a new MediaError object whose code attribute is
+    // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
+    m_error = err;
+
+    // 3 - Queue a task to fire a simple event named error at the media element.
+    scheduleEvent(eventNames().errorEvent);
+
+    setSourceState(MediaSource::closedKeyword());
+
+    // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
+    // task to fire a simple event called emptied at the element.
+    m_networkState = NETWORK_EMPTY;
+    scheduleEvent(eventNames().emptiedEvent);
+
+    // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
+    setShouldDelayLoadEvent(false);
+
+    // 6 - Abort the overall resource selection algorithm.
+    m_currentSourceNode = 0;
+}
+
+void HTMLMediaElement::cancelPendingEventsAndCallbacks()
+{
+    LOG(Media, "HTMLMediaElement::cancelPendingEventsAndCallbacks");
+    m_asyncEventQueue->cancelAllEvents();
+
+    for (Node* node = firstChild(); node; node = node->nextSibling()) {
+        if (node->hasTagName(sourceTag))
+            static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
+    }
+}
+
+Document* HTMLMediaElement::mediaPlayerOwningDocument()
+{
+    Document* d = document();
+
+    if (!d)
+        d = ownerDocument();
+
+    return d;
+}
+
+void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
+{
+    beginProcessingMediaPlayerCallback();
+    setNetworkState(m_player->networkState());
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaLoadingFailed(MediaPlayer::NetworkState error)
+{
+    stopPeriodicTimers();
+
+    // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
+    // <source> children, schedule the next one
+    if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
+
+        if (m_currentSourceNode)
+            m_currentSourceNode->scheduleErrorEvent();
+        else
+            LOG(Media, "HTMLMediaElement::setNetworkState - error event not sent, <source> was removed");
+
+        if (havePotentialSourceChild()) {
+            LOG(Media, "HTMLMediaElement::setNetworkState - scheduling next <source>");
+            scheduleNextSourceChild();
+        } else {
+            LOG(Media, "HTMLMediaElement::setNetworkState - no more <source> elements, waiting");
+            waitForSourceChange();
+        }
+
+        return;
+    }
+
+    if (error == MediaPlayer::NetworkError && m_readyState >= HAVE_METADATA)
+        mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
+    else if (error == MediaPlayer::DecodeError)
+        mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
+    else if ((error == MediaPlayer::FormatError || error == MediaPlayer::NetworkError) && m_loadState == LoadingFromSrcAttr)
+        noneSupported();
+
+    updateDisplayState();
+    if (hasMediaControls()) {
+        mediaControls()->reset();
+        mediaControls()->reportedError();
+    }
+}
+
+void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
+{
+    LOG(Media, "HTMLMediaElement::setNetworkState(%d) - current state is %d", static_cast<int>(state), static_cast<int>(m_networkState));
+
+    if (state == MediaPlayer::Empty) {
+        // Just update the cached state and leave, we can't do anything.
+        m_networkState = NETWORK_EMPTY;
+        return;
+    }
+
+    if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
+        mediaLoadingFailed(state);
+        return;
+    }
+
+    if (state == MediaPlayer::Idle) {
+        if (m_networkState > NETWORK_IDLE) {
+            changeNetworkStateFromLoadingToIdle();
+            setShouldDelayLoadEvent(false);
+        } else {
+            m_networkState = NETWORK_IDLE;
+        }
+    }
+
+    if (state == MediaPlayer::Loading) {
+        if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
+            startProgressEventTimer();
+        m_networkState = NETWORK_LOADING;
+    }
+
+    if (state == MediaPlayer::Loaded) {
+        if (m_networkState != NETWORK_IDLE)
+            changeNetworkStateFromLoadingToIdle();
+        m_completelyLoaded = true;
+    }
+
+    if (hasMediaControls())
+        mediaControls()->updateStatusDisplay();
+}
+
+void HTMLMediaElement::changeNetworkStateFromLoadingToIdle()
+{
+    m_progressEventTimer.stop();
+    if (hasMediaControls() && m_player->didLoadingProgress())
+        mediaControls()->bufferingProgressed();
+
+    // Schedule one last progress event so we guarantee that at least one is fired
+    // for files that load very quickly.
+    scheduleEvent(eventNames().progressEvent);
+    scheduleEvent(eventNames().suspendEvent);
+    m_networkState = NETWORK_IDLE;
+}
+
+void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
+{
+    beginProcessingMediaPlayerCallback();
+
+    setReadyState(m_player->readyState());
+
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
+{
+    LOG(Media, "HTMLMediaElement::setReadyState(%d) - current state is %d,", static_cast<int>(state), static_cast<int>(m_readyState));
+
+    // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
+    bool wasPotentiallyPlaying = potentiallyPlaying();
+
+    ReadyState oldState = m_readyState;
+    ReadyState newState = static_cast<ReadyState>(state);
+
+    bool tracksAreReady = !RuntimeEnabledFeatures::webkitVideoTrackEnabled() || textTracksAreReady();
+
+    if (newState == oldState && m_tracksAreReady == tracksAreReady)
+        return;
+
+    m_tracksAreReady = tracksAreReady;
+
+    if (tracksAreReady)
+        m_readyState = newState;
+    else {
+        // If a media file has text tracks the readyState may not progress beyond HAVE_FUTURE_DATA until
+        // the text tracks are ready, regardless of the state of the media file.
+        if (newState <= HAVE_METADATA)
+            m_readyState = newState;
+        else
+            m_readyState = HAVE_CURRENT_DATA;
+    }
+
+    if (oldState > m_readyStateMaximum)
+        m_readyStateMaximum = oldState;
+
+    if (m_networkState == NETWORK_EMPTY)
+        return;
+
+    if (m_seeking) {
+        // 4.8.10.9, step 11
+        if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
+            scheduleEvent(eventNames().waitingEvent);
+
+        // 4.8.10.10 step 14 & 15.
+        if (m_readyState >= HAVE_CURRENT_DATA)
+            finishSeek();
+    } else {
+        if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
+            // 4.8.10.8
+            scheduleTimeupdateEvent(false);
+            scheduleEvent(eventNames().waitingEvent);
+        }
+    }
+
+    if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
+        prepareMediaFragmentURI();
+        scheduleEvent(eventNames().durationchangeEvent);
+        scheduleEvent(eventNames().loadedmetadataEvent);
+        if (hasMediaControls())
+            mediaControls()->loadedMetadata();
+        if (renderer())
+            renderer()->updateFromElement();
+    }
+
+    bool shouldUpdateDisplayState = false;
+
+    if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
+        m_haveFiredLoadedData = true;
+        shouldUpdateDisplayState = true;
+        scheduleEvent(eventNames().loadeddataEvent);
+        setShouldDelayLoadEvent(false);
+        applyMediaFragmentURI();
+    }
+
+    bool isPotentiallyPlaying = potentiallyPlaying();
+    if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady) {
+        scheduleEvent(eventNames().canplayEvent);
+        if (isPotentiallyPlaying)
+            scheduleEvent(eventNames().playingEvent);
+        shouldUpdateDisplayState = true;
+    }
+
+    if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && tracksAreReady) {
+        if (oldState <= HAVE_CURRENT_DATA)
+            scheduleEvent(eventNames().canplayEvent);
+
+        scheduleEvent(eventNames().canplaythroughEvent);
+
+        if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
+            scheduleEvent(eventNames().playingEvent);
+
+        if (m_autoplaying && m_paused && autoplay() && !document()->isSandboxed(SandboxAutomaticFeatures) && !userGestureRequiredForRateChange()) {
+            m_paused = false;
+            invalidateCachedTime();
+            scheduleEvent(eventNames().playEvent);
+            scheduleEvent(eventNames().playingEvent);
+        }
+
+        shouldUpdateDisplayState = true;
+    }
+
+    if (shouldUpdateDisplayState) {
+        updateDisplayState();
+        if (hasMediaControls()) {
+            mediaControls()->refreshClosedCaptionsButtonVisibility();
+            mediaControls()->updateStatusDisplay();
+        }
+    }
+
+    updatePlayState();
+    updateMediaController();
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        updateActiveTextTrackCues(currentTime());
+}
+
+#if ENABLE(ENCRYPTED_MEDIA)
+void HTMLMediaElement::mediaPlayerKeyAdded(MediaPlayer*, const String& keySystem, const String& sessionId)
+{
+    MediaKeyEventInit initializer;
+    initializer.keySystem = keySystem;
+    initializer.sessionId = sessionId;
+    initializer.bubbles = false;
+    initializer.cancelable = false;
+
+    RefPtr<Event> event = MediaKeyEvent::create(eventNames().webkitkeyaddedEvent, initializer);
+    event->setTarget(this);
+    m_asyncEventQueue->enqueueEvent(event.release());
+}
+
+void HTMLMediaElement::mediaPlayerKeyError(MediaPlayer*, const String& keySystem, const String& sessionId, MediaPlayerClient::MediaKeyErrorCode errorCode, unsigned short systemCode)
+{
+    MediaKeyError::Code mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN;
+    switch (errorCode) {
+    case MediaPlayerClient::UnknownError:
+        mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN;
+        break;
+    case MediaPlayerClient::ClientError:
+        mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_CLIENT;
+        break;
+    case MediaPlayerClient::ServiceError:
+        mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_SERVICE;
+        break;
+    case MediaPlayerClient::OutputError:
+        mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_OUTPUT;
+        break;
+    case MediaPlayerClient::HardwareChangeError:
+        mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_HARDWARECHANGE;
+        break;
+    case MediaPlayerClient::DomainError:
+        mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_DOMAIN;
+        break;
+    }
+
+    MediaKeyEventInit initializer;
+    initializer.keySystem = keySystem;
+    initializer.sessionId = sessionId;
+    initializer.errorCode = MediaKeyError::create(mediaKeyErrorCode);
+    initializer.systemCode = systemCode;
+    initializer.bubbles = false;
+    initializer.cancelable = false;
+
+    RefPtr<Event> event = MediaKeyEvent::create(eventNames().webkitkeyerrorEvent, initializer);
+    event->setTarget(this);
+    m_asyncEventQueue->enqueueEvent(event.release());
+}
+
+void HTMLMediaElement::mediaPlayerKeyMessage(MediaPlayer*, const String& keySystem, const String& sessionId, const unsigned char* message, unsigned messageLength, const KURL& defaultURL)
+{
+    MediaKeyEventInit initializer;
+    initializer.keySystem = keySystem;
+    initializer.sessionId = sessionId;
+    initializer.message = Uint8Array::create(message, messageLength);
+    initializer.defaultURL = defaultURL;
+    initializer.bubbles = false;
+    initializer.cancelable = false;
+
+    RefPtr<Event> event = MediaKeyEvent::create(eventNames().webkitkeymessageEvent, initializer);
+    event->setTarget(this);
+    m_asyncEventQueue->enqueueEvent(event.release());
+}
+
+bool HTMLMediaElement::mediaPlayerKeyNeeded(MediaPlayer*, const String& keySystem, const String& sessionId, const unsigned char* initData, unsigned initDataLength)
+{
+    if (!hasEventListeners(eventNames().webkitneedkeyEvent)) {
+        m_error = MediaError::create(MediaError::MEDIA_ERR_ENCRYPTED);
+        scheduleEvent(eventNames().errorEvent);
+        return false;
+    }
+
+    MediaKeyEventInit initializer;
+    initializer.keySystem = keySystem;
+    initializer.sessionId = sessionId;
+    initializer.initData = Uint8Array::create(initData, initDataLength);
+    initializer.bubbles = false;
+    initializer.cancelable = false;
+
+    RefPtr<Event> event = MediaKeyEvent::create(eventNames().webkitneedkeyEvent, initializer);
+    event->setTarget(this);
+    m_asyncEventQueue->enqueueEvent(event.release());
+    return true;
+}
+#endif
+
+#if ENABLE(ENCRYPTED_MEDIA_V2)
+bool HTMLMediaElement::mediaPlayerKeyNeeded(MediaPlayer*, Uint8Array* initData)
+{
+    if (!hasEventListeners("webkitneedkey")) {
+        m_error = MediaError::create(MediaError::MEDIA_ERR_ENCRYPTED);
+        scheduleEvent(eventNames().errorEvent);
+        return false;
+    }
+
+    MediaKeyNeededEventInit initializer;
+    initializer.initData = initData;
+    initializer.bubbles = false;
+    initializer.cancelable = false;
+
+    RefPtr<Event> event = MediaKeyNeededEvent::create(eventNames().webkitneedkeyEvent, initializer);
+    event->setTarget(this);
+    m_asyncEventQueue->enqueueEvent(event.release());
+
+    return true;
+}
+
+void HTMLMediaElement::setMediaKeys(MediaKeys* mediaKeys)
+{
+    if (m_mediaKeys == mediaKeys)
+        return;
+
+    if (m_mediaKeys)
+        m_mediaKeys->setMediaElement(0);
+    m_mediaKeys = mediaKeys;
+    if (m_mediaKeys)
+        m_mediaKeys->setMediaElement(this);
+}
+#endif
+
+void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
+{
+    ASSERT(m_player);
+    if (m_networkState != NETWORK_LOADING)
+        return;
+
+    double time = WTF::currentTime();
+    double timedelta = time - m_previousProgressTime;
+
+    if (m_player->didLoadingProgress()) {
+        scheduleEvent(eventNames().progressEvent);
+        m_previousProgressTime = time;
+        m_sentStalledEvent = false;
+        if (renderer())
+            renderer()->updateFromElement();
+        if (hasMediaControls())
+            mediaControls()->bufferingProgressed();
+    } else if (timedelta > 3.0 && !m_sentStalledEvent) {
+        scheduleEvent(eventNames().stalledEvent);
+        m_sentStalledEvent = true;
+        setShouldDelayLoadEvent(false);
+    }
+}
+
+void HTMLMediaElement::rewind(double timeDelta)
+{
+    LOG(Media, "HTMLMediaElement::rewind(%f)", timeDelta);
+    setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), IGNORE_EXCEPTION);
+}
+
+void HTMLMediaElement::returnToRealtime()
+{
+    LOG(Media, "HTMLMediaElement::returnToRealtime");
+    setCurrentTime(maxTimeSeekable(), IGNORE_EXCEPTION);
+}
+
+void HTMLMediaElement::addPlayedRange(double start, double end)
+{
+    LOG(Media, "HTMLMediaElement::addPlayedRange(%f, %f)", start, end);
+    if (!m_playedTimeRanges)
+        m_playedTimeRanges = TimeRanges::create();
+    m_playedTimeRanges->add(start, end);
+}
+
+bool HTMLMediaElement::supportsSave() const
+{
+    return m_player ? m_player->supportsSave() : false;
+}
+
+bool HTMLMediaElement::supportsScanning() const
+{
+    return m_player ? m_player->supportsScanning() : false;
+}
+
+void HTMLMediaElement::prepareToPlay()
+{
+    LOG(Media, "HTMLMediaElement::prepareToPlay(%p)", this);
+    if (m_havePreparedToPlay)
+        return;
+    m_havePreparedToPlay = true;
+    m_player->prepareToPlay();
+}
+
+void HTMLMediaElement::seek(double time, ExceptionCode& ec)
+{
+    LOG(Media, "HTMLMediaElement::seek(%f)", time);
+
+    // 4.8.9.9 Seeking
+
+    // 1 - If the media element's readyState is HAVE_NOTHING, then raise an INVALID_STATE_ERR exception.
+    if (m_readyState == HAVE_NOTHING || !m_player) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    // If the media engine has been told to postpone loading data, let it go ahead now.
+    if (m_preload < MediaPlayer::Auto && m_readyState < HAVE_FUTURE_DATA)
+        prepareToPlay();
+
+    // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
+    refreshCachedTime();
+    double now = currentTime();
+
+    // 2 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
+    // already running. Abort that other instance of the algorithm without waiting for the step that
+    // it is running to complete.
+    // Nothing specific to be done here.
+
+    // 3 - Set the seeking IDL attribute to true.
+    // The flag will be cleared when the engine tells us the time has actually changed.
+    m_seeking = true;
+
+    // 5 - If the new playback position is later than the end of the media resource, then let it be the end
+    // of the media resource instead.
+    time = min(time, duration());
+
+    // 6 - If the new playback position is less than the earliest possible position, let it be that position instead.
+    double earliestTime = m_player->startTime();
+    time = max(time, earliestTime);
+
+    // Ask the media engine for the time value in the movie's time scale before comparing with current time. This
+    // is necessary because if the seek time is not equal to currentTime but the delta is less than the movie's
+    // time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and
+    // not generate a timechanged callback. This means m_seeking will never be cleared and we will never
+    // fire a 'seeked' event.
+#if !LOG_DISABLED
+    double mediaTime = m_player->mediaTimeForTimeValue(time);
+    if (time != mediaTime)
+        LOG(Media, "HTMLMediaElement::seek(%f) - media timeline equivalent is %f", time, mediaTime);
+#endif
+    time = m_player->mediaTimeForTimeValue(time);
+
+    // 7 - If the (possibly now changed) new playback position is not in one of the ranges given in the
+    // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute
+    // that is the nearest to the new playback position. ... If there are no ranges given in the seekable
+    // attribute then set the seeking IDL attribute to false and abort these steps.
+    RefPtr<TimeRanges> seekableRanges = seekable();
+
+    // Short circuit seeking to the current time by just firing the events if no seek is required.
+    // Don't skip calling the media engine if we are in poster mode because a seek should always
+    // cancel poster display.
+    bool noSeekRequired = !seekableRanges->length() || (time == now && displayMode() != Poster);
+
+    // Always notify the media engine of a seek if the source is not closed. This ensures that the source is
+    // always in a flushed state when the 'seeking' event fires.
+    if (m_mediaSource && m_mediaSource->readyState() != MediaSource::closedKeyword())
+        noSeekRequired = false;
+
+    if (noSeekRequired) {
+        if (time == now) {
+            scheduleEvent(eventNames().seekingEvent);
+            scheduleTimeupdateEvent(false);
+            scheduleEvent(eventNames().seekedEvent);
+        }
+        m_seeking = false;
+        return;
+    }
+    time = seekableRanges->nearest(time);
+
+    if (m_playing) {
+        if (m_lastSeekTime < now)
+            addPlayedRange(m_lastSeekTime, now);
+    }
+    m_lastSeekTime = time;
+    m_sentEndEvent = false;
+
+    // 8 - Set the current playback position to the given new playback position
+    m_player->seek(time);
+
+    // 9 - Queue a task to fire a simple event named seeking at the element.
+    scheduleEvent(eventNames().seekingEvent);
+
+    // 10 - Queue a task to fire a simple event named timeupdate at the element.
+    scheduleTimeupdateEvent(false);
+
+    // 11-15 are handled, if necessary, when the engine signals a readystate change.
+}
+
+void HTMLMediaElement::finishSeek()
+{
+    LOG(Media, "HTMLMediaElement::finishSeek");
+
+    // 4.8.10.9 Seeking step 14
+    m_seeking = false;
+
+    // 4.8.10.9 Seeking step 15
+    scheduleEvent(eventNames().seekedEvent);
+
+    setDisplayMode(Video);
+}
+
+HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
+{
+    return m_readyState;
+}
+
+MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
+{
+    return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
+}
+
+bool HTMLMediaElement::hasAudio() const
+{
+    return m_player ? m_player->hasAudio() : false;
+}
+
+bool HTMLMediaElement::seeking() const
+{
+    return m_seeking;
+}
+
+void HTMLMediaElement::refreshCachedTime() const
+{
+    m_cachedTime = m_player->currentTime();
+    m_cachedTimeWallClockUpdateTime = WTF::currentTime();
+}
+
+void HTMLMediaElement::invalidateCachedTime()
+{
+    LOG(Media, "HTMLMediaElement::invalidateCachedTime");
+
+    // Don't try to cache movie time when playback first starts as the time reported by the engine
+    // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it
+    // too early.
+    static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
+
+    m_minimumWallClockTimeToCacheMediaTime = WTF::currentTime() + minimumTimePlayingBeforeCacheSnapshot;
+    m_cachedTime = MediaPlayer::invalidTime();
+}
+
+// playback state
+double HTMLMediaElement::currentTime() const
+{
+#if LOG_CACHED_TIME_WARNINGS
+    static const double minCachedDeltaForWarning = 0.01;
+#endif
+
+    if (!m_player)
+        return 0;
+
+    if (m_seeking) {
+        LOG(Media, "HTMLMediaElement::currentTime - seeking, returning %f", m_lastSeekTime);
+        return m_lastSeekTime;
+    }
+
+    if (m_cachedTime != MediaPlayer::invalidTime() && m_paused) {
+#if LOG_CACHED_TIME_WARNINGS
+        double delta = m_cachedTime - m_player->currentTime();
+        if (delta > minCachedDeltaForWarning)
+            LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when paused", delta);
+#endif
+        return m_cachedTime;
+    }
+
+    // Is it too soon use a cached time?
+    double now = WTF::currentTime();
+    double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
+
+    if (maximumDurationToCacheMediaTime && m_cachedTime != MediaPlayer::invalidTime() && !m_paused && now > m_minimumWallClockTimeToCacheMediaTime) {
+        double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
+
+        // Not too soon, use the cached time only if it hasn't expired.
+        if (wallClockDelta < maximumDurationToCacheMediaTime) {
+            double adjustedCacheTime = m_cachedTime + (m_playbackRate * wallClockDelta);
+
+#if LOG_CACHED_TIME_WARNINGS
+            double delta = adjustedCacheTime - m_player->currentTime();
+            if (delta > minCachedDeltaForWarning)
+                LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when playing", delta);
+#endif
+            return adjustedCacheTime;
+        }
+    }
+
+#if LOG_CACHED_TIME_WARNINGS
+    if (maximumDurationToCacheMediaTime && now > m_minimumWallClockTimeToCacheMediaTime && m_cachedTime != MediaPlayer::invalidTime()) {
+        double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
+        double delta = m_cachedTime + (m_playbackRate * wallClockDelta) - m_player->currentTime();
+        LOG(Media, "HTMLMediaElement::currentTime - cached time was %f seconds off of media time when it expired", delta);
+    }
+#endif
+
+    refreshCachedTime();
+
+    return m_cachedTime;
+}
+
+void HTMLMediaElement::setCurrentTime(double time, ExceptionCode& ec)
+{
+    if (m_mediaController) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    seek(time, ec);
+}
+
+double HTMLMediaElement::startTime() const
+{
+    if (!m_player)
+        return 0;
+    return m_player->startTime();
+}
+
+double HTMLMediaElement::initialTime() const
+{
+    if (m_fragmentStartTime != MediaPlayer::invalidTime())
+        return m_fragmentStartTime;
+
+    if (!m_player)
+        return 0;
+
+    return m_player->initialTime();
+}
+
+double HTMLMediaElement::duration() const
+{
+    if (m_player && m_readyState >= HAVE_METADATA)
+        return m_player->duration();
+
+    return numeric_limits<double>::quiet_NaN();
+}
+
+bool HTMLMediaElement::paused() const
+{
+    return m_paused;
+}
+
+double HTMLMediaElement::defaultPlaybackRate() const
+{
+    return m_defaultPlaybackRate;
+}
+
+void HTMLMediaElement::setDefaultPlaybackRate(double rate)
+{
+    if (m_defaultPlaybackRate != rate) {
+        m_defaultPlaybackRate = rate;
+        scheduleEvent(eventNames().ratechangeEvent);
+    }
+}
+
+double HTMLMediaElement::playbackRate() const
+{
+    return m_playbackRate;
+}
+
+void HTMLMediaElement::setPlaybackRate(double rate)
+{
+    LOG(Media, "HTMLMediaElement::setPlaybackRate(%f)", rate);
+
+    if (m_playbackRate != rate) {
+        m_playbackRate = rate;
+        invalidateCachedTime();
+        scheduleEvent(eventNames().ratechangeEvent);
+    }
+
+    if (m_player && potentiallyPlaying() && m_player->rate() != rate && !m_mediaController)
+        m_player->setRate(rate);
+}
+
+void HTMLMediaElement::updatePlaybackRate()
+{
+    double effectiveRate = m_mediaController ? m_mediaController->playbackRate() : m_playbackRate;
+    if (m_player && potentiallyPlaying() && m_player->rate() != effectiveRate)
+        m_player->setRate(effectiveRate);
+}
+
+bool HTMLMediaElement::webkitPreservesPitch() const
+{
+    return m_webkitPreservesPitch;
+}
+
+void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
+{
+    LOG(Media, "HTMLMediaElement::setWebkitPreservesPitch(%s)", boolString(preservesPitch));
+
+    m_webkitPreservesPitch = preservesPitch;
+
+    if (!m_player)
+        return;
+
+    m_player->setPreservesPitch(preservesPitch);
+}
+
+bool HTMLMediaElement::ended() const
+{
+    // 4.8.10.8 Playing the media resource
+    // The ended attribute must return true if the media element has ended
+    // playback and the direction of playback is forwards, and false otherwise.
+    return endedPlayback() && m_playbackRate > 0;
+}
+
+bool HTMLMediaElement::autoplay() const
+{
+    return fastHasAttribute(autoplayAttr);
+}
+
+void HTMLMediaElement::setAutoplay(bool b)
+{
+    LOG(Media, "HTMLMediaElement::setAutoplay(%s)", boolString(b));
+    setBooleanAttribute(autoplayAttr, b);
+}
+
+String HTMLMediaElement::preload() const
+{
+    switch (m_preload) {
+    case MediaPlayer::None:
+        return ASCIILiteral("none");
+        break;
+    case MediaPlayer::MetaData:
+        return ASCIILiteral("metadata");
+        break;
+    case MediaPlayer::Auto:
+        return ASCIILiteral("auto");
+        break;
+    }
+
+    ASSERT_NOT_REACHED();
+    return String();
+}
+
+void HTMLMediaElement::setPreload(const String& preload)
+{
+    LOG(Media, "HTMLMediaElement::setPreload(%s)", preload.utf8().data());
+    setAttribute(preloadAttr, preload);
+}
+
+void HTMLMediaElement::play()
+{
+    LOG(Media, "HTMLMediaElement::play()");
+
+    if (userGestureRequiredForRateChange() && !ScriptController::processingUserGesture())
+        return;
+    if (ScriptController::processingUserGesture())
+        removeBehaviorsRestrictionsAfterFirstUserGesture();
+
+    Settings* settings = document()->settings();
+    if (settings && settings->needsSiteSpecificQuirks() && m_dispatchingCanPlayEvent && !m_loadInitiatedByUserGesture) {
+        // It should be impossible to be processing the canplay event while handling a user gesture
+        // since it is dispatched asynchronously.
+        ASSERT(!ScriptController::processingUserGesture());
+        String host = document()->baseURL().host();
+        if (host.endsWith(".npr.org", false) || equalIgnoringCase(host, "npr.org"))
+            return;
+    }
+
+    playInternal();
+}
+
+void HTMLMediaElement::playInternal()
+{
+    LOG(Media, "HTMLMediaElement::playInternal");
+
+    // 4.8.10.9. Playing the media resource
+    if (!m_player || m_networkState == NETWORK_EMPTY)
+        scheduleDelayedAction(LoadMediaResource);
+
+    if (endedPlayback())
+        seek(0, IGNORE_EXCEPTION);
+
+    if (m_mediaController)
+        m_mediaController->bringElementUpToSpeed(this);
+
+    if (m_paused) {
+        m_paused = false;
+        invalidateCachedTime();
+        scheduleEvent(eventNames().playEvent);
+
+        if (m_readyState <= HAVE_CURRENT_DATA)
+            scheduleEvent(eventNames().waitingEvent);
+        else if (m_readyState >= HAVE_FUTURE_DATA)
+            scheduleEvent(eventNames().playingEvent);
+    }
+    m_autoplaying = false;
+
+    updatePlayState();
+    updateMediaController();
+}
+
+void HTMLMediaElement::pause()
+{
+    LOG(Media, "HTMLMediaElement::pause()");
+
+    if (userGestureRequiredForRateChange() && !ScriptController::processingUserGesture())
+        return;
+
+    pauseInternal();
+}
+
+
+void HTMLMediaElement::pauseInternal()
+{
+    LOG(Media, "HTMLMediaElement::pauseInternal");
+
+    // 4.8.10.9. Playing the media resource
+    if (!m_player || m_networkState == NETWORK_EMPTY)
+        scheduleDelayedAction(LoadMediaResource);
+
+    m_autoplaying = false;
+
+    if (!m_paused) {
+        m_paused = true;
+        scheduleTimeupdateEvent(false);
+        scheduleEvent(eventNames().pauseEvent);
+    }
+
+    updatePlayState();
+}
+
+void HTMLMediaElement::setSourceState(const String& state)
+{
+    if (!m_mediaSource)
+         return;
+
+    m_mediaSource->setReadyState(state);
+    if (state == MediaSource::closedKeyword())
+        m_mediaSource = 0;
+}
+
+#if ENABLE(ENCRYPTED_MEDIA)
+void HTMLMediaElement::webkitGenerateKeyRequest(const String& keySystem, PassRefPtr<Uint8Array> initData, ExceptionCode& ec)
+{
+    if (keySystem.isEmpty()) {
+        ec = SYNTAX_ERR;
+        return;
+    }
+
+    if (!m_player) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    const unsigned char* initDataPointer = 0;
+    unsigned initDataLength = 0;
+    if (initData) {
+        initDataPointer = initData->data();
+        initDataLength = initData->length();
+    }
+
+    MediaPlayer::MediaKeyException result = m_player->generateKeyRequest(keySystem, initDataPointer, initDataLength);
+    ec = exceptionCodeForMediaKeyException(result);
+}
+
+void HTMLMediaElement::webkitGenerateKeyRequest(const String& keySystem, ExceptionCode& ec)
+{
+    webkitGenerateKeyRequest(keySystem, Uint8Array::create(0), ec);
+}
+
+void HTMLMediaElement::webkitAddKey(const String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> initData, const String& sessionId, ExceptionCode& ec)
+{
+    if (keySystem.isEmpty()) {
+        ec = SYNTAX_ERR;
+        return;
+    }
+
+    if (!key) {
+        ec = SYNTAX_ERR;
+        return;
+    }
+
+    if (!key->length()) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+
+    if (!m_player) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    const unsigned char* initDataPointer = 0;
+    unsigned initDataLength = 0;
+    if (initData) {
+        initDataPointer = initData->data();
+        initDataLength = initData->length();
+    }
+
+    MediaPlayer::MediaKeyException result = m_player->addKey(keySystem, key->data(), key->length(), initDataPointer, initDataLength, sessionId);
+    ec = exceptionCodeForMediaKeyException(result);
+}
+
+void HTMLMediaElement::webkitAddKey(const String& keySystem, PassRefPtr<Uint8Array> key, ExceptionCode& ec)
+{
+    webkitAddKey(keySystem, key, Uint8Array::create(0), String(), ec);
+}
+
+void HTMLMediaElement::webkitCancelKeyRequest(const String& keySystem, const String& sessionId, ExceptionCode& ec)
+{
+    if (keySystem.isEmpty()) {
+        ec = SYNTAX_ERR;
+        return;
+    }
+
+    if (!m_player) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    MediaPlayer::MediaKeyException result = m_player->cancelKeyRequest(keySystem, sessionId);
+    ec = exceptionCodeForMediaKeyException(result);
+}
+
+#endif
+
+bool HTMLMediaElement::loop() const
+{
+    return fastHasAttribute(loopAttr);
+}
+
+void HTMLMediaElement::setLoop(bool b)
+{
+    LOG(Media, "HTMLMediaElement::setLoop(%s)", boolString(b));
+    setBooleanAttribute(loopAttr, b);
+}
+
+bool HTMLMediaElement::controls() const
+{
+    Frame* frame = document()->frame();
+
+    // always show controls when scripting is disabled
+    if (frame && !frame->script()->canExecuteScripts(NotAboutToExecuteScript))
+        return true;
+
+    // Always show controls when in full screen mode.
+    if (isFullscreen())
+        return true;
+
+    return fastHasAttribute(controlsAttr);
+}
+
+void HTMLMediaElement::setControls(bool b)
+{
+    LOG(Media, "HTMLMediaElement::setControls(%s)", boolString(b));
+    setBooleanAttribute(controlsAttr, b);
+}
+
+double HTMLMediaElement::volume() const
+{
+    return m_volume;
+}
+
+void HTMLMediaElement::setVolume(double vol, ExceptionCode& ec)
+{
+    LOG(Media, "HTMLMediaElement::setVolume(%f)", vol);
+
+    if (vol < 0.0f || vol > 1.0f) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    if (m_volume != vol) {
+        m_volume = vol;
+        updateVolume();
+        scheduleEvent(eventNames().volumechangeEvent);
+    }
+}
+
+bool HTMLMediaElement::muted() const
+{
+    return m_muted;
+}
+
+void HTMLMediaElement::setMuted(bool muted)
+{
+    LOG(Media, "HTMLMediaElement::setMuted(%s)", boolString(muted));
+
+    if (m_muted != muted) {
+        m_muted = muted;
+        // Avoid recursion when the player reports volume changes.
+        if (!processingMediaPlayerCallback()) {
+            if (m_player) {
+                m_player->setMuted(m_muted);
+                if (hasMediaControls())
+                    mediaControls()->changedMute();
+            }
+        }
+        scheduleEvent(eventNames().volumechangeEvent);
+    }
+}
+
+void HTMLMediaElement::togglePlayState()
+{
+    LOG(Media, "HTMLMediaElement::togglePlayState - canPlay() is %s", boolString(canPlay()));
+
+    // We can safely call the internal play/pause methods, which don't check restrictions, because
+    // this method is only called from the built-in media controller
+    if (canPlay()) {
+        updatePlaybackRate();
+        playInternal();
+    } else
+        pauseInternal();
+}
+
+void HTMLMediaElement::beginScrubbing()
+{
+    LOG(Media, "HTMLMediaElement::beginScrubbing - paused() is %s", boolString(paused()));
+
+    if (!paused()) {
+        if (ended()) {
+            // Because a media element stays in non-paused state when it reaches end, playback resumes
+            // when the slider is dragged from the end to another position unless we pause first. Do
+            // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
+            pause();
+        } else {
+            // Not at the end but we still want to pause playback so the media engine doesn't try to
+            // continue playing during scrubbing. Pause without generating an event as we will
+            // unpause after scrubbing finishes.
+            setPausedInternal(true);
+        }
+    }
+}
+
+void HTMLMediaElement::endScrubbing()
+{
+    LOG(Media, "HTMLMediaElement::endScrubbing - m_pausedInternal is %s", boolString(m_pausedInternal));
+
+    if (m_pausedInternal)
+        setPausedInternal(false);
+}
+
+// The spec says to fire periodic timeupdate events (those sent while playing) every
+// "15 to 250ms", we choose the slowest frequency
+static const double maxTimeupdateEventFrequency = 0.25;
+
+void HTMLMediaElement::startPlaybackProgressTimer()
+{
+    if (m_playbackProgressTimer.isActive())
+        return;
+
+    m_previousProgressTime = WTF::currentTime();
+    m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
+}
+
+void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
+{
+    ASSERT(m_player);
+
+    if (m_fragmentEndTime != MediaPlayer::invalidTime() && currentTime() >= m_fragmentEndTime && m_playbackRate > 0) {
+        m_fragmentEndTime = MediaPlayer::invalidTime();
+        if (!m_mediaController && !m_paused) {
+            // changes paused to true and fires a simple event named pause at the media element.
+            pauseInternal();
+        }
+    }
+
+    scheduleTimeupdateEvent(true);
+
+    if (!m_playbackRate)
+        return;
+
+    if (!m_paused && hasMediaControls())
+        mediaControls()->playbackProgressed();
+
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        updateActiveTextTrackCues(currentTime());
+}
+
+void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
+{
+    double now = WTF::currentTime();
+    double timedelta = now - m_lastTimeUpdateEventWallTime;
+
+    // throttle the periodic events
+    if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
+        return;
+
+    // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
+    // event at a given time so filter here
+    double movieTime = currentTime();
+    if (movieTime != m_lastTimeUpdateEventMovieTime) {
+        scheduleEvent(eventNames().timeupdateEvent);
+        m_lastTimeUpdateEventWallTime = now;
+        m_lastTimeUpdateEventMovieTime = movieTime;
+    }
+}
+
+bool HTMLMediaElement::canPlay() const
+{
+    return paused() || ended() || m_readyState < HAVE_METADATA;
+}
+
+double HTMLMediaElement::percentLoaded() const
+{
+    if (!m_player)
+        return 0;
+    double duration = m_player->duration();
+
+    if (!duration || std::isinf(duration))
+        return 0;
+
+    double buffered = 0;
+    RefPtr<TimeRanges> timeRanges = m_player->buffered();
+    for (unsigned i = 0; i < timeRanges->length(); ++i) {
+        double start = timeRanges->start(i, IGNORE_EXCEPTION);
+        double end = timeRanges->end(i, IGNORE_EXCEPTION);
+        buffered += end - start;
+    }
+    return buffered / duration;
+}
+
+void HTMLMediaElement::mediaPlayerDidAddTrack(PassRefPtr<InbandTextTrackPrivate> prpTrack)
+{
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return;
+
+    // 4.8.10.12.2 Sourcing in-band text tracks
+    // 1. Associate the relevant data with a new text track and its corresponding new TextTrack object.
+    RefPtr<InbandTextTrack> textTrack = InbandTextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, prpTrack);
+
+    // 2. Set the new text track's kind, label, and language based on the semantics of the relevant data,
+    // as defined by the relevant specification. If there is no label in that data, then the label must
+    // be set to the empty string.
+    // 3. Associate the text track list of cues with the rules for updating the text track rendering appropriate
+    // for the format in question.
+    // 4. If the new text track's kind is metadata, then set the text track in-band metadata track dispatch type
+    // as follows, based on the type of the media resource:
+    // 5. Populate the new text track's list of cues with the cues parsed so far, folllowing the guidelines for exposing
+    // cues, and begin updating it dynamically as necessary.
+    //   - Thess are all done by the media engine.
+
+    // 6. Set the new text track's readiness state to loaded.
+    textTrack->setReadinessState(TextTrack::Loaded);
+
+    // 7. Set the new text track's mode to the mode consistent with the user's preferences and the requirements of
+    // the relevant specification for the data.
+    //  - This will happen in configureTextTracks()
+    scheduleDelayedAction(LoadTextTrackResource);
+
+    // 8. Add the new text track to the media element's list of text tracks.
+    // 9. Fire an event with the name addtrack, that does not bubble and is not cancelable, and that uses the TrackEvent
+    // interface, with the track attribute initialized to the text track's TextTrack object, at the media element's
+    // textTracks attribute's TextTrackList object.
+    addTrack(textTrack.get());
+}
+
+void HTMLMediaElement::mediaPlayerDidRemoveTrack(PassRefPtr<InbandTextTrackPrivate> prpTrack)
+{
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return;
+
+    if (!m_textTracks)
+        return;
+
+    // This cast is safe because we created the InbandTextTrack with the InbandTextTrackPrivate
+    // passed to mediaPlayerDidAddTrack.
+    RefPtr<InbandTextTrack> textTrack = static_cast<InbandTextTrack*>(prpTrack->client());
+    if (!textTrack)
+        return;
+
+    removeTrack(textTrack.get());
+}
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+void HTMLMediaElement::setSelectedTextTrack(PassRefPtr<PlatformTextTrack> platformTrack)
+{
+    if (!m_textTracks)
+        return;
+
+    TrackDisplayUpdateScope scope(this);
+
+    if (!platformTrack) {
+        setSelectedTextTrack(0);
+        return;
+    }
+
+    TextTrack* textTrack;
+    size_t i;
+    for (i = 0; i < m_textTracks->length(); ++i) {
+        textTrack = m_textTracks->item(i);
+
+        if (textTrack->platformTextTrack() == platformTrack)
+            break;
+    }
+
+    if (i == m_textTracks->length())
+        return;
+    setSelectedTextTrack(textTrack);
+}
+
+Vector<RefPtr<PlatformTextTrack> > HTMLMediaElement::platformTextTracks()
+{
+    if (!m_textTracks || !m_textTracks->length())
+        return Vector<RefPtr<PlatformTextTrack> >();
+
+    Vector<RefPtr<PlatformTextTrack> > platformTracks;
+    for (size_t i = 0; i < m_textTracks->length(); ++i)
+        platformTracks.append(m_textTracks->item(i)->platformTextTrack());
+
+    return platformTracks;
+}
+
+void HTMLMediaElement::notifyMediaPlayerOfTextTrackChanges()
+{
+    if (!m_textTracks || !m_textTracks->length() || !platformTextTrackMenu())
+        return;
+
+    m_platformMenu->tracksDidChange();
+}
+
+PlatformTextTrackMenuInterface* HTMLMediaElement::platformTextTrackMenu()
+{
+    if (m_platformMenu)
+        return m_platformMenu.get();
+
+    if (!m_player->implementsTextTrackControls())
+        return 0;
+
+    m_platformMenu = m_player->textTrackMenu();
+    if (!m_platformMenu)
+        return 0;
+
+    m_platformMenu->setClient(this);
+
+    return m_platformMenu.get();
+}
+#endif // #if USE(PLATFORM_TEXT_TRACK_MENU)
+
+void HTMLMediaElement::closeCaptionTracksChanged()
+{
+    if (hasMediaControls())
+        mediaControls()->closedCaptionTracksChanged();
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    if (m_player->implementsTextTrackControls())
+        scheduleDelayedAction(TextTrackChangesNotification);
+#endif
+}
+
+void HTMLMediaElement::addTrack(TextTrack* track)
+{
+    textTracks()->append(track);
+
+    closeCaptionTracksChanged();
+}
+
+void HTMLMediaElement::removeTrack(TextTrack* track)
+{
+    TrackDisplayUpdateScope scope(this);
+    TextTrackCueList* cues = track->cues();
+    if (cues)
+        textTrackRemoveCues(track, cues);
+    m_textTracks->remove(track);
+
+    closeCaptionTracksChanged();
+}
+
+void HTMLMediaElement::removeAllInbandTracks()
+{
+    if (!m_textTracks)
+        return;
+
+    TrackDisplayUpdateScope scope(this);
+    for (int i = m_textTracks->length() - 1; i >= 0; --i) {
+        TextTrack* track = m_textTracks->item(i);
+
+        if (track->trackType() == TextTrack::InBand)
+            removeTrack(track);
+    }
+}
+
+PassRefPtr<TextTrack> HTMLMediaElement::addTextTrack(const String& kind, const String& label, const String& language, ExceptionCode& ec)
+{
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return 0;
+
+    // 4.8.10.12.4 Text track API
+    // The addTextTrack(kind, label, language) method of media elements, when invoked, must run the following steps:
+
+    // 1. If kind is not one of the following strings, then throw a SyntaxError exception and abort these steps
+    if (!TextTrack::isValidKindKeyword(kind)) {
+        ec = SYNTAX_ERR;
+        return 0;
+    }
+
+    // 2. If the label argument was omitted, let label be the empty string.
+    // 3. If the language argument was omitted, let language be the empty string.
+    // 4. Create a new TextTrack object.
+
+    // 5. Create a new text track corresponding to the new object, and set its text track kind to kind, its text
+    // track label to label, its text track language to language...
+    RefPtr<TextTrack> textTrack = TextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, kind, label, language);
+
+    // Note, due to side effects when changing track parameters, we have to
+    // first append the track to the text track list.
+
+    // 6. Add the new text track to the media element's list of text tracks.
+    addTrack(textTrack.get());
+
+    // ... its text track readiness state to the text track loaded state ...
+    textTrack->setReadinessState(TextTrack::Loaded);
+
+    // ... its text track mode to the text track hidden mode, and its text track list of cues to an empty list ...
+    textTrack->setMode(TextTrack::hiddenKeyword());
+
+    return textTrack.release();
+}
+
+TextTrackList* HTMLMediaElement::textTracks()
+{
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return 0;
+
+    if (!m_textTracks)
+        m_textTracks = TextTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
+
+    return m_textTracks.get();
+}
+
+void HTMLMediaElement::didAddTrack(HTMLTrackElement* trackElement)
+{
+    ASSERT(trackElement->hasTagName(trackTag));
+
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return;
+
+    // 4.8.10.12.3 Sourcing out-of-band text tracks
+    // When a track element's parent element changes and the new parent is a media element,
+    // then the user agent must add the track element's corresponding text track to the
+    // media element's list of text tracks ... [continues in TextTrackList::append]
+    RefPtr<TextTrack> textTrack = trackElement->track();
+    if (!textTrack)
+        return;
+
+    addTrack(textTrack.get());
+
+    // Do not schedule the track loading until parsing finishes so we don't start before all tracks
+    // in the markup have been added.
+    if (!m_parsingInProgress)
+        scheduleDelayedAction(LoadTextTrackResource);
+
+    if (hasMediaControls())
+        mediaControls()->closedCaptionTracksChanged();
+}
+
+void HTMLMediaElement::didRemoveTrack(HTMLTrackElement* trackElement)
+{
+    ASSERT(trackElement->hasTagName(trackTag));
+
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return;
+
+#if !LOG_DISABLED
+    if (trackElement->hasTagName(trackTag)) {
+        KURL url = trackElement->getNonEmptyURLAttribute(srcAttr);
+        LOG(Media, "HTMLMediaElement::didRemoveTrack - 'src' is %s", urlForLoggingMedia(url).utf8().data());
+    }
+#endif
+
+    RefPtr<TextTrack> textTrack = trackElement->track();
+    if (!textTrack)
+        return;
+
+    textTrack->setHasBeenConfigured(false);
+
+    if (!m_textTracks)
+        return;
+
+    // 4.8.10.12.3 Sourcing out-of-band text tracks
+    // When a track element's parent element changes and the old parent was a media element,
+    // then the user agent must remove the track element's corresponding text track from the
+    // media element's list of text tracks.
+    removeTrack(textTrack.get());
+
+    size_t index = m_textTracksWhenResourceSelectionBegan.find(textTrack.get());
+    if (index != notFound)
+        m_textTracksWhenResourceSelectionBegan.remove(index);
+}
+
+bool HTMLMediaElement::userPrefersCaptions() const
+{
+    Page* page = document()->page();
+    if (!page)
+        return false;
+
+    CaptionUserPreferences* captionPreferences = page->group().captionPreferences();
+    return captionPreferences->userHasCaptionPreferences() && captionPreferences->shouldShowCaptions();
+}
+
+void HTMLMediaElement::configureTextTrackGroup(const TrackGroup& group)
+{
+    ASSERT(group.tracks.size());
+
+    LOG(Media, "HTMLMediaElement::configureTextTrackGroup(%d)", group.kind);
+
+    Page* page = document()->page();
+    CaptionUserPreferences* captionPreferences = page? page->group().captionPreferences() : 0;
+
+    // First, find the track in the group that should be enabled (if any).
+    Vector<RefPtr<TextTrack> > currentlyEnabledTracks;
+    RefPtr<TextTrack> trackToEnable;
+    RefPtr<TextTrack> defaultTrack;
+    RefPtr<TextTrack> fallbackTrack;
+    int highestTrackScore = 0;
+    for (size_t i = 0; i < group.tracks.size(); ++i) {
+        RefPtr<TextTrack> textTrack = group.tracks[i];
+
+        if (m_processingPreferenceChange && textTrack->mode() == TextTrack::showingKeyword())
+            currentlyEnabledTracks.append(textTrack);
+
+        int trackScore = captionPreferences ? captionPreferences->textTrackSelectionScore(textTrack.get(), this) : 0;
+        if (trackScore) {
+            // * If the text track kind is { [subtitles or captions] [descriptions] } and the user has indicated an interest in having a
+            // track with this text track kind, text track language, and text track label enabled, and there is no
+            // other text track in the media element's list of text tracks with a text track kind of either subtitles
+            // or captions whose text track mode is showing
+            // ...
+            // * If the text track kind is chapters and the text track language is one that the user agent has reason
+            // to believe is appropriate for the user, and there is no other text track in the media element's list of
+            // text tracks with a text track kind of chapters whose text track mode is showing
+            //    Let the text track mode be showing.
+            if (trackScore > highestTrackScore) {
+                highestTrackScore = trackScore;
+                trackToEnable = textTrack;
+            }
+
+            if (!defaultTrack && textTrack->isDefault())
+                defaultTrack = textTrack;
+            if (!defaultTrack && !fallbackTrack)
+                fallbackTrack = textTrack;
+        } else if (!group.visibleTrack && !defaultTrack && textTrack->isDefault()) {
+            // * If the track element has a default attribute specified, and there is no other text track in the media
+            // element's list of text tracks whose text track mode is showing or showing by default
+            //    Let the text track mode be showing by default.
+            defaultTrack = textTrack;
+        }
+    }
+
+    if (!trackToEnable && defaultTrack)
+        trackToEnable = defaultTrack;
+
+    // If no track matches the user's preferred language and non was marked 'default', enable the first track
+    // because the user has explicitly stated a preference for this kind of track.
+    if (!fallbackTrack && m_closedCaptionsVisible && group.kind == TrackGroup::CaptionsAndSubtitles)
+        fallbackTrack = group.tracks[0];
+
+    if (!trackToEnable && fallbackTrack)
+        trackToEnable = fallbackTrack;
+
+    if (currentlyEnabledTracks.size()) {
+        for (size_t i = 0; i < currentlyEnabledTracks.size(); ++i) {
+            RefPtr<TextTrack> textTrack = currentlyEnabledTracks[i];
+            if (textTrack != trackToEnable)
+                textTrack->setMode(TextTrack::disabledKeyword());
+        }
+    }
+
+    if (trackToEnable)
+        trackToEnable->setMode(TextTrack::showingKeyword());
+}
+
+void HTMLMediaElement::setSelectedTextTrack(TextTrack* trackToSelect)
+{
+    TextTrackList* trackList = textTracks();
+    if (!trackList || !trackList->length())
+        return;
+    if (trackToSelect && !trackList->contains(trackToSelect))
+        return;
+
+    for (int i = 0, length = trackList->length(); i < length; ++i) {
+        TextTrack* track = trackList->item(i);
+        if (!trackToSelect || track != trackToSelect)
+            track->setMode(TextTrack::disabledKeyword());
+        else
+            track->setMode(TextTrack::showingKeyword());
+    }
+
+    CaptionUserPreferences* captionPreferences = document()->page() ? document()->page()->group().captionPreferences() : 0;
+    if (captionPreferences) {
+        captionPreferences->setShouldShowCaptions(trackToSelect);
+        if (trackToSelect && trackToSelect->language().length())
+            captionPreferences->setPreferredLanguage(trackToSelect->language());
+    }
+}
+
+void HTMLMediaElement::configureTextTracks()
+{
+    TrackGroup captionAndSubtitleTracks(TrackGroup::CaptionsAndSubtitles);
+    TrackGroup descriptionTracks(TrackGroup::Description);
+    TrackGroup chapterTracks(TrackGroup::Chapter);
+    TrackGroup metadataTracks(TrackGroup::Metadata);
+    TrackGroup otherTracks(TrackGroup::Other);
+
+    if (!m_textTracks)
+        return;
+
+    for (size_t i = 0; i < m_textTracks->length(); ++i) {
+        RefPtr<TextTrack> textTrack = m_textTracks->item(i);
+        if (!textTrack)
+            continue;
+
+        String kind = textTrack->kind();
+        TrackGroup* currentGroup;
+        if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword())
+            currentGroup = &captionAndSubtitleTracks;
+        else if (kind == TextTrack::descriptionsKeyword())
+            currentGroup = &descriptionTracks;
+        else if (kind == TextTrack::chaptersKeyword())
+            currentGroup = &chapterTracks;
+        else if (kind == TextTrack::metadataKeyword())
+            currentGroup = &metadataTracks;
+        else
+            currentGroup = &otherTracks;
+
+        if (!currentGroup->visibleTrack && textTrack->mode() == TextTrack::showingKeyword())
+            currentGroup->visibleTrack = textTrack;
+        if (!currentGroup->defaultTrack && textTrack->isDefault())
+            currentGroup->defaultTrack = textTrack;
+
+        // Do not add this track to the group if it has already been automatically configured
+        // as we only want to call configureTextTrack once per track so that adding another
+        // track after the initial configuration doesn't reconfigure every track - only those
+        // that should be changed by the new addition. For example all metadata tracks are
+        // disabled by default, and we don't want a track that has been enabled by script
+        // to be disabled automatically when a new metadata track is added later.
+        if (textTrack->hasBeenConfigured())
+            continue;
+
+        if (textTrack->language().length())
+            currentGroup->hasSrcLang = true;
+        currentGroup->tracks.append(textTrack);
+    }
+
+    if (captionAndSubtitleTracks.tracks.size())
+        configureTextTrackGroup(captionAndSubtitleTracks);
+    if (descriptionTracks.tracks.size())
+        configureTextTrackGroup(descriptionTracks);
+    if (chapterTracks.tracks.size())
+        configureTextTrackGroup(chapterTracks);
+    if (metadataTracks.tracks.size())
+        configureTextTrackGroup(metadataTracks);
+    if (otherTracks.tracks.size())
+        configureTextTrackGroup(otherTracks);
+
+    if (hasMediaControls())
+        mediaControls()->closedCaptionTracksChanged();
+}
+
+bool HTMLMediaElement::havePotentialSourceChild()
+{
+    // Stash the current <source> node and next nodes so we can restore them after checking
+    // to see there is another potential.
+    RefPtr<HTMLSourceElement> currentSourceNode = m_currentSourceNode;
+    RefPtr<Node> nextNode = m_nextChildNodeToConsider;
+
+    KURL nextURL = selectNextSourceChild(0, 0, DoNothing);
+
+    m_currentSourceNode = currentSourceNode;
+    m_nextChildNodeToConsider = nextNode;
+
+    return nextURL.isValid();
+}
+
+KURL HTMLMediaElement::selectNextSourceChild(ContentType* contentType, String* keySystem, InvalidURLAction actionIfInvalid)
+{
+#if !LOG_DISABLED
+    // Don't log if this was just called to find out if there are any valid <source> elements.
+    bool shouldLog = actionIfInvalid != DoNothing;
+    if (shouldLog)
+        LOG(Media, "HTMLMediaElement::selectNextSourceChild");
+#endif
+
+    if (!m_nextChildNodeToConsider) {
+#if !LOG_DISABLED
+        if (shouldLog)
+            LOG(Media, "HTMLMediaElement::selectNextSourceChild -> 0x0000, \"\"");
+#endif
+        return KURL();
+    }
+
+    KURL mediaURL;
+    Node* node;
+    HTMLSourceElement* source = 0;
+    String type;
+    String system;
+    bool lookingForStartNode = m_nextChildNodeToConsider;
+    bool canUseSourceElement = false;
+    bool okToLoadSourceURL;
+
+    NodeVector potentialSourceNodes;
+    getChildNodes(this, potentialSourceNodes);
+
+    for (unsigned i = 0; !canUseSourceElement && i < potentialSourceNodes.size(); ++i) {
+        node = potentialSourceNodes[i].get();
+        if (lookingForStartNode && m_nextChildNodeToConsider != node)
+            continue;
+        lookingForStartNode = false;
+
+        if (!node->hasTagName(sourceTag))
+            continue;
+        if (node->parentNode() != this)
+            continue;
+
+        source = static_cast<HTMLSourceElement*>(node);
+
+        // If candidate does not have a src attribute, or if its src attribute's value is the empty string ... jump down to the failed step below
+        mediaURL = source->getNonEmptyURLAttribute(srcAttr);
+#if !LOG_DISABLED
+        if (shouldLog)
+            LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'src' is %s", urlForLoggingMedia(mediaURL).utf8().data());
+#endif
+        if (mediaURL.isEmpty())
+            goto check_again;
+
+        if (source->fastHasAttribute(mediaAttr)) {
+            MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
+            RefPtr<MediaQuerySet> media = MediaQuerySet::createAllowingDescriptionSyntax(source->media());
+#if !LOG_DISABLED
+            if (shouldLog)
+                LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'media' is %s", source->media().utf8().data());
+#endif
+            if (!screenEval.eval(media.get()))
+                goto check_again;
+        }
+
+        type = source->type();
+        // FIXME(82965): Add support for keySystem in <source> and set system from source.
+        if (type.isEmpty() && mediaURL.protocolIsData())
+            type = mimeTypeFromDataURL(mediaURL);
+        if (!type.isEmpty() || !system.isEmpty()) {
+#if !LOG_DISABLED
+            if (shouldLog)
+                LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'type' is '%s' - key system is '%s'", type.utf8().data(), system.utf8().data());
+#endif
+            if (!MediaPlayer::supportsType(ContentType(type), system, mediaURL, this))
+                goto check_again;
+        }
+
+        // Is it safe to load this url?
+        okToLoadSourceURL = isSafeToLoadURL(mediaURL, actionIfInvalid) && dispatchBeforeLoadEvent(mediaURL.string());
+
+        // A 'beforeload' event handler can mutate the DOM, so check to see if the source element is still a child node.
+        if (node->parentNode() != this) {
+            LOG(Media, "HTMLMediaElement::selectNextSourceChild : 'beforeload' removed current element");
+            source = 0;
+            goto check_again;
+        }
+
+        if (!okToLoadSourceURL)
+            goto check_again;
+
+        // Making it this far means the <source> looks reasonable.
+        canUseSourceElement = true;
+
+check_again:
+        if (!canUseSourceElement && actionIfInvalid == Complain && source)
+            source->scheduleErrorEvent();
+    }
+
+    if (canUseSourceElement) {
+        if (contentType)
+            *contentType = ContentType(type);
+        if (keySystem)
+            *keySystem = system;
+        m_currentSourceNode = source;
+        m_nextChildNodeToConsider = source->nextSibling();
+    } else {
+        m_currentSourceNode = 0;
+        m_nextChildNodeToConsider = 0;
+    }
+
+#if !LOG_DISABLED
+    if (shouldLog)
+        LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %p, %s", m_currentSourceNode.get(), canUseSourceElement ? urlForLoggingMedia(mediaURL).utf8().data() : "");
+#endif
+    return canUseSourceElement ? mediaURL : KURL();
+}
+
+void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
+{
+    LOG(Media, "HTMLMediaElement::sourceWasAdded(%p)", source);
+
+#if !LOG_DISABLED
+    if (source->hasTagName(sourceTag)) {
+        KURL url = source->getNonEmptyURLAttribute(srcAttr);
+        LOG(Media, "HTMLMediaElement::sourceWasAdded - 'src' is %s", urlForLoggingMedia(url).utf8().data());
+    }
+#endif
+
+    // We should only consider a <source> element when there is not src attribute at all.
+    if (fastHasAttribute(srcAttr))
+        return;
+
+    // 4.8.8 - If a source element is inserted as a child of a media element that has no src
+    // attribute and whose networkState has the value NETWORK_EMPTY, the user agent must invoke
+    // the media element's resource selection algorithm.
+    if (networkState() == HTMLMediaElement::NETWORK_EMPTY) {
+        scheduleDelayedAction(LoadMediaResource);
+        m_nextChildNodeToConsider = source;
+        return;
+    }
+
+    if (m_currentSourceNode && source == m_currentSourceNode->nextSibling()) {
+        LOG(Media, "HTMLMediaElement::sourceWasAdded - <source> inserted immediately after current source");
+        m_nextChildNodeToConsider = source;
+        return;
+    }
+
+    if (m_nextChildNodeToConsider)
+        return;
+
+    // 4.8.9.5, resource selection algorithm, source elements section:
+    // 21. Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
+    // 22. Asynchronously await a stable state...
+    // 23. Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case
+    // it hasn't been fired yet).
+    setShouldDelayLoadEvent(true);
+
+    // 24. Set the networkState back to NETWORK_LOADING.
+    m_networkState = NETWORK_LOADING;
+
+    // 25. Jump back to the find next candidate step above.
+    m_nextChildNodeToConsider = source;
+    scheduleNextSourceChild();
+}
+
+void HTMLMediaElement::sourceWasRemoved(HTMLSourceElement* source)
+{
+    LOG(Media, "HTMLMediaElement::sourceWasRemoved(%p)", source);
+
+#if !LOG_DISABLED
+    if (source->hasTagName(sourceTag)) {
+        KURL url = source->getNonEmptyURLAttribute(srcAttr);
+        LOG(Media, "HTMLMediaElement::sourceWasRemoved - 'src' is %s", urlForLoggingMedia(url).utf8().data());
+    }
+#endif
+
+    if (source != m_currentSourceNode && source != m_nextChildNodeToConsider)
+        return;
+
+    if (source == m_nextChildNodeToConsider) {
+        if (m_currentSourceNode)
+            m_nextChildNodeToConsider = m_currentSourceNode->nextSibling();
+        LOG(Media, "HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p", m_nextChildNodeToConsider.get());
+    } else if (source == m_currentSourceNode) {
+        // Clear the current source node pointer, but don't change the movie as the spec says:
+        // 4.8.8 - Dynamically modifying a source element and its attribute when the element is already
+        // inserted in a video or audio element will have no effect.
+        m_currentSourceNode = 0;
+        LOG(Media, "HTMLMediaElement::sourceRemoved - m_currentSourceNode set to 0");
+    }
+}
+
+void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerTimeChanged");
+
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        updateActiveTextTrackCues(currentTime());
+
+    beginProcessingMediaPlayerCallback();
+
+    invalidateCachedTime();
+
+    // 4.8.10.9 step 14 & 15.  Needed if no ReadyState change is associated with the seek.
+    if (m_seeking && m_readyState >= HAVE_CURRENT_DATA && !m_player->seeking())
+        finishSeek();
+
+    // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity,
+    // it will only queue a 'timeupdate' event if we haven't already posted one at the current
+    // movie time.
+    scheduleTimeupdateEvent(false);
+
+    double now = currentTime();
+    double dur = duration();
+
+    // When the current playback position reaches the end of the media resource when the direction of
+    // playback is forwards, then the user agent must follow these steps:
+    if (!std::isnan(dur) && dur && now >= dur && m_playbackRate > 0) {
+        // If the media element has a loop attribute specified and does not have a current media controller,
+        if (loop() && !m_mediaController) {
+            m_sentEndEvent = false;
+            //  then seek to the earliest possible position of the media resource and abort these steps.
+            seek(startTime(), IGNORE_EXCEPTION);
+        } else {
+            // If the media element does not have a current media controller, and the media element
+            // has still ended playback, and the direction of playback is still forwards, and paused
+            // is false,
+            if (!m_mediaController && !m_paused) {
+                // changes paused to true and fires a simple event named pause at the media element.
+                m_paused = true;
+                scheduleEvent(eventNames().pauseEvent);
+            }
+            // Queue a task to fire a simple event named ended at the media element.
+            if (!m_sentEndEvent) {
+                m_sentEndEvent = true;
+                scheduleEvent(eventNames().endedEvent);
+            }
+            // If the media element has a current media controller, then report the controller state
+            // for the media element's current media controller.
+            updateMediaController();
+        }
+    }
+    else
+        m_sentEndEvent = false;
+
+    updatePlayState();
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerVolumeChanged");
+
+    beginProcessingMediaPlayerCallback();
+    if (m_player) {
+        double vol = m_player->volume();
+        if (vol != m_volume) {
+            m_volume = vol;
+            updateVolume();
+            scheduleEvent(eventNames().volumechangeEvent);
+        }
+    }
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerMuteChanged");
+
+    beginProcessingMediaPlayerCallback();
+    if (m_player)
+        setMuted(m_player->muted());
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer* player)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged");
+
+    beginProcessingMediaPlayerCallback();
+
+    scheduleEvent(eventNames().durationchangeEvent);
+    mediaPlayerCharacteristicChanged(player);
+
+    double now = currentTime();
+    double dur = duration();
+    if (now > dur)
+        seek(dur, IGNORE_EXCEPTION);
+
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerRateChanged");
+
+    beginProcessingMediaPlayerCallback();
+
+    // Stash the rate in case the one we tried to set isn't what the engine is
+    // using (eg. it can't handle the rate we set)
+    m_playbackRate = m_player->rate();
+    if (m_playing)
+        invalidateCachedTime();
+
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaPlayerPlaybackStateChanged(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerPlaybackStateChanged");
+
+    if (!m_player || m_pausedInternal)
+        return;
+
+    beginProcessingMediaPlayerCallback();
+    if (m_player->paused())
+        pauseInternal();
+    else
+        playInternal();
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerSawUnsupportedTracks");
+
+    // The MediaPlayer came across content it cannot completely handle.
+    // This is normally acceptable except when we are in a standalone
+    // MediaDocument. If so, tell the document what has happened.
+    if (ownerDocument()->isMediaDocument()) {
+        MediaDocument* mediaDocument = toMediaDocument(ownerDocument());
+        mediaDocument->mediaElementSawUnsupportedTracks();
+    }
+}
+
+void HTMLMediaElement::mediaPlayerResourceNotSupported(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerResourceNotSupported");
+
+    // The MediaPlayer came across content which no installed engine supports.
+    mediaLoadingFailed(MediaPlayer::FormatError);
+}
+
+// MediaPlayerPresentation methods
+void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
+{
+    beginProcessingMediaPlayerCallback();
+    updateDisplayState();
+    if (renderer())
+        renderer()->repaint();
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerSizeChanged");
+
+    beginProcessingMediaPlayerCallback();
+    if (renderer())
+        renderer()->updateFromElement();
+    endProcessingMediaPlayerCallback();
+}
+
+bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
+{
+    if (renderer() && renderer()->isVideo()) {
+        ASSERT(renderer()->view());
+        return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
+    }
+    return false;
+}
+
+void HTMLMediaElement::mediaPlayerRenderingModeChanged(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerRenderingModeChanged");
+
+    // Kick off a fake recalcStyle that will update the compositing tree.
+    setNeedsStyleRecalc(SyntheticStyleChange);
+}
+
+void HTMLMediaElement::mediaPlayerEngineUpdated(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerEngineUpdated");
+    beginProcessingMediaPlayerCallback();
+    if (renderer())
+        renderer()->updateFromElement();
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable");
+    beginProcessingMediaPlayerCallback();
+    if (displayMode() == PosterWaitingForVideo) {
+        setDisplayMode(Video);
+        mediaPlayerRenderingModeChanged(m_player.get());
+    }
+    endProcessingMediaPlayerCallback();
+}
+
+void HTMLMediaElement::mediaPlayerCharacteristicChanged(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerCharacteristicChanged");
+
+    beginProcessingMediaPlayerCallback();
+    if (hasMediaControls())
+        mediaControls()->reset();
+    if (renderer())
+        renderer()->updateFromElement();
+    endProcessingMediaPlayerCallback();
+}
+
+PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
+{
+    if (!m_player)
+        return TimeRanges::create();
+    return m_player->buffered();
+}
+
+PassRefPtr<TimeRanges> HTMLMediaElement::played()
+{
+    if (m_playing) {
+        double time = currentTime();
+        if (time > m_lastSeekTime)
+            addPlayedRange(m_lastSeekTime, time);
+    }
+
+    if (!m_playedTimeRanges)
+        m_playedTimeRanges = TimeRanges::create();
+
+    return m_playedTimeRanges->copy();
+}
+
+PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
+{
+    return m_player ? m_player->seekable() : TimeRanges::create();
+}
+
+bool HTMLMediaElement::potentiallyPlaying() const
+{
+    // "pausedToBuffer" means the media engine's rate is 0, but only because it had to stop playing
+    // when it ran out of buffered data. A movie is this state is "potentially playing", modulo the
+    // checks in couldPlayIfEnoughData().
+    bool pausedToBuffer = m_readyStateMaximum >= HAVE_FUTURE_DATA && m_readyState < HAVE_FUTURE_DATA;
+    return (pausedToBuffer || m_readyState >= HAVE_FUTURE_DATA) && couldPlayIfEnoughData() && !isBlockedOnMediaController();
+}
+
+bool HTMLMediaElement::couldPlayIfEnoughData() const
+{
+    return !paused() && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
+}
+
+bool HTMLMediaElement::endedPlayback() const
+{
+    double dur = duration();
+    if (!m_player || std::isnan(dur))
+        return false;
+
+    // 4.8.10.8 Playing the media resource
+
+    // A media element is said to have ended playback when the element's
+    // readyState attribute is HAVE_METADATA or greater,
+    if (m_readyState < HAVE_METADATA)
+        return false;
+
+    // and the current playback position is the end of the media resource and the direction
+    // of playback is forwards, Either the media element does not have a loop attribute specified,
+    // or the media element has a current media controller.
+    double now = currentTime();
+    if (m_playbackRate > 0)
+        return dur > 0 && now >= dur && (!loop() || m_mediaController);
+
+    // or the current playback position is the earliest possible position and the direction
+    // of playback is backwards
+    if (m_playbackRate < 0)
+        return now <= 0;
+
+    return false;
+}
+
+bool HTMLMediaElement::stoppedDueToErrors() const
+{
+    if (m_readyState >= HAVE_METADATA && m_error) {
+        RefPtr<TimeRanges> seekableRanges = seekable();
+        if (!seekableRanges->contain(currentTime()))
+            return true;
+    }
+
+    return false;
+}
+
+bool HTMLMediaElement::pausedForUserInteraction() const
+{
+//    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
+    return false;
+}
+
+double HTMLMediaElement::minTimeSeekable() const
+{
+    return 0;
+}
+
+double HTMLMediaElement::maxTimeSeekable() const
+{
+    return m_player ? m_player->maxTimeSeekable() : 0;
+}
+
+void HTMLMediaElement::updateVolume()
+{
+    if (!m_player)
+        return;
+
+    // Avoid recursion when the player reports volume changes.
+    if (!processingMediaPlayerCallback()) {
+        double volumeMultiplier = 1;
+        bool shouldMute = m_muted;
+
+        if (m_mediaController) {
+            volumeMultiplier *= m_mediaController->volume();
+            shouldMute = m_mediaController->muted();
+        }
+
+        m_player->setMuted(shouldMute);
+        m_player->setVolume(m_volume * volumeMultiplier);
+    }
+
+    if (hasMediaControls())
+        mediaControls()->changedVolume();
+}
+
+void HTMLMediaElement::updatePlayState()
+{
+    if (!m_player)
+        return;
+
+    if (m_pausedInternal) {
+        if (!m_player->paused())
+            m_player->pause();
+        refreshCachedTime();
+        m_playbackProgressTimer.stop();
+        if (hasMediaControls())
+            mediaControls()->playbackStopped();
+        return;
+    }
+
+    bool shouldBePlaying = potentiallyPlaying();
+    bool playerPaused = m_player->paused();
+
+    LOG(Media, "HTMLMediaElement::updatePlayState - shouldBePlaying = %s, playerPaused = %s",
+        boolString(shouldBePlaying), boolString(playerPaused));
+
+    if (shouldBePlaying) {
+        setDisplayMode(Video);
+        invalidateCachedTime();
+
+        if (playerPaused) {
+            // Set rate, muted before calling play in case they were set before the media engine was setup.
+            // The media engine should just stash the rate and muted values since it isn't already playing.
+            m_player->setRate(m_playbackRate);
+            m_player->setMuted(m_muted);
+
+            m_player->play();
+        }
+
+        if (hasMediaControls())
+            mediaControls()->playbackStarted();
+        startPlaybackProgressTimer();
+        m_playing = true;
+
+    } else { // Should not be playing right now
+        if (!playerPaused)
+            m_player->pause();
+        refreshCachedTime();
+
+        m_playbackProgressTimer.stop();
+        m_playing = false;
+        double time = currentTime();
+        if (time > m_lastSeekTime)
+            addPlayedRange(m_lastSeekTime, time);
+
+        if (couldPlayIfEnoughData())
+            prepareToPlay();
+
+        if (hasMediaControls())
+            mediaControls()->playbackStopped();
+    }
+
+    updateMediaController();
+
+    if (renderer())
+        renderer()->updateFromElement();
+}
+
+void HTMLMediaElement::setPausedInternal(bool b)
+{
+    m_pausedInternal = b;
+    updatePlayState();
+}
+
+void HTMLMediaElement::stopPeriodicTimers()
+{
+    m_progressEventTimer.stop();
+    m_playbackProgressTimer.stop();
+}
+
+void HTMLMediaElement::userCancelledLoad()
+{
+    LOG(Media, "HTMLMediaElement::userCancelledLoad");
+
+    // If the media data fetching process is aborted by the user:
+
+    // 1 - The user agent should cancel the fetching process.
+    clearMediaPlayer(-1);
+
+    if (m_networkState == NETWORK_EMPTY || m_completelyLoaded)
+        return;
+
+    // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED.
+    m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
+
+    // 3 - Queue a task to fire a simple event named error at the media element.
+    scheduleEvent(eventNames().abortEvent);
+
+    setSourceState(MediaSource::closedKeyword());
+
+    // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
+    // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
+    // simple event named emptied at the element. Otherwise, set the element's networkState
+    // attribute to the NETWORK_IDLE value.
+    if (m_readyState == HAVE_NOTHING) {
+        m_networkState = NETWORK_EMPTY;
+        scheduleEvent(eventNames().emptiedEvent);
+    }
+    else
+        m_networkState = NETWORK_IDLE;
+
+    // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
+    setShouldDelayLoadEvent(false);
+
+    // 6 - Abort the overall resource selection algorithm.
+    m_currentSourceNode = 0;
+
+    // Reset m_readyState since m_player is gone.
+    m_readyState = HAVE_NOTHING;
+    updateMediaController();
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        updateActiveTextTrackCues(0);
+}
+
+void HTMLMediaElement::clearMediaPlayer(int flags)
+{
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    if (platformTextTrackMenu()) {
+        m_platformMenu->setClient(0);
+        m_platformMenu = 0;
+    }
+#endif
+
+    removeAllInbandTracks();
+
+    setSourceState(MediaSource::closedKeyword());
+
+    m_player.clear();
+    stopPeriodicTimers();
+    m_loadTimer.stop();
+
+    m_pendingActionFlags &= ~flags;
+    m_loadState = WaitingForSource;
+
+    if (m_textTracks)
+        configureTextTrackDisplay();
+}
+
+bool HTMLMediaElement::canSuspend() const
+{
+    return true;
+}
+
+void HTMLMediaElement::stop()
+{
+    LOG(Media, "HTMLMediaElement::stop");
+
+    m_inActiveDocument = false;
+    userCancelledLoad();
+
+    // Stop the playback without generating events
+    m_playing = false;
+    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 WillDeferLoading:
+            // Do nothing, we don't pause media playback in these cases.
+            break;
+    }
+}
+
+void HTMLMediaElement::resume()
+{
+    LOG(Media, "HTMLMediaElement::resume");
+
+    m_inActiveDocument = true;
+    setPausedInternal(false);
+
+    if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
+        // Restart the load if it was aborted in the middle by moving the document to the page cache.
+        // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
+        //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
+        // This behavior is not specified but it seems like a sensible thing to do.
+        // As it is not safe to immedately start loading now, let's schedule a load.
+        scheduleDelayedAction(LoadMediaResource);
+    }
+
+    if (renderer())
+        renderer()->updateFromElement();
+}
+
+bool HTMLMediaElement::hasPendingActivity() const
+{
+    return (hasAudio() && isPlaying()) || m_asyncEventQueue->hasPendingEvents();
+}
+
+bool HTMLMediaElement::requiresTextTrackRepresentation() const
+{
+    return m_player ? m_player->requiresTextTrackRepresentation() : 0;
+}
+
+void HTMLMediaElement::setTextTrackRepresentation(TextTrackRepresentation* representation)
+{
+    if (m_player)
+        m_player->setTextTrackRepresentation(representation);
+}
+
+bool HTMLMediaElement::isFullscreen() const
+{
+    return document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this;
+}
+
+void HTMLMediaElement::enterFullscreen()
+{
+    LOG(Media, "HTMLMediaElement::enterFullscreen");
+
+    if (document()->settings() && document()->settings()->fullScreenEnabled())
+        document()->requestFullScreenForElement(this, 0, Document::ExemptIFrameAllowFullScreenRequirement);
+}
+
+void HTMLMediaElement::exitFullscreen()
+{
+    LOG(Media, "HTMLMediaElement::exitFullscreen");
+
+    if (document()->settings() && document()->settings()->fullScreenEnabled() && isFullscreen())
+        document()->webkitCancelFullScreen();
+}
+
+void HTMLMediaElement::didBecomeFullscreenElement()
+{
+    if (hasMediaControls())
+        mediaControls()->enteredFullscreen();
+}
+
+void HTMLMediaElement::willStopBeingFullscreenElement()
+{
+    if (hasMediaControls())
+        mediaControls()->exitedFullscreen();
+}
+
+PlatformMedia HTMLMediaElement::platformMedia() const
+{
+    return m_player ? m_player->platformMedia() : NoPlatformMedia;
+}
+
+PlatformLayer* HTMLMediaElement::platformLayer() const
+{
+    return m_player ? m_player->platformLayer() : 0;
+}
+
+bool HTMLMediaElement::hasClosedCaptions() const
+{
+    if (m_player && m_player->hasClosedCaptions())
+        return true;
+
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled() && m_textTracks)
+    for (unsigned i = 0; i < m_textTracks->length(); ++i) {
+        if (m_textTracks->item(i)->readinessState() == TextTrack::FailedToLoad)
+            continue;
+
+        if (m_textTracks->item(i)->kind() == TextTrack::captionsKeyword()
+            || m_textTracks->item(i)->kind() == TextTrack::subtitlesKeyword())
+            return true;
+    }
+    return false;
+}
+
+bool HTMLMediaElement::closedCaptionsVisible() const
+{
+    return m_closedCaptionsVisible;
+}
+
+void HTMLMediaElement::updateTextTrackDisplay()
+{
+    LOG(Media, "HTMLMediaElement::updateTextTrackDisplay");
+
+    if (!hasMediaControls() && !createMediaControls())
+        return;
+
+    mediaControls()->updateTextTrackDisplay();
+}
+
+void HTMLMediaElement::setClosedCaptionsVisible(bool closedCaptionVisible)
+{
+    LOG(Media, "HTMLMediaElement::setClosedCaptionsVisible(%s)", boolString(closedCaptionVisible));
+
+    if (!m_player || !hasClosedCaptions())
+        return;
+
+    m_closedCaptionsVisible = closedCaptionVisible;
+    m_player->setClosedCaptionsVisible(closedCaptionVisible);
+
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled()) {
+        m_processingPreferenceChange = true;
+        markCaptionAndSubtitleTracksAsUnconfigured();
+        m_processingPreferenceChange = false;
+
+        updateTextTrackDisplay();
+    }
+}
+
+void HTMLMediaElement::setWebkitClosedCaptionsVisible(bool visible)
+{
+    setClosedCaptionsVisible(visible);
+}
+
+bool HTMLMediaElement::webkitClosedCaptionsVisible() const
+{
+    return closedCaptionsVisible();
+}
+
+
+bool HTMLMediaElement::webkitHasClosedCaptions() const
+{
+    return hasClosedCaptions();
+}
+
+unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const
+{
+    if (!m_player)
+        return 0;
+    return m_player->audioDecodedByteCount();
+}
+
+unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const
+{
+    if (!m_player)
+        return 0;
+    return m_player->videoDecodedByteCount();
+}
+
+bool HTMLMediaElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == srcAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay)
+{
+    if (m_shouldDelayLoadEvent == shouldDelay)
+        return;
+
+    LOG(Media, "HTMLMediaElement::setShouldDelayLoadEvent(%s)", boolString(shouldDelay));
+
+    m_shouldDelayLoadEvent = shouldDelay;
+    if (shouldDelay)
+        document()->incrementLoadEventDelayCount();
+    else
+        document()->decrementLoadEventDelayCount();
+}
+
+
+void HTMLMediaElement::getSitesInMediaCache(Vector<String>& sites)
+{
+    MediaPlayer::getSitesInMediaCache(sites);
+}
+
+void HTMLMediaElement::clearMediaCache()
+{
+    MediaPlayer::clearMediaCache();
+}
+
+void HTMLMediaElement::clearMediaCacheForSite(const String& site)
+{
+    MediaPlayer::clearMediaCacheForSite(site);
+}
+
+void HTMLMediaElement::resetMediaEngines()
+{
+    MediaPlayer::resetMediaEngines();
+}
+
+MediaControls* HTMLMediaElement::mediaControls() const
+{
+    return toMediaControls(userAgentShadowRoot()->firstChild());
+}
+
+bool HTMLMediaElement::hasMediaControls() const
+{
+    if (ShadowRoot* userAgent = userAgentShadowRoot()) {
+        Node* node = userAgent->firstChild();
+        ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isMediaControls());
+        return node;
+    }
+
+    return false;
+}
+
+bool HTMLMediaElement::createMediaControls()
+{
+    if (hasMediaControls())
+        return true;
+
+    RefPtr<MediaControls> mediaControls = MediaControls::create(document());
+    if (!mediaControls)
+        return false;
+
+    mediaControls->setMediaController(m_mediaController ? m_mediaController.get() : static_cast<MediaControllerInterface*>(this));
+    mediaControls->reset();
+    if (isFullscreen())
+        mediaControls->enteredFullscreen();
+
+    ensureUserAgentShadowRoot()->appendChild(mediaControls, ASSERT_NO_EXCEPTION);
+
+    if (!controls() || !inDocument())
+        mediaControls->hide();
+
+    return true;
+}
+
+void HTMLMediaElement::configureMediaControls()
+{
+    if (!controls() || !inDocument()) {
+        if (hasMediaControls())
+            mediaControls()->hide();
+        return;
+    }
+
+    if (!hasMediaControls() && !createMediaControls())
+        return;
+
+    mediaControls()->show();
+}
+
+void HTMLMediaElement::configureTextTrackDisplay()
+{
+    ASSERT(m_textTracks);
+    LOG(Media, "HTMLMediaElement::configureTextTrackDisplay");
+
+    if (m_processingPreferenceChange)
+        return;
+
+    bool haveVisibleTextTrack = false;
+    for (unsigned i = 0; i < m_textTracks->length(); ++i) {
+        if (m_textTracks->item(i)->mode() == TextTrack::showingKeyword()) {
+            haveVisibleTextTrack = true;
+            break;
+        }
+    }
+
+    if (m_haveVisibleTextTrack == haveVisibleTextTrack)
+        return;
+    m_haveVisibleTextTrack = haveVisibleTextTrack;
+    m_closedCaptionsVisible = m_haveVisibleTextTrack;
+
+    if (!m_haveVisibleTextTrack && !hasMediaControls())
+        return;
+    if (!hasMediaControls() && !createMediaControls())
+        return;
+
+    mediaControls()->changedClosedCaptionsVisibility();
+
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        updateTextTrackDisplay();
+}
+
+void HTMLMediaElement::captionPreferencesChanged()
+{
+    if (!isVideo())
+        return;
+
+    if (hasMediaControls())
+        mediaControls()->textTrackPreferencesChanged();
+
+    setClosedCaptionsVisible(userPrefersCaptions());
+}
+
+void HTMLMediaElement::markCaptionAndSubtitleTracksAsUnconfigured()
+{
+    if (!m_textTracks)
+        return;
+
+    // Mark all tracks as not "configured" so that configureTextTracks()
+    // will reconsider which tracks to display in light of new user preferences
+    // (e.g. default tracks should not be displayed if the user has turned off
+    // captions and non-default tracks should be displayed based on language
+    // preferences if the user has turned captions on).
+    for (unsigned i = 0; i < m_textTracks->length(); ++i) {
+        RefPtr<TextTrack> textTrack = m_textTracks->item(i);
+        String kind = textTrack->kind();
+
+        if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword())
+            textTrack->setHasBeenConfigured(false);
+    }
+    configureTextTracks();
+}
+
+
+void* HTMLMediaElement::preDispatchEventHandler(Event* event)
+{
+    if (event && event->type() == eventNames().webkitfullscreenchangeEvent)
+        configureMediaControls();
+
+    return 0;
+}
+
+void HTMLMediaElement::createMediaPlayer()
+{
+#if ENABLE(WEB_AUDIO)
+    if (m_audioSourceNode)
+        m_audioSourceNode->lock();
+#endif
+
+    if (m_mediaSource)
+        m_mediaSource->setReadyState(MediaSource::closedKeyword());
+
+    m_player = MediaPlayer::create(this);
+
+#if ENABLE(WEB_AUDIO)
+    if (m_audioSourceNode) {
+        // When creating the player, make sure its AudioSourceProvider knows about the MediaElementAudioSourceNode.
+        if (audioSourceProvider())
+            audioSourceProvider()->setClient(m_audioSourceNode);
+
+        m_audioSourceNode->unlock();
+    }
+#endif
+}
+
+#if ENABLE(WEB_AUDIO)
+void HTMLMediaElement::setAudioSourceNode(MediaElementAudioSourceNode* sourceNode)
+{
+    m_audioSourceNode = sourceNode;
+
+    if (audioSourceProvider())
+        audioSourceProvider()->setClient(m_audioSourceNode);
+}
+
+AudioSourceProvider* HTMLMediaElement::audioSourceProvider()
+{
+    if (m_player)
+        return m_player->audioSourceProvider();
+
+    return 0;
+}
+#endif
+
+const String& HTMLMediaElement::mediaGroup() const
+{
+    return m_mediaGroup;
+}
+
+void HTMLMediaElement::setMediaGroup(const String& group)
+{
+    if (m_mediaGroup == group)
+        return;
+    m_mediaGroup = group;
+
+    // When a media element is created with a mediagroup attribute, and when a media element's mediagroup
+    // attribute is set, changed, or removed, the user agent must run the following steps:
+    // 1. Let m [this] be the media element in question.
+    // 2. Let m have no current media controller, if it currently has one.
+    setController(0);
+
+    // 3. If m's mediagroup attribute is being removed, then abort these steps.
+    if (group.isNull() || group.isEmpty())
+        return;
+
+    // 4. If there is another media element whose Document is the same as m's Document (even if one or both
+    // of these elements are not actually in the Document),
+    HashSet<HTMLMediaElement*> elements = documentToElementSetMap().get(document());
+    for (HashSet<HTMLMediaElement*>::iterator i = elements.begin(); i != elements.end(); ++i) {
+        if (*i == this)
+            continue;
+
+        // and which also has a mediagroup attribute, and whose mediagroup attribute has the same value as
+        // the new value of m's mediagroup attribute,
+        if ((*i)->mediaGroup() == group) {
+            //  then let controller be that media element's current media controller.
+            setController((*i)->controller());
+            return;
+        }
+    }
+
+    // Otherwise, let controller be a newly created MediaController.
+    setController(MediaController::create(Node::scriptExecutionContext()));
+}
+
+MediaController* HTMLMediaElement::controller() const
+{
+    return m_mediaController.get();
+}
+
+void HTMLMediaElement::setController(PassRefPtr<MediaController> controller)
+{
+    if (m_mediaController)
+        m_mediaController->removeMediaElement(this);
+
+    m_mediaController = controller;
+
+    if (m_mediaController)
+        m_mediaController->addMediaElement(this);
+
+    if (hasMediaControls())
+        mediaControls()->setMediaController(m_mediaController ? m_mediaController.get() : static_cast<MediaControllerInterface*>(this));
+}
+
+void HTMLMediaElement::updateMediaController()
+{
+    if (m_mediaController)
+        m_mediaController->reportControllerState();
+}
+
+bool HTMLMediaElement::dispatchEvent(PassRefPtr<Event> event)
+{
+    bool dispatchResult;
+    bool isCanPlayEvent;
+
+    isCanPlayEvent = (event->type() == eventNames().canplayEvent);
+
+    if (isCanPlayEvent)
+        m_dispatchingCanPlayEvent = true;
+
+    dispatchResult = HTMLElement::dispatchEvent(event);
+
+    if (isCanPlayEvent)
+        m_dispatchingCanPlayEvent = false;
+
+    return dispatchResult;
+}
+
+bool HTMLMediaElement::isBlocked() const
+{
+    // A media element is a blocked media element if its readyState attribute is in the
+    // HAVE_NOTHING state, the HAVE_METADATA state, or the HAVE_CURRENT_DATA state,
+    if (m_readyState <= HAVE_CURRENT_DATA)
+        return true;
+
+    // or if the element has paused for user interaction.
+    return pausedForUserInteraction();
+}
+
+bool HTMLMediaElement::isBlockedOnMediaController() const
+{
+    if (!m_mediaController)
+        return false;
+
+    // A media element is blocked on its media controller if the MediaController is a blocked
+    // media controller,
+    if (m_mediaController->isBlocked())
+        return true;
+
+    // or if its media controller position is either before the media resource's earliest possible
+    // position relative to the MediaController's timeline or after the end of the media resource
+    // relative to the MediaController's timeline.
+    double mediaControllerPosition = m_mediaController->currentTime();
+    if (mediaControllerPosition < startTime() || mediaControllerPosition > startTime() + duration())
+        return true;
+
+    return false;
+}
+
+void HTMLMediaElement::prepareMediaFragmentURI()
+{
+    MediaFragmentURIParser fragmentParser(m_currentSrc);
+    double dur = duration();
+
+    double start = fragmentParser.startTime();
+    if (start != MediaFragmentURIParser::invalidTimeValue() && start > 0) {
+        m_fragmentStartTime = start;
+        if (m_fragmentStartTime > dur)
+            m_fragmentStartTime = dur;
+    } else
+        m_fragmentStartTime = MediaPlayer::invalidTime();
+
+    double end = fragmentParser.endTime();
+    if (end != MediaFragmentURIParser::invalidTimeValue() && end > 0 && end > m_fragmentStartTime) {
+        m_fragmentEndTime = end;
+        if (m_fragmentEndTime > dur)
+            m_fragmentEndTime = dur;
+    } else
+        m_fragmentEndTime = MediaPlayer::invalidTime();
+
+    if (m_fragmentStartTime != MediaPlayer::invalidTime() && m_readyState < HAVE_FUTURE_DATA)
+        prepareToPlay();
+}
+
+void HTMLMediaElement::applyMediaFragmentURI()
+{
+    if (m_fragmentStartTime != MediaPlayer::invalidTime()) {
+        m_sentEndEvent = false;
+        seek(m_fragmentStartTime, IGNORE_EXCEPTION);
+    }
+}
+
+String HTMLMediaElement::mediaPlayerReferrer() const
+{
+    Frame* frame = document()->frame();
+    if (!frame)
+        return String();
+
+    return SecurityPolicy::generateReferrerHeader(document()->referrerPolicy(), m_currentSrc, frame->loader()->outgoingReferrer());
+}
+
+String HTMLMediaElement::mediaPlayerUserAgent() const
+{
+    Frame* frame = document()->frame();
+    if (!frame)
+        return String();
+
+    return frame->loader()->userAgent(m_currentSrc);
+
+}
+
+MediaPlayerClient::CORSMode HTMLMediaElement::mediaPlayerCORSMode() const
+{
+    if (!fastHasAttribute(HTMLNames::crossoriginAttr))
+        return Unspecified;
+    if (equalIgnoringCase(fastGetAttribute(HTMLNames::crossoriginAttr), "use-credentials"))
+        return UseCredentials;
+    return Anonymous;
+}
+
+bool HTMLMediaElement::mediaPlayerNeedsSiteSpecificHacks() const
+{
+    Settings* settings = document()->settings();
+    return settings && settings->needsSiteSpecificQuirks();
+}
+
+String HTMLMediaElement::mediaPlayerDocumentHost() const
+{
+    return document()->url().host();
+}
+
+void HTMLMediaElement::mediaPlayerEnterFullscreen()
+{
+    enterFullscreen();
+}
+
+void HTMLMediaElement::mediaPlayerExitFullscreen()
+{
+    exitFullscreen();
+}
+
+bool HTMLMediaElement::mediaPlayerIsFullscreen() const
+{
+    return isFullscreen();
+}
+
+bool HTMLMediaElement::mediaPlayerIsFullscreenPermitted() const
+{
+    return !userGestureRequiredForFullscreen() || ScriptController::processingUserGesture();
+}
+
+bool HTMLMediaElement::mediaPlayerIsVideo() const
+{
+    return isVideo();
+}
+
+LayoutRect HTMLMediaElement::mediaPlayerContentBoxRect() const
+{
+    if (renderer())
+        return renderer()->enclosingBox()->contentBoxRect();
+    return LayoutRect();
+}
+
+void HTMLMediaElement::mediaPlayerSetSize(const IntSize& size)
+{
+    setAttribute(widthAttr, String::number(size.width()));
+    setAttribute(heightAttr, String::number(size.height()));
+}
+
+void HTMLMediaElement::mediaPlayerPause()
+{
+    pause();
+}
+
+void HTMLMediaElement::mediaPlayerPlay()
+{
+    play();
+}
+
+bool HTMLMediaElement::mediaPlayerIsPaused() const
+{
+    return paused();
+}
+
+bool HTMLMediaElement::mediaPlayerIsLooping() const
+{
+    return loop();
+}
+
+HostWindow* HTMLMediaElement::mediaPlayerHostWindow()
+{
+    return mediaPlayerOwningDocument()->view()->hostWindow();
+}
+
+IntRect HTMLMediaElement::mediaPlayerWindowClipRect()
+{
+    return mediaPlayerOwningDocument()->view()->windowClipRect();
+}
+
+CachedResourceLoader* HTMLMediaElement::mediaPlayerCachedResourceLoader()
+{
+    return mediaPlayerOwningDocument()->cachedResourceLoader();
+}
+
+void HTMLMediaElement::removeBehaviorsRestrictionsAfterFirstUserGesture()
+{
+    m_restrictions = NoRestrictions;
+}
+
+void HTMLMediaElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
+    HTMLElement::reportMemoryUsage(memoryObjectInfo);
+    ActiveDOMObject::reportMemoryUsage(memoryObjectInfo);
+    info.addMember(m_loadTimer, "loadTimer");
+    info.addMember(m_progressEventTimer, "progressEventTimer");
+    info.addMember(m_playbackProgressTimer, "playbackProgressTimer");
+    info.addMember(m_playedTimeRanges, "playedTimeRanges");
+    info.addMember(m_asyncEventQueue, "asyncEventQueue");
+    info.addMember(m_currentSrc, "currentSrc");
+    info.addMember(m_error, "error");
+    info.addMember(m_currentSourceNode, "currentSourceNode");
+    info.addMember(m_nextChildNodeToConsider, "nextChildNodeToConsider");
+    info.addMember(m_player, "player");
+    info.addMember(m_mediaSource, "mediaSource");
+    info.addMember(m_textTracks, "textTracks");
+    info.addMember(m_textTracksWhenResourceSelectionBegan, "textTracksWhenResourceSelectionBegan");
+    info.addMember(m_cueTree, "cueTree");
+    info.addMember(m_currentlyActiveCues, "currentlyActiveCues");
+    info.addMember(m_mediaGroup, "mediaGroup");
+    info.addMember(m_mediaController, "mediaController");
+
+#if ENABLE(WEB_AUDIO)
+    info.addMember(m_audioSourceNode, "audioSourceNode");
+#endif
+
+}
+
+}
diff --git a/Source/core/html/HTMLMediaElement.h b/Source/core/html/HTMLMediaElement.h
new file mode 100644
index 0000000..e30ce8b
--- /dev/null
+++ b/Source/core/html/HTMLMediaElement.h
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 COMPUTER, 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 COMPUTER, 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 HTMLMediaElement_h
+#define HTMLMediaElement_h
+
+#include "core/dom/ActiveDOMObject.h"
+#include "core/dom/GenericEventQueue.h"
+#include "core/html/HTMLElement.h"
+#include "core/html/MediaControllerInterface.h"
+#include "core/platform/graphics/MediaPlayer.h"
+
+#include "core/html/track/TextTrack.h"
+#include "core/html/track/TextTrackCue.h"
+#include "core/platform/PODIntervalTree.h"
+
+namespace WebCore {
+
+#if ENABLE(WEB_AUDIO)
+class AudioSourceProvider;
+class MediaElementAudioSourceNode;
+#endif
+class Event;
+class HTMLSourceElement;
+class HTMLTrackElement;
+class MediaController;
+class MediaControls;
+class MediaError;
+class KURL;
+class TextTrackList;
+class TimeRanges;
+#if ENABLE(ENCRYPTED_MEDIA_V2)
+class MediaKeys;
+#endif
+
+class InbandTextTrackPrivate;
+
+typedef PODIntervalTree<double, TextTrackCue*> CueIntervalTree;
+typedef CueIntervalTree::IntervalType CueInterval;
+typedef Vector<CueInterval> CueList;
+
+// FIXME: The inheritance from MediaPlayerClient here should be private inheritance.
+// But it can't be until the Chromium WebMediaPlayerClientImpl class is fixed so it
+// no longer depends on typecasting a MediaPlayerClient to an HTMLMediaElement.
+
+class HTMLMediaElement : public HTMLElement, public MediaPlayerClient, public MediaPlayerSupportsTypeClient, public ActiveDOMObject, public MediaControllerInterface
+    , private TextTrackClient
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    , public PlatformTextTrackMenuClient
+#endif
+{
+public:
+    MediaPlayer* player() const { return m_player.get(); }
+
+    virtual bool isVideo() const = 0;
+    virtual bool hasVideo() const { return false; }
+    virtual bool hasAudio() const;
+
+    void rewind(double timeDelta);
+    void returnToRealtime();
+
+    // Eventually overloaded in HTMLVideoElement
+    virtual bool supportsFullscreen() const { return false; };
+
+    virtual bool supportsSave() const;
+    virtual bool supportsScanning() const;
+    
+    PlatformMedia platformMedia() const;
+    PlatformLayer* platformLayer() const;
+
+    enum DelayedActionType {
+        LoadMediaResource = 1 << 0,
+        LoadTextTrackResource = 1 << 1,
+        TextTrackChangesNotification = 1 << 2
+    };
+    void scheduleDelayedAction(DelayedActionType);
+    
+    MediaPlayer::MovieLoadType movieLoadType() const;
+    
+    bool inActiveDocument() const { return m_inActiveDocument; }
+    
+// DOM API
+// error state
+    PassRefPtr<MediaError> error() const;
+
+// network state
+    void setSrc(const String&);
+    const KURL& currentSrc() const { return m_currentSrc; }
+
+    enum NetworkState { NETWORK_EMPTY, NETWORK_IDLE, NETWORK_LOADING, NETWORK_NO_SOURCE };
+    NetworkState networkState() const;
+
+    String preload() const;    
+    void setPreload(const String&);
+
+    PassRefPtr<TimeRanges> buffered() const;
+    void load();
+    String canPlayType(const String& mimeType, const String& keySystem = String(), const KURL& = KURL()) const;
+
+// ready state
+    ReadyState readyState() const;
+    bool seeking() const;
+
+// playback state
+    double currentTime() const;
+    void setCurrentTime(double, ExceptionCode&);
+    double initialTime() const;
+    double startTime() const;
+    double duration() const;
+    bool paused() const;
+    double defaultPlaybackRate() const;
+    void setDefaultPlaybackRate(double);
+    double playbackRate() const;
+    void setPlaybackRate(double);
+    void updatePlaybackRate();
+    bool webkitPreservesPitch() const;
+    void setWebkitPreservesPitch(bool);
+    PassRefPtr<TimeRanges> played();
+    PassRefPtr<TimeRanges> seekable() const;
+    bool ended() const;
+    bool autoplay() const;    
+    void setAutoplay(bool b);
+    bool loop() const;    
+    void setLoop(bool b);
+    void play();
+    void pause();
+
+// captions
+    bool webkitHasClosedCaptions() const;
+    bool webkitClosedCaptionsVisible() const;
+    void setWebkitClosedCaptionsVisible(bool);
+
+// Statistics
+    unsigned webkitAudioDecodedByteCount() const;
+    unsigned webkitVideoDecodedByteCount() const;
+
+//  Media Source.
+    void setSourceState(const String&);
+
+#if ENABLE(ENCRYPTED_MEDIA)
+    void webkitGenerateKeyRequest(const String& keySystem, PassRefPtr<Uint8Array> initData, ExceptionCode&);
+    void webkitGenerateKeyRequest(const String& keySystem, ExceptionCode&);
+    void webkitAddKey(const String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> initData, const String& sessionId, ExceptionCode&);
+    void webkitAddKey(const String& keySystem, PassRefPtr<Uint8Array> key, ExceptionCode&);
+    void webkitCancelKeyRequest(const String& keySystem, const String& sessionId, ExceptionCode&);
+
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitkeyadded);
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitkeyerror);
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitkeymessage);
+#endif
+#if ENABLE(ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA_V2)
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitneedkey);
+#endif
+
+#if ENABLE(ENCRYPTED_MEDIA_V2)
+    MediaKeys* mediaKeys() const { return m_mediaKeys.get(); }
+    void setMediaKeys(MediaKeys*);
+#endif
+
+// controls
+    bool controls() const;
+    void setControls(bool);
+    double volume() const;
+    void setVolume(double, ExceptionCode&);
+    bool muted() const;
+    void setMuted(bool);
+
+    void togglePlayState();
+    void beginScrubbing();
+    void endScrubbing();
+    
+    bool canPlay() const;
+
+    double percentLoaded() const;
+
+    PassRefPtr<TextTrack> addTextTrack(const String& kind, const String& label, const String& language, ExceptionCode&);
+    PassRefPtr<TextTrack> addTextTrack(const String& kind, const String& label, ExceptionCode& ec) { return addTextTrack(kind, label, emptyString(), ec); }
+    PassRefPtr<TextTrack> addTextTrack(const String& kind, ExceptionCode& ec) { return addTextTrack(kind, emptyString(), emptyString(), ec); }
+
+    TextTrackList* textTracks();
+    CueList currentlyActiveCues() const { return m_currentlyActiveCues; }
+
+    void addTrack(TextTrack*);
+    void removeTrack(TextTrack*);
+    void removeAllInbandTracks();
+    void closeCaptionTracksChanged();
+    void notifyMediaPlayerOfTextTrackChanges();
+
+    virtual void didAddTrack(HTMLTrackElement*);
+    virtual void didRemoveTrack(HTMLTrackElement*);
+
+    virtual void mediaPlayerDidAddTrack(PassRefPtr<InbandTextTrackPrivate>) OVERRIDE;
+    virtual void mediaPlayerDidRemoveTrack(PassRefPtr<InbandTextTrackPrivate>) OVERRIDE;
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    virtual void setSelectedTextTrack(PassRefPtr<PlatformTextTrack>) OVERRIDE;
+    virtual Vector<RefPtr<PlatformTextTrack> > platformTextTracks() OVERRIDE;
+    PlatformTextTrackMenuInterface* platformTextTrackMenu();
+#endif
+
+    struct TrackGroup {
+        enum GroupKind { CaptionsAndSubtitles, Description, Chapter, Metadata, Other };
+
+        TrackGroup(GroupKind kind)
+            : visibleTrack(0)
+            , defaultTrack(0)
+            , kind(kind)
+            , hasSrcLang(false)
+        {
+        }
+
+        Vector<RefPtr<TextTrack> > tracks;
+        RefPtr<TextTrack> visibleTrack;
+        RefPtr<TextTrack> defaultTrack;
+        GroupKind kind;
+        bool hasSrcLang;
+    };
+
+    void configureTextTrackGroupForLanguage(const TrackGroup&) const;
+    void configureTextTracks();
+    void configureTextTrackGroup(const TrackGroup&);
+
+    void setSelectedTextTrack(TextTrack*);
+    static int textTracksOffIndex() { return -1; }
+    static int textTracksIndexNotFound() { return -2; }
+
+    bool userPrefersCaptions() const;
+    bool textTracksAreReady() const;
+    void configureTextTrackDisplay();
+    void updateTextTrackDisplay();
+
+    // TextTrackClient
+    virtual void textTrackReadyStateChanged(TextTrack*);
+    virtual void textTrackKindChanged(TextTrack*);
+    virtual void textTrackModeChanged(TextTrack*);
+    virtual void textTrackAddCues(TextTrack*, const TextTrackCueList*);
+    virtual void textTrackRemoveCues(TextTrack*, const TextTrackCueList*);
+    virtual void textTrackAddCue(TextTrack*, PassRefPtr<TextTrackCue>);
+    virtual void textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue>);
+
+    bool requiresTextTrackRepresentation() const;
+    void setTextTrackRepresentation(TextTrackRepresentation*);
+
+    // EventTarget function.
+    // Both Node (via HTMLElement) and ActiveDOMObject define this method, which
+    // causes an ambiguity error at compile time. This class's constructor
+    // ensures that both implementations return document, so return the result
+    // of one of them here.
+    virtual ScriptExecutionContext* scriptExecutionContext() const OVERRIDE { return HTMLElement::scriptExecutionContext(); }
+
+    bool hasSingleSecurityOrigin() const { return !m_player || m_player->hasSingleSecurityOrigin(); }
+    
+    bool isFullscreen() const;
+    void enterFullscreen();
+    void exitFullscreen();
+
+    bool hasClosedCaptions() const;
+    bool closedCaptionsVisible() const;
+    void setClosedCaptionsVisible(bool);
+
+    MediaControls* mediaControls() const;
+
+    void sourceWasRemoved(HTMLSourceElement*);
+    void sourceWasAdded(HTMLSourceElement*);
+
+    // Media cache management.
+    static void getSitesInMediaCache(Vector<String>&);
+    static void clearMediaCache();
+    static void clearMediaCacheForSite(const String&);
+    static void resetMediaEngines();
+
+    bool isPlaying() const { return m_playing; }
+
+    virtual bool hasPendingActivity() const;
+
+#if ENABLE(WEB_AUDIO)
+    MediaElementAudioSourceNode* audioSourceNode() { return m_audioSourceNode; }
+    void setAudioSourceNode(MediaElementAudioSourceNode*);
+
+    AudioSourceProvider* audioSourceProvider();
+#endif
+
+    enum InvalidURLAction { DoNothing, Complain };
+    bool isSafeToLoadURL(const KURL&, InvalidURLAction);
+
+    const String& mediaGroup() const;
+    void setMediaGroup(const String&);
+
+    MediaController* controller() const;
+    void setController(PassRefPtr<MediaController>);
+
+    virtual bool dispatchEvent(PassRefPtr<Event>) OVERRIDE;
+
+    virtual void reportMemoryUsage(MemoryObjectInfo*) const;
+
+protected:
+    HTMLMediaElement(const QualifiedName&, Document*, bool);
+    virtual ~HTMLMediaElement();
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual void finishParsingChildren();
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+    virtual void attach() OVERRIDE;
+
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+
+    enum DisplayMode { Unknown, None, Poster, PosterWaitingForVideo, Video };
+    DisplayMode displayMode() const { return m_displayMode; }
+    virtual void setDisplayMode(DisplayMode mode) { m_displayMode = mode; }
+    
+    virtual bool isMediaElement() const { return true; }
+
+    // Restrictions to change default behaviors.
+    enum BehaviorRestrictionFlags {
+        NoRestrictions = 0,
+        RequireUserGestureForLoadRestriction = 1 << 0,
+        RequireUserGestureForRateChangeRestriction = 1 << 1,
+        RequireUserGestureForFullscreenRestriction = 1 << 2,
+        RequirePageConsentToLoadMediaRestriction = 1 << 3,
+    };
+    typedef unsigned BehaviorRestrictions;
+    
+    bool userGestureRequiredForLoad() const { return m_restrictions & RequireUserGestureForLoadRestriction; }
+    bool userGestureRequiredForRateChange() const { return m_restrictions & RequireUserGestureForRateChangeRestriction; }
+    bool userGestureRequiredForFullscreen() const { return m_restrictions & RequireUserGestureForFullscreenRestriction; }
+    bool pageConsentRequiredForLoad() const { return m_restrictions & RequirePageConsentToLoadMediaRestriction; }
+    
+    void addBehaviorRestriction(BehaviorRestrictions restriction) { m_restrictions |= restriction; }
+    void removeBehaviorRestriction(BehaviorRestrictions restriction) { m_restrictions &= ~restriction; }
+
+    bool ignoreTrackDisplayUpdateRequests() const { return m_ignoreTrackDisplayUpdate > 0; }
+    void beginIgnoringTrackDisplayUpdateRequests();
+    void endIgnoringTrackDisplayUpdateRequests();
+
+private:
+    void createMediaPlayer();
+
+    virtual bool alwaysCreateUserAgentShadowRoot() const OVERRIDE { return true; }
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+
+    virtual bool hasCustomFocusLogic() const OVERRIDE;
+    virtual bool supportsFocus() const;
+    virtual bool isMouseFocusable() const;
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const OVERRIDE;
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual void didRecalcStyle(StyleChange);
+    
+    virtual void didBecomeFullscreenElement();
+    virtual void willStopBeingFullscreenElement();
+
+    // ActiveDOMObject functions.
+    virtual bool canSuspend() const;
+    virtual void suspend(ReasonForSuspension);
+    virtual void resume();
+    virtual void stop();
+
+    virtual void updateDisplayState() { }
+    
+    void setReadyState(MediaPlayer::ReadyState);
+    void setNetworkState(MediaPlayer::NetworkState);
+
+    virtual Document* mediaPlayerOwningDocument();
+    virtual void mediaPlayerNetworkStateChanged(MediaPlayer*);
+    virtual void mediaPlayerReadyStateChanged(MediaPlayer*);
+    virtual void mediaPlayerTimeChanged(MediaPlayer*);
+    virtual void mediaPlayerVolumeChanged(MediaPlayer*);
+    virtual void mediaPlayerMuteChanged(MediaPlayer*);
+    virtual void mediaPlayerDurationChanged(MediaPlayer*);
+    virtual void mediaPlayerRateChanged(MediaPlayer*);
+    virtual void mediaPlayerPlaybackStateChanged(MediaPlayer*);
+    virtual void mediaPlayerSawUnsupportedTracks(MediaPlayer*);
+    virtual void mediaPlayerResourceNotSupported(MediaPlayer*);
+    virtual void mediaPlayerRepaint(MediaPlayer*);
+    virtual void mediaPlayerSizeChanged(MediaPlayer*);
+    virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*);
+    virtual void mediaPlayerRenderingModeChanged(MediaPlayer*);
+    virtual void mediaPlayerEngineUpdated(MediaPlayer*);
+    
+    virtual void mediaPlayerFirstVideoFrameAvailable(MediaPlayer*);
+    virtual void mediaPlayerCharacteristicChanged(MediaPlayer*);
+
+#if ENABLE(ENCRYPTED_MEDIA)
+    virtual void mediaPlayerKeyAdded(MediaPlayer*, const String& keySystem, const String& sessionId) OVERRIDE;
+    virtual void mediaPlayerKeyError(MediaPlayer*, const String& keySystem, const String& sessionId, MediaPlayerClient::MediaKeyErrorCode, unsigned short systemCode) OVERRIDE;
+    virtual void mediaPlayerKeyMessage(MediaPlayer*, const String& keySystem, const String& sessionId, const unsigned char* message, unsigned messageLength, const KURL& defaultURL) OVERRIDE;
+    virtual bool mediaPlayerKeyNeeded(MediaPlayer*, const String& keySystem, const String& sessionId, const unsigned char* initData, unsigned initDataLength) OVERRIDE;
+#endif
+
+#if ENABLE(ENCRYPTED_MEDIA_V2)
+    virtual bool mediaPlayerKeyNeeded(MediaPlayer*, Uint8Array*);
+#endif
+
+    virtual String mediaPlayerReferrer() const OVERRIDE;
+    virtual String mediaPlayerUserAgent() const OVERRIDE;
+    virtual CORSMode mediaPlayerCORSMode() const OVERRIDE;
+
+    virtual bool mediaPlayerNeedsSiteSpecificHacks() const OVERRIDE;
+    virtual String mediaPlayerDocumentHost() const OVERRIDE;
+
+    virtual void mediaPlayerEnterFullscreen() OVERRIDE;
+    virtual void mediaPlayerExitFullscreen() OVERRIDE;
+    virtual bool mediaPlayerIsFullscreen() const OVERRIDE;
+    virtual bool mediaPlayerIsFullscreenPermitted() const OVERRIDE;
+    virtual bool mediaPlayerIsVideo() const OVERRIDE;
+    virtual LayoutRect mediaPlayerContentBoxRect() const OVERRIDE;
+    virtual void mediaPlayerSetSize(const IntSize&) OVERRIDE;
+    virtual void mediaPlayerPause() OVERRIDE;
+    virtual void mediaPlayerPlay() OVERRIDE;
+    virtual bool mediaPlayerIsPaused() const OVERRIDE;
+    virtual bool mediaPlayerIsLooping() const OVERRIDE;
+    virtual HostWindow* mediaPlayerHostWindow() OVERRIDE;
+    virtual IntRect mediaPlayerWindowClipRect() OVERRIDE;
+    virtual CachedResourceLoader* mediaPlayerCachedResourceLoader() OVERRIDE;
+
+    void loadTimerFired(Timer<HTMLMediaElement>*);
+    void progressEventTimerFired(Timer<HTMLMediaElement>*);
+    void playbackProgressTimerFired(Timer<HTMLMediaElement>*);
+    void startPlaybackProgressTimer();
+    void startProgressEventTimer();
+    void stopPeriodicTimers();
+
+    void seek(double time, ExceptionCode&);
+    void finishSeek();
+    void checkIfSeekNeeded();
+    void addPlayedRange(double start, double end);
+    
+    void scheduleTimeupdateEvent(bool periodicEvent);
+    void scheduleEvent(const AtomicString& eventName);
+    
+    // loading
+    void selectMediaResource();
+    void loadResource(const KURL&, ContentType&, const String& keySystem);
+    void scheduleNextSourceChild();
+    void loadNextSourceChild();
+    void userCancelledLoad();
+    void clearMediaPlayer(int flags);
+    bool havePotentialSourceChild();
+    void noneSupported();
+    void mediaEngineError(PassRefPtr<MediaError> err);
+    void cancelPendingEventsAndCallbacks();
+    void waitForSourceChange();
+    void prepareToPlay();
+
+    KURL selectNextSourceChild(ContentType*, String* keySystem, InvalidURLAction);
+
+    void mediaLoadingFailed(MediaPlayer::NetworkState);
+
+    void updateActiveTextTrackCues(double);
+    HTMLTrackElement* showingTrackWithSameKind(HTMLTrackElement*) const;
+
+    void markCaptionAndSubtitleTracksAsUnconfigured();
+    virtual void captionPreferencesChanged() OVERRIDE;
+
+    // These "internal" functions do not check user gesture restrictions.
+    void loadInternal();
+    void playInternal();
+    void pauseInternal();
+
+    void prepareForLoad();
+    void allowVideoRendering();
+
+    bool processingMediaPlayerCallback() const { return m_processingMediaPlayerCallback > 0; }
+    void beginProcessingMediaPlayerCallback() { ++m_processingMediaPlayerCallback; }
+    void endProcessingMediaPlayerCallback() { ASSERT(m_processingMediaPlayerCallback); --m_processingMediaPlayerCallback; }
+
+    void updateVolume();
+    void updatePlayState();
+    bool potentiallyPlaying() const;
+    bool endedPlayback() const;
+    bool stoppedDueToErrors() const;
+    bool pausedForUserInteraction() const;
+    bool couldPlayIfEnoughData() const;
+
+    double minTimeSeekable() const;
+    double maxTimeSeekable() const;
+
+    // Pauses playback without changing any states or generating events
+    void setPausedInternal(bool);
+
+    void setPlaybackRateInternal(double);
+
+    void setShouldDelayLoadEvent(bool);
+    void invalidateCachedTime();
+    void refreshCachedTime() const;
+
+    bool hasMediaControls() const;
+    bool createMediaControls();
+    void configureMediaControls();
+
+    void prepareMediaFragmentURI();
+    void applyMediaFragmentURI();
+
+    virtual void* preDispatchEventHandler(Event*);
+
+    void changeNetworkStateFromLoadingToIdle();
+
+    void removeBehaviorsRestrictionsAfterFirstUserGesture();
+
+    void updateMediaController();
+    bool isBlocked() const;
+    bool isBlockedOnMediaController() const;
+    bool hasCurrentSrc() const { return !m_currentSrc.isEmpty(); }
+    bool isLiveStream() const { return movieLoadType() == MediaPlayer::LiveStream; }
+    bool isAutoplaying() const { return m_autoplaying; }
+
+    Timer<HTMLMediaElement> m_loadTimer;
+    Timer<HTMLMediaElement> m_progressEventTimer;
+    Timer<HTMLMediaElement> m_playbackProgressTimer;
+    RefPtr<TimeRanges> m_playedTimeRanges;
+    OwnPtr<GenericEventQueue> m_asyncEventQueue;
+
+    double m_playbackRate;
+    double m_defaultPlaybackRate;
+    bool m_webkitPreservesPitch;
+    NetworkState m_networkState;
+    ReadyState m_readyState;
+    ReadyState m_readyStateMaximum;
+    KURL m_currentSrc;
+
+    RefPtr<MediaError> m_error;
+
+    double m_volume;
+    double m_lastSeekTime;
+    
+    unsigned m_previousProgress;
+    double m_previousProgressTime;
+
+    // The last time a timeupdate event was sent (wall clock).
+    double m_lastTimeUpdateEventWallTime;
+
+    // The last time a timeupdate event was sent in movie time.
+    double m_lastTimeUpdateEventMovieTime;
+    
+    // Loading state.
+    enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement };
+    LoadState m_loadState;
+    RefPtr<HTMLSourceElement> m_currentSourceNode;
+    RefPtr<Node> m_nextChildNodeToConsider;
+
+    OwnPtr<MediaPlayer> m_player;
+
+    BehaviorRestrictions m_restrictions;
+    
+    MediaPlayer::Preload m_preload;
+
+    DisplayMode m_displayMode;
+
+    // Counter incremented while processing a callback from the media player, so we can avoid
+    // calling the media engine recursively.
+    int m_processingMediaPlayerCallback;
+
+    RefPtr<MediaSource> m_mediaSource;
+
+    mutable double m_cachedTime;
+    mutable double m_cachedTimeWallClockUpdateTime;
+    mutable double m_minimumWallClockTimeToCacheMediaTime;
+
+    double m_fragmentStartTime;
+    double m_fragmentEndTime;
+
+    typedef unsigned PendingActionFlags;
+    PendingActionFlags m_pendingActionFlags;
+
+    bool m_playing : 1;
+    bool m_shouldDelayLoadEvent : 1;
+    bool m_haveFiredLoadedData : 1;
+    bool m_inActiveDocument : 1;
+    bool m_autoplaying : 1;
+    bool m_muted : 1;
+    bool m_paused : 1;
+    bool m_seeking : 1;
+
+    // data has not been loaded since sending a "stalled" event
+    bool m_sentStalledEvent : 1;
+
+    // time has not changed since sending an "ended" event
+    bool m_sentEndEvent : 1;
+
+    bool m_pausedInternal : 1;
+
+    // Not all media engines provide enough information about a file to be able to
+    // support progress events so setting m_sendProgressEvents disables them 
+    bool m_sendProgressEvents : 1;
+
+    bool m_closedCaptionsVisible : 1;
+
+    bool m_dispatchingCanPlayEvent : 1;
+    bool m_loadInitiatedByUserGesture : 1;
+    bool m_completelyLoaded : 1;
+    bool m_havePreparedToPlay : 1;
+    bool m_parsingInProgress : 1;
+
+    bool m_tracksAreReady : 1;
+    bool m_haveVisibleTextTrack : 1;
+    bool m_processingPreferenceChange : 1;
+    double m_lastTextTrackUpdateTime;
+
+    RefPtr<TextTrackList> m_textTracks;
+    Vector<RefPtr<TextTrack> > m_textTracksWhenResourceSelectionBegan;
+
+    CueIntervalTree m_cueTree;
+
+    CueList m_currentlyActiveCues;
+    int m_ignoreTrackDisplayUpdate;
+
+#if ENABLE(WEB_AUDIO)
+    // This is a weak reference, since m_audioSourceNode holds a reference to us.
+    // The value is set just after the MediaElementAudioSourceNode is created.
+    // The value is cleared in MediaElementAudioSourceNode::~MediaElementAudioSourceNode().
+    MediaElementAudioSourceNode* m_audioSourceNode;
+#endif
+
+    String m_mediaGroup;
+    friend class MediaController;
+    RefPtr<MediaController> m_mediaController;
+
+    friend class TrackDisplayUpdateScope;
+
+#if ENABLE(ENCRYPTED_MEDIA_V2)
+    RefPtr<MediaKeys> m_mediaKeys;
+#endif
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    RefPtr<PlatformTextTrackMenuInterface> m_platformMenu;
+#endif
+};
+
+#ifndef NDEBUG
+// Template specializations required by PodIntervalTree in debug mode.
+template <>
+struct ValueToString<double> {
+    static String string(const double value)
+    {
+        return String::number(value);
+    }
+};
+
+template <>
+struct ValueToString<TextTrackCue*> {
+    static String string(TextTrackCue* const& cue)
+    {
+        return String::format("%p id=%s interval=%f-->%f cue=%s)", cue, cue->id().utf8().data(), cue->startTime(), cue->endTime(), cue->text().utf8().data());
+    }
+};
+#endif
+
+inline bool isMediaElement(Node* node)
+{
+    return node && node->isElementNode() && toElement(node)->isMediaElement();
+}
+
+inline HTMLMediaElement* toMediaElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isMediaElement(node));
+    return static_cast<HTMLMediaElement*>(node);
+}
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLMediaElement.idl b/Source/core/html/HTMLMediaElement.idl
new file mode 100644
index 0000000..0dbe3ed
--- /dev/null
+++ b/Source/core/html/HTMLMediaElement.idl
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007, 2010, 2011, 2012 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    ActiveDOMObject
+] interface HTMLMediaElement : HTMLElement {
+
+// error state
+readonly attribute MediaError error;
+
+// network state
+[Reflect, URL] attribute DOMString src;
+[URL] readonly attribute DOMString currentSrc;
+
+const unsigned short NETWORK_EMPTY = 0;
+const unsigned short NETWORK_IDLE = 1;
+const unsigned short NETWORK_LOADING = 2;
+const unsigned short NETWORK_NO_SOURCE = 3;
+readonly attribute unsigned short networkState;
+attribute DOMString preload;
+
+readonly attribute TimeRanges buffered;
+void load();
+#if defined(ENABLE_ENCRYPTED_MEDIA) && ENABLE_ENCRYPTED_MEDIA
+    DOMString canPlayType([Default=Undefined] optional DOMString type, [Default=Undefined, TreatNullAs=NullString, TreatUndefinedAs=NullString] optional DOMString keySystem);
+#elif defined(ENABLE_ENCRYPTED_MEDIA_V2) && ENABLE_ENCRYPTED_MEDIA_V2
+    DOMString canPlayType([Default=Undefined] optional DOMString type, [Default=Undefined, TreatNullAs=NullString, TreatUndefinedAs=NullString] optional DOMString keySystem);
+#else
+DOMString canPlayType([Default=Undefined] optional DOMString type);
+#endif
+
+// ready state
+const unsigned short HAVE_NOTHING = 0;
+const unsigned short HAVE_METADATA = 1;
+const unsigned short HAVE_CURRENT_DATA = 2;
+const unsigned short HAVE_FUTURE_DATA = 3;
+const unsigned short HAVE_ENOUGH_DATA = 4;
+readonly attribute unsigned short readyState;
+readonly attribute boolean seeking;
+
+// playback state
+[SetterRaisesException] attribute double currentTime;
+readonly attribute double initialTime;
+readonly attribute double startTime;
+readonly attribute double duration;
+readonly attribute boolean paused;
+attribute double defaultPlaybackRate;
+attribute double playbackRate;
+readonly attribute TimeRanges played;
+readonly attribute TimeRanges seekable;
+readonly attribute boolean ended;
+[Reflect] attribute boolean autoplay;
+[Reflect] attribute boolean loop;
+void play();
+void pause();
+
+// controls
+attribute boolean controls;
+[SetterRaisesException] attribute double volume;
+attribute boolean muted;
+[Reflect=muted] attribute boolean defaultMuted;
+
+// WebKit extensions
+attribute boolean webkitPreservesPitch;
+
+readonly attribute boolean webkitHasClosedCaptions;
+attribute boolean webkitClosedCaptionsVisible;
+
+// The number of bytes consumed by the media decoder.
+readonly attribute unsigned long webkitAudioDecodedByteCount;
+readonly attribute unsigned long webkitVideoDecodedByteCount;
+
+#if defined(ENABLE_ENCRYPTED_MEDIA) && ENABLE_ENCRYPTED_MEDIA
+
+#if defined(ENABLE_ENCRYPTED_MEDIA_V2) && ENABLE_ENCRYPTED_MEDIA_V2
+[EnabledAtRuntime=encryptedMedia, RaisesException, DeprecateAs=PrefixedMediaGenerateKeyRequest] void webkitGenerateKeyRequest([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString keySystem, optional Uint8Array initData);
+[EnabledAtRuntime=encryptedMedia, RaisesException, DeprecateAs=PrefixedMediaAddKey] void webkitAddKey([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString keySystem, Uint8Array key, optional Uint8Array initData, [Default=NullString] optional DOMString sessionId);
+#else
+[EnabledAtRuntime=encryptedMedia, RaisesException] void webkitGenerateKeyRequest([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString keySystem, optional Uint8Array initData);
+[EnabledAtRuntime=encryptedMedia, RaisesException] void webkitAddKey([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString keySystem, Uint8Array key, optional Uint8Array initData, [Default=NullString] optional DOMString sessionId);
+#endif
+[EnabledAtRuntime=encryptedMedia, RaisesException] void webkitCancelKeyRequest([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString keySystem, [Default=NullString] optional DOMString sessionId);
+
+    [EnabledAtRuntime=encryptedMedia] attribute EventListener onwebkitkeyadded;
+    [EnabledAtRuntime=encryptedMedia] attribute EventListener onwebkitkeyerror;
+    [EnabledAtRuntime=encryptedMedia] attribute EventListener onwebkitkeymessage;
+#endif
+    [Conditional=ENCRYPTED_MEDIA|ENCRYPTED_MEDIA_V2, EnabledAtRuntime=encryptedMedia] attribute EventListener onwebkitneedkey;
+#if defined(ENABLE_ENCRYPTED_MEDIA_V2) && ENABLE_ENCRYPTED_MEDIA_V2
+    [EnabledAtRuntime=encryptedMedia] attribute MediaKeys mediaKeys;
+#endif
+
+[EnabledAtRuntime=webkitVideoTrack, RaisesException] TextTrack addTextTrack(DOMString kind, optional DOMString label, optional DOMString language);
+[EnabledAtRuntime=webkitVideoTrack] readonly attribute TextTrackList textTracks;
+
+[Reflect, TreatNullAs=NullString] attribute DOMString mediaGroup;
+[CustomSetter] attribute MediaController controller;
+};
diff --git a/Source/core/html/HTMLMenuElement.cpp b/Source/core/html/HTMLMenuElement.cpp
new file mode 100644
index 0000000..57e1cd1
--- /dev/null
+++ b/Source/core/html/HTMLMenuElement.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLMenuElement.h"
+
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLMenuElement::HTMLMenuElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(menuTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLMenuElement> HTMLMenuElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLMenuElement(tagName, document));
+}
+
+}
diff --git a/Source/core/html/HTMLMenuElement.h b/Source/core/html/HTMLMenuElement.h
new file mode 100644
index 0000000..a4c5b8c
--- /dev/null
+++ b/Source/core/html/HTMLMenuElement.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLMenuElement_h
+#define HTMLMenuElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLMenuElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLMenuElement> create(const QualifiedName&, Document*);
+    
+private:
+    HTMLMenuElement(const QualifiedName&, Document*);
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLMenuElement.idl b/Source/core/html/HTMLMenuElement.idl
new file mode 100644
index 0000000..ea756fc
--- /dev/null
+++ b/Source/core/html/HTMLMenuElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLMenuElement : HTMLElement {
+    [Reflect] attribute boolean compact;
+};
+
diff --git a/Source/core/html/HTMLMetaElement.cpp b/Source/core/html/HTMLMetaElement.cpp
new file mode 100644
index 0000000..b88d483
--- /dev/null
+++ b/Source/core/html/HTMLMetaElement.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLMetaElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLMetaElement::HTMLMetaElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(metaTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLMetaElement> HTMLMetaElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLMetaElement(tagName, document));
+}
+
+void HTMLMetaElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == http_equivAttr)
+        process();
+    else if (name == contentAttr)
+        process();
+    else if (name == nameAttr) {
+        // Do nothing
+    } else
+        HTMLElement::parseAttribute(name, value);
+}
+
+Node::InsertionNotificationRequest HTMLMetaElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+    if (insertionPoint->inDocument())
+        process();
+    return InsertionDone;
+}
+
+void HTMLMetaElement::process()
+{
+    if (!inDocument())
+        return;
+
+    const AtomicString& contentValue = fastGetAttribute(contentAttr);
+    if (contentValue.isNull())
+        return;
+
+    if (equalIgnoringCase(name(), "viewport"))
+        document()->processViewport(contentValue, ViewportArguments::ViewportMeta);
+    else if (equalIgnoringCase(name(), "referrer"))
+        document()->processReferrerPolicy(contentValue);
+    else if (equalIgnoringCase(name(), "handheldfriendly") && equalIgnoringCase(contentValue, "true"))
+        document()->processViewport("width=device-width", ViewportArguments::HandheldFriendlyMeta);
+    else if (equalIgnoringCase(name(), "mobileoptimized"))
+        document()->processViewport("width=device-width, initial-scale=1", ViewportArguments::MobileOptimizedMeta);
+
+    // Get the document to process the tag, but only if we're actually part of DOM tree (changing a meta tag while
+    // it's not in the tree shouldn't have any effect on the document)
+    const AtomicString& httpEquivValue = fastGetAttribute(http_equivAttr);
+    if (!httpEquivValue.isNull())
+        document()->processHttpEquiv(httpEquivValue, contentValue);
+}
+
+String HTMLMetaElement::content() const
+{
+    return getAttribute(contentAttr);
+}
+
+String HTMLMetaElement::httpEquiv() const
+{
+    return getAttribute(http_equivAttr);
+}
+
+String HTMLMetaElement::name() const
+{
+    return getNameAttribute();
+}
+
+}
diff --git a/Source/core/html/HTMLMetaElement.h b/Source/core/html/HTMLMetaElement.h
new file mode 100644
index 0000000..d445f92
--- /dev/null
+++ b/Source/core/html/HTMLMetaElement.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLMetaElement_h
+#define HTMLMetaElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLMetaElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLMetaElement> create(const QualifiedName&, Document*);
+
+    String content() const;
+    String httpEquiv() const;
+    String name() const;
+
+private:
+    HTMLMetaElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+
+    void process();
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLMetaElement.idl b/Source/core/html/HTMLMetaElement.idl
new file mode 100644
index 0000000..4f7e9cd
--- /dev/null
+++ b/Source/core/html/HTMLMetaElement.idl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLMetaElement : HTMLElement {
+    [Reflect] attribute DOMString content;
+    [Reflect=http_equiv] attribute DOMString httpEquiv;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute DOMString scheme;
+};
+
diff --git a/Source/core/html/HTMLMeterElement.cpp b/Source/core/html/HTMLMeterElement.cpp
new file mode 100644
index 0000000..f9e89c4
--- /dev/null
+++ b/Source/core/html/HTMLMeterElement.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "core/html/HTMLMeterElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/shadow/MeterShadowElement.h"
+#include "core/page/Page.h"
+#include "core/rendering/RenderMeter.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document)
+    : LabelableElement(tagName, document)
+{
+    ASSERT(hasTagName(meterTag));
+    ScriptWrappable::init(this);
+}
+
+HTMLMeterElement::~HTMLMeterElement()
+{
+}
+
+PassRefPtr<HTMLMeterElement> HTMLMeterElement::create(const QualifiedName& tagName, Document* document)
+{
+    RefPtr<HTMLMeterElement> meter = adoptRef(new HTMLMeterElement(tagName, document));
+    meter->ensureUserAgentShadowRoot();
+    return meter;
+}
+
+RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+    if (hasAuthorShadowRoot() || !document()->page()->theme()->supportsMeter(style->appearance()))
+        return RenderObject::createObject(this, style);
+
+    return new (arena) RenderMeter(this);
+}
+
+bool HTMLMeterElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
+{
+    return childContext.isOnUpperEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext);
+}
+
+void HTMLMeterElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == valueAttr || name == minAttr || name == maxAttr || name == lowAttr || name == highAttr || name == optimumAttr)
+        didElementStateChange();
+    else
+        LabelableElement::parseAttribute(name, value);
+}
+
+double HTMLMeterElement::min() const
+{
+    return parseToDoubleForNumberType(getAttribute(minAttr), 0);
+}
+
+void HTMLMeterElement::setMin(double min, ExceptionCode& ec)
+{
+    if (!std::isfinite(min)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    setAttribute(minAttr, String::number(min));
+}
+
+double HTMLMeterElement::max() const
+{
+    return std::max(parseToDoubleForNumberType(getAttribute(maxAttr), std::max(1.0, min())), min());
+}
+
+void HTMLMeterElement::setMax(double max, ExceptionCode& ec)
+{
+    if (!std::isfinite(max)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    setAttribute(maxAttr, String::number(max));
+}
+
+double HTMLMeterElement::value() const
+{
+    double value = parseToDoubleForNumberType(getAttribute(valueAttr), 0);
+    return std::min(std::max(value, min()), max());
+}
+
+void HTMLMeterElement::setValue(double value, ExceptionCode& ec)
+{
+    if (!std::isfinite(value)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    setAttribute(valueAttr, String::number(value));
+}
+
+double HTMLMeterElement::low() const
+{
+    double low = parseToDoubleForNumberType(getAttribute(lowAttr), min());
+    return std::min(std::max(low, min()), max());
+}
+
+void HTMLMeterElement::setLow(double low, ExceptionCode& ec)
+{
+    if (!std::isfinite(low)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    setAttribute(lowAttr, String::number(low));
+}
+
+double HTMLMeterElement::high() const
+{
+    double high = parseToDoubleForNumberType(getAttribute(highAttr), max());
+    return std::min(std::max(high, low()), max());
+}
+
+void HTMLMeterElement::setHigh(double high, ExceptionCode& ec)
+{
+    if (!std::isfinite(high)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    setAttribute(highAttr, String::number(high));
+}
+
+double HTMLMeterElement::optimum() const
+{
+    double optimum = parseToDoubleForNumberType(getAttribute(optimumAttr), (max() + min()) / 2);
+    return std::min(std::max(optimum, min()), max());
+}
+
+void HTMLMeterElement::setOptimum(double optimum, ExceptionCode& ec)
+{
+    if (!std::isfinite(optimum)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    setAttribute(optimumAttr, String::number(optimum));
+}
+
+HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const
+{
+    double lowValue = low();
+    double highValue = high();
+    double theValue = value();
+    double optimumValue = optimum();
+
+    if (optimumValue < lowValue) {
+        // The optimum range stays under low
+        if (theValue <= lowValue)
+            return GaugeRegionOptimum;
+        if (theValue <= highValue)
+            return GaugeRegionSuboptimal;
+        return GaugeRegionEvenLessGood;
+    }
+    
+    if (highValue < optimumValue) {
+        // The optimum range stays over high
+        if (highValue <= theValue)
+            return GaugeRegionOptimum;
+        if (lowValue <= theValue)
+            return GaugeRegionSuboptimal;
+        return GaugeRegionEvenLessGood;
+    }
+
+    // The optimum range stays between high and low.
+    // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case
+    // because the value is never less or greater than min or max.
+    if (lowValue <= theValue && theValue <= highValue)
+        return GaugeRegionOptimum;
+    return GaugeRegionSuboptimal;
+}
+
+double HTMLMeterElement::valueRatio() const
+{
+    double min = this->min();
+    double max = this->max();
+    double value = this->value();
+
+    if (max <= min)
+        return 0;
+    return (value - min) / (max - min);
+}
+
+void HTMLMeterElement::didElementStateChange()
+{
+    m_value->setWidthPercentage(valueRatio()*100);
+    m_value->updatePseudo();
+    if (RenderMeter* render = renderMeter())
+        render->updateFromElement();
+}
+
+RenderMeter* HTMLMeterElement::renderMeter() const
+{
+    if (renderer() && renderer()->isMeter())
+        return static_cast<RenderMeter*>(renderer());
+
+    RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer();
+    ASSERT(!renderObject || renderObject->isMeter());
+    return static_cast<RenderMeter*>(renderObject);
+}
+
+void HTMLMeterElement::didAddUserAgentShadowRoot(ShadowRoot* root)
+{
+    ASSERT(!m_value);
+
+    RefPtr<MeterInnerElement> inner = MeterInnerElement::create(document());
+    root->appendChild(inner);
+
+    RefPtr<MeterBarElement> bar = MeterBarElement::create(document());
+    m_value = MeterValueElement::create(document());
+    m_value->setWidthPercentage(0);
+    m_value->updatePseudo();
+    bar->appendChild(m_value, ASSERT_NO_EXCEPTION);
+
+    inner->appendChild(bar, ASSERT_NO_EXCEPTION);
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLMeterElement.h b/Source/core/html/HTMLMeterElement.h
new file mode 100644
index 0000000..0ed11eb
--- /dev/null
+++ b/Source/core/html/HTMLMeterElement.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLMeterElement_h
+#define HTMLMeterElement_h
+
+#include "core/html/LabelableElement.h"
+
+namespace WebCore {
+
+class MeterValueElement;
+class RenderMeter;
+
+class HTMLMeterElement FINAL : public LabelableElement {
+public:
+    static PassRefPtr<HTMLMeterElement> create(const QualifiedName&, Document*);
+
+    enum GaugeRegion {
+        GaugeRegionOptimum,
+        GaugeRegionSuboptimal,
+        GaugeRegionEvenLessGood
+    };
+
+    double min() const;
+    void setMin(double, ExceptionCode&);
+
+    double max() const;
+    void setMax(double, ExceptionCode&);
+
+    double value() const;
+    void setValue(double, ExceptionCode&);
+
+    double low() const;
+    void setLow(double, ExceptionCode&);
+
+    double high() const;
+    void setHigh(double, ExceptionCode&);
+
+    double optimum() const;
+    void setOptimum(double, ExceptionCode&);
+
+    double valueRatio() const;
+    GaugeRegion gaugeRegion() const;
+
+    bool canContainRangeEndPoint() const { return false; }
+
+private:
+    HTMLMeterElement(const QualifiedName&, Document*);
+    virtual ~HTMLMeterElement();
+
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+    RenderMeter* renderMeter() const;
+
+    virtual bool supportLabels() const OVERRIDE { return true; }
+
+    virtual bool recalcWillValidate() const { return false; }
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const OVERRIDE;
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    void didElementStateChange();
+    virtual void didAddUserAgentShadowRoot(ShadowRoot*) OVERRIDE;
+
+    RefPtr<MeterValueElement> m_value;
+};
+
+inline bool isHTMLMeterElement(Node* node)
+{
+    return node->hasTagName(HTMLNames::meterTag);
+}
+
+inline HTMLMeterElement* toHTMLMeterElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLMeterElement(node));
+    return static_cast<HTMLMeterElement*>(node);
+}
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLMeterElement.idl b/Source/core/html/HTMLMeterElement.idl
new file mode 100644
index 0000000..12f067a
--- /dev/null
+++ b/Source/core/html/HTMLMeterElement.idl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLMeterElement : HTMLElement {
+             [SetterRaisesException] attribute double value;
+             [SetterRaisesException] attribute double min;
+             [SetterRaisesException] attribute double max;
+             [SetterRaisesException] attribute double low;
+             [SetterRaisesException] attribute double high;
+             [SetterRaisesException] attribute double optimum;
+    readonly attribute NodeList labels;
+};
diff --git a/Source/core/html/HTMLModElement.cpp b/Source/core/html/HTMLModElement.cpp
new file mode 100644
index 0000000..cbe20a3
--- /dev/null
+++ b/Source/core/html/HTMLModElement.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLModElement.h"
+
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLModElement::HTMLModElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLModElement> HTMLModElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLModElement(tagName, document));
+}
+
+bool HTMLModElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == citeAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+}
diff --git a/Source/core/html/HTMLModElement.h b/Source/core/html/HTMLModElement.h
new file mode 100644
index 0000000..158a9c3
--- /dev/null
+++ b/Source/core/html/HTMLModElement.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLModElement_h
+#define HTMLModElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLModElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLModElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLModElement(const QualifiedName&, Document*);
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLModElement.idl b/Source/core/html/HTMLModElement.idl
new file mode 100644
index 0000000..ccb8da4
--- /dev/null
+++ b/Source/core/html/HTMLModElement.idl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLModElement : HTMLElement {
+    [Reflect, URL] attribute DOMString cite;
+    [Reflect] attribute DOMString dateTime;
+};
+
diff --git a/Source/core/html/HTMLNameCollection.cpp b/Source/core/html/HTMLNameCollection.cpp
new file mode 100644
index 0000000..4712443
--- /dev/null
+++ b/Source/core/html/HTMLNameCollection.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2011, 2012 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLNameCollection.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Element.h"
+#include "core/dom/NodeRareData.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLObjectElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLNameCollection::HTMLNameCollection(Node* document, CollectionType type, const AtomicString& name)
+    : HTMLCollection(document, type, OverridesItemAfter)
+    , m_name(name)
+{
+}
+
+HTMLNameCollection::~HTMLNameCollection()
+{
+    ASSERT(ownerNode());
+    ASSERT(ownerNode()->isDocumentNode());
+    ASSERT(type() == WindowNamedItems || type() == DocumentNamedItems);
+
+    ownerNode()->nodeLists()->removeCacheWithAtomicName(this, type(), m_name);
+}
+
+Element* HTMLNameCollection::virtualItemAfter(unsigned& offsetInArray, Element* previous) const
+{
+    ASSERT_UNUSED(offsetInArray, !offsetInArray);
+    ASSERT(previous != ownerNode());
+
+    Element* current;
+    if (!previous)
+        current = ElementTraversal::firstWithin(ownerNode());
+    else
+        current = ElementTraversal::next(previous, ownerNode());
+
+    for (; current; current = ElementTraversal::next(current, ownerNode())) {
+        switch (type()) {
+        case WindowNamedItems:
+            // find only images, forms, applets, embeds and objects by name, 
+            // but anything by id
+            if (current->hasTagName(imgTag)
+                || current->hasTagName(formTag)
+                || current->hasTagName(appletTag)
+                || current->hasTagName(embedTag)
+                || current->hasTagName(objectTag)) {
+                if (current->getNameAttribute() == m_name)
+                    return current;
+            }
+            if (current->getIdAttribute() == m_name)
+                return current;
+            break;
+        case DocumentNamedItems:
+            // find images, forms, applets, embeds, objects and iframes by name, 
+            // applets and object by id, and images by id but only if they have
+            // a name attribute (this very strange rule matches IE)
+            if (current->hasTagName(formTag) || current->hasTagName(embedTag) || current->hasTagName(iframeTag)) {
+                if (current->getNameAttribute() == m_name)
+                    return current;
+            } else if (current->hasTagName(appletTag)) {
+                if (current->getNameAttribute() == m_name || current->getIdAttribute() == m_name)
+                    return current;
+            } else if (current->hasTagName(objectTag)) {
+                if ((current->getNameAttribute() == m_name || current->getIdAttribute() == m_name)
+                    && static_cast<HTMLObjectElement*>(current)->isDocNamedItem())
+                    return current;
+            } else if (current->hasTagName(imgTag)) {
+                if (current->getNameAttribute() == m_name || (current->getIdAttribute() == m_name && current->hasName()))
+                    return current;
+            }
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+        }
+    }
+
+    return 0;
+}
+
+}
diff --git a/Source/core/html/HTMLNameCollection.h b/Source/core/html/HTMLNameCollection.h
new file mode 100644
index 0000000..099e470
--- /dev/null
+++ b/Source/core/html/HTMLNameCollection.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLNameCollection_h
+#define HTMLNameCollection_h
+
+#include "core/html/HTMLCollection.h"
+
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+class Document;
+
+class HTMLNameCollection : public HTMLCollection {
+public:
+    static PassRefPtr<HTMLNameCollection> create(Node* document, CollectionType type, const AtomicString& name)
+    {
+        return adoptRef(new HTMLNameCollection(document, type, name));
+    }
+
+    ~HTMLNameCollection();
+
+private:
+    HTMLNameCollection(Node*, CollectionType, const AtomicString& name);
+
+    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
+
+    AtomicString m_name;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/HTMLOListElement.cpp b/Source/core/html/HTMLOListElement.cpp
new file mode 100644
index 0000000..413df06
--- /dev/null
+++ b/Source/core/html/HTMLOListElement.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLOListElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/rendering/RenderListItem.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLOListElement::HTMLOListElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_start(0xBADBEEF)
+    , m_itemCount(0)
+    , m_hasExplicitStart(false)
+    , m_isReversed(false)
+    , m_shouldRecalculateItemCount(false)
+{
+    ASSERT(hasTagName(olTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLOListElement> HTMLOListElement::create(Document* document)
+{
+    return adoptRef(new HTMLOListElement(olTag, document));
+}
+
+PassRefPtr<HTMLOListElement> HTMLOListElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLOListElement(tagName, document));
+}
+
+bool HTMLOListElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == typeAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLOListElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == typeAttr) {
+        if (value == "a")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueLowerAlpha);
+        else if (value == "A")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueUpperAlpha);
+        else if (value == "i")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueLowerRoman);
+        else if (value == "I")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueUpperRoman);
+        else if (value == "1")
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, CSSValueDecimal);
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLOListElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == startAttr) {
+        int oldStart = start();
+        bool canParse;
+        int parsedStart = value.toInt(&canParse);
+        m_hasExplicitStart = canParse;
+        m_start = canParse ? parsedStart : 0xBADBEEF;
+        if (oldStart == start())
+            return;
+        updateItemValues();
+    } else if (name == reversedAttr) {
+        bool reversed = !value.isNull();
+        if (reversed == m_isReversed)
+            return;
+        m_isReversed = reversed;
+        updateItemValues();
+    } else
+        HTMLElement::parseAttribute(name, value);
+}
+
+void HTMLOListElement::setStart(int start)
+{
+    setAttribute(startAttr, String::number(start));
+}
+
+void HTMLOListElement::updateItemValues()
+{
+    RenderListItem::updateItemValuesForOrderedList(this);
+}
+
+void HTMLOListElement::recalculateItemCount()
+{
+    m_itemCount = RenderListItem::itemCountForOrderedList(this);
+    m_shouldRecalculateItemCount = false;
+}
+
+}
diff --git a/Source/core/html/HTMLOListElement.h b/Source/core/html/HTMLOListElement.h
new file mode 100644
index 0000000..7bf0608
--- /dev/null
+++ b/Source/core/html/HTMLOListElement.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLOListElement_h
+#define HTMLOListElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLOListElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLOListElement> create(Document*);
+    static PassRefPtr<HTMLOListElement> create(const QualifiedName&, Document*);
+
+    int start() const { return m_hasExplicitStart ? m_start : (m_isReversed ? itemCount() : 1); }
+    void setStart(int);
+
+    bool isReversed() const { return m_isReversed; }
+
+    void itemCountChanged() { m_shouldRecalculateItemCount = true; }
+
+private:
+    HTMLOListElement(const QualifiedName&, Document*);
+        
+    void updateItemValues();
+
+    unsigned itemCount() const
+    {
+        if (m_shouldRecalculateItemCount)
+            const_cast<HTMLOListElement*>(this)->recalculateItemCount();
+        return m_itemCount;
+    }
+
+    void recalculateItemCount();
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    int m_start;
+    unsigned m_itemCount;
+
+    bool m_hasExplicitStart : 1;
+    bool m_isReversed : 1;
+    bool m_shouldRecalculateItemCount : 1;
+};
+
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLOListElement.idl b/Source/core/html/HTMLOListElement.idl
new file mode 100644
index 0000000..1e51615
--- /dev/null
+++ b/Source/core/html/HTMLOListElement.idl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLOListElement : HTMLElement {
+    [Reflect] attribute boolean compact;
+    attribute long start;
+    [Reflect] attribute boolean reversed;
+    [Reflect] attribute DOMString type;
+};
+
diff --git a/Source/core/html/HTMLObjectElement.cpp b/Source/core/html/HTMLObjectElement.cpp
new file mode 100644
index 0000000..d481cf5
--- /dev/null
+++ b/Source/core/html/HTMLObjectElement.cpp
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLObjectElement.h"
+
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/Text.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLImageLoader.h"
+#include "core/html/HTMLMetaElement.h"
+#include "core/html/HTMLParamElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/cache/CachedImage.h"
+#include "core/page/Chrome.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/platform/MIMETypeRegistry.h"
+#include "core/platform/Widget.h"
+#include "core/plugins/PluginView.h"
+#include "core/rendering/RenderEmbeddedObject.h"
+#include "core/rendering/RenderImage.h"
+#include "core/rendering/RenderWidget.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLObjectElement::HTMLObjectElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser) 
+    : HTMLPlugInImageElement(tagName, document, createdByParser, ShouldNotPreferPlugInsForImages)
+    , m_docNamedItem(true)
+    , m_useFallbackContent(false)
+{
+    ASSERT(hasTagName(objectTag));
+    setForm(form ? form : findFormAncestor());
+    ScriptWrappable::init(this);
+}
+
+inline HTMLObjectElement::~HTMLObjectElement()
+{
+}
+
+PassRefPtr<HTMLObjectElement> HTMLObjectElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
+{
+    return adoptRef(new HTMLObjectElement(tagName, document, form, createdByParser));
+}
+
+RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() const
+{
+    document()->updateLayoutIgnorePendingStylesheets();
+    return renderPart(); // This will return 0 if the renderer is not a RenderPart.
+}
+
+bool HTMLObjectElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == borderAttr)
+        return true;
+    return HTMLPlugInImageElement::isPresentationAttribute(name);
+}
+
+void HTMLObjectElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == borderAttr)
+        applyBorderAttributeToStyle(value, style);
+    else
+        HTMLPlugInImageElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLObjectElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == formAttr)
+        formAttributeChanged();
+    else if (name == typeAttr) {
+        m_serviceType = value.lower();
+        size_t pos = m_serviceType.find(";");
+        if (pos != notFound)
+            m_serviceType = m_serviceType.left(pos);
+        if (renderer())
+            setNeedsWidgetUpdate(true);
+    } else if (name == dataAttr) {
+        m_url = stripLeadingAndTrailingHTMLSpaces(value);
+        if (renderer()) {
+            setNeedsWidgetUpdate(true);
+            if (isImageType()) {
+                if (!m_imageLoader)
+                    m_imageLoader = adoptPtr(new HTMLImageLoader(this));
+                m_imageLoader->updateFromElementIgnoringPreviousError();
+            }
+        }
+    } else if (name == classidAttr) {
+        m_classId = value;
+        if (renderer())
+            setNeedsWidgetUpdate(true);
+    } else if (name == onbeforeloadAttr)
+        setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, name, value));
+    else
+        HTMLPlugInImageElement::parseAttribute(name, value);
+}
+
+static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues)
+{
+    // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
+    // require "src" attribute).
+    int srcIndex = -1, dataIndex = -1;
+    for (unsigned int i = 0; i < paramNames->size(); ++i) {
+        if (equalIgnoringCase((*paramNames)[i], "src"))
+            srcIndex = i;
+        else if (equalIgnoringCase((*paramNames)[i], "data"))
+            dataIndex = i;
+    }
+    
+    if (srcIndex == -1 && dataIndex != -1) {
+        paramNames->append("src");
+        paramValues->append((*paramValues)[dataIndex]);
+    }
+}
+
+// FIXME: This function should not deal with url or serviceType!
+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.
+    for (Node* child = firstChild(); child; child = child->nextSibling()) {
+        if (!child->hasTagName(paramTag))
+            continue;
+
+        HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
+        String name = p->name();
+        if (name.isEmpty())
+            continue;
+
+        uniqueParamNames.add(name.impl());
+        paramNames.append(p->name());
+        paramValues.append(p->value());
+
+        // FIXME: url adjustment does not belong in this function.
+        if (url.isEmpty() && urlParameter.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
+            urlParameter = stripLeadingAndTrailingHTMLSpaces(p->value());
+        // FIXME: serviceType calculation does not belong in this function.
+        if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
+            serviceType = p->value();
+            size_t pos = serviceType.find(";");
+            if (pos != notFound)
+                serviceType = serviceType.left(pos);
+        }
+    }
+    
+    // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
+    // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
+    // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
+    // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
+    // else our Java plugin will misinterpret it. [4004531]
+    String codebase;
+    if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
+        codebase = "codebase";
+        uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
+    }
+    
+    // Turn the attributes of the <object> element into arrays, but don't override <param> values.
+    if (hasAttributes()) {
+        for (unsigned i = 0; i < attributeCount(); ++i) {
+            const Attribute* attribute = attributeItem(i);
+            const AtomicString& name = attribute->name().localName();
+            if (!uniqueParamNames.contains(name.impl())) {
+                paramNames.append(name.string());
+                paramValues.append(attribute->value().string());
+            }
+        }
+    }
+    
+    mapDataParamToSrc(&paramNames, &paramValues);
+    
+    // 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, shouldPreferPlugInsForImages()))
+            url = urlParameter;
+    }
+}
+
+    
+bool HTMLObjectElement::hasFallbackContent() const
+{
+    for (Node* child = firstChild(); child; child = child->nextSibling()) {
+        // Ignore whitespace-only text, and <param> tags, any other content is fallback content.
+        if (child->isTextNode()) {
+            if (!toText(child)->containsOnlyWhitespace())
+                return true;
+        } else if (!child->hasTagName(paramTag))
+            return true;
+    }
+    return false;
+}
+    
+bool HTMLObjectElement::shouldAllowQuickTimeClassIdQuirk()
+{
+    // This site-specific hack maintains compatibility with Mac OS X Wiki Server,
+    // which embeds QuickTime movies using an object tag containing QuickTime's
+    // ActiveX classid. Treat this classid as valid only if OS X Server's unique
+    // 'generator' meta tag is present. Only apply this quirk if there is no
+    // fallback content, which ensures the quirk will disable itself if Wiki
+    // Server is updated to generate an alternate embed tag as fallback content.
+    if (!document()->page()
+        || !document()->page()->settings()->needsSiteSpecificQuirks()
+        || hasFallbackContent()
+        || !equalIgnoringCase(classId(), "clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"))
+        return false;
+
+    RefPtr<NodeList> metaElements = document()->getElementsByTagName(HTMLNames::metaTag.localName());
+    unsigned length = metaElements->length();
+    for (unsigned i = 0; i < length; ++i) {
+        ASSERT(metaElements->item(i)->isHTMLElement());
+        HTMLMetaElement* metaElement = static_cast<HTMLMetaElement*>(metaElements->item(i));
+        if (equalIgnoringCase(metaElement->name(), "generator") && metaElement->content().startsWith("Mac OS X Server Web Services Server", false))
+            return true;
+    }
+    
+    return false;
+}
+    
+bool HTMLObjectElement::hasValidClassId()
+{
+    if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType()) && classId().startsWith("java:", false))
+        return true;
+    
+    if (shouldAllowQuickTimeClassIdQuirk())
+        return true;
+
+    // HTML5 says that fallback content should be rendered if a non-empty
+    // classid is specified for which the UA can't find a suitable plug-in.
+    return classId().isEmpty();
+}
+
+// FIXME: This should be unified with HTMLEmbedElement::updateWidget and
+// moved down into HTMLPluginImageElement.cpp
+void HTMLObjectElement::updateWidget(PluginCreationOption pluginCreationOption)
+{
+    ASSERT(!renderEmbeddedObject()->showsUnavailablePluginIndicator());
+    ASSERT(needsWidgetUpdate());
+    setNeedsWidgetUpdate(false);
+    // FIXME: This should ASSERT isFinishedParsingChildren() instead.
+    if (!isFinishedParsingChildren())
+        return;
+
+    // FIXME: I'm not sure it's ever possible to get into updateWidget during a
+    // removal, but just in case we should avoid loading the frame to prevent
+    // security bugs.
+    if (!SubframeLoadingDisabler::canLoadFrame(this))
+        return;
+
+    String url = this->url();
+    String serviceType = this->serviceType();
+
+    // FIXME: These should be joined into a PluginParameters class.
+    Vector<String> paramNames;
+    Vector<String> paramValues;
+    parametersForPlugin(paramNames, paramValues, url, serviceType);
+
+    // Note: url is modified above by parametersForPlugin.
+    if (!allowedToLoadFrameURL(url))
+        return;
+
+    bool fallbackContent = hasFallbackContent();
+    renderEmbeddedObject()->setHasFallbackContent(fallbackContent);
+
+    // FIXME: It's sadness that we have this special case here.
+    //        See http://trac.webkit.org/changeset/25128 and
+    //        plugins/netscape-plugin-setwindow-size.html
+    if (pluginCreationOption == CreateOnlyNonNetscapePlugins && wouldLoadAsNetscapePlugin(url, serviceType)) {
+        // Ensure updateWidget() is called again during layout to create the Netscape plug-in.
+        setNeedsWidgetUpdate(true);
+        return;
+    }
+
+    RefPtr<HTMLObjectElement> protect(this); // beforeload and plugin loading can make arbitrary DOM mutations.
+    bool beforeLoadAllowedLoad = dispatchBeforeLoadEvent(url);
+    if (!renderer()) // Do not load the plugin if beforeload removed this element or its renderer.
+        return;
+
+    SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
+    bool success = beforeLoadAllowedLoad && hasValidClassId() && loader->requestObject(this, url, getNameAttribute(), serviceType, paramNames, paramValues);
+    if (!success && fallbackContent)
+        renderFallbackContent();
+}
+
+bool HTMLObjectElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    // FIXME: This check should not be needed, detached documents never render!
+    Frame* frame = document()->frame();
+    if (!frame)
+        return false;
+
+    return HTMLPlugInImageElement::rendererIsNeeded(context);
+}
+
+Node::InsertionNotificationRequest HTMLObjectElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLPlugInImageElement::insertedInto(insertionPoint);
+    FormAssociatedElement::insertedInto(insertionPoint);
+    return InsertionDone;
+}
+
+void HTMLObjectElement::removedFrom(ContainerNode* insertionPoint)
+{
+    HTMLPlugInImageElement::removedFrom(insertionPoint);
+    FormAssociatedElement::removedFrom(insertionPoint);
+}
+
+void HTMLObjectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    updateDocNamedItem();
+    if (inDocument() && !useFallbackContent()) {
+        setNeedsWidgetUpdate(true);
+        setNeedsStyleRecalc();
+    }
+    HTMLPlugInImageElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+}
+
+bool HTMLObjectElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == dataAttr || (attribute.name() == usemapAttr && attribute.value().string()[0] != '#') || HTMLPlugInImageElement::isURLAttribute(attribute);
+}
+
+const AtomicString& HTMLObjectElement::imageSourceURL() const
+{
+    return getAttribute(dataAttr);
+}
+
+void HTMLObjectElement::renderFallbackContent()
+{
+    if (useFallbackContent())
+        return;
+    
+    if (!inDocument())
+        return;
+
+    // Before we give up and use fallback content, check to see if this is a MIME type issue.
+    if (m_imageLoader && m_imageLoader->image() && m_imageLoader->image()->status() != CachedResource::LoadError) {
+        m_serviceType = m_imageLoader->image()->response().mimeType();
+        if (!isImageType()) {
+            // If we don't think we have an image type anymore, then clear the image from the loader.
+            m_imageLoader->setImage(0);
+            reattach();
+            return;
+        }
+    }
+
+    m_useFallbackContent = true;
+
+    // FIXME: Style gets recalculated which is suboptimal.
+    detach();
+    attach();
+}
+
+// FIXME: This should be removed, all callers are almost certainly wrong.
+static bool isRecognizedTagName(const QualifiedName& tagName)
+{
+    DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, tagList, ());
+    if (tagList.isEmpty()) {
+        QualifiedName** tags = HTMLNames::getHTMLTags();
+        for (size_t i = 0; i < HTMLNames::HTMLTagsCount; i++) {
+            if (*tags[i] == bgsoundTag
+                || *tags[i] == commandTag
+                || *tags[i] == detailsTag
+                || *tags[i] == figcaptionTag
+                || *tags[i] == figureTag
+                || *tags[i] == summaryTag
+                || *tags[i] == trackTag) {
+                // Even though we have atoms for these tags, we don't want to
+                // treat them as "recognized tags" for the purpose of parsing
+                // because that changes how we parse documents.
+                continue;
+            }
+            tagList.add(tags[i]->localName().impl());
+        }
+    }
+    return tagList.contains(tagName.localName().impl());
+}
+
+void HTMLObjectElement::updateDocNamedItem()
+{
+    // The rule is "<object> elements with no children other than
+    // <param> elements, unknown elements and whitespace can be
+    // found by name in a document, and other <object> elements cannot."
+    bool wasNamedItem = m_docNamedItem;
+    bool isNamedItem = true;
+    Node* child = firstChild();
+    while (child && isNamedItem) {
+        if (child->isElementNode()) {
+            Element* element = toElement(child);
+            // FIXME: Use of isRecognizedTagName is almost certainly wrong here.
+            if (isRecognizedTagName(element->tagQName()) && !element->hasTagName(paramTag))
+                isNamedItem = false;
+        } else if (child->isTextNode()) {
+            if (!toText(child)->containsOnlyWhitespace())
+                isNamedItem = false;
+        } else
+            isNamedItem = false;
+        child = child->nextSibling();
+    }
+    if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
+        HTMLDocument* document = toHTMLDocument(this->document());
+        if (isNamedItem) {
+            document->addNamedItem(getNameAttribute());
+            document->addExtraNamedItem(getIdAttribute());
+        } else {
+            document->removeNamedItem(getNameAttribute());
+            document->removeExtraNamedItem(getIdAttribute());
+        }
+    }
+    m_docNamedItem = isNamedItem;
+}
+
+bool HTMLObjectElement::containsJavaApplet() const
+{
+    if (MIMETypeRegistry::isJavaAppletMIMEType(getAttribute(typeAttr)))
+        return true;
+        
+    for (Element* child = ElementTraversal::firstWithin(this); child; child = ElementTraversal::nextSkippingChildren(child, this)) {
+        if (child->hasTagName(paramTag)
+                && equalIgnoringCase(child->getNameAttribute(), "type")
+                && MIMETypeRegistry::isJavaAppletMIMEType(child->getAttribute(valueAttr).string()))
+            return true;
+        if (child->hasTagName(objectTag)
+                && static_cast<HTMLObjectElement*>(child)->containsJavaApplet())
+            return true;
+        if (child->hasTagName(appletTag))
+            return true;
+    }
+    
+    return false;
+}
+
+void HTMLObjectElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
+
+    addSubresourceURL(urls, document()->completeURL(getAttribute(dataAttr)));
+
+    // FIXME: Passing a string that starts with "#" to the completeURL function does
+    // not seem like it would work. The image element has similar but not identical code.
+    const AtomicString& useMap = getAttribute(usemapAttr);
+    if (useMap.startsWith('#'))
+        addSubresourceURL(urls, document()->completeURL(useMap));
+}
+
+void HTMLObjectElement::didMoveToNewDocument(Document* oldDocument)
+{
+    FormAssociatedElement::didMoveToNewDocument(oldDocument);
+    HTMLPlugInImageElement::didMoveToNewDocument(oldDocument);
+}
+
+bool HTMLObjectElement::appendFormData(FormDataList& encoding, bool)
+{
+    if (name().isEmpty())
+        return false;
+
+    Widget* widget = pluginWidget();
+    if (!widget || !widget->isPluginView())
+        return false;
+    String value;
+    if (!toPluginView(widget)->getFormValue(value))
+        return false;
+    encoding.appendData(name(), value);
+    return true;
+}
+
+HTMLFormElement* HTMLObjectElement::virtualForm() const
+{
+    return FormAssociatedElement::form();
+}
+
+}
diff --git a/Source/core/html/HTMLObjectElement.h b/Source/core/html/HTMLObjectElement.h
new file mode 100644
index 0000000..ce0ff8e
--- /dev/null
+++ b/Source/core/html/HTMLObjectElement.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2006, 2007, 2008, 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLObjectElement_h
+#define HTMLObjectElement_h
+
+#include "core/html/FormAssociatedElement.h"
+#include "core/html/HTMLPlugInImageElement.h"
+
+namespace WebCore {
+
+class HTMLFormElement;
+
+class HTMLObjectElement FINAL : public HTMLPlugInImageElement, public FormAssociatedElement {
+public:
+    static PassRefPtr<HTMLObjectElement> create(const QualifiedName&, Document*, HTMLFormElement*, bool createdByParser);
+    virtual ~HTMLObjectElement();
+
+    bool isDocNamedItem() const { return m_docNamedItem; }
+
+    const String& classId() const { return m_classId; }
+
+    bool containsJavaApplet() const;
+
+    virtual bool useFallbackContent() const { return m_useFallbackContent; }
+    void renderFallbackContent();
+
+    // Implementations of FormAssociatedElement
+    HTMLFormElement* form() const { return FormAssociatedElement::form(); }
+
+    virtual bool isFormControlElement() const { return false; }
+
+    virtual bool isEnumeratable() const { return true; }
+    virtual bool appendFormData(FormDataList&, bool);
+
+    // Implementations of constraint validation API.
+    // Note that the object elements are always barred from constraint validation.
+    virtual String validationMessage() const OVERRIDE { return String(); }
+    bool checkValidity() { return true; }
+    virtual void setCustomValidity(const String&) OVERRIDE { }
+
+    using Node::ref;
+    using Node::deref;
+
+    virtual bool canContainRangeEndPoint() const { return useFallbackContent(); }
+
+private:
+    HTMLObjectElement(const QualifiedName&, Document*, HTMLFormElement*, bool createdByParser);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+    virtual const AtomicString& imageSourceURL() const OVERRIDE;
+
+    virtual RenderWidget* renderWidgetForJSBindings() const;
+
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+
+    virtual void updateWidget(PluginCreationOption);
+    void updateDocNamedItem();
+
+    bool hasFallbackContent() const;
+    
+    // FIXME: This function should not deal with url or serviceType
+    // so that we can better share code between <object> and <embed>.
+    void parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType);
+    
+    bool shouldAllowQuickTimeClassIdQuirk();
+    bool hasValidClassId();
+
+    virtual void refFormAssociatedElement() { ref(); }
+    virtual void derefFormAssociatedElement() { deref(); }
+    virtual HTMLFormElement* virtualForm() const;
+
+    virtual bool shouldRegisterAsNamedItem() const OVERRIDE { return isDocNamedItem(); }
+    virtual bool shouldRegisterAsExtraNamedItem() const OVERRIDE { return isDocNamedItem(); }
+
+    String m_classId;
+    bool m_docNamedItem : 1;
+    bool m_useFallbackContent : 1;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/HTMLObjectElement.idl b/Source/core/html/HTMLObjectElement.idl
new file mode 100644
index 0000000..6082baa
--- /dev/null
+++ b/Source/core/html/HTMLObjectElement.idl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2006, 2007, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomNamedGetter,
+    CustomNamedSetter,
+    CustomIndexedGetter,
+    CustomIndexedSetter,
+    CustomCall
+] interface HTMLObjectElement : HTMLElement {
+    readonly attribute HTMLFormElement form;
+    [Reflect] attribute DOMString code;
+    [Reflect] attribute DOMString align;
+    [Reflect] attribute DOMString archive;
+    [Reflect] attribute DOMString border;
+    [Reflect] attribute DOMString codeBase;
+    [Reflect] attribute DOMString codeType;
+    [Reflect, URL] attribute DOMString data;
+    [Reflect] attribute boolean declare;
+    [Reflect] attribute DOMString height;
+    [Reflect] attribute long hspace;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute DOMString standby;
+    [Reflect] attribute DOMString type;
+    [Reflect] attribute DOMString useMap;
+    [Reflect] attribute long vspace;
+    [Reflect] attribute DOMString width;
+    readonly attribute boolean willValidate;
+    readonly attribute ValidityState validity;
+    readonly attribute DOMString validationMessage;
+    boolean checkValidity();
+    void setCustomValidity([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString error);
+
+    // Introduced in DOM Level 2:
+    [CheckSecurityForNode] readonly attribute Document contentDocument;
+
+#if defined(ENABLE_SVG) && ENABLE_SVG
+    [CheckSecurityForNode, RaisesException] SVGDocument getSVGDocument();
+#endif
+};
+
diff --git a/Source/core/html/HTMLOptGroupElement.cpp b/Source/core/html/HTMLOptGroupElement.cpp
new file mode 100644
index 0000000..f7da957
--- /dev/null
+++ b/Source/core/html/HTMLOptGroupElement.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLOptGroupElement.h"
+
+#include "HTMLNames.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/Document.h"
+#include "core/dom/NodeRenderStyle.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/html/HTMLSelectElement.h"
+#include "core/rendering/RenderMenuList.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLOptGroupElement::HTMLOptGroupElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(optgroupTag));
+    setHasCustomStyleCallbacks();
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLOptGroupElement> HTMLOptGroupElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLOptGroupElement(tagName, document));
+}
+
+bool HTMLOptGroupElement::isDisabledFormControl() const
+{
+    return fastHasAttribute(disabledAttr);
+}
+
+bool HTMLOptGroupElement::supportsFocus() const
+{
+    return HTMLElement::supportsFocus();
+}
+
+bool HTMLOptGroupElement::isFocusable() const
+{
+    // Optgroup elements do not have a renderer so we check the renderStyle instead.
+    return supportsFocus() && renderStyle() && renderStyle()->display() != NONE;
+}
+
+const AtomicString& HTMLOptGroupElement::formControlType() const
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, optgroup, ("optgroup", AtomicString::ConstructFromLiteral));
+    return optgroup;
+}
+
+void HTMLOptGroupElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    recalcSelectOptions();
+    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+}
+
+void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    HTMLElement::parseAttribute(name, value);
+    recalcSelectOptions();
+
+    if (name == disabledAttr)
+        didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled);
+}
+
+void HTMLOptGroupElement::recalcSelectOptions()
+{
+    ContainerNode* select = parentNode();
+    while (select && !select->hasTagName(selectTag))
+        select = select->parentNode();
+    if (select)
+        toHTMLSelectElement(select)->setRecalcListItems();
+}
+
+void HTMLOptGroupElement::attach()
+{
+    HTMLElement::attach();
+    // If after attaching nothing called styleForRenderer() on this node we
+    // manually cache the value. This happens if our parent doesn't have a
+    // renderer like <optgroup> or if it doesn't allow children like <select>.
+    if (!m_style && parentNode()->renderStyle())
+        updateNonRenderStyle();
+}
+
+void HTMLOptGroupElement::detach()
+{
+    m_style.clear();
+    HTMLElement::detach();
+}
+
+void HTMLOptGroupElement::updateNonRenderStyle()
+{
+    m_style = document()->styleResolver()->styleForElement(this);
+}
+
+RenderStyle* HTMLOptGroupElement::nonRendererStyle() const
+{
+    return m_style.get();
+}
+
+PassRefPtr<RenderStyle> HTMLOptGroupElement::customStyleForRenderer()
+{
+    // styleForRenderer is called whenever a new style should be associated
+    // with an Element so now is a good time to update our cached style.
+    updateNonRenderStyle();
+    return m_style;
+}
+
+String HTMLOptGroupElement::groupLabelText() const
+{
+    String itemText = document()->displayStringModifiedByEncoding(getAttribute(labelAttr));
+    
+    // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior.
+    itemText = itemText.stripWhiteSpace();
+    // We want to collapse our whitespace too.  This will match other browsers.
+    itemText = itemText.simplifyWhiteSpace();
+        
+    return itemText;
+}
+    
+HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const
+{
+    ContainerNode* select = parentNode();
+    while (select && !select->hasTagName(selectTag))
+        select = select->parentNode();
+    
+    if (!select)
+       return 0;
+    
+    return toHTMLSelectElement(select);
+}
+
+void HTMLOptGroupElement::accessKeyAction(bool)
+{
+    HTMLSelectElement* select = ownerSelectElement();
+    // send to the parent to bring focus to the list box
+    if (select && !select->focused())
+        select->accessKeyAction(false);
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLOptGroupElement.h b/Source/core/html/HTMLOptGroupElement.h
new file mode 100644
index 0000000..c6be9d1
--- /dev/null
+++ b/Source/core/html/HTMLOptGroupElement.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLOptGroupElement_h
+#define HTMLOptGroupElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+    
+class HTMLSelectElement;
+
+class HTMLOptGroupElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLOptGroupElement> create(const QualifiedName&, Document*);
+
+    virtual bool isDisabledFormControl() const OVERRIDE;
+    HTMLSelectElement* ownerSelectElement() const;
+    
+    String groupLabelText() const;
+
+private:
+    HTMLOptGroupElement(const QualifiedName&, Document*);
+
+    virtual const AtomicString& formControlType() const;
+    virtual bool supportsFocus() const;
+    virtual bool isFocusable() const;
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool rendererIsNeeded(const NodeRenderingContext&) { return false; }
+    virtual void attach();
+    virtual void detach();
+
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
+    virtual void accessKeyAction(bool sendMouseEvents);
+
+    // <optgroup> never has a renderer so we manually manage a cached style.
+    void updateNonRenderStyle();
+    virtual RenderStyle* nonRendererStyle() const OVERRIDE;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+
+    void recalcSelectOptions();
+
+    RefPtr<RenderStyle> m_style;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLOptGroupElement.idl b/Source/core/html/HTMLOptGroupElement.idl
new file mode 100644
index 0000000..26a782f
--- /dev/null
+++ b/Source/core/html/HTMLOptGroupElement.idl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLOptGroupElement : HTMLElement {
+    [Reflect] attribute boolean disabled;
+    [Reflect] attribute DOMString label;
+};
+
diff --git a/Source/core/html/HTMLOptionElement.cpp b/Source/core/html/HTMLOptionElement.cpp
new file mode 100644
index 0000000..3add454
--- /dev/null
+++ b/Source/core/html/HTMLOptionElement.cpp
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Motorola Mobility, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLOptionElement.h"
+
+#include "HTMLNames.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/NodeRenderStyle.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/ScriptElement.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLDataListElement.h"
+#include "core/html/HTMLSelectElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/rendering/RenderMenuList.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLOptionElement::HTMLOptionElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_disabled(false)
+    , m_isSelected(false)
+{
+    ASSERT(hasTagName(optionTag));
+    setHasCustomStyleCallbacks();
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLOptionElement> HTMLOptionElement::create(Document* document)
+{
+    return adoptRef(new HTMLOptionElement(optionTag, document));
+}
+
+PassRefPtr<HTMLOptionElement> HTMLOptionElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLOptionElement(tagName, document));
+}
+
+PassRefPtr<HTMLOptionElement> HTMLOptionElement::createForJSConstructor(Document* document, const String& data, const String& value,
+        bool defaultSelected, bool selected, ExceptionCode& ec)
+{
+    RefPtr<HTMLOptionElement> element = adoptRef(new HTMLOptionElement(optionTag, document));
+
+    RefPtr<Text> text = Text::create(document, data.isNull() ? "" : data);
+
+    ec = 0;
+    element->appendChild(text.release(), ec);
+    if (ec)
+        return 0;
+
+    if (!value.isNull())
+        element->setValue(value);
+    if (defaultSelected)
+        element->setAttribute(selectedAttr, emptyAtom);
+    element->setSelected(selected);
+
+    return element.release();
+}
+
+void HTMLOptionElement::attach()
+{
+    HTMLElement::attach();
+    // If after attaching nothing called styleForRenderer() on this node we
+    // manually cache the value. This happens if our parent doesn't have a
+    // renderer like <optgroup> or if it doesn't allow children like <select>.
+    if (!m_style && parentNode()->renderStyle())
+        updateNonRenderStyle();
+}
+
+void HTMLOptionElement::detach()
+{
+    m_style.clear();
+    HTMLElement::detach();
+}
+
+bool HTMLOptionElement::supportsFocus() const
+{
+    return HTMLElement::supportsFocus();
+}
+
+bool HTMLOptionElement::isFocusable() const
+{
+    // Option elements do not have a renderer so we check the renderStyle instead.
+    return supportsFocus() && renderStyle() && renderStyle()->display() != NONE;
+}
+
+String HTMLOptionElement::text() const
+{
+    Document* document = this->document();
+    String text;
+
+    // WinIE does not use the label attribute, so as a quirk, we ignore it.
+    if (!document->inQuirksMode())
+        text = fastGetAttribute(labelAttr);
+
+    // FIXME: The following treats an element with the label attribute set to
+    // the empty string the same as an element with no label attribute at all.
+    // Is that correct? If it is, then should the label function work the same way?
+    if (text.isEmpty())
+        text = collectOptionInnerText();
+
+    // FIXME: Is displayStringModifiedByEncoding helpful here?
+    // If it's correct here, then isn't it needed in the value and label functions too?
+    return document->displayStringModifiedByEncoding(text).stripWhiteSpace(isHTMLSpace).simplifyWhiteSpace(isHTMLSpace);
+}
+
+void HTMLOptionElement::setText(const String &text, ExceptionCode& ec)
+{
+    RefPtr<Node> protectFromMutationEvents(this);
+
+    // Changing the text causes a recalc of a select's items, which will reset the selected
+    // index to the first item if the select is single selection with a menu list. We attempt to
+    // preserve the selected item.
+    RefPtr<HTMLSelectElement> select = ownerSelectElement();
+    bool selectIsMenuList = select && select->usesMenuList();
+    int oldSelectedIndex = selectIsMenuList ? select->selectedIndex() : -1;
+
+    // Handle the common special case where there's exactly 1 child node, and it's a text node.
+    Node* child = firstChild();
+    if (child && child->isTextNode() && !child->nextSibling())
+        toText(child)->setData(text, ec);
+    else {
+        removeChildren();
+        appendChild(Text::create(document(), text), ec);
+    }
+    
+    if (selectIsMenuList && select->selectedIndex() != oldSelectedIndex)
+        select->setSelectedIndex(oldSelectedIndex);
+}
+
+void HTMLOptionElement::accessKeyAction(bool)
+{
+    HTMLSelectElement* select = ownerSelectElement();
+    if (select)
+        select->accessKeySetSelectedIndex(index());
+}
+
+int HTMLOptionElement::index() const
+{
+    // It would be faster to cache the index, but harder to get it right in all cases.
+
+    HTMLSelectElement* selectElement = ownerSelectElement();
+    if (!selectElement)
+        return 0;
+
+    int optionIndex = 0;
+
+    const Vector<HTMLElement*>& items = selectElement->listItems();
+    size_t length = items.size();
+    for (size_t i = 0; i < length; ++i) {
+        if (!items[i]->hasTagName(optionTag))
+            continue;
+        if (items[i] == this)
+            return optionIndex;
+        ++optionIndex;
+    }
+
+    return 0;
+}
+
+void HTMLOptionElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+#if ENABLE(DATALIST_ELEMENT)
+    if (name == valueAttr) {
+        if (HTMLDataListElement* dataList = ownerDataListElement())
+            dataList->optionElementChildrenChanged();
+    } else
+#endif
+    if (name == disabledAttr) {
+        bool oldDisabled = m_disabled;
+        m_disabled = !value.isNull();
+        if (oldDisabled != m_disabled) {
+            didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled);
+            if (renderer() && renderer()->style()->hasAppearance())
+                renderer()->theme()->stateChanged(renderer(), EnabledState);
+        }
+    } else if (name == selectedAttr) {
+        // FIXME: This doesn't match what the HTML specification says.
+        // The specification implies that removing the selected attribute or
+        // changing the value of a selected attribute that is already present
+        // has no effect on whether the element is selected. Further, it seems
+        // that we need to do more than just set m_isSelected to select in that
+        // case; we'd need to do the other work from the setSelected function.
+        m_isSelected = !value.isNull();
+    } else
+        HTMLElement::parseAttribute(name, value);
+}
+
+String HTMLOptionElement::value() const
+{
+    const AtomicString& value = fastGetAttribute(valueAttr);
+    if (!value.isNull())
+        return value;
+    return collectOptionInnerText().stripWhiteSpace(isHTMLSpace).simplifyWhiteSpace(isHTMLSpace);
+}
+
+void HTMLOptionElement::setValue(const String& value)
+{
+    setAttribute(valueAttr, value);
+}
+
+bool HTMLOptionElement::selected()
+{
+    if (HTMLSelectElement* select = ownerSelectElement()) {
+        // If a stylesheet contains option:checked selectors, this function is
+        // called during parsing. updateListItemSelectedStates() is O(N) where N
+        // is the number of option elements, so the <select> parsing would be
+        // O(N^2) without isParsingInProgress check. Also,
+        // updateListItemSelectedStates() determines default selection, and we'd
+        // like to avoid to determine default selection with incomplete option
+        // list.
+        if (select->isParsingInProgress())
+            return m_isSelected;
+        select->updateListItemSelectedStates();
+    }
+    return m_isSelected;
+}
+
+void HTMLOptionElement::setSelected(bool selected)
+{
+    if (m_isSelected == selected)
+        return;
+
+    setSelectedState(selected);
+
+    if (HTMLSelectElement* select = ownerSelectElement())
+        select->optionSelectionStateChanged(this, selected);
+}
+
+void HTMLOptionElement::setSelectedState(bool selected)
+{
+    if (m_isSelected == selected)
+        return;
+
+    m_isSelected = selected;
+    didAffectSelector(AffectedSelectorChecked);
+
+    if (HTMLSelectElement* select = ownerSelectElement())
+        select->invalidateSelectedItems();
+}
+
+void HTMLOptionElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+#if ENABLE(DATALIST_ELEMENT)
+    if (HTMLDataListElement* dataList = ownerDataListElement())
+        dataList->optionElementChildrenChanged();
+    else
+#endif
+    if (HTMLSelectElement* select = ownerSelectElement())
+        select->optionElementChildrenChanged();
+    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+}
+
+#if ENABLE(DATALIST_ELEMENT)
+HTMLDataListElement* HTMLOptionElement::ownerDataListElement() const
+{
+    for (ContainerNode* parent = parentNode(); parent ; parent = parent->parentNode()) {
+        if (parent->hasTagName(datalistTag))
+            return static_cast<HTMLDataListElement*>(parent);
+    }
+    return 0;
+}
+#endif
+
+HTMLSelectElement* HTMLOptionElement::ownerSelectElement() const
+{
+    ContainerNode* select = parentNode();
+    while (select && !select->hasTagName(selectTag))
+        select = select->parentNode();
+
+    if (!select)
+        return 0;
+
+    return toHTMLSelectElement(select);
+}
+
+String HTMLOptionElement::label() const
+{
+    const AtomicString& label = fastGetAttribute(labelAttr);
+    if (!label.isNull())
+        return label; 
+    return collectOptionInnerText().stripWhiteSpace(isHTMLSpace).simplifyWhiteSpace(isHTMLSpace);
+}
+
+void HTMLOptionElement::setLabel(const String& label)
+{
+    setAttribute(labelAttr, label);
+}
+
+void HTMLOptionElement::updateNonRenderStyle()
+{
+    m_style = document()->styleResolver()->styleForElement(this);
+}
+
+RenderStyle* HTMLOptionElement::nonRendererStyle() const
+{
+    return m_style.get();
+}
+
+PassRefPtr<RenderStyle> HTMLOptionElement::customStyleForRenderer()
+{
+    // styleForRenderer is called whenever a new style should be associated
+    // with an Element so now is a good time to update our cached style.
+    updateNonRenderStyle();
+    return m_style;
+}
+
+void HTMLOptionElement::didRecalcStyle(StyleChange)
+{
+    // FIXME: This is nasty, we ask our owner select to repaint even if the new
+    // style is exactly the same.
+    if (HTMLSelectElement* select = ownerSelectElement()) {
+        if (RenderObject* renderer = select->renderer())
+            renderer->repaint();
+    }
+}
+
+String HTMLOptionElement::textIndentedToRespectGroupLabel() const
+{
+    ContainerNode* parent = parentNode();
+    if (parent && parent->hasTagName(optgroupTag))
+        return "    " + text();
+    return text();
+}
+
+bool HTMLOptionElement::isDisabledFormControl() const
+{
+    if (ownElementDisabled())
+        return true;
+
+    if (!parentNode() || !parentNode()->isHTMLElement())
+        return false;
+
+    HTMLElement* parentElement = static_cast<HTMLElement*>(parentNode());
+    return parentElement->hasTagName(optgroupTag) && parentElement->isDisabledFormControl();
+}
+
+Node::InsertionNotificationRequest HTMLOptionElement::insertedInto(ContainerNode* insertionPoint)
+{
+    if (HTMLSelectElement* select = ownerSelectElement()) {
+        select->setRecalcListItems();
+        // Do not call selected() since calling updateListItemSelectedStates()
+        // at this time won't do the right thing. (Why, exactly?)
+        // FIXME: Might be better to call this unconditionally, always passing m_isSelected,
+        // rather than only calling it if we are selected.
+        if (m_isSelected)
+            select->optionSelectionStateChanged(this, true);
+        select->scrollToSelection();
+    }
+
+    return HTMLElement::insertedInto(insertionPoint);
+}
+
+String HTMLOptionElement::collectOptionInnerText() const
+{
+    StringBuilder text;
+    for (Node* node = firstChild(); node; ) {
+        if (node->isTextNode())
+            text.append(node->nodeValue());
+        // Text nodes inside script elements are not part of the option text.
+        if (node->isElementNode() && toScriptElementIfPossible(toElement(node)))
+            node = NodeTraversal::nextSkippingChildren(node, this);
+        else
+            node = NodeTraversal::next(node, this);
+    }
+    return text.toString();
+}
+
+#ifndef NDEBUG
+
+HTMLOptionElement* toHTMLOptionElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(optionTag));
+    return static_cast<HTMLOptionElement*>(node);
+}
+
+const HTMLOptionElement* toHTMLOptionElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(optionTag));
+    return static_cast<const HTMLOptionElement*>(node);
+}
+
+#endif
+
+} // namespace
diff --git a/Source/core/html/HTMLOptionElement.h b/Source/core/html/HTMLOptionElement.h
new file mode 100644
index 0000000..dac0d62
--- /dev/null
+++ b/Source/core/html/HTMLOptionElement.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLOptionElement_h
+#define HTMLOptionElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLDataListElement;
+class HTMLSelectElement;
+
+class HTMLOptionElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLOptionElement> create(Document*);
+    static PassRefPtr<HTMLOptionElement> create(const QualifiedName&, Document*);
+    static PassRefPtr<HTMLOptionElement> createForJSConstructor(Document*, const String& data, const String& value,
+       bool defaultSelected, bool selected, ExceptionCode&);
+
+    virtual String text() const;
+    void setText(const String&, ExceptionCode&);
+
+    int index() const;
+
+    String value() const;
+    void setValue(const String&);
+
+    bool selected();
+    void setSelected(bool);
+
+#if ENABLE(DATALIST_ELEMENT)
+    HTMLDataListElement* ownerDataListElement() const;
+#endif
+    HTMLSelectElement* ownerSelectElement() const;
+
+    String label() const;
+    void setLabel(const String&);
+
+    bool ownElementDisabled() const { return m_disabled; }
+
+    virtual bool isDisabledFormControl() const OVERRIDE;
+
+    String textIndentedToRespectGroupLabel() const;
+
+    void setSelectedState(bool);
+
+private:
+    HTMLOptionElement(const QualifiedName&, Document*);
+
+    virtual bool supportsFocus() const;
+    virtual bool isFocusable() const;
+    virtual bool rendererIsNeeded(const NodeRenderingContext&) { return false; }
+    virtual void attach();
+    virtual void detach();
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void accessKeyAction(bool);
+
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
+    // <option> never has a renderer so we manually manage a cached style.
+    void updateNonRenderStyle();
+    virtual RenderStyle* nonRendererStyle() const OVERRIDE;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+
+    void didRecalcStyle(StyleChange) OVERRIDE;
+
+    String collectOptionInnerText() const;
+
+    bool m_disabled;
+    bool m_isSelected;
+    RefPtr<RenderStyle> m_style;
+};
+
+HTMLOptionElement* toHTMLOptionElement(Node*);
+const HTMLOptionElement* toHTMLOptionElement(const Node*);
+void toHTMLOptionElement(const HTMLOptionElement*); // This overload will catch anyone doing an unnecessary cast.
+
+#ifdef NDEBUG
+
+// The debug versions of these, with assertions, are not inlined.
+
+inline HTMLOptionElement* toHTMLOptionElement(Node* node)
+{
+    return static_cast<HTMLOptionElement*>(node);
+}
+
+inline const HTMLOptionElement* toHTMLOptionElement(const Node* node)
+{
+    return static_cast<const HTMLOptionElement*>(node);
+}
+
+#endif
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLOptionElement.idl b/Source/core/html/HTMLOptionElement.idl
new file mode 100644
index 0000000..e47ca9f
--- /dev/null
+++ b/Source/core/html/HTMLOptionElement.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple, Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    NamedConstructor=Option([Default=NullString] optional DOMString data, [Default=NullString] optional DOMString value, [Default=Undefined] optional boolean defaultSelected, [Default=Undefined] optional boolean selected),
+    RaisesException
+] interface HTMLOptionElement : HTMLElement {
+    [Reflect] attribute boolean disabled;
+    readonly attribute HTMLFormElement form;
+    attribute DOMString label;
+    [Reflect=selected] attribute boolean defaultSelected;
+    attribute boolean selected;
+    attribute DOMString value;
+
+    [SetterRaisesException] attribute DOMString text;
+    readonly attribute long index;
+};
diff --git a/Source/core/html/HTMLOptionsCollection.cpp b/Source/core/html/HTMLOptionsCollection.cpp
new file mode 100644
index 0000000..9be4ba0
--- /dev/null
+++ b/Source/core/html/HTMLOptionsCollection.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2006, 2011, 2012 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLOptionsCollection.h"
+
+#include "core/dom/ExceptionCode.h"
+#include "core/html/HTMLOptionElement.h"
+#include "core/html/HTMLSelectElement.h"
+
+namespace WebCore {
+
+HTMLOptionsCollection::HTMLOptionsCollection(Node* select)
+    : HTMLCollection(select, SelectOptions, DoesNotOverrideItemAfter)
+{
+    ASSERT(select->hasTagName(HTMLNames::selectTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLOptionsCollection> HTMLOptionsCollection::create(Node* select, CollectionType)
+{
+    return adoptRef(new HTMLOptionsCollection(select));
+}
+
+void HTMLOptionsCollection::add(PassRefPtr<HTMLOptionElement> element, ExceptionCode& ec)
+{
+    add(element, length(), ec);
+}
+
+void HTMLOptionsCollection::add(PassRefPtr<HTMLOptionElement> element, int index, ExceptionCode& ec)
+{
+    HTMLOptionElement* newOption = element.get();
+
+    if (!newOption) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+
+    if (index < -1) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    ec = 0;
+    HTMLSelectElement* select = toHTMLSelectElement(ownerNode());
+
+    if (index == -1 || unsigned(index) >= length())
+        select->add(newOption, 0, ec);
+    else
+        select->add(newOption, static_cast<HTMLOptionElement*>(item(index)), ec);
+
+    ASSERT(!ec);
+}
+
+void HTMLOptionsCollection::remove(int index)
+{
+    toHTMLSelectElement(ownerNode())->remove(index);
+}
+
+int HTMLOptionsCollection::selectedIndex() const
+{
+    return toHTMLSelectElement(ownerNode())->selectedIndex();
+}
+
+void HTMLOptionsCollection::setSelectedIndex(int index)
+{
+    toHTMLSelectElement(ownerNode())->setSelectedIndex(index);
+}
+
+void HTMLOptionsCollection::setLength(unsigned length, ExceptionCode& ec)
+{
+    toHTMLSelectElement(ownerNode())->setLength(length, ec);
+}
+
+} //namespace
diff --git a/Source/core/html/HTMLOptionsCollection.h b/Source/core/html/HTMLOptionsCollection.h
new file mode 100644
index 0000000..e5ddb5a
--- /dev/null
+++ b/Source/core/html/HTMLOptionsCollection.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLOptionsCollection_h
+#define HTMLOptionsCollection_h
+
+#include "core/html/HTMLCollection.h"
+
+namespace WebCore {
+
+class HTMLOptionElement;
+class HTMLSelectElement;
+
+typedef int ExceptionCode;
+
+class HTMLOptionsCollection : public HTMLCollection {
+public:
+    static PassRefPtr<HTMLOptionsCollection> create(Node*, CollectionType);
+
+    void add(PassRefPtr<HTMLOptionElement>, ExceptionCode&);
+    void add(PassRefPtr<HTMLOptionElement>, int index, ExceptionCode&);
+    void remove(int index);
+
+    int selectedIndex() const;
+    void setSelectedIndex(int);
+
+    void setLength(unsigned, ExceptionCode&);
+
+private:
+    HTMLOptionsCollection(Node*);
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLOptionsCollection.idl b/Source/core/html/HTMLOptionsCollection.idl
new file mode 100644
index 0000000..f5ee73d
--- /dev/null
+++ b/Source/core/html/HTMLOptionsCollection.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomIndexedSetter,
+    CustomNamedGetter,
+    GenerateIsReachable=ImplOwnerNodeRoot,
+    CustomIndexedGetter,
+    DependentLifetime,
+] interface HTMLOptionsCollection : HTMLCollection {
+    attribute long selectedIndex;
+    [CustomSetter, SetterRaisesException] attribute unsigned long length;
+
+    [Custom] Node namedItem([Default=Undefined] optional DOMString name);
+
+    [Custom, RaisesException] void add([Default=Undefined] optional HTMLOptionElement option, 
+                      optional unsigned long index);
+    [Custom] void remove([Default=Undefined] optional unsigned long index);
+};
+
diff --git a/Source/core/html/HTMLOutputElement.cpp b/Source/core/html/HTMLOutputElement.cpp
new file mode 100644
index 0000000..d196825
--- /dev/null
+++ b/Source/core/html/HTMLOutputElement.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/HTMLOutputElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/html/HTMLFormElement.h"
+
+namespace WebCore {
+
+inline HTMLOutputElement::HTMLOutputElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+    : HTMLFormControlElement(tagName, document, form)
+    , m_isDefaultValueMode(true)
+    , m_isSetTextContentInProgress(false)
+    , m_defaultValue("")
+    , m_tokens(DOMSettableTokenList::create())
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLOutputElement> HTMLOutputElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+{
+    return adoptRef(new HTMLOutputElement(tagName, document, form));
+}
+
+const AtomicString& HTMLOutputElement::formControlType() const
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, output, ("output", AtomicString::ConstructFromLiteral));
+    return output;
+}
+
+bool HTMLOutputElement::supportsFocus() const
+{
+    return HTMLElement::supportsFocus();
+}
+
+void HTMLOutputElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == HTMLNames::forAttr)
+        setFor(value);
+    else
+        HTMLFormControlElement::parseAttribute(name, value);
+}
+
+DOMSettableTokenList* HTMLOutputElement::htmlFor() const
+{
+    return m_tokens.get();
+}
+
+void HTMLOutputElement::setFor(const String& value)
+{
+    m_tokens->setValue(value);
+}
+
+void HTMLOutputElement::childrenChanged(bool createdByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    HTMLFormControlElement::childrenChanged(createdByParser, beforeChange, afterChange, childCountDelta);
+
+    if (createdByParser || m_isSetTextContentInProgress) {
+        m_isSetTextContentInProgress = false;
+        return;
+    }
+
+    if (m_isDefaultValueMode)
+        m_defaultValue = textContent();
+}
+
+void HTMLOutputElement::reset()
+{
+    // The reset algorithm for output elements is to set the element's
+    // value mode flag to "default" and then to set the element's textContent
+    // attribute to the default value.
+    m_isDefaultValueMode = true;
+    if (m_defaultValue == value())
+        return;
+    setTextContentInternal(m_defaultValue);
+}
+
+String HTMLOutputElement::value() const
+{
+    return textContent();
+}
+
+void HTMLOutputElement::setValue(const String& value)
+{
+    // The value mode flag set to "value" when the value attribute is set.
+    m_isDefaultValueMode = false;
+    if (value == this->value())
+        return;
+    setTextContentInternal(value);
+}
+
+String HTMLOutputElement::defaultValue() const
+{
+    return m_defaultValue;
+}
+
+void HTMLOutputElement::setDefaultValue(const String& value)
+{
+    if (m_defaultValue == value)
+        return;
+    m_defaultValue = value;
+    // The spec requires the value attribute set to the default value
+    // when the element's value mode flag to "default".
+    if (m_isDefaultValueMode)
+        setTextContentInternal(value);
+}
+
+void HTMLOutputElement::setTextContentInternal(const String& value)
+{
+    ASSERT(!m_isSetTextContentInProgress);
+    m_isSetTextContentInProgress = true;
+    setTextContent(value, IGNORE_EXCEPTION);
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLOutputElement.h b/Source/core/html/HTMLOutputElement.h
new file mode 100644
index 0000000..4b27451
--- /dev/null
+++ b/Source/core/html/HTMLOutputElement.h
@@ -0,0 +1,76 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 HTMLOutputElement_h
+#define HTMLOutputElement_h
+
+#include "core/html/DOMSettableTokenList.h"
+#include "core/html/HTMLFormControlElement.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class HTMLOutputElement FINAL : public HTMLFormControlElement {
+public:
+    static PassRefPtr<HTMLOutputElement> create(const QualifiedName&, Document*, HTMLFormElement*);
+
+    virtual bool willValidate() const { return false; }
+
+    String value() const;
+    void setValue(const String&);
+    String defaultValue() const;
+    void setDefaultValue(const String&);
+    void setFor(const String&);
+    DOMSettableTokenList* htmlFor() const;
+    
+    virtual bool canContainRangeEndPoint() const { return false; }
+
+private:
+    HTMLOutputElement(const QualifiedName&, Document*, HTMLFormElement*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual const AtomicString& formControlType() const;
+    virtual bool isEnumeratable() const { return true; }
+    virtual bool supportLabels() const OVERRIDE { return true; }
+    virtual bool supportsFocus() const;
+    virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+    virtual void reset();
+
+    void setTextContentInternal(const String&);
+
+    bool m_isDefaultValueMode;
+    bool m_isSetTextContentInProgress;
+    String m_defaultValue;
+    RefPtr<DOMSettableTokenList> m_tokens;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLOutputElement.idl b/Source/core/html/HTMLOutputElement.idl
new file mode 100644
index 0000000..7edaca2
--- /dev/null
+++ b/Source/core/html/HTMLOutputElement.idl
@@ -0,0 +1,41 @@
+/*
+ * 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. 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.
+ */
+
+interface HTMLOutputElement : HTMLElement {
+    readonly attribute DOMSettableTokenList htmlFor;
+    readonly attribute HTMLFormElement form;
+    [Reflect] attribute DOMString name;
+
+    readonly attribute DOMString type;
+    [TreatNullAs=NullString] attribute DOMString defaultValue;
+    [TreatNullAs=NullString] attribute DOMString value;
+
+    readonly attribute boolean willValidate;
+    readonly attribute ValidityState validity;
+    readonly attribute DOMString validationMessage;
+    boolean checkValidity();
+    void setCustomValidity([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString error);
+
+    readonly attribute NodeList labels;
+};
diff --git a/Source/core/html/HTMLParagraphElement.cpp b/Source/core/html/HTMLParagraphElement.cpp
new file mode 100644
index 0000000..0b6a362
--- /dev/null
+++ b/Source/core/html/HTMLParagraphElement.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLParagraphElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLParagraphElement::HTMLParagraphElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(pTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLParagraphElement> HTMLParagraphElement::create(Document* document)
+{
+    return adoptRef(new HTMLParagraphElement(pTag, document));
+}
+
+PassRefPtr<HTMLParagraphElement> HTMLParagraphElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLParagraphElement(tagName, document));
+}
+
+bool HTMLParagraphElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == alignAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLParagraphElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == alignAttr) {
+        if (equalIgnoringCase(value, "middle") || equalIgnoringCase(value, "center"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueWebkitCenter);
+        else if (equalIgnoringCase(value, "left"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueWebkitLeft);
+        else if (equalIgnoringCase(value, "right"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueWebkitRight);
+        else
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, value);
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+}
diff --git a/Source/core/html/HTMLParagraphElement.h b/Source/core/html/HTMLParagraphElement.h
new file mode 100644
index 0000000..fd0110b
--- /dev/null
+++ b/Source/core/html/HTMLParagraphElement.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLParagraphElement_h
+#define HTMLParagraphElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLParagraphElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLParagraphElement> create(Document*);
+    static PassRefPtr<HTMLParagraphElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLParagraphElement(const QualifiedName&, Document*);
+
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // HTMLParagraphElement_h
diff --git a/Source/core/html/HTMLParagraphElement.idl b/Source/core/html/HTMLParagraphElement.idl
new file mode 100644
index 0000000..e6bd9e8
--- /dev/null
+++ b/Source/core/html/HTMLParagraphElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLParagraphElement : HTMLElement {
+    [Reflect] attribute DOMString align;
+};
+
diff --git a/Source/core/html/HTMLParamElement.cpp b/Source/core/html/HTMLParamElement.cpp
new file mode 100644
index 0000000..d5ddc38
--- /dev/null
+++ b/Source/core/html/HTMLParamElement.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
+ * Copyright (C) 2004, 2005, 2006, 2008, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLParamElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLParamElement::HTMLParamElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(paramTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLParamElement> HTMLParamElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLParamElement(tagName, document));
+}
+
+String HTMLParamElement::name() const
+{
+    if (hasName())
+        return getNameAttribute();
+    return document()->isHTMLDocument() ? emptyAtom : getIdAttribute();
+}
+
+String HTMLParamElement::value() const
+{
+    return fastGetAttribute(valueAttr);
+}
+
+bool HTMLParamElement::isURLParameter(const String& name)
+{
+    return equalIgnoringCase(name, "data") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "src");
+}
+
+bool HTMLParamElement::isURLAttribute(const Attribute& attribute) const
+{
+    if (attribute.name() == valueAttr && isURLParameter(name()))
+        return true;
+    return HTMLElement::isURLAttribute(attribute);
+}
+
+void HTMLParamElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLElement::addSubresourceAttributeURLs(urls);
+
+    if (!isURLParameter(name()))
+        return;
+
+    addSubresourceURL(urls, document()->completeURL(value()));
+}
+
+}
diff --git a/Source/core/html/HTMLParamElement.h b/Source/core/html/HTMLParamElement.h
new file mode 100644
index 0000000..b855d84
--- /dev/null
+++ b/Source/core/html/HTMLParamElement.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLParamElement_h
+#define HTMLParamElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLParamElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLParamElement> create(const QualifiedName&, Document*);
+
+    String name() const;
+    String value() const;
+
+    static bool isURLParameter(const String&);
+
+private:
+    HTMLParamElement(const QualifiedName&, Document*);
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/HTMLParamElement.idl b/Source/core/html/HTMLParamElement.idl
new file mode 100644
index 0000000..fea2594
--- /dev/null
+++ b/Source/core/html/HTMLParamElement.idl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLParamElement : HTMLElement {
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute DOMString type;
+    [Reflect] attribute DOMString value;
+    [Reflect] attribute DOMString valueType;
+};
+
diff --git a/Source/core/html/HTMLPlugInElement.cpp b/Source/core/html/HTMLPlugInElement.cpp
new file mode 100644
index 0000000..5497e78
--- /dev/null
+++ b/Source/core/html/HTMLPlugInElement.cpp
@@ -0,0 +1,248 @@
+/**
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLPlugInElement.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/npruntime_impl.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/loader/FrameLoader.h"
+#include "core/page/Chrome.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/EventHandler.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameTree.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/platform/Widget.h"
+#include "core/plugins/PluginView.h"
+#include "core/rendering/RenderEmbeddedObject.h"
+#include "core/rendering/RenderWidget.h"
+#include <wtf/UnusedParam.h>
+
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document* doc)
+    : HTMLFrameOwnerElement(tagName, doc)
+    , m_NPObject(0)
+    , m_isCapturingMouseEvents(false)
+    , m_inBeforeLoadEventHandler(false)
+    , m_displayState(Playing)
+{
+}
+
+HTMLPlugInElement::~HTMLPlugInElement()
+{
+    ASSERT(!m_instance); // cleared in detach()
+
+    if (m_NPObject) {
+        _NPN_ReleaseObject(m_NPObject);
+        m_NPObject = 0;
+    }
+}
+
+bool HTMLPlugInElement::canProcessDrag() const
+{
+    const PluginView* plugin = pluginWidget() && pluginWidget()->isPluginView() ? static_cast<const PluginView*>(pluginWidget()) : 0;
+    return plugin ? plugin->canProcessDrag() : false;
+}
+
+bool HTMLPlugInElement::willRespondToMouseClickEvents()
+{
+    if (isDisabledFormControl())
+        return false;
+    RenderObject* r = renderer();
+    if (!r)
+        return false;
+    if (!r->isEmbeddedObject() && !r->isWidget())
+        return false;
+    return true;
+}
+
+void HTMLPlugInElement::detach()
+{
+    m_instance.clear();
+
+    if (m_isCapturingMouseEvents) {
+        if (Frame* frame = document()->frame())
+            frame->eventHandler()->setCapturingMouseEventsNode(0);
+        m_isCapturingMouseEvents = false;
+    }
+
+    if (m_NPObject) {
+        _NPN_ReleaseObject(m_NPObject);
+        m_NPObject = 0;
+    }
+
+    HTMLFrameOwnerElement::detach();
+}
+
+void HTMLPlugInElement::resetInstance()
+{
+    m_instance.clear();
+}
+
+PassScriptInstance HTMLPlugInElement::getInstance()
+{
+    Frame* frame = document()->frame();
+    if (!frame)
+        return 0;
+
+    // If the host dynamically turns off JavaScript (or Java) we will still return
+    // the cached allocated Bindings::Instance.  Not supporting this edge-case is OK.
+    if (m_instance)
+        return m_instance;
+
+    if (Widget* widget = pluginWidget())
+        m_instance = frame->script()->createScriptInstanceForWidget(widget);
+
+    return m_instance;
+}
+
+bool HTMLPlugInElement::dispatchBeforeLoadEvent(const String& sourceURL)
+{
+    // FIXME: Our current plug-in loading design can't guarantee the following
+    // assertion is true, since plug-in loading can be initiated during layout,
+    // and synchronous layout can be initiated in a beforeload event handler!
+    // See <http://webkit.org/b/71264>.
+    // ASSERT(!m_inBeforeLoadEventHandler);
+    m_inBeforeLoadEventHandler = true;
+    bool beforeLoadAllowedLoad = HTMLFrameOwnerElement::dispatchBeforeLoadEvent(sourceURL);
+    m_inBeforeLoadEventHandler = false;
+    return beforeLoadAllowedLoad;
+}
+
+Widget* HTMLPlugInElement::pluginWidget() const
+{
+    if (m_inBeforeLoadEventHandler) {
+        // The plug-in hasn't loaded yet, and it makes no sense to try to load if beforeload handler happened to touch the plug-in element.
+        // That would recursively call beforeload for the same element.
+        return 0;
+    }
+
+    RenderWidget* renderWidget = renderWidgetForJSBindings();
+    if (!renderWidget)
+        return 0;
+
+    return renderWidget->widget();
+}
+
+bool HTMLPlugInElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == widthAttr || name == heightAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr)
+        return true;
+    return HTMLFrameOwnerElement::isPresentationAttribute(name);
+}
+
+void HTMLPlugInElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == widthAttr)
+        addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+    else if (name == heightAttr)
+        addHTMLLengthToStyle(style, CSSPropertyHeight, value);
+    else if (name == vspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
+    } else if (name == hspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
+    } else if (name == alignAttr)
+        applyAlignmentAttributeToStyle(value, style);
+    else
+        HTMLFrameOwnerElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLPlugInElement::defaultEventHandler(Event* event)
+{
+    // Firefox seems to use a fake event listener to dispatch events to plug-in (tested with mouse events only).
+    // This is observable via different order of events - in Firefox, event listeners specified in HTML attributes fires first, then an event
+    // gets dispatched to plug-in, and only then other event listeners fire. Hopefully, this difference does not matter in practice.
+
+    // FIXME: Mouse down and scroll events are passed down to plug-in via custom code in EventHandler; these code paths should be united.
+
+    RenderObject* r = renderer();
+    if (r && r->isEmbeddedObject()) {
+        if (toRenderEmbeddedObject(r)->showsUnavailablePluginIndicator()) {
+            toRenderEmbeddedObject(r)->handleUnavailablePluginIndicatorEvent(event);
+            return;
+        }
+
+        if (displayState() < Playing)
+            return;
+    }
+
+    if (!r || !r->isWidget())
+        return;
+    RefPtr<Widget> widget = toRenderWidget(r)->widget();
+    if (!widget)
+        return;
+    widget->handleEvent(event);
+    if (event->defaultHandled())
+        return;
+    HTMLFrameOwnerElement::defaultEventHandler(event);
+}
+
+bool HTMLPlugInElement::isKeyboardFocusable(KeyboardEvent* event) const
+{
+    UNUSED_PARAM(event);
+    if (!document()->page())
+        return false;
+
+    const PluginView* plugin = pluginWidget() && pluginWidget()->isPluginView() ? static_cast<const PluginView*>(pluginWidget()) : 0;
+    if (plugin)
+        return plugin->supportsKeyboardFocus();
+
+    return false;
+}
+
+bool HTMLPlugInElement::isPluginElement() const
+{
+    return true;
+}
+
+bool HTMLPlugInElement::supportsFocus() const
+{
+    if (HTMLFrameOwnerElement::supportsFocus())
+        return true;
+
+    if (useFallbackContent() || !renderer() || !renderer()->isEmbeddedObject())
+        return false;
+    return !toRenderEmbeddedObject(renderer())->showsUnavailablePluginIndicator();
+}
+
+NPObject* HTMLPlugInElement::getNPObject()
+{
+    ASSERT(document()->frame());
+    if (!m_NPObject)
+        m_NPObject = document()->frame()->script()->createScriptObjectForPluginElement(this);
+    return m_NPObject;
+}
+
+}
diff --git a/Source/core/html/HTMLPlugInElement.h b/Source/core/html/HTMLPlugInElement.h
new file mode 100644
index 0000000..939d7f7
--- /dev/null
+++ b/Source/core/html/HTMLPlugInElement.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2012 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLPlugInElement_h
+#define HTMLPlugInElement_h
+
+#include "core/html/HTMLFrameOwnerElement.h"
+#include "core/platform/graphics/Image.h"
+
+#include "bindings/v8/ScriptInstance.h"
+
+struct NPObject;
+
+namespace WebCore {
+
+class RenderEmbeddedObject;
+class RenderWidget;
+class Widget;
+
+class HTMLPlugInElement : public HTMLFrameOwnerElement {
+public:
+    virtual ~HTMLPlugInElement();
+
+    void resetInstance();
+
+    PassScriptInstance getInstance();
+
+    Widget* pluginWidget() const;
+
+    enum DisplayState {
+        Restarting,
+        RestartingWithPendingMouseClick,
+        Playing
+    };
+    DisplayState displayState() const { return m_displayState; }
+    virtual void setDisplayState(DisplayState state) { m_displayState = state; }
+
+    NPObject* getNPObject();
+
+    bool isCapturingMouseEvents() const { return m_isCapturingMouseEvents; }
+    void setIsCapturingMouseEvents(bool capturing) { m_isCapturingMouseEvents = capturing; }
+
+    bool canContainRangeEndPoint() const { return false; }
+
+    bool canProcessDrag() const;
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+    virtual bool isPlugInImageElement() const { return false; }
+
+protected:
+    HTMLPlugInElement(const QualifiedName& tagName, Document*);
+
+    virtual void detach();
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    virtual bool useFallbackContent() const { return false; }
+
+    virtual bool dispatchBeforeLoadEvent(const String& sourceURL) OVERRIDE;
+
+private:
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+
+    virtual void defaultEventHandler(Event*);
+
+    virtual RenderWidget* renderWidgetForJSBindings() const = 0;
+
+    virtual bool supportsFocus() const OVERRIDE;
+
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual bool isPluginElement() const;
+
+    mutable ScriptInstance m_instance;
+    NPObject* m_NPObject;
+    bool m_isCapturingMouseEvents;
+    bool m_inBeforeLoadEventHandler;
+    DisplayState m_displayState;
+};
+
+inline HTMLPlugInElement* toHTMLPlugInElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isPluginElement());
+    return static_cast<HTMLPlugInElement*>(node);
+}
+
+inline const HTMLPlugInElement* toHTMLPlugInElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isPluginElement());
+    return static_cast<const HTMLPlugInElement*>(node);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toHTMLPlugInElement(const HTMLPlugInElement*);
+
+} // namespace WebCore
+
+#endif // HTMLPlugInElement_h
diff --git a/Source/core/html/HTMLPlugInImageElement.cpp b/Source/core/html/HTMLPlugInImageElement.cpp
new file mode 100644
index 0000000..aa7c0b7
--- /dev/null
+++ b/Source/core/html/HTMLPlugInImageElement.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2008, 2011, 2012 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLPlugInImageElement.h"
+
+#include "bindings/v8/ScriptController.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/NodeRenderStyle.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLImageLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/page/Chrome.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/PlugInClient.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/page/Settings.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/Logging.h"
+#include "core/platform/SchemeRegistry.h"
+#include "core/platform/graphics/Image.h"
+#include "core/rendering/RenderEmbeddedObject.h"
+#include "core/rendering/RenderImage.h"
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+typedef Vector<RefPtr<HTMLPlugInImageElement> > HTMLPlugInImageElementList;
+
+static const int sizingTinyDimensionThreshold = 40;
+static const int sizingSmallWidthThreshold = 250;
+static const int sizingMediumWidthThreshold = 450;
+static const int sizingMediumHeightThreshold = 300;
+static const float sizingFullPageAreaRatioThreshold = 0.96;
+static const float autostartSoonAfterUserGestureThreshold = 5.0;
+
+HTMLPlugInImageElement::HTMLPlugInImageElement(const QualifiedName& tagName, Document* document, bool createdByParser, PreferPlugInsForImagesOption preferPlugInsForImagesOption)
+    : HTMLPlugInElement(tagName, document)
+    // m_needsWidgetUpdate(!createdByParser) allows HTMLObjectElement to delay
+    // widget updates until after all children are parsed.  For HTMLEmbedElement
+    // this delay is unnecessary, but it is simpler to make both classes share
+    // the same codepath in this class.
+    , m_needsWidgetUpdate(!createdByParser)
+    , m_shouldPreferPlugInsForImages(preferPlugInsForImagesOption == ShouldPreferPlugInsForImages)
+    , m_createdDuringUserGesture(ScriptController::processingUserGesture())
+{
+    setHasCustomStyleCallbacks();
+}
+
+HTMLPlugInImageElement::~HTMLPlugInImageElement()
+{
+}
+
+void HTMLPlugInImageElement::setDisplayState(DisplayState state)
+{
+    HTMLPlugInElement::setDisplayState(state);
+}
+
+RenderEmbeddedObject* HTMLPlugInImageElement::renderEmbeddedObject() const
+{
+    // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers
+    // when using fallback content.
+    if (!renderer() || !renderer()->isEmbeddedObject())
+        return 0;
+    return toRenderEmbeddedObject(renderer());
+}
+
+bool HTMLPlugInImageElement::isImageType()
+{
+    if (m_serviceType.isEmpty() && protocolIs(m_url, "data"))
+        m_serviceType = mimeTypeFromDataURL(m_url);
+
+    if (Frame* frame = document()->frame()) {
+        KURL completedURL = document()->completeURL(m_url);
+        return frame->loader()->client()->objectContentType(completedURL, m_serviceType, shouldPreferPlugInsForImages()) == ObjectContentImage;
+    }
+
+    return Image::supportsType(m_serviceType);
+}
+
+// We don't use m_url, as it may not be the final URL that the object loads,
+// depending on <param> values. 
+bool HTMLPlugInImageElement::allowedToLoadFrameURL(const String& url)
+{
+    KURL completeURL = document()->completeURL(url);
+
+    if (contentFrame() && protocolIsJavaScript(completeURL)
+        && !document()->securityOrigin()->canAccess(contentDocument()->securityOrigin()))
+        return false;
+
+    return document()->frame()->isURLAllowed(completeURL);
+}
+
+// We don't use m_url, or m_serviceType as they may not be the final values
+// that <object> uses depending on <param> values. 
+bool HTMLPlugInImageElement::wouldLoadAsNetscapePlugin(const String& url, const String& serviceType)
+{
+    ASSERT(document());
+    ASSERT(document()->frame());
+    KURL completedURL;
+    if (!url.isEmpty())
+        completedURL = document()->completeURL(url);
+
+    FrameLoader* frameLoader = document()->frame()->loader();
+    ASSERT(frameLoader);
+    if (frameLoader->client()->objectContentType(completedURL, serviceType, shouldPreferPlugInsForImages()) == ObjectContentNetscapePlugin)
+        return true;
+    return false;
+}
+
+RenderObject* HTMLPlugInImageElement::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+    // Fallback content breaks the DOM->Renderer class relationship of this
+    // class and all superclasses because createObject won't necessarily
+    // return a RenderEmbeddedObject, RenderPart or even RenderWidget.
+    if (useFallbackContent())
+        return RenderObject::createObject(this, style);
+
+    if (isImageType()) {
+        RenderImage* image = new (arena) RenderImage(this);
+        image->setImageResource(RenderImageResource::create());
+        return image;
+    }
+
+    return new (arena) RenderEmbeddedObject(this);
+}
+
+void HTMLPlugInImageElement::willRecalcStyle(StyleChange)
+{
+    // FIXME: Why is this necessary?  Manual re-attach is almost always wrong.
+    if (!useFallbackContent() && needsWidgetUpdate() && renderer() && !isImageType())
+        reattach();
+}
+
+void HTMLPlugInImageElement::attach()
+{
+    PostAttachCallbackDisabler disabler(this);
+
+    bool isImage = isImageType();
+    
+    if (!isImage)
+        queuePostAttachCallback(&HTMLPlugInImageElement::updateWidgetCallback, this);
+
+    HTMLPlugInElement::attach();
+
+    if (isImage && renderer() && !useFallbackContent()) {
+        if (!m_imageLoader)
+            m_imageLoader = adoptPtr(new HTMLImageLoader(this));
+        m_imageLoader->updateFromElement();
+    }
+}
+
+void HTMLPlugInImageElement::detach()
+{
+    // FIXME: Because of the insanity that is HTMLPlugInImageElement::recalcStyle,
+    // we can end up detaching during an attach() call, before we even have a
+    // renderer.  In that case, don't mark the widget for update.
+    if (attached() && renderer() && !useFallbackContent())
+        // Update the widget the next time we attach (detaching destroys the plugin).
+        setNeedsWidgetUpdate(true);
+    HTMLPlugInElement::detach();
+}
+
+void HTMLPlugInImageElement::updateWidgetIfNecessary()
+{
+    document()->updateStyleIfNeeded();
+
+    if (!needsWidgetUpdate() || useFallbackContent() || isImageType())
+        return;
+
+    if (!renderEmbeddedObject() || renderEmbeddedObject()->showsUnavailablePluginIndicator())
+        return;
+
+    updateWidget(CreateOnlyNonNetscapePlugins);
+}
+
+void HTMLPlugInImageElement::finishParsingChildren()
+{
+    HTMLPlugInElement::finishParsingChildren();
+    if (useFallbackContent())
+        return;
+    
+    setNeedsWidgetUpdate(true);
+    if (inDocument())
+        setNeedsStyleRecalc();    
+}
+
+void HTMLPlugInImageElement::didMoveToNewDocument(Document* oldDocument)
+{
+    if (m_imageLoader)
+        m_imageLoader->elementDidMoveToNewDocument();
+    HTMLPlugInElement::didMoveToNewDocument(oldDocument);
+}
+
+void HTMLPlugInImageElement::updateWidgetCallback(Node* n, unsigned)
+{
+    static_cast<HTMLPlugInImageElement*>(n)->updateWidgetIfNecessary();
+}
+
+void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url)
+{
+    LOG(Plugins, "%p Plug-in URL: %s", this, m_url.utf8().data());
+    LOG(Plugins, "   Loaded URL: %s", url.string().utf8().data());
+
+    m_loadedUrl = url;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLPlugInImageElement.h b/Source/core/html/HTMLPlugInImageElement.h
new file mode 100644
index 0000000..b6824f2
--- /dev/null
+++ b/Source/core/html/HTMLPlugInImageElement.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2008, 2009, 2011, 2012 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLPlugInImageElement_h
+#define HTMLPlugInImageElement_h
+
+#include "core/html/HTMLPlugInElement.h"
+
+#include "core/rendering/style/RenderStyle.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class HTMLImageLoader;
+class FrameLoader;
+class Image;
+class MouseEvent;
+class Widget;
+
+enum PluginCreationOption {
+    CreateAnyWidgetType,
+    CreateOnlyNonNetscapePlugins,
+};
+
+enum PreferPlugInsForImagesOption {
+    ShouldPreferPlugInsForImages,
+    ShouldNotPreferPlugInsForImages
+};
+
+// Base class for HTMLObjectElement and HTMLEmbedElement
+class HTMLPlugInImageElement : public HTMLPlugInElement {
+public:
+    virtual ~HTMLPlugInImageElement();
+
+    RenderEmbeddedObject* renderEmbeddedObject() const;
+
+    virtual void setDisplayState(DisplayState) OVERRIDE;
+
+    virtual void updateWidget(PluginCreationOption) = 0;
+
+    const String& serviceType() const { return m_serviceType; }
+    const String& url() const { return m_url; }
+    const KURL& loadedUrl() const { return m_loadedUrl; }
+
+    const String loadedMimeType() const
+    {
+        String mimeType = serviceType();
+        if (mimeType.isEmpty())
+            mimeType = mimeTypeFromURL(m_loadedUrl);
+        return mimeType;
+    }
+
+    bool shouldPreferPlugInsForImages() const { return m_shouldPreferPlugInsForImages; }
+
+    // Public for FrameView::addWidgetToUpdate()
+    bool needsWidgetUpdate() const { return m_needsWidgetUpdate; }
+    void setNeedsWidgetUpdate(bool needsWidgetUpdate) { m_needsWidgetUpdate = needsWidgetUpdate; }
+
+    // Plug-in URL might not be the same as url() with overriding parameters.
+    void subframeLoaderWillCreatePlugIn(const KURL& plugInURL);
+    
+protected:
+    HTMLPlugInImageElement(const QualifiedName& tagName, Document*, bool createdByParser, PreferPlugInsForImagesOption);
+
+    bool isImageType();
+
+    OwnPtr<HTMLImageLoader> m_imageLoader;
+    String m_serviceType;
+    String m_url;
+    KURL m_loadedUrl;
+    
+    static void updateWidgetCallback(Node*, unsigned = 0);
+    virtual void attach();
+    virtual void detach();
+
+    bool allowedToLoadFrameURL(const String& url);
+    bool wouldLoadAsNetscapePlugin(const String& url, const String& serviceType);
+
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+
+private:
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual void willRecalcStyle(StyleChange) OVERRIDE FINAL;
+
+    virtual void finishParsingChildren();
+
+    void updateWidgetIfNecessary();
+
+    void swapRendererTimerFired(Timer<HTMLPlugInImageElement>*);
+
+    void restartSimilarPlugIns();
+
+    virtual bool isPlugInImageElement() const OVERRIDE { return true; }
+
+    bool m_needsWidgetUpdate;
+    bool m_shouldPreferPlugInsForImages;
+    bool m_createdDuringUserGesture;
+};
+
+inline HTMLPlugInImageElement* toHTMLPlugInImageElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isPluginElement());
+    HTMLPlugInElement* plugInElement = static_cast<HTMLPlugInElement*>(node);
+    ASSERT_WITH_SECURITY_IMPLICATION(plugInElement->isPlugInImageElement());
+    return static_cast<HTMLPlugInImageElement*>(plugInElement);
+}
+
+inline const HTMLPlugInImageElement* toHTMLPlugInImageElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isPluginElement());
+    const HTMLPlugInElement* plugInElement = static_cast<const HTMLPlugInElement*>(node);
+    ASSERT_WITH_SECURITY_IMPLICATION(plugInElement->isPlugInImageElement());
+    return static_cast<const HTMLPlugInImageElement*>(plugInElement);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toHTMLPlugInImageElement(const HTMLPlugInImageElement*);
+
+} // namespace WebCore
+
+#endif // HTMLPlugInImageElement_h
diff --git a/Source/core/html/HTMLPreElement.cpp b/Source/core/html/HTMLPreElement.cpp
new file mode 100644
index 0000000..1e92f02
--- /dev/null
+++ b/Source/core/html/HTMLPreElement.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLPreElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/css/StylePropertySet.h"
+#include "core/dom/Attribute.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLPreElement::HTMLPreElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLPreElement> HTMLPreElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLPreElement(tagName, document));
+}
+
+bool HTMLPreElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == wrapAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLPreElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == wrapAttr)
+        style->setProperty(CSSPropertyWhiteSpace, CSSValuePreWrap);
+    else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+}
diff --git a/Source/core/html/HTMLPreElement.h b/Source/core/html/HTMLPreElement.h
new file mode 100644
index 0000000..4c544d9
--- /dev/null
+++ b/Source/core/html/HTMLPreElement.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLPreElement_h
+#define HTMLPreElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLPreElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLPreElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLPreElement(const QualifiedName&, Document*);
+
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // HTMLPreElement_h
diff --git a/Source/core/html/HTMLPreElement.idl b/Source/core/html/HTMLPreElement.idl
new file mode 100644
index 0000000..807248c
--- /dev/null
+++ b/Source/core/html/HTMLPreElement.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All right reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLPreElement : HTMLElement {
+    // FIXME: DOM spec says that width should be of type DOMString
+    // see http://bugs.webkit.org/show_bug.cgi?id=8992
+    [Reflect] attribute long width;
+    
+    // Extensions
+    [Reflect] attribute boolean wrap;
+};
+
diff --git a/Source/core/html/HTMLProgressElement.cpp b/Source/core/html/HTMLProgressElement.cpp
new file mode 100644
index 0000000..5f7cef6
--- /dev/null
+++ b/Source/core/html/HTMLProgressElement.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "core/html/HTMLProgressElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/shadow/ProgressShadowElement.h"
+#include "core/rendering/RenderProgress.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+const double HTMLProgressElement::IndeterminatePosition = -1;
+const double HTMLProgressElement::InvalidPosition = -2;
+
+HTMLProgressElement::HTMLProgressElement(const QualifiedName& tagName, Document* document)
+    : LabelableElement(tagName, document)
+    , m_value(0)
+{
+    ASSERT(hasTagName(progressTag));
+    ScriptWrappable::init(this);
+}
+
+HTMLProgressElement::~HTMLProgressElement()
+{
+}
+
+PassRefPtr<HTMLProgressElement> HTMLProgressElement::create(const QualifiedName& tagName, Document* document)
+{
+    RefPtr<HTMLProgressElement> progress = adoptRef(new HTMLProgressElement(tagName, document));
+    progress->ensureUserAgentShadowRoot();
+    return progress.release();
+}
+
+RenderObject* HTMLProgressElement::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+    if (!style->hasAppearance() || hasAuthorShadowRoot())
+        return RenderObject::createObject(this, style);
+
+    return new (arena) RenderProgress(this);
+}
+
+bool HTMLProgressElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
+{
+    return childContext.isOnUpperEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext);
+}
+
+RenderProgress* HTMLProgressElement::renderProgress() const
+{
+    if (renderer() && renderer()->isProgress())
+        return static_cast<RenderProgress*>(renderer());
+
+    RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer();
+    ASSERT_WITH_SECURITY_IMPLICATION(!renderObject || renderObject->isProgress());
+    return static_cast<RenderProgress*>(renderObject);
+}
+
+void HTMLProgressElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == valueAttr)
+        didElementStateChange();
+    else if (name == maxAttr)
+        didElementStateChange();
+    else
+        LabelableElement::parseAttribute(name, value);
+}
+
+void HTMLProgressElement::attach()
+{
+    LabelableElement::attach();
+    if (RenderProgress* render = renderProgress())
+        render->updateFromElement();
+}
+
+double HTMLProgressElement::value() const
+{
+    double value = parseToDoubleForNumberType(fastGetAttribute(valueAttr));
+    return !std::isfinite(value) || value < 0 ? 0 : std::min(value, max());
+}
+
+void HTMLProgressElement::setValue(double value, ExceptionCode& ec)
+{
+    if (!std::isfinite(value)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    setAttribute(valueAttr, String::number(value >= 0 ? value : 0));
+}
+
+double HTMLProgressElement::max() const
+{
+    double max = parseToDoubleForNumberType(getAttribute(maxAttr));
+    return !std::isfinite(max) || max <= 0 ? 1 : max;
+}
+
+void HTMLProgressElement::setMax(double max, ExceptionCode& ec)
+{
+    if (!std::isfinite(max)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    setAttribute(maxAttr, String::number(max > 0 ? max : 1));
+}
+
+double HTMLProgressElement::position() const
+{
+    if (!isDeterminate())
+        return HTMLProgressElement::IndeterminatePosition;
+    return value() / max();
+}
+
+bool HTMLProgressElement::isDeterminate() const
+{
+    return fastHasAttribute(valueAttr);
+}
+    
+void HTMLProgressElement::didElementStateChange()
+{
+    m_value->setWidthPercentage(position() * 100);
+    if (RenderProgress* render = renderProgress()) {
+        bool wasDeterminate = render->isDeterminate();
+        render->updateFromElement();
+        if (wasDeterminate != isDeterminate())
+            didAffectSelector(AffectedSelectorIndeterminate);
+    }
+}
+
+void HTMLProgressElement::didAddUserAgentShadowRoot(ShadowRoot* root)
+{
+    ASSERT(!m_value);
+
+    RefPtr<ProgressInnerElement> inner = ProgressInnerElement::create(document());
+    root->appendChild(inner);
+
+    RefPtr<ProgressBarElement> bar = ProgressBarElement::create(document());
+    RefPtr<ProgressValueElement> value = ProgressValueElement::create(document());
+    m_value = value.get();
+    m_value->setWidthPercentage(HTMLProgressElement::IndeterminatePosition * 100);
+    bar->appendChild(m_value, ASSERT_NO_EXCEPTION);
+
+    inner->appendChild(bar, ASSERT_NO_EXCEPTION);
+}
+
+bool HTMLProgressElement::shouldAppearIndeterminate() const
+{
+    return !isDeterminate();
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLProgressElement.h b/Source/core/html/HTMLProgressElement.h
new file mode 100644
index 0000000..839aef1
--- /dev/null
+++ b/Source/core/html/HTMLProgressElement.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLProgressElement_h
+#define HTMLProgressElement_h
+
+#include "core/html/LabelableElement.h"
+
+namespace WebCore {
+
+class ProgressValueElement;
+class RenderProgress;
+
+class HTMLProgressElement FINAL : public LabelableElement {
+public:
+    static const double IndeterminatePosition;
+    static const double InvalidPosition;
+
+    static PassRefPtr<HTMLProgressElement> create(const QualifiedName&, Document*);
+
+    double value() const;
+    void setValue(double, ExceptionCode&);
+
+    double max() const;
+    void setMax(double, ExceptionCode&);
+
+    double position() const;
+
+    virtual bool canContainRangeEndPoint() const { return false; }
+
+private:
+    HTMLProgressElement(const QualifiedName&, Document*);
+    virtual ~HTMLProgressElement();
+
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+    virtual bool shouldAppearIndeterminate() const OVERRIDE;
+    virtual bool supportLabels() const OVERRIDE { return true; }
+
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const OVERRIDE;
+    RenderProgress* renderProgress() const;
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    virtual void attach();
+
+    void didElementStateChange();
+    virtual void didAddUserAgentShadowRoot(ShadowRoot*) OVERRIDE;
+    bool isDeterminate() const;
+
+    ProgressValueElement* m_value;
+};
+
+inline bool isHTMLProgressElement(Node* node)
+{
+    ASSERT(node);
+    return node->hasTagName(HTMLNames::progressTag);
+}
+
+inline HTMLProgressElement* toHTMLProgressElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLProgressElement(node));
+    return static_cast<HTMLProgressElement*>(node);
+}
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLProgressElement.idl b/Source/core/html/HTMLProgressElement.idl
new file mode 100644
index 0000000..a2f3f32
--- /dev/null
+++ b/Source/core/html/HTMLProgressElement.idl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLProgressElement : HTMLElement {
+             [SetterRaisesException] attribute  double                value;
+             [SetterRaisesException] attribute  double                max;
+    readonly attribute  double                position;
+    readonly attribute  NodeList              labels;
+};
+
diff --git a/Source/core/html/HTMLQuoteElement.cpp b/Source/core/html/HTMLQuoteElement.cpp
new file mode 100644
index 0000000..fb93f45
--- /dev/null
+++ b/Source/core/html/HTMLQuoteElement.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLQuoteElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Document.h"
+#include "core/dom/DocumentStyleSheetCollection.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLQuoteElement::HTMLQuoteElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(qTag) || hasTagName(blockquoteTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLQuoteElement> HTMLQuoteElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLQuoteElement(tagName, document));
+}
+
+Node::InsertionNotificationRequest HTMLQuoteElement::insertedInto(ContainerNode* insertionPoint)
+{
+    if (hasTagName(qTag))
+        document()->styleSheetCollection()->setUsesBeforeAfterRulesOverride(true);
+
+    return HTMLElement::insertedInto(insertionPoint);
+}
+
+bool HTMLQuoteElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == citeAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+}
diff --git a/Source/core/html/HTMLQuoteElement.h b/Source/core/html/HTMLQuoteElement.h
new file mode 100644
index 0000000..add536c
--- /dev/null
+++ b/Source/core/html/HTMLQuoteElement.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLQuoteElement_h
+#define HTMLQuoteElement_h
+
+#include "core/html/HTMLElement.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class HTMLQuoteElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLQuoteElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLQuoteElement(const QualifiedName&, Document*);
+    
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLQuoteElement.idl b/Source/core/html/HTMLQuoteElement.idl
new file mode 100644
index 0000000..c53a1a2
--- /dev/null
+++ b/Source/core/html/HTMLQuoteElement.idl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLQuoteElement : HTMLElement {
+    [Reflect, URL] attribute DOMString cite;
+};
diff --git a/Source/core/html/HTMLScriptElement.cpp b/Source/core/html/HTMLScriptElement.cpp
new file mode 100644
index 0000000..bf60a04
--- /dev/null
+++ b/Source/core/html/HTMLScriptElement.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLScriptElement.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/Text.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLScriptElement::HTMLScriptElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool alreadyStarted)
+    : HTMLElement(tagName, document)
+    , ScriptElement(this, wasInsertedByParser, alreadyStarted)
+{
+    ASSERT(hasTagName(scriptTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLScriptElement> HTMLScriptElement::create(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool alreadyStarted)
+{
+    return adoptRef(new HTMLScriptElement(tagName, document, wasInsertedByParser, alreadyStarted));
+}
+
+bool HTMLScriptElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == srcAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+void HTMLScriptElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+    ScriptElement::childrenChanged();
+}
+
+void HTMLScriptElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == srcAttr)
+        handleSourceAttribute(value);
+    else if (name == asyncAttr)
+        handleAsyncAttribute();
+    else if (name == onbeforeloadAttr)
+        setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, name, value));
+    else
+        HTMLElement::parseAttribute(name, value);
+}
+
+Node::InsertionNotificationRequest HTMLScriptElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+    ScriptElement::insertedInto(insertionPoint);
+    return InsertionDone;
+}
+
+void HTMLScriptElement::setText(const String &value)
+{
+    RefPtr<Node> protectFromMutationEvents(this);
+
+    int numChildren = childNodeCount();
+
+    if (numChildren == 1 && firstChild()->isTextNode()) {
+        toText(firstChild())->setData(value, IGNORE_EXCEPTION);
+        return;
+    }
+
+    if (numChildren > 0)
+        removeChildren();
+
+    appendChild(document()->createTextNode(value.impl()), IGNORE_EXCEPTION);
+}
+
+void HTMLScriptElement::setAsync(bool async)
+{
+    setBooleanAttribute(asyncAttr, async);
+    handleAsyncAttribute();
+}
+
+bool HTMLScriptElement::async() const
+{
+    return fastHasAttribute(asyncAttr) || forceAsync();
+}
+
+KURL HTMLScriptElement::src() const
+{
+    return document()->completeURL(sourceAttributeValue());
+}
+
+void HTMLScriptElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLElement::addSubresourceAttributeURLs(urls);
+
+    addSubresourceURL(urls, src());
+}
+
+String HTMLScriptElement::sourceAttributeValue() const
+{
+    return getAttribute(srcAttr).string();
+}
+
+String HTMLScriptElement::charsetAttributeValue() const
+{
+    return getAttribute(charsetAttr).string();
+}
+
+String HTMLScriptElement::typeAttributeValue() const
+{
+    return getAttribute(typeAttr).string();
+}
+
+String HTMLScriptElement::languageAttributeValue() const
+{
+    return getAttribute(languageAttr).string();
+}
+
+String HTMLScriptElement::forAttributeValue() const
+{
+    return getAttribute(forAttr).string();
+}
+
+String HTMLScriptElement::eventAttributeValue() const
+{
+    return getAttribute(eventAttr).string();
+}
+
+bool HTMLScriptElement::asyncAttributeValue() const
+{
+    return fastHasAttribute(asyncAttr);
+}
+
+bool HTMLScriptElement::deferAttributeValue() const
+{
+    return fastHasAttribute(deferAttr);
+}
+
+bool HTMLScriptElement::hasSourceAttribute() const
+{
+    return fastHasAttribute(srcAttr);
+}
+
+void HTMLScriptElement::dispatchLoadEvent()
+{
+    ASSERT(!haveFiredLoadEvent());
+    setHaveFiredLoadEvent(true);
+
+    dispatchEvent(Event::create(eventNames().loadEvent, false, false));
+}
+
+PassRefPtr<Element> HTMLScriptElement::cloneElementWithoutAttributesAndChildren()
+{
+    return adoptRef(new HTMLScriptElement(tagQName(), document(), false, alreadyStarted()));
+}
+
+}
diff --git a/Source/core/html/HTMLScriptElement.h b/Source/core/html/HTMLScriptElement.h
new file mode 100644
index 0000000..dd1c1f6
--- /dev/null
+++ b/Source/core/html/HTMLScriptElement.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLScriptElement_h
+#define HTMLScriptElement_h
+
+#include "core/dom/ScriptElement.h"
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLScriptElement FINAL : public HTMLElement, public ScriptElement {
+public:
+    static PassRefPtr<HTMLScriptElement> create(const QualifiedName&, Document*, bool wasInsertedByParser, bool alreadyStarted = false);
+
+    String text() const { return scriptContent(); }
+    void setText(const String&);
+
+    KURL src() const;
+
+    void setAsync(bool);
+    bool async() const;
+
+private:
+    HTMLScriptElement(const QualifiedName&, Document*, bool wasInsertedByParser, bool alreadyStarted);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+
+    virtual String sourceAttributeValue() const;
+    virtual String charsetAttributeValue() const;
+    virtual String typeAttributeValue() const;
+    virtual String languageAttributeValue() const;
+    virtual String forAttributeValue() const;
+    virtual String eventAttributeValue() const;
+    virtual bool asyncAttributeValue() const;
+    virtual bool deferAttributeValue() const;
+    virtual bool hasSourceAttribute() const;
+
+    virtual void dispatchLoadEvent();
+
+    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren();
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLScriptElement.idl b/Source/core/html/HTMLScriptElement.idl
new file mode 100644
index 0000000..cb8a909
--- /dev/null
+++ b/Source/core/html/HTMLScriptElement.idl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLScriptElement : HTMLElement {
+    [TreatNullAs=NullString] attribute DOMString text;
+    [Reflect=for] attribute DOMString htmlFor;
+    [Reflect] attribute DOMString event;
+    [Reflect] attribute DOMString charset;
+    attribute boolean async;
+    [Reflect] attribute boolean defer;
+    [Reflect, URL] attribute DOMString src;
+    [Reflect] attribute DOMString type;
+    [Reflect] attribute DOMString crossOrigin;
+    [Reflect, EnabledAtRuntime=experimentalContentSecurityPolicyFeatures] attribute DOMString nonce;
+};
diff --git a/Source/core/html/HTMLSelectElement.cpp b/Source/core/html/HTMLSelectElement.cpp
new file mode 100644
index 0000000..5767d02
--- /dev/null
+++ b/Source/core/html/HTMLSelectElement.cpp
@@ -0,0 +1,1577 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLSelectElement.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/accessibility/AXObjectCache.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/html/FormController.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLOptGroupElement.h"
+#include "core/html/HTMLOptionElement.h"
+#include "core/html/HTMLOptionsCollection.h"
+#include "core/page/Chrome.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/EventHandler.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/page/SpatialNavigation.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/PlatformMouseEvent.h"
+#include "core/rendering/RenderListBox.h"
+#include "core/rendering/RenderMenuList.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/unicode/Unicode.h>
+
+using namespace std;
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// Upper limit agreed upon with representatives of Opera and Mozilla.
+static const unsigned maxSelectItems = 10000;
+
+HTMLSelectElement::HTMLSelectElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
+    : HTMLFormControlElementWithState(tagName, document, form)
+    , m_typeAhead(this)
+    , m_size(0)
+    , m_lastOnChangeIndex(-1)
+    , m_activeSelectionAnchorIndex(-1)
+    , m_activeSelectionEndIndex(-1)
+    , m_isProcessingUserDrivenChange(false)
+    , m_multiple(false)
+    , m_activeSelectionState(false)
+    , m_shouldRecalcListItems(false)
+    , m_isParsingInProgress(createdByParser)
+{
+    ASSERT(hasTagName(selectTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLSelectElement> HTMLSelectElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
+{
+    ASSERT(tagName.matches(selectTag));
+    return adoptRef(new HTMLSelectElement(tagName, document, form, createdByParser));
+}
+
+const AtomicString& HTMLSelectElement::formControlType() const
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(const AtomicString, selectOne, ("select-one", AtomicString::ConstructFromLiteral));
+    return m_multiple ? selectMultiple : selectOne;
+}
+
+void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement)
+{
+    deselectItemsWithoutValidation(excludeElement);
+    setNeedsValidityCheck();
+}
+
+void HTMLSelectElement::optionSelectedByUser(int optionIndex, bool fireOnChangeNow, bool allowMultipleSelection)
+{
+    // User interaction such as mousedown events can cause list box select elements to send change events.
+    // This produces that same behavior for changes triggered by other code running on behalf of the user.
+    if (!usesMenuList()) {
+        updateSelectedState(optionToListIndex(optionIndex), allowMultipleSelection, false);
+        setNeedsValidityCheck();
+        if (fireOnChangeNow)
+            listBoxOnChange();
+        return;
+    }
+
+    // Bail out if this index is already the selected one, to avoid running unnecessary JavaScript that can mess up
+    // autofill when there is no actual change (see https://bugs.webkit.org/show_bug.cgi?id=35256 and <rdar://7467917>).
+    // The selectOption function does not behave this way, possibly because other callers need a change event even
+    // in cases where the selected option is not change.
+    if (optionIndex == selectedIndex())
+        return;
+
+    selectOption(optionIndex, DeselectOtherOptions | (fireOnChangeNow ? DispatchChangeEvent : 0) | UserDriven);
+}
+
+bool HTMLSelectElement::hasPlaceholderLabelOption() const
+{
+    // The select element has no placeholder label option if it has an attribute "multiple" specified or a display size of non-1.
+    // 
+    // The condition "size() > 1" is not compliant with the HTML5 spec as of Dec 3, 2010. "size() != 1" is correct.
+    // Using "size() > 1" here because size() may be 0 in WebKit.
+    // See the discussion at https://bugs.webkit.org/show_bug.cgi?id=43887
+    //
+    // "0 size()" happens when an attribute "size" is absent or an invalid size attribute is specified.
+    // In this case, the display size should be assumed as the default.
+    // The default display size is 1 for non-multiple select elements, and 4 for multiple select elements.
+    //
+    // Finally, if size() == 0 and non-multiple, the display size can be assumed as 1.
+    if (multiple() || size() > 1)
+        return false;
+
+    int listIndex = optionToListIndex(0);
+    ASSERT(listIndex >= 0);
+    if (listIndex < 0)
+        return false;
+    HTMLOptionElement* option = static_cast<HTMLOptionElement*>(listItems()[listIndex]);
+    return !listIndex && option->value().isEmpty();
+}
+
+String HTMLSelectElement::validationMessage() const
+{
+    if (!willValidate())
+        return String();
+
+    if (customError())
+        return customValidationMessage();
+
+    return valueMissing() ? validationMessageValueMissingForSelectText() : String();
+}
+
+bool HTMLSelectElement::valueMissing() const
+{
+    if (!willValidate())
+        return false;
+
+    if (!isRequired())
+        return false;
+
+    int firstSelectionIndex = selectedIndex();
+
+    // If a non-placeholer label option is selected (firstSelectionIndex > 0), it's not value-missing.
+    return firstSelectionIndex < 0 || (!firstSelectionIndex && hasPlaceholderLabelOption());
+}
+
+void HTMLSelectElement::listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow)
+{
+    if (!multiple())
+        optionSelectedByUser(listToOptionIndex(listIndex), fireOnChangeNow, false);
+    else {
+        updateSelectedState(listIndex, allowMultiplySelections, shift);
+        setNeedsValidityCheck();
+        if (fireOnChangeNow)
+            listBoxOnChange();
+    }
+}
+
+bool HTMLSelectElement::usesMenuList() const
+{
+    const Page* page = document()->page();
+    RefPtr<RenderTheme> renderTheme = page ? page->theme() : RenderTheme::defaultTheme();
+    if (renderTheme->delegatesMenuListRendering())
+        return true;
+
+    return !m_multiple && m_size <= 1;
+}
+
+int HTMLSelectElement::activeSelectionStartListIndex() const
+{
+    if (m_activeSelectionAnchorIndex >= 0)
+        return m_activeSelectionAnchorIndex;
+    return optionToListIndex(selectedIndex());
+}
+
+int HTMLSelectElement::activeSelectionEndListIndex() const
+{
+    if (m_activeSelectionEndIndex >= 0)
+        return m_activeSelectionEndIndex;
+    return lastSelectedListIndex();
+}
+
+void HTMLSelectElement::add(HTMLElement* element, HTMLElement* before, ExceptionCode& ec)
+{
+    // Make sure the element is ref'd and deref'd so we don't leak it.
+    RefPtr<HTMLElement> protectNewChild(element);
+
+    if (!element || !(element->hasLocalName(optionTag) || element->hasLocalName(hrTag)))
+        return;
+
+    insertBefore(element, before, ec);
+    setNeedsValidityCheck();
+}
+
+void HTMLSelectElement::remove(int optionIndex)
+{
+    int listIndex = optionToListIndex(optionIndex);
+    if (listIndex < 0)
+        return;
+
+    listItems()[listIndex]->remove(IGNORE_EXCEPTION);
+}
+
+void HTMLSelectElement::remove(HTMLOptionElement* option)
+{
+    if (option->ownerSelectElement() != this)
+        return;
+
+    option->remove(IGNORE_EXCEPTION);
+}
+
+String HTMLSelectElement::value() const
+{
+    const Vector<HTMLElement*>& items = listItems();
+    for (unsigned i = 0; i < items.size(); i++) {
+        if (items[i]->hasLocalName(optionTag) && static_cast<HTMLOptionElement*>(items[i])->selected())
+            return static_cast<HTMLOptionElement*>(items[i])->value();
+    }
+    return "";
+}
+
+void HTMLSelectElement::setValue(const String &value)
+{
+    // We clear the previously selected option(s) when needed, to guarantee calling setSelectedIndex() only once.
+    if (value.isNull()) {
+        setSelectedIndex(-1);
+        return;
+    }
+
+    // Find the option with value() matching the given parameter and make it the current selection.
+    const Vector<HTMLElement*>& items = listItems();
+    unsigned optionIndex = 0;
+    for (unsigned i = 0; i < items.size(); i++) {
+        if (items[i]->hasLocalName(optionTag)) {
+            if (static_cast<HTMLOptionElement*>(items[i])->value() == value) {
+                setSelectedIndex(optionIndex);
+                return;
+            }
+            optionIndex++;
+        }
+    }
+
+    setSelectedIndex(-1);
+}
+
+bool HTMLSelectElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == alignAttr) {
+        // Don't map 'align' attribute. This matches what Firefox, Opera and IE do.
+        // See http://bugs.webkit.org/show_bug.cgi?id=12072
+        return false;
+    }
+
+    return HTMLFormControlElementWithState::isPresentationAttribute(name);
+}
+
+void HTMLSelectElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == sizeAttr) {
+        int oldSize = m_size;
+        // Set the attribute value to a number.
+        // This is important since the style rules for this attribute can determine the appearance property.
+        int size = value.toInt();
+        String attrSize = String::number(size);
+        if (attrSize != value) {
+            // FIXME: This is horribly factored.
+            if (Attribute* sizeAttribute = ensureUniqueElementData()->getAttributeItem(sizeAttr))
+                sizeAttribute->setValue(attrSize);
+        }
+        size = max(size, 1);
+
+        // Ensure that we've determined selectedness of the items at least once prior to changing the size.
+        if (oldSize != size)
+            updateListItemSelectedStates();
+
+        m_size = size;
+        setNeedsValidityCheck();
+        if (m_size != oldSize && attached()) {
+            reattach();
+            setRecalcListItems();
+        }
+    } else if (name == multipleAttr)
+        parseMultipleAttribute(value);
+    else if (name == accesskeyAttr) {
+        // FIXME: ignore for the moment.
+        //
+    } else
+        HTMLFormControlElementWithState::parseAttribute(name, value);
+}
+
+bool HTMLSelectElement::isKeyboardFocusable(KeyboardEvent* event) const
+{
+    if (renderer())
+        return isFocusable();
+    return HTMLFormControlElementWithState::isKeyboardFocusable(event);
+}
+
+bool HTMLSelectElement::isMouseFocusable() const
+{
+    if (renderer())
+        return isFocusable();
+    return HTMLFormControlElementWithState::isMouseFocusable();
+}
+
+bool HTMLSelectElement::canSelectAll() const
+{
+    return !usesMenuList();
+}
+
+RenderObject* HTMLSelectElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    if (usesMenuList())
+        return new (arena) RenderMenuList(this);
+    return new (arena) RenderListBox(this);
+}
+
+bool HTMLSelectElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
+{
+    if (!HTMLFormControlElementWithState::childShouldCreateRenderer(childContext))
+        return false;
+    if (!usesMenuList())
+        return childContext.node()->hasTagName(HTMLNames::optionTag) || childContext.node()->hasTagName(HTMLNames::optgroupTag) || validationMessageShadowTreeContains(childContext.node());
+    return validationMessageShadowTreeContains(childContext.node());
+}
+
+PassRefPtr<HTMLCollection> HTMLSelectElement::selectedOptions()
+{
+    updateListItemSelectedStates();
+    return ensureCachedHTMLCollection(SelectedOptions);
+}
+
+PassRefPtr<HTMLOptionsCollection> HTMLSelectElement::options()
+{
+    return static_cast<HTMLOptionsCollection*>(ensureCachedHTMLCollection(SelectOptions).get());
+}
+
+void HTMLSelectElement::updateListItemSelectedStates()
+{
+    if (!m_shouldRecalcListItems)
+        return;
+    recalcListItems();
+    setNeedsValidityCheck();
+}
+
+void HTMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    setRecalcListItems();
+    setNeedsValidityCheck();
+
+    HTMLFormControlElementWithState::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+}
+
+void HTMLSelectElement::optionElementChildrenChanged()
+{
+    setRecalcListItems();
+    setNeedsValidityCheck();
+
+    if (renderer()) {
+        if (AXObjectCache* cache = renderer()->document()->existingAXObjectCache())
+            cache->childrenChanged(this);
+    }
+}
+
+void HTMLSelectElement::accessKeyAction(bool sendMouseEvents)
+{
+    focus();
+    dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
+}
+
+void HTMLSelectElement::setMultiple(bool multiple)
+{
+    bool oldMultiple = this->multiple();
+    int oldSelectedIndex = selectedIndex();
+    setAttribute(multipleAttr, multiple ? "" : 0);
+
+    // Restore selectedIndex after changing the multiple flag to preserve
+    // selection as single-line and multi-line has different defaults.
+    if (oldMultiple != this->multiple())
+        setSelectedIndex(oldSelectedIndex);
+}
+
+void HTMLSelectElement::setSize(int size)
+{
+    setAttribute(sizeAttr, String::number(size));
+}
+
+Node* HTMLSelectElement::namedItem(const AtomicString& name)
+{
+    return options()->namedItem(name);
+}
+
+Node* HTMLSelectElement::item(unsigned index)
+{
+    return options()->item(index);
+}
+
+void HTMLSelectElement::setOption(unsigned index, HTMLOptionElement* option, ExceptionCode& ec)
+{
+    ec = 0;
+    if (index > maxSelectItems - 1)
+        index = maxSelectItems - 1;
+    int diff = index - length();
+    RefPtr<HTMLElement> before = 0;
+    // Out of array bounds? First insert empty dummies.
+    if (diff > 0) {
+        setLength(index, ec);
+        // Replace an existing entry?
+    } else if (diff < 0) {
+        before = toHTMLElement(options()->item(index+1));
+        remove(index);
+    }
+    // Finally add the new element.
+    if (!ec) {
+        add(option, before.get(), ec);
+        if (diff >= 0 && option->selected())
+            optionSelectionStateChanged(option, true);
+    }
+}
+
+void HTMLSelectElement::setLength(unsigned newLen, ExceptionCode& ec)
+{
+    ec = 0;
+    if (newLen > maxSelectItems)
+        newLen = maxSelectItems;
+    int diff = length() - newLen;
+
+    if (diff < 0) { // Add dummy elements.
+        do {
+            RefPtr<Element> option = document()->createElement(optionTag, false);
+            ASSERT(option);
+            add(toHTMLElement(option.get()), 0, ec);
+            if (ec)
+                break;
+        } while (++diff);
+    } else {
+        const Vector<HTMLElement*>& items = listItems();
+
+        // Removing children fires mutation events, which might mutate the DOM further, so we first copy out a list
+        // of elements that we intend to remove then attempt to remove them one at a time.
+        Vector<RefPtr<Element> > itemsToRemove;
+        size_t optionIndex = 0;
+        for (size_t i = 0; i < items.size(); ++i) {
+            Element* item = items[i];
+            if (item->hasLocalName(optionTag) && optionIndex++ >= newLen) {
+                ASSERT(item->parentNode());
+                itemsToRemove.append(item);
+            }
+        }
+
+        for (size_t i = 0; i < itemsToRemove.size(); ++i) {
+            Element* item = itemsToRemove[i].get();
+            if (item->parentNode())
+                item->parentNode()->removeChild(item, ec);
+        }
+    }
+    setNeedsValidityCheck();
+}
+
+bool HTMLSelectElement::isRequiredFormControl() const
+{
+    return isRequired();
+}
+
+// Returns the 1st valid item |skip| items from |listIndex| in direction |direction| if there is one.
+// Otherwise, it returns the valid item closest to that boundary which is past |listIndex| if there is one.
+// Otherwise, it returns |listIndex|.
+// Valid means that it is enabled and an option element.
+int HTMLSelectElement::nextValidIndex(int listIndex, SkipDirection direction, int skip) const
+{
+    ASSERT(direction == -1 || direction == 1);
+    const Vector<HTMLElement*>& listItems = this->listItems();
+    int lastGoodIndex = listIndex;
+    int size = listItems.size();
+    for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex += direction) {
+        --skip;
+        if (!listItems[listIndex]->isDisabledFormControl() && listItems[listIndex]->hasTagName(optionTag)) {
+            lastGoodIndex = listIndex;
+            if (skip <= 0)
+                break;
+        }
+    }
+    return lastGoodIndex;
+}
+
+int HTMLSelectElement::nextSelectableListIndex(int startIndex) const
+{
+    return nextValidIndex(startIndex, SkipForwards, 1);
+}
+
+int HTMLSelectElement::previousSelectableListIndex(int startIndex) const
+{
+    if (startIndex == -1)
+        startIndex = listItems().size();
+    return nextValidIndex(startIndex, SkipBackwards, 1);
+}
+
+int HTMLSelectElement::firstSelectableListIndex() const
+{
+    const Vector<HTMLElement*>& items = listItems();
+    int index = nextValidIndex(items.size(), SkipBackwards, INT_MAX);
+    if (static_cast<size_t>(index) == items.size())
+        return -1;
+    return index;
+}
+
+int HTMLSelectElement::lastSelectableListIndex() const
+{
+    return nextValidIndex(-1, SkipForwards, INT_MAX);
+}
+
+// Returns the index of the next valid item one page away from |startIndex| in direction |direction|.
+int HTMLSelectElement::nextSelectableListIndexPageAway(int startIndex, SkipDirection direction) const
+{
+    const Vector<HTMLElement*>& items = listItems();
+    // Can't use m_size because renderer forces a minimum size.
+    int pageSize = 0;
+    if (renderer()->isListBox())
+        pageSize = toRenderListBox(renderer())->size() - 1; // -1 so we still show context.
+
+    // One page away, but not outside valid bounds.
+    // If there is a valid option item one page away, the index is chosen.
+    // If there is no exact one page away valid option, returns startIndex or the most far index.
+    int edgeIndex = (direction == SkipForwards) ? 0 : (items.size() - 1);
+    int skipAmount = pageSize + ((direction == SkipForwards) ? startIndex : (edgeIndex - startIndex));
+    return nextValidIndex(edgeIndex, direction, skipAmount);
+}
+
+void HTMLSelectElement::selectAll()
+{
+    ASSERT(!usesMenuList());
+    if (!renderer() || !m_multiple)
+        return;
+
+    // Save the selection so it can be compared to the new selectAll selection
+    // when dispatching change events.
+    saveLastSelection();
+
+    m_activeSelectionState = true;
+    setActiveSelectionAnchorIndex(nextSelectableListIndex(-1));
+    setActiveSelectionEndIndex(previousSelectableListIndex(-1));
+
+    updateListBoxSelection(false);
+    listBoxOnChange();
+    setNeedsValidityCheck();
+}
+
+void HTMLSelectElement::saveLastSelection()
+{
+    if (usesMenuList()) {
+        m_lastOnChangeIndex = selectedIndex();
+        return;
+    }
+
+    m_lastOnChangeSelection.clear();
+    const Vector<HTMLElement*>& items = listItems();
+    for (unsigned i = 0; i < items.size(); ++i) {
+        HTMLElement* element = items[i];
+        m_lastOnChangeSelection.append(element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected());
+    }
+}
+
+void HTMLSelectElement::setActiveSelectionAnchorIndex(int index)
+{
+    m_activeSelectionAnchorIndex = index;
+
+    // Cache the selection state so we can restore the old selection as the new
+    // selection pivots around this anchor index.
+    m_cachedStateForActiveSelection.clear();
+
+    const Vector<HTMLElement*>& items = listItems();
+    for (unsigned i = 0; i < items.size(); ++i) {
+        HTMLElement* element = items[i];
+        m_cachedStateForActiveSelection.append(element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected());
+    }
+}
+
+void HTMLSelectElement::setActiveSelectionEndIndex(int index)
+{
+    m_activeSelectionEndIndex = index;
+}
+
+void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
+{
+    ASSERT(renderer() && (renderer()->isListBox() || m_multiple));
+    ASSERT(!listItems().size() || m_activeSelectionAnchorIndex >= 0);
+
+    unsigned start = min(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);
+    unsigned end = max(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);
+
+    const Vector<HTMLElement*>& items = listItems();
+    for (unsigned i = 0; i < items.size(); ++i) {
+        HTMLElement* element = items[i];
+        if (!element->hasTagName(optionTag) || toHTMLOptionElement(element)->isDisabledFormControl())
+            continue;
+
+        if (i >= start && i <= end)
+            toHTMLOptionElement(element)->setSelectedState(m_activeSelectionState);
+        else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.size())
+            toHTMLOptionElement(element)->setSelectedState(false);
+        else
+            toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiveSelection[i]);
+    }
+
+    scrollToSelection();
+    setNeedsValidityCheck();
+    notifyFormStateChanged();
+}
+
+void HTMLSelectElement::listBoxOnChange()
+{
+    ASSERT(!usesMenuList() || m_multiple);
+
+    const Vector<HTMLElement*>& items = listItems();
+
+    // If the cached selection list is empty, or the size has changed, then fire
+    // dispatchFormControlChangeEvent, and return early.
+    if (m_lastOnChangeSelection.isEmpty() || m_lastOnChangeSelection.size() != items.size()) {
+        dispatchFormControlChangeEvent();
+        return;
+    }
+
+    // Update m_lastOnChangeSelection and fire dispatchFormControlChangeEvent.
+    bool fireOnChange = false;
+    for (unsigned i = 0; i < items.size(); ++i) {
+        HTMLElement* element = items[i];
+        bool selected = element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected();
+        if (selected != m_lastOnChangeSelection[i])
+            fireOnChange = true;
+        m_lastOnChangeSelection[i] = selected;
+    }
+
+    if (fireOnChange)
+        dispatchFormControlChangeEvent();
+}
+
+void HTMLSelectElement::dispatchChangeEventForMenuList()
+{
+    ASSERT(usesMenuList());
+
+    int selected = selectedIndex();
+    if (m_lastOnChangeIndex != selected && m_isProcessingUserDrivenChange) {
+        m_lastOnChangeIndex = selected;
+        m_isProcessingUserDrivenChange = false;
+        dispatchFormControlChangeEvent();
+    }
+}
+
+void HTMLSelectElement::scrollToSelection()
+{
+    if (usesMenuList())
+        return;
+
+    if (RenderObject* renderer = this->renderer())
+        toRenderListBox(renderer)->selectionChanged();
+}
+
+void HTMLSelectElement::setOptionsChangedOnRenderer()
+{
+    if (RenderObject* renderer = this->renderer()) {
+        if (usesMenuList())
+            toRenderMenuList(renderer)->setOptionsChanged(true);
+        else
+            toRenderListBox(renderer)->setOptionsChanged(true);
+    }
+}
+
+const Vector<HTMLElement*>& HTMLSelectElement::listItems() const
+{
+    if (m_shouldRecalcListItems)
+        recalcListItems();
+    else {
+#if !ASSERT_DISABLED
+        Vector<HTMLElement*> items = m_listItems;
+        recalcListItems(false);
+        ASSERT(items == m_listItems);
+#endif
+    }
+
+    return m_listItems;
+}
+
+void HTMLSelectElement::invalidateSelectedItems()
+{
+    if (HTMLCollection* collection = cachedHTMLCollection(SelectedOptions))
+        collection->invalidateCache();
+}
+
+void HTMLSelectElement::setRecalcListItems()
+{
+    m_shouldRecalcListItems = true;
+    // Manual selection anchor is reset when manipulating the select programmatically.
+    m_activeSelectionAnchorIndex = -1;
+    setOptionsChangedOnRenderer();
+    setNeedsStyleRecalc();
+    if (!inDocument()) {
+        if (HTMLCollection* collection = cachedHTMLCollection(SelectOptions))
+            collection->invalidateCache();
+    }
+    if (!inDocument())
+        invalidateSelectedItems();
+    
+    if (renderer()) {
+        if (AXObjectCache* cache = renderer()->document()->existingAXObjectCache())
+            cache->childrenChanged(this);
+    }
+}
+
+void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
+{
+    m_listItems.clear();
+
+    m_shouldRecalcListItems = false;
+
+    HTMLOptionElement* foundSelected = 0;
+    HTMLOptionElement* firstOption = 0;
+    for (Element* currentElement = ElementTraversal::firstWithin(this); currentElement; ) {
+        if (!currentElement->isHTMLElement()) {
+            currentElement = ElementTraversal::nextSkippingChildren(currentElement, this);
+            continue;
+        }
+        HTMLElement* current = toHTMLElement(currentElement);
+
+        // optgroup tags may not nest. However, both FireFox and IE will
+        // flatten the tree automatically, so we follow suit.
+        // (http://www.w3.org/TR/html401/interact/forms.html#h-17.6)
+        if (current->hasTagName(optgroupTag)) {
+            m_listItems.append(current);
+            if (Element* nextElement = ElementTraversal::firstWithin(current)) {
+                currentElement = nextElement;
+                continue;
+            }
+        }
+
+        if (current->hasTagName(optionTag)) {
+            m_listItems.append(current);
+
+            if (updateSelectedStates && !m_multiple) {
+                HTMLOptionElement* option = toHTMLOptionElement(current);
+                if (!firstOption)
+                    firstOption = option;
+                if (option->selected()) {
+                    if (foundSelected)
+                        foundSelected->setSelectedState(false);
+                    foundSelected = option;
+                } else if (m_size <= 1 && !foundSelected && !option->isDisabledFormControl()) {
+                    foundSelected = option;
+                    foundSelected->setSelectedState(true);
+                }
+            }
+        }
+
+        if (current->hasTagName(hrTag))
+            m_listItems.append(current);
+
+        // In conforming HTML code, only <optgroup> and <option> will be found
+        // within a <select>. We call NodeTraversal::nextSkippingChildren so that we only step
+        // into those tags that we choose to. For web-compat, we should cope
+        // with the case where odd tags like a <div> have been added but we
+        // handle this because such tags have already been removed from the
+        // <select>'s subtree at this point.
+        currentElement = ElementTraversal::nextSkippingChildren(currentElement, this);
+    }
+
+    if (!foundSelected && m_size <= 1 && firstOption && !firstOption->selected())
+        firstOption->setSelectedState(true);
+}
+
+int HTMLSelectElement::selectedIndex() const
+{
+    unsigned index = 0;
+
+    // Return the number of the first option selected.
+    const Vector<HTMLElement*>& items = listItems();
+    for (size_t i = 0; i < items.size(); ++i) {
+        HTMLElement* element = items[i];
+        if (element->hasTagName(optionTag)) {
+            if (toHTMLOptionElement(element)->selected())
+                return index;
+            ++index;
+        }
+    }
+
+    return -1;
+}
+
+void HTMLSelectElement::setSelectedIndex(int index)
+{
+    selectOption(index, DeselectOtherOptions);
+}
+
+void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, bool optionIsSelected)
+{
+    ASSERT(option->ownerSelectElement() == this);
+    if (optionIsSelected)
+        selectOption(option->index());
+    else if (!usesMenuList())
+        selectOption(-1);
+    else
+        selectOption(nextSelectableListIndex(-1));
+}
+
+void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags)
+{
+    bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions);
+
+    const Vector<HTMLElement*>& items = listItems();
+    int listIndex = optionToListIndex(optionIndex);
+
+    HTMLElement* element = 0;
+    if (listIndex >= 0) {
+        element = items[listIndex];
+        if (element->hasTagName(optionTag)) {
+            if (m_activeSelectionAnchorIndex < 0 || shouldDeselect)
+                setActiveSelectionAnchorIndex(listIndex);
+            if (m_activeSelectionEndIndex < 0 || shouldDeselect)
+                setActiveSelectionEndIndex(listIndex);
+            toHTMLOptionElement(element)->setSelectedState(true);
+        }
+    }
+
+    if (shouldDeselect)
+        deselectItemsWithoutValidation(element);
+
+    // For the menu list case, this is what makes the selected element appear.
+    if (RenderObject* renderer = this->renderer())
+        renderer->updateFromElement();
+
+    scrollToSelection();
+
+    if (usesMenuList()) {
+        m_isProcessingUserDrivenChange = flags & UserDriven;
+        if (flags & DispatchChangeEvent)
+            dispatchChangeEventForMenuList();
+        if (RenderObject* renderer = this->renderer()) {
+            if (usesMenuList())
+                toRenderMenuList(renderer)->didSetSelectedIndex(listIndex);
+            else if (renderer->isListBox())
+                toRenderListBox(renderer)->selectionChanged();
+        }
+    }
+
+    setNeedsValidityCheck();
+    notifyFormStateChanged();
+}
+
+int HTMLSelectElement::optionToListIndex(int optionIndex) const
+{
+    const Vector<HTMLElement*>& items = listItems();
+    int listSize = static_cast<int>(items.size());
+    if (optionIndex < 0 || optionIndex >= listSize)
+        return -1;
+
+    int optionIndex2 = -1;
+    for (int listIndex = 0; listIndex < listSize; ++listIndex) {
+        if (items[listIndex]->hasTagName(optionTag)) {
+            ++optionIndex2;
+            if (optionIndex2 == optionIndex)
+                return listIndex;
+        }
+    }
+
+    return -1;
+}
+
+int HTMLSelectElement::listToOptionIndex(int listIndex) const
+{
+    const Vector<HTMLElement*>& items = listItems();
+    if (listIndex < 0 || listIndex >= static_cast<int>(items.size()) || !items[listIndex]->hasTagName(optionTag))
+        return -1;
+
+    // Actual index of option not counting OPTGROUP entries that may be in list.
+    int optionIndex = 0;
+    for (int i = 0; i < listIndex; ++i) {
+        if (items[i]->hasTagName(optionTag))
+            ++optionIndex;
+    }
+
+    return optionIndex;
+}
+
+void HTMLSelectElement::dispatchFocusEvent(PassRefPtr<Node> oldFocusedNode, FocusDirection direction)
+{
+    // Save the selection so it can be compared to the new selection when
+    // dispatching change events during blur event dispatch.
+    if (usesMenuList())
+        saveLastSelection();
+    HTMLFormControlElementWithState::dispatchFocusEvent(oldFocusedNode, direction);
+}
+
+void HTMLSelectElement::dispatchBlurEvent(PassRefPtr<Node> newFocusedNode)
+{
+    // We only need to fire change events here for menu lists, because we fire
+    // change events for list boxes whenever the selection change is actually made.
+    // This matches other browsers' behavior.
+    if (usesMenuList())
+        dispatchChangeEventForMenuList();
+    HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedNode);
+}
+
+void HTMLSelectElement::deselectItemsWithoutValidation(HTMLElement* excludeElement)
+{
+    const Vector<HTMLElement*>& items = listItems();
+    for (unsigned i = 0; i < items.size(); ++i) {
+        HTMLElement* element = items[i];
+        if (element != excludeElement && element->hasTagName(optionTag))
+            toHTMLOptionElement(element)->setSelectedState(false);
+    }
+}
+
+FormControlState HTMLSelectElement::saveFormControlState() const
+{
+    const Vector<HTMLElement*>& items = listItems();
+    size_t length = items.size();
+    FormControlState state;
+    for (unsigned i = 0; i < length; ++i) {
+        if (!items[i]->hasTagName(optionTag))
+            continue;
+        HTMLOptionElement* option = toHTMLOptionElement(items[i]);
+        if (!option->selected())
+            continue;
+        state.append(option->value());
+        if (!multiple())
+            break;
+    }
+    return state;
+}
+
+size_t HTMLSelectElement::searchOptionsForValue(const String& value, size_t listIndexStart, size_t listIndexEnd) const
+{
+    const Vector<HTMLElement*>& items = listItems();
+    size_t loopEndIndex = std::min(items.size(), listIndexEnd);
+    for (size_t i = listIndexStart; i < loopEndIndex; ++i) {
+        if (!items[i]->hasLocalName(optionTag))
+            continue;
+        if (static_cast<HTMLOptionElement*>(items[i])->value() == value)
+            return i;
+    }
+    return notFound;
+}
+
+void HTMLSelectElement::restoreFormControlState(const FormControlState& state)
+{
+    recalcListItems();
+
+    const Vector<HTMLElement*>& items = listItems();
+    size_t itemsSize = items.size();
+    if (!itemsSize)
+        return;
+
+    for (size_t i = 0; i < itemsSize; ++i) {
+        if (!items[i]->hasLocalName(optionTag))
+            continue;
+        static_cast<HTMLOptionElement*>(items[i])->setSelectedState(false);
+    }
+
+    if (!multiple()) {
+        size_t foundIndex = searchOptionsForValue(state[0], 0, itemsSize);
+        if (foundIndex != notFound)
+            toHTMLOptionElement(items[foundIndex])->setSelectedState(true);
+    } else {
+        size_t startIndex = 0;
+        for (size_t i = 0; i < state.valueSize(); ++i) {
+            const String& value = state[i];
+            size_t foundIndex = searchOptionsForValue(value, startIndex, itemsSize);
+            if (foundIndex == notFound)
+                foundIndex = searchOptionsForValue(value, 0, startIndex);
+            if (foundIndex == notFound)
+                continue;
+            toHTMLOptionElement(items[foundIndex])->setSelectedState(true);
+            startIndex = foundIndex + 1;
+        }
+    }
+
+    setOptionsChangedOnRenderer();
+    setNeedsValidityCheck();
+}
+
+void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value)
+{
+    bool oldUsesMenuList = usesMenuList();
+    m_multiple = !value.isNull();
+    setNeedsValidityCheck();
+    if (oldUsesMenuList != usesMenuList())
+        reattachIfAttached();
+}
+
+bool HTMLSelectElement::appendFormData(FormDataList& list, bool)
+{
+    const AtomicString& name = this->name();
+    if (name.isEmpty())
+        return false;
+
+    bool successful = false;
+    const Vector<HTMLElement*>& items = listItems();
+
+    for (unsigned i = 0; i < items.size(); ++i) {
+        HTMLElement* element = items[i];
+        if (element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected() && !toHTMLOptionElement(element)->isDisabledFormControl()) {
+            list.appendData(name, toHTMLOptionElement(element)->value());
+            successful = true;
+        }
+    }
+
+    // It's possible that this is a menulist with multiple options and nothing
+    // will be submitted (!successful). We won't send a unselected non-disabled
+    // option as fallback. This behavior matches to other browsers.
+    return successful;
+} 
+
+void HTMLSelectElement::reset()
+{
+    HTMLOptionElement* firstOption = 0;
+    HTMLOptionElement* selectedOption = 0;
+
+    const Vector<HTMLElement*>& items = listItems();
+    for (unsigned i = 0; i < items.size(); ++i) {
+        HTMLElement* element = items[i];
+        if (!element->hasTagName(optionTag))
+            continue;
+
+        if (items[i]->fastHasAttribute(selectedAttr)) {
+            if (selectedOption && !m_multiple)
+                selectedOption->setSelectedState(false);
+            toHTMLOptionElement(element)->setSelectedState(true);
+            selectedOption = toHTMLOptionElement(element);
+        } else
+            toHTMLOptionElement(element)->setSelectedState(false);
+
+        if (!firstOption)
+            firstOption = toHTMLOptionElement(element);
+    }
+
+    if (!selectedOption && firstOption && !m_multiple && m_size <= 1)
+        firstOption->setSelectedState(true);
+
+    setOptionsChangedOnRenderer();
+    setNeedsStyleRecalc();
+    setNeedsValidityCheck();
+}
+
+#if !OS(WINDOWS)
+bool HTMLSelectElement::platformHandleKeydownEvent(KeyboardEvent* event)
+{
+    const Page* page = document()->page();
+    RefPtr<RenderTheme> renderTheme = page ? page->theme() : RenderTheme::defaultTheme();
+
+    if (!renderTheme->popsMenuByArrowKeys())
+        return false;
+
+    if (!isSpatialNavigationEnabled(document()->frame())) {
+        if (event->keyIdentifier() == "Down" || event->keyIdentifier() == "Up") {
+            focus();
+            // Calling focus() may cause us to lose our renderer. Return true so
+            // that our caller doesn't process the event further, but don't set
+            // the event as handled.
+            if (!renderer())
+                return true;
+
+            // Save the selection so it can be compared to the new selection
+            // when dispatching change events during selectOption, which
+            // gets called from RenderMenuList::valueChanged, which gets called
+            // after the user makes a selection from the menu.
+            saveLastSelection();
+            if (RenderMenuList* menuList = toRenderMenuList(renderer()))
+                menuList->showPopup();
+            event->setDefaultHandled();
+        }
+        return true;
+    }
+
+    return false;
+}
+#endif
+
+void HTMLSelectElement::menuListDefaultEventHandler(Event* event)
+{
+    const Page* page = document()->page();
+    RefPtr<RenderTheme> renderTheme = page ? page->theme() : RenderTheme::defaultTheme();
+
+    if (event->type() == eventNames().keydownEvent) {
+        if (!renderer() || !event->isKeyboardEvent())
+            return;
+
+        if (platformHandleKeydownEvent(static_cast<KeyboardEvent*>(event)))
+            return;
+
+        // When using spatial navigation, we want to be able to navigate away
+        // from the select element when the user hits any of the arrow keys,
+        // instead of changing the selection.
+        if (isSpatialNavigationEnabled(document()->frame())) {
+            if (!m_activeSelectionState)
+                return;
+        }
+
+        const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier();
+        bool handled = true;
+        const Vector<HTMLElement*>& listItems = this->listItems();
+        int listIndex = optionToListIndex(selectedIndex());
+
+        if (keyIdentifier == "Down" || keyIdentifier == "Right")
+            listIndex = nextValidIndex(listIndex, SkipForwards, 1);
+        else if (keyIdentifier == "Up" || keyIdentifier == "Left")
+            listIndex = nextValidIndex(listIndex, SkipBackwards, 1);
+        else if (keyIdentifier == "PageDown")
+            listIndex = nextValidIndex(listIndex, SkipForwards, 3);
+        else if (keyIdentifier == "PageUp")
+            listIndex = nextValidIndex(listIndex, SkipBackwards, 3);
+        else if (keyIdentifier == "Home")
+            listIndex = nextValidIndex(-1, SkipForwards, 1);
+        else if (keyIdentifier == "End")
+            listIndex = nextValidIndex(listItems.size(), SkipBackwards, 1);
+        else
+            handled = false;
+
+        if (handled && static_cast<size_t>(listIndex) < listItems.size())
+            selectOption(listToOptionIndex(listIndex), DeselectOtherOptions | DispatchChangeEvent | UserDriven);
+
+        if (handled)
+            event->setDefaultHandled();
+    }
+
+    // Use key press event here since sending simulated mouse events
+    // on key down blocks the proper sending of the key press event.
+    if (event->type() == eventNames().keypressEvent) {
+        if (!renderer() || !event->isKeyboardEvent())
+            return;
+
+        int keyCode = static_cast<KeyboardEvent*>(event)->keyCode();
+        bool handled = false;
+
+        if (keyCode == ' ' && isSpatialNavigationEnabled(document()->frame())) {
+            // Use space to toggle arrow key handling for selection change or spatial navigation.
+            m_activeSelectionState = !m_activeSelectionState;
+            event->setDefaultHandled();
+            return;
+        }
+
+        if (renderTheme->popsMenuBySpaceOrReturn()) {
+            if (keyCode == ' ' || keyCode == '\r') {
+                focus();
+
+                // Calling focus() may remove the renderer or change the
+                // renderer type.
+                if (!renderer() || !renderer()->isMenuList())
+                    return;
+
+                // Save the selection so it can be compared to the new selection
+                // when dispatching change events during selectOption, which
+                // gets called from RenderMenuList::valueChanged, which gets called
+                // after the user makes a selection from the menu.
+                saveLastSelection();
+                if (RenderMenuList* menuList = toRenderMenuList(renderer()))
+                    menuList->showPopup();
+                handled = true;
+            }
+        } else if (renderTheme->popsMenuByArrowKeys()) {
+            if (keyCode == ' ') {
+                focus();
+
+                // Calling focus() may remove the renderer or change the
+                // renderer type.
+                if (!renderer() || !renderer()->isMenuList())
+                    return;
+
+                // Save the selection so it can be compared to the new selection
+                // when dispatching change events during selectOption, which
+                // gets called from RenderMenuList::valueChanged, which gets called
+                // after the user makes a selection from the menu.
+                saveLastSelection();
+                if (RenderMenuList* menuList = toRenderMenuList(renderer()))
+                    menuList->showPopup();
+                handled = true;
+            } else if (keyCode == '\r') {
+                if (form())
+                    form()->submitImplicitly(event, false);
+                dispatchChangeEventForMenuList();
+                handled = true;
+            }
+        }
+
+        if (handled)
+            event->setDefaultHandled();
+    }
+
+    if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+        focus();
+        if (renderer() && renderer()->isMenuList()) {
+            if (RenderMenuList* menuList = toRenderMenuList(renderer())) {
+                if (menuList->popupIsVisible())
+                    menuList->hidePopup();
+                else {
+                    // Save the selection so it can be compared to the new
+                    // selection when we call onChange during selectOption,
+                    // which gets called from RenderMenuList::valueChanged,
+                    // which gets called after the user makes a selection from
+                    // the menu.
+                    saveLastSelection();
+                    menuList->showPopup();
+                }
+            }
+        }
+        event->setDefaultHandled();
+    }
+
+    if (event->type() == eventNames().blurEvent) {
+        if (RenderMenuList* menuList = toRenderMenuList(renderer())) {
+            if (menuList->popupIsVisible())
+                menuList->hidePopup();
+        }
+    }
+}
+
+void HTMLSelectElement::updateSelectedState(int listIndex, bool multi, bool shift)
+{
+    ASSERT(listIndex >= 0);
+
+    // Save the selection so it can be compared to the new selection when
+    // dispatching change events during mouseup, or after autoscroll finishes.
+    saveLastSelection();
+
+    m_activeSelectionState = true;
+
+    bool shiftSelect = m_multiple && shift;
+    bool multiSelect = m_multiple && multi && !shift;
+
+    HTMLElement* clickedElement = listItems()[listIndex];
+    if (clickedElement->hasTagName(optionTag)) {
+        // Keep track of whether an active selection (like during drag
+        // selection), should select or deselect.
+        if (toHTMLOptionElement(clickedElement)->selected() && multiSelect)
+            m_activeSelectionState = false;
+        if (!m_activeSelectionState)
+            toHTMLOptionElement(clickedElement)->setSelectedState(false);
+    }
+
+    // If we're not in any special multiple selection mode, then deselect all
+    // other items, excluding the clicked option. If no option was clicked, then
+    // this will deselect all items in the list.
+    if (!shiftSelect && !multiSelect)
+        deselectItemsWithoutValidation(clickedElement);
+
+    // If the anchor hasn't been set, and we're doing a single selection or a
+    // shift selection, then initialize the anchor to the first selected index.
+    if (m_activeSelectionAnchorIndex < 0 && !multiSelect)
+        setActiveSelectionAnchorIndex(selectedIndex());
+
+    // Set the selection state of the clicked option.
+    if (clickedElement->hasTagName(optionTag) && !toHTMLOptionElement(clickedElement)->isDisabledFormControl())
+        toHTMLOptionElement(clickedElement)->setSelectedState(true);
+
+    // If there was no selectedIndex() for the previous initialization, or If
+    // we're doing a single selection, or a multiple selection (using cmd or
+    // ctrl), then initialize the anchor index to the listIndex that just got
+    // clicked.
+    if (m_activeSelectionAnchorIndex < 0 || !shiftSelect)
+        setActiveSelectionAnchorIndex(listIndex);
+
+    setActiveSelectionEndIndex(listIndex);
+    updateListBoxSelection(!multiSelect);
+}
+
+void HTMLSelectElement::listBoxDefaultEventHandler(Event* event)
+{
+    const Vector<HTMLElement*>& listItems = this->listItems();
+
+    if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+        focus();
+        // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event.
+        if (!renderer())
+            return;
+
+        // Convert to coords relative to the list box if needed.
+        MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+        IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouseEvent->absoluteLocation(), UseTransforms));
+        int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize(localOffset));
+        if (listIndex >= 0) {
+            if (!isDisabledFormControl()) {
+#if OS(DARWIN)
+                updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent->shiftKey());
+#else
+                updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent->shiftKey());
+#endif
+            }
+            if (Frame* frame = document()->frame())
+                frame->eventHandler()->setMouseDownMayStartAutoscroll();
+
+            event->setDefaultHandled();
+        }
+    } else if (event->type() == eventNames().mousemoveEvent && event->isMouseEvent() && !toRenderBox(renderer())->canBeScrolledAndHasScrollableArea()) {
+        MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+        if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown())
+            return;
+
+        IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouseEvent->absoluteLocation(), UseTransforms));
+        int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize(localOffset));
+        if (listIndex >= 0) {
+            if (!isDisabledFormControl()) {
+                if (m_multiple) {
+                    // Only extend selection if there is something selected.
+                    if (m_activeSelectionAnchorIndex < 0)
+                        return;
+
+                    setActiveSelectionEndIndex(listIndex);
+                    updateListBoxSelection(false);
+                } else {
+                    setActiveSelectionAnchorIndex(listIndex);
+                    setActiveSelectionEndIndex(listIndex);
+                    updateListBoxSelection(true);
+                }
+            }
+            event->setDefaultHandled();
+        }
+    } else if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton && document()->frame()->eventHandler()->autoscrollRenderer() != renderer()) {
+        // This makes sure we fire dispatchFormControlChangeEvent for a single
+        // click. For drag selection, onChange will fire when the autoscroll
+        // timer stops.
+        listBoxOnChange();
+    } else if (event->type() == eventNames().keydownEvent) {
+        if (!event->isKeyboardEvent())
+            return;
+        const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier();
+
+        bool handled = false;
+        int endIndex = 0;
+        if (m_activeSelectionEndIndex < 0) {
+            // Initialize the end index
+            if (keyIdentifier == "Down" || keyIdentifier == "PageDown") {
+                int startIndex = lastSelectedListIndex();
+                handled = true;
+                if (keyIdentifier == "Down")
+                    endIndex = nextSelectableListIndex(startIndex);
+                else
+                    endIndex = nextSelectableListIndexPageAway(startIndex, SkipForwards);
+            } else if (keyIdentifier == "Up" || keyIdentifier == "PageUp") {
+                int startIndex = optionToListIndex(selectedIndex());
+                handled = true;
+                if (keyIdentifier == "Up")
+                    endIndex = previousSelectableListIndex(startIndex);
+                else
+                    endIndex = nextSelectableListIndexPageAway(startIndex, SkipBackwards);
+            }
+        } else {
+            // Set the end index based on the current end index.
+            if (keyIdentifier == "Down") {
+                endIndex = nextSelectableListIndex(m_activeSelectionEndIndex);
+                handled = true;
+            } else if (keyIdentifier == "Up") {
+                endIndex = previousSelectableListIndex(m_activeSelectionEndIndex);
+                handled = true;
+            } else if (keyIdentifier == "PageDown") {
+                endIndex = nextSelectableListIndexPageAway(m_activeSelectionEndIndex, SkipForwards);
+                handled = true;
+            } else if (keyIdentifier == "PageUp") {
+                endIndex = nextSelectableListIndexPageAway(m_activeSelectionEndIndex, SkipBackwards);
+                handled = true;
+            }
+        }
+        if (keyIdentifier == "Home") {
+            endIndex = firstSelectableListIndex();
+            handled = true;
+        } else if (keyIdentifier == "End") {
+            endIndex = lastSelectableListIndex();
+            handled = true;
+        }
+
+        if (isSpatialNavigationEnabled(document()->frame()))
+            // Check if the selection moves to the boundary.
+            if (keyIdentifier == "Left" || keyIdentifier == "Right" || ((keyIdentifier == "Down" || keyIdentifier == "Up") && endIndex == m_activeSelectionEndIndex))
+                return;
+
+        if (endIndex >= 0 && handled) {
+            // Save the selection so it can be compared to the new selection
+            // when dispatching change events immediately after making the new
+            // selection.
+            saveLastSelection();
+
+            ASSERT_UNUSED(listItems, !listItems.size() || static_cast<size_t>(endIndex) < listItems.size());
+            setActiveSelectionEndIndex(endIndex);
+
+            bool selectNewItem = !m_multiple || static_cast<KeyboardEvent*>(event)->shiftKey() || !isSpatialNavigationEnabled(document()->frame());
+            if (selectNewItem)
+                m_activeSelectionState = true;
+            // If the anchor is unitialized, or if we're going to deselect all
+            // other options, then set the anchor index equal to the end index.
+            bool deselectOthers = !m_multiple || (!static_cast<KeyboardEvent*>(event)->shiftKey() && selectNewItem);
+            if (m_activeSelectionAnchorIndex < 0 || deselectOthers) {
+                if (deselectOthers)
+                    deselectItemsWithoutValidation();
+                setActiveSelectionAnchorIndex(m_activeSelectionEndIndex);
+            }
+
+            toRenderListBox(renderer())->scrollToRevealElementAtListIndex(endIndex);
+            if (selectNewItem) {
+                updateListBoxSelection(deselectOthers);
+                listBoxOnChange();
+            } else
+                scrollToSelection();
+
+            event->setDefaultHandled();
+        }
+    } else if (event->type() == eventNames().keypressEvent) {
+        if (!event->isKeyboardEvent())
+            return;
+        int keyCode = static_cast<KeyboardEvent*>(event)->keyCode();
+
+        if (keyCode == '\r') {
+            if (form())
+                form()->submitImplicitly(event, false);
+            event->setDefaultHandled();
+        } else if (m_multiple && keyCode == ' ' && isSpatialNavigationEnabled(document()->frame())) {
+            // Use space to toggle selection change.
+            m_activeSelectionState = !m_activeSelectionState;
+            updateSelectedState(listToOptionIndex(m_activeSelectionEndIndex), true /*multi*/, false /*shift*/);
+            listBoxOnChange();
+            event->setDefaultHandled();
+        }
+    }
+}
+
+void HTMLSelectElement::defaultEventHandler(Event* event)
+{
+    if (!renderer())
+        return;
+
+    if (isDisabledFormControl()) {
+        HTMLFormControlElementWithState::defaultEventHandler(event);
+        return;
+    }
+
+    if (usesMenuList())
+        menuListDefaultEventHandler(event);
+    else 
+        listBoxDefaultEventHandler(event);
+    if (event->defaultHandled())
+        return;
+
+    if (event->type() == eventNames().keypressEvent && event->isKeyboardEvent()) {
+        KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event);
+        if (!keyboardEvent->ctrlKey() && !keyboardEvent->altKey() && !keyboardEvent->metaKey() && isPrintableChar(keyboardEvent->charCode())) {
+            typeAheadFind(keyboardEvent);
+            event->setDefaultHandled();
+            return;
+        }
+    }
+    HTMLFormControlElementWithState::defaultEventHandler(event);
+}
+
+int HTMLSelectElement::lastSelectedListIndex() const
+{
+    const Vector<HTMLElement*>& items = listItems();
+    for (size_t i = items.size(); i;) {
+        HTMLElement* element = items[--i];
+        if (element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected())
+            return i;
+    }
+    return -1;
+}
+
+int HTMLSelectElement::indexOfSelectedOption() const
+{
+    return optionToListIndex(selectedIndex());
+}
+
+int HTMLSelectElement::optionCount() const
+{
+    return listItems().size();
+}
+
+String HTMLSelectElement::optionAtIndex(int index) const
+{
+    const Vector<HTMLElement*>& items = listItems();
+    
+    HTMLElement* element = items[index];
+    if (!element->hasTagName(optionTag) || toHTMLOptionElement(element)->isDisabledFormControl())
+        return String();
+    return toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
+}
+
+void HTMLSelectElement::typeAheadFind(KeyboardEvent* event)
+{
+    int index = m_typeAhead.handleEvent(event, TypeAhead::MatchPrefix | TypeAhead::CycleFirstChar);
+    if (index < 0)
+        return;
+    selectOption(listToOptionIndex(index), DeselectOtherOptions | DispatchChangeEvent | UserDriven);
+    if (!usesMenuList())
+        listBoxOnChange();
+}
+
+Node::InsertionNotificationRequest HTMLSelectElement::insertedInto(ContainerNode* insertionPoint)
+{
+    // When the element is created during document parsing, it won't have any
+    // items yet - but for innerHTML and related methods, this method is called
+    // after the whole subtree is constructed.
+    recalcListItems();
+    HTMLFormControlElementWithState::insertedInto(insertionPoint);
+    return InsertionDone;
+}
+
+void HTMLSelectElement::accessKeySetSelectedIndex(int index)
+{    
+    // First bring into focus the list box.
+    if (!focused())
+        accessKeyAction(false);
+    
+    // If this index is already selected, unselect. otherwise update the selected index.
+    const Vector<HTMLElement*>& items = listItems();
+    int listIndex = optionToListIndex(index);
+    if (listIndex >= 0) {
+        HTMLElement* element = items[listIndex];
+        if (element->hasTagName(optionTag)) {
+            if (toHTMLOptionElement(element)->selected())
+                toHTMLOptionElement(element)->setSelectedState(false);
+            else
+                selectOption(index, DispatchChangeEvent | UserDriven);
+        }
+    }
+
+    if (usesMenuList())
+        dispatchChangeEventForMenuList();
+    else
+        listBoxOnChange();
+
+    scrollToSelection();
+}
+
+unsigned HTMLSelectElement::length() const
+{
+    unsigned options = 0;
+
+    const Vector<HTMLElement*>& items = listItems();
+    for (unsigned i = 0; i < items.size(); ++i) {
+        if (items[i]->hasTagName(optionTag))
+            ++options;
+    }
+
+    return options;
+}
+
+void HTMLSelectElement::finishParsingChildren()
+{
+    HTMLFormControlElementWithState::finishParsingChildren();
+    m_isParsingInProgress = false;
+    updateListItemSelectedStates();
+}
+
+} // namespace
diff --git a/Source/core/html/HTMLSelectElement.h b/Source/core/html/HTMLSelectElement.h
new file mode 100644
index 0000000..5d93e02
--- /dev/null
+++ b/Source/core/html/HTMLSelectElement.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLSelectElement_h
+#define HTMLSelectElement_h
+
+#include "core/dom/Event.h"
+#include "core/html/HTMLFormControlElementWithState.h"
+#include "core/html/HTMLOptionsCollection.h"
+#include "core/html/TypeAhead.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class HTMLOptionElement;
+
+class HTMLSelectElement : public HTMLFormControlElementWithState, public TypeAheadDataSource {
+public:
+    static PassRefPtr<HTMLSelectElement> create(const QualifiedName&, Document*, HTMLFormElement*, bool createdByParser);
+
+    int selectedIndex() const;
+    void setSelectedIndex(int);
+
+    void optionSelectedByUser(int index, bool dispatchChangeEvent, bool allowMultipleSelection = false);
+
+    // For ValidityState
+    virtual String validationMessage() const OVERRIDE;
+    virtual bool valueMissing() const OVERRIDE;
+
+    unsigned length() const;
+
+    int size() const { return m_size; }
+    bool multiple() const { return m_multiple; }
+
+    bool usesMenuList() const;
+
+    void add(HTMLElement*, HTMLElement* beforeElement, ExceptionCode&);
+    void remove(int index);
+    void remove(HTMLOptionElement*);
+
+    String value() const;
+    void setValue(const String&);
+
+    PassRefPtr<HTMLOptionsCollection> options();
+    PassRefPtr<HTMLCollection> selectedOptions();
+
+    void optionElementChildrenChanged();
+
+    void setRecalcListItems();
+    void invalidateSelectedItems();
+    void updateListItemSelectedStates();
+
+    const Vector<HTMLElement*>& listItems() const;
+
+    virtual void accessKeyAction(bool sendMouseEvents);
+    void accessKeySetSelectedIndex(int);
+
+    void setMultiple(bool);
+
+    void setSize(int);
+
+    void setOption(unsigned index, HTMLOptionElement*, ExceptionCode&);
+    void setLength(unsigned, ExceptionCode&);
+
+    Node* namedItem(const AtomicString& name);
+    Node* item(unsigned index);
+
+    void scrollToSelection();
+
+    void listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow = true);
+
+    bool canSelectAll() const;
+    void selectAll();
+    int listToOptionIndex(int listIndex) const;
+    void listBoxOnChange();
+    int optionToListIndex(int optionIndex) const;
+    int activeSelectionStartListIndex() const;
+    int activeSelectionEndListIndex() const;
+    void setActiveSelectionAnchorIndex(int);
+    void setActiveSelectionEndIndex(int);
+    void updateListBoxSelection(bool deselectOtherOptions);
+    
+    // For use in the implementation of HTMLOptionElement.
+    void optionSelectionStateChanged(HTMLOptionElement*, bool optionIsSelected);
+    bool isParsingInProgress() const { return m_isParsingInProgress; }
+
+protected:
+    HTMLSelectElement(const QualifiedName&, Document*, HTMLFormElement*, bool createdByParser);
+
+private:
+    virtual const AtomicString& formControlType() const;
+    
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual bool isMouseFocusable() const;
+
+    virtual void dispatchFocusEvent(PassRefPtr<Node> oldFocusedNode, FocusDirection) OVERRIDE;
+    virtual void dispatchBlurEvent(PassRefPtr<Node> newFocusedNode);
+    
+    virtual bool canStartSelection() const { return false; }
+
+    virtual bool isEnumeratable() const { return true; }
+    virtual bool supportLabels() const OVERRIDE { return true; }
+
+    virtual FormControlState saveFormControlState() const OVERRIDE;
+    virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+
+    virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle *);
+    virtual bool appendFormData(FormDataList&, bool);
+
+    virtual void reset();
+
+    virtual void defaultEventHandler(Event*);
+
+    void dispatchChangeEventForMenuList();
+    
+    void recalcListItems(bool updateSelectedStates = true) const;
+
+    void deselectItems(HTMLOptionElement* excludeElement = 0);
+    void typeAheadFind(KeyboardEvent*);
+    void saveLastSelection();
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+
+    virtual bool isOptionalFormControl() const { return !isRequiredFormControl(); }
+    virtual bool isRequiredFormControl() const;
+
+    bool hasPlaceholderLabelOption() const;
+
+    enum SelectOptionFlag {
+        DeselectOtherOptions = 1 << 0,
+        DispatchChangeEvent = 1 << 1,
+        UserDriven = 1 << 2,
+    };
+    typedef unsigned SelectOptionFlags;
+    void selectOption(int optionIndex, SelectOptionFlags = 0);
+    void deselectItemsWithoutValidation(HTMLElement* elementToExclude = 0);
+    void parseMultipleAttribute(const AtomicString&);
+    int lastSelectedListIndex() const;
+    void updateSelectedState(int listIndex, bool multi, bool shift);
+    void menuListDefaultEventHandler(Event*);
+    bool platformHandleKeydownEvent(KeyboardEvent*);
+    void listBoxDefaultEventHandler(Event*);
+    void setOptionsChangedOnRenderer();
+    size_t searchOptionsForValue(const String&, size_t listIndexStart, size_t listIndexEnd) const;
+
+    enum SkipDirection {
+        SkipBackwards = -1,
+        SkipForwards = 1
+    };
+    int nextValidIndex(int listIndex, SkipDirection, int skip) const;
+    int nextSelectableListIndex(int startIndex) const;
+    int previousSelectableListIndex(int startIndex) const;
+    int firstSelectableListIndex() const;
+    int lastSelectableListIndex() const;
+    int nextSelectableListIndexPageAway(int startIndex, SkipDirection) const;
+
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+    virtual void finishParsingChildren() OVERRIDE;
+
+    // TypeAheadDataSource functions.
+    virtual int indexOfSelectedOption() const OVERRIDE;
+    virtual int optionCount() const OVERRIDE;
+    virtual String optionAtIndex(int index) const OVERRIDE;
+
+    // m_listItems contains HTMLOptionElement, HTMLOptGroupElement, and HTMLHRElement objects.
+    mutable Vector<HTMLElement*> m_listItems;
+    Vector<bool> m_lastOnChangeSelection;
+    Vector<bool> m_cachedStateForActiveSelection;
+    TypeAhead m_typeAhead;
+    int m_size;
+    int m_lastOnChangeIndex;
+    int m_activeSelectionAnchorIndex;
+    int m_activeSelectionEndIndex;
+    bool m_isProcessingUserDrivenChange;
+    bool m_multiple;
+    bool m_activeSelectionState;
+    mutable bool m_shouldRecalcListItems;
+    bool m_isParsingInProgress;
+};
+
+inline bool isHTMLSelectElement(const Node* node)
+{
+    return node->hasTagName(HTMLNames::selectTag);
+}
+
+inline HTMLSelectElement* toHTMLSelectElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLSelectElement(node));
+    return static_cast<HTMLSelectElement*>(node);
+}
+
+inline const HTMLSelectElement* toHTMLSelectElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLSelectElement(node));
+    return static_cast<const HTMLSelectElement*>(node);
+}
+
+void toHTMLSelectElement(const HTMLSelectElement*); // This overload will catch anyone doing an unnecessary cast.
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLSelectElement.idl b/Source/core/html/HTMLSelectElement.idl
new file mode 100644
index 0000000..5fd7bb5
--- /dev/null
+++ b/Source/core/html/HTMLSelectElement.idl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+[
+    CustomIndexedSetter,
+    SkipVTableValidation
+] interface HTMLSelectElement : HTMLElement {
+    [Reflect] attribute boolean autofocus;
+    [Reflect] attribute boolean disabled;
+    readonly attribute HTMLFormElement form;
+    attribute boolean multiple;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute boolean required;
+    attribute long size;
+
+    readonly attribute DOMString type;
+
+    readonly attribute HTMLOptionsCollection options;
+    [SetterRaisesException] attribute unsigned long length;
+
+    getter Node item([IsIndex,Default=Undefined] optional unsigned long index);
+    Node namedItem([Default=Undefined] optional DOMString name);
+     [RaisesException] void add([Default=Undefined] optional HTMLElement element,
+                            [Default=Undefined] optional HTMLElement before);
+    // In JavaScript, we support both option index and option object parameters.
+    // As of this writing this cannot be auto-generated.
+    [Custom] void remove(/* indexOrOption */);
+    readonly attribute HTMLCollection selectedOptions;
+    attribute long selectedIndex;
+    [TreatNullAs=NullString] attribute DOMString value;
+
+    readonly attribute boolean willValidate;
+    readonly attribute ValidityState validity;
+    readonly attribute DOMString validationMessage;
+    boolean checkValidity();
+    void setCustomValidity([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString error);
+
+    readonly attribute NodeList labels;
+};
diff --git a/Source/core/html/HTMLSelectElementWin.cpp b/Source/core/html/HTMLSelectElementWin.cpp
new file mode 100644
index 0000000..4b0b944
--- /dev/null
+++ b/Source/core/html/HTMLSelectElementWin.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 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 "core/html/HTMLSelectElement.h"
+
+#if OS(WINDOWS)
+
+#include "core/dom/Element.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/rendering/RenderMenuList.h"
+
+namespace WebCore {
+
+bool HTMLSelectElement::platformHandleKeydownEvent(KeyboardEvent* event)
+{
+    // Allow (Shift) F4 and (Ctrl/Shift) Alt/AltGr + Up/Down arrow to pop the menu, matching Firefox.
+    bool eventShowsMenu = (!event->altKey() && !event->ctrlKey() && event->keyIdentifier() == "F4")
+        || ((event->altGraphKey() || event->altKey()) && (event->keyIdentifier() == "Down" || event->keyIdentifier() == "Up"));
+    if (!eventShowsMenu)
+        return false;
+
+    // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex,
+    // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
+    saveLastSelection();
+    if (RenderMenuList* menuList = toRenderMenuList(renderer()))
+        menuList->showPopup();
+
+    int index = selectedIndex();
+    ASSERT(index >= 0);
+    ASSERT_WITH_SECURITY_IMPLICATION(index < static_cast<int>(listItems().size()));
+    setSelectedIndex(index);
+    event->setDefaultHandled();
+    return true;
+}
+
+}
+
+#endif
diff --git a/Source/core/html/HTMLSourceElement.cpp b/Source/core/html/HTMLSourceElement.cpp
new file mode 100644
index 0000000..0c42dda
--- /dev/null
+++ b/Source/core/html/HTMLSourceElement.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007, 2008, 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+#include "core/html/HTMLSourceElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/platform/Logging.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLSourceElement::HTMLSourceElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_errorEventTimer(this, &HTMLSourceElement::errorEventTimerFired)
+{
+    LOG(Media, "HTMLSourceElement::HTMLSourceElement - %p", this);
+    ASSERT(hasTagName(sourceTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLSourceElement> HTMLSourceElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLSourceElement(tagName, document));
+}
+
+Node::InsertionNotificationRequest HTMLSourceElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+    Element* parent = parentElement();
+    if (parent && parent->isMediaElement())
+        static_cast<HTMLMediaElement*>(parentNode())->sourceWasAdded(this);
+    return InsertionDone;
+}
+
+void HTMLSourceElement::removedFrom(ContainerNode* removalRoot)
+{
+    Element* parent = parentElement();
+    if (!parent && removalRoot->isElementNode())
+        parent = toElement(removalRoot);
+    if (parent && parent->isMediaElement())
+        toMediaElement(parent)->sourceWasRemoved(this);
+    HTMLElement::removedFrom(removalRoot);
+}
+
+void HTMLSourceElement::setSrc(const String& url)
+{
+    setAttribute(srcAttr, url);
+}
+
+String HTMLSourceElement::media() const
+{
+    return getAttribute(mediaAttr);
+}
+
+void HTMLSourceElement::setMedia(const String& media)
+{
+    setAttribute(mediaAttr, media);
+}
+
+String HTMLSourceElement::type() const
+{
+    return getAttribute(typeAttr);
+}
+
+void HTMLSourceElement::setType(const String& type)
+{
+    setAttribute(typeAttr, type);
+}
+
+void HTMLSourceElement::scheduleErrorEvent()
+{
+    LOG(Media, "HTMLSourceElement::scheduleErrorEvent - %p", this);
+    if (m_errorEventTimer.isActive())
+        return;
+
+    m_errorEventTimer.startOneShot(0);
+}
+
+void HTMLSourceElement::cancelPendingErrorEvent()
+{
+    LOG(Media, "HTMLSourceElement::cancelPendingErrorEvent - %p", this);
+    m_errorEventTimer.stop();
+}
+
+void HTMLSourceElement::errorEventTimerFired(Timer<HTMLSourceElement>*)
+{
+    LOG(Media, "HTMLSourceElement::errorEventTimerFired - %p", this);
+    dispatchEvent(Event::create(eventNames().errorEvent, false, true));
+}
+
+bool HTMLSourceElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == srcAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+}
diff --git a/Source/core/html/HTMLSourceElement.h b/Source/core/html/HTMLSourceElement.h
new file mode 100644
index 0000000..7e7c5ed
--- /dev/null
+++ b/Source/core/html/HTMLSourceElement.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007, 2008, 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 COMPUTER, 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 COMPUTER, 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 HTMLSourceElement_h
+#define HTMLSourceElement_h
+
+#include "core/html/HTMLElement.h"
+#include "core/platform/Timer.h"
+
+namespace WebCore {
+
+class HTMLSourceElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLSourceElement> create(const QualifiedName&, Document*);
+
+    String media() const;
+    String type() const;
+    void setSrc(const String&);    
+    void setMedia(const String&);
+    void setType(const String&);
+    
+    void scheduleErrorEvent();
+    void cancelPendingErrorEvent();
+
+private:
+    HTMLSourceElement(const QualifiedName&, Document*);
+    
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+    void errorEventTimerFired(Timer<HTMLSourceElement>*);
+
+    Timer<HTMLSourceElement> m_errorEventTimer;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLSourceElement.idl b/Source/core/html/HTMLSourceElement.idl
new file mode 100644
index 0000000..67e69f7
--- /dev/null
+++ b/Source/core/html/HTMLSourceElement.idl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007, 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+interface HTMLSourceElement : HTMLElement {
+[Reflect, URL] attribute DOMString src;
+    attribute DOMString type;
+    attribute DOMString media;
+};
diff --git a/Source/core/html/HTMLSpanElement.cpp b/Source/core/html/HTMLSpanElement.cpp
new file mode 100644
index 0000000..560ffb4
--- /dev/null
+++ b/Source/core/html/HTMLSpanElement.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include "config.h"
+#include "core/html/HTMLSpanElement.h"
+
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLSpanElement::HTMLSpanElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(spanTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLSpanElement> HTMLSpanElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLSpanElement(tagName, document));
+}
+
+}
diff --git a/Source/core/html/HTMLSpanElement.h b/Source/core/html/HTMLSpanElement.h
new file mode 100644
index 0000000..27c2eb4
--- /dev/null
+++ b/Source/core/html/HTMLSpanElement.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 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 HTMLSpanElement_h
+#define HTMLSpanElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLSpanElement : public HTMLElement {
+public:
+    static PassRefPtr<HTMLSpanElement> create(const QualifiedName&, Document*);
+
+protected:
+    HTMLSpanElement(const QualifiedName&, Document*);
+};
+
+}
+
+#endif
diff --git a/Source/core/html/HTMLSpanElement.idl b/Source/core/html/HTMLSpanElement.idl
new file mode 100644
index 0000000..49eb843
--- /dev/null
+++ b/Source/core/html/HTMLSpanElement.idl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+// http://www.whatwg.org/specs/web-apps/current-work/#htmlspanelement
+[
+    SkipVTableValidation
+] interface HTMLSpanElement : HTMLElement {
+};
+
diff --git a/Source/core/html/HTMLStyleElement.cpp b/Source/core/html/HTMLStyleElement.cpp
new file mode 100644
index 0000000..29a7b9c
--- /dev/null
+++ b/Source/core/html/HTMLStyleElement.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2010 Apple Inc. All rights reserved.
+ *           (C) 2007 Rob Buis (buis@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLStyleElement.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/css/MediaList.h"
+#include "core/css/StyleSheetContents.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/ContextFeatures.h"
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventSender.h"
+#include "core/dom/ScriptableDocumentParser.h"
+#include "core/dom/ShadowRoot.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static StyleEventSender& styleLoadEventSender()
+{
+    DEFINE_STATIC_LOCAL(StyleEventSender, sharedLoadEventSender, (eventNames().loadEvent));
+    return sharedLoadEventSender;
+}
+
+inline HTMLStyleElement::HTMLStyleElement(const QualifiedName& tagName, Document* document, bool createdByParser)
+    : HTMLElement(tagName, document)
+    , StyleElement(document, createdByParser)
+    , m_firedLoad(false)
+    , m_loadedSheet(false)
+    , m_scopedStyleRegistrationState(NotRegistered)
+{
+    ASSERT(hasTagName(styleTag));
+    ScriptWrappable::init(this);
+}
+
+HTMLStyleElement::~HTMLStyleElement()
+{
+    // During tear-down, willRemove isn't called, so m_scopedStyleRegistrationState may still be RegisteredAsScoped or RegisteredInShadowRoot here.
+    // Therefore we can't ASSERT(m_scopedStyleRegistrationState == NotRegistered).
+    StyleElement::clearDocumentData(document(), this);
+
+    styleLoadEventSender().cancelEvent(this);
+}
+
+PassRefPtr<HTMLStyleElement> HTMLStyleElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
+{
+    return adoptRef(new HTMLStyleElement(tagName, document, createdByParser));
+}
+
+void HTMLStyleElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == titleAttr && m_sheet)
+        m_sheet->setTitle(value);
+    else if (name == scopedAttr && ContextFeatures::styleScopedEnabled(document()))
+        scopedAttributeChanged(!value.isNull());
+    else if (name == mediaAttr && inDocument() && document()->renderer() && m_sheet) {
+        m_sheet->setMediaQueries(MediaQuerySet::createAllowingDescriptionSyntax(value));
+        document()->styleResolverChanged(RecalcStyleImmediately);
+    } else
+        HTMLElement::parseAttribute(name, value);
+}
+
+void HTMLStyleElement::scopedAttributeChanged(bool scoped)
+{
+    ASSERT(ContextFeatures::styleScopedEnabled(document()));
+
+    if (!inDocument())
+        return;
+
+    if (scoped) {
+        // As any <style> in a shadow tree is treated as "scoped",
+        // need to remove the <style> from its shadow root.
+        if (m_scopedStyleRegistrationState == RegisteredInShadowRoot)
+            unregisterWithScopingNode(containingShadowRoot());
+
+        if (m_scopedStyleRegistrationState != RegisteredAsScoped)
+            registerWithScopingNode(true);
+        return;
+    }
+
+    // If the <style> was scoped, need to remove the <style> from the scoping
+    // element, i.e. the parent node.
+    if (m_scopedStyleRegistrationState == RegisteredAsScoped)
+        unregisterWithScopingNode(parentNode());
+
+    // As any <style> in a shadow tree is treated as "scoped",
+    // need to add the <style> to its shadow root.
+    if (isInShadowTree() && m_scopedStyleRegistrationState != RegisteredInShadowRoot)
+        registerWithScopingNode(false);
+}
+
+void HTMLStyleElement::finishParsingChildren()
+{
+    StyleElement::finishParsingChildren(this);
+    HTMLElement::finishParsingChildren();
+}
+
+void HTMLStyleElement::registerWithScopingNode(bool scoped)
+{
+    // Note: We cannot rely on the 'scoped' element already being present when this method is invoked.
+    // Therefore we cannot rely on scoped()!
+    ASSERT(m_scopedStyleRegistrationState == NotRegistered);
+    ASSERT(inDocument());
+    if (m_scopedStyleRegistrationState != NotRegistered)
+        return;
+
+    ContainerNode* scope = scoped ? parentNode() : containingShadowRoot();
+    if (!scope)
+        return;
+    if (!scope->isElementNode() && !scope->isShadowRoot()) {
+        // DocumentFragment nodes should never be inDocument,
+        // <style> should not be a child of Document, PI or some such.
+        ASSERT_NOT_REACHED();
+        return;
+    }
+    scope->registerScopedHTMLStyleChild();
+    if (scope->isShadowRoot())
+        scope->shadowHost()->setNeedsStyleRecalc();
+    else
+        scope->setNeedsStyleRecalc();
+    if (inDocument() && !document()->parsing() && document()->renderer())
+        document()->styleResolverChanged(DeferRecalcStyle);
+
+    m_scopedStyleRegistrationState = scoped ? RegisteredAsScoped : RegisteredInShadowRoot;
+}
+
+void HTMLStyleElement::unregisterWithScopingNode(ContainerNode* scope)
+{
+    ASSERT(m_scopedStyleRegistrationState != NotRegistered || !ContextFeatures::styleScopedEnabled(document()));
+    if (!isRegisteredAsScoped())
+        return;
+
+    ASSERT(scope);
+    if (scope) {
+        ASSERT(scope->hasScopedHTMLStyleChild());
+        scope->unregisterScopedHTMLStyleChild();
+        scope->setNeedsStyleRecalc();
+    }
+    if (inDocument() && !document()->parsing() && document()->renderer())
+        document()->styleResolverChanged(DeferRecalcStyle);
+
+    m_scopedStyleRegistrationState = NotRegistered;
+}
+
+Node::InsertionNotificationRequest HTMLStyleElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+    if (insertionPoint->inDocument()) {
+        StyleElement::insertedIntoDocument(document(), this);
+        if (m_scopedStyleRegistrationState == NotRegistered && (scoped() || isInShadowTree()))
+            registerWithScopingNode(scoped());
+    }
+
+    return InsertionDone;
+}
+
+void HTMLStyleElement::removedFrom(ContainerNode* insertionPoint)
+{
+    HTMLElement::removedFrom(insertionPoint);
+
+    // In the current implementation, <style scoped> is only registered if the node is in the document.
+    // That is, because willRemove() is also called if an ancestor is removed from the document.
+    // Now, if we want to register <style scoped> even if it's not inDocument,
+    // we'd need to find a way to discern whether that is the case, or whether <style scoped> itself is about to be removed.
+    if (m_scopedStyleRegistrationState != NotRegistered) {
+        ContainerNode* scope;
+        if (m_scopedStyleRegistrationState == RegisteredInShadowRoot) {
+            scope = containingShadowRoot();
+            if (!scope)
+                scope = insertionPoint->containingShadowRoot();
+        } else
+            scope = parentNode() ? parentNode() : insertionPoint;
+        unregisterWithScopingNode(scope);
+    }
+
+    if (insertionPoint->inDocument())
+        StyleElement::removedFromDocument(document(), this);
+}
+
+void HTMLStyleElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+    StyleElement::childrenChanged(this);
+}
+
+const AtomicString& HTMLStyleElement::media() const
+{
+    return getAttribute(mediaAttr);
+}
+
+const AtomicString& HTMLStyleElement::type() const
+{
+    return getAttribute(typeAttr);
+}
+
+bool HTMLStyleElement::scoped() const
+{
+    return fastHasAttribute(scopedAttr) && ContextFeatures::styleScopedEnabled(document());
+}
+
+void HTMLStyleElement::setScoped(bool scopedValue)
+{
+    setBooleanAttribute(scopedAttr, scopedValue);
+}
+
+Element* HTMLStyleElement::scopingElement() const
+{
+    if (!scoped())
+        return 0;
+
+    // FIXME: This probably needs to be refined for scoped stylesheets within shadow DOM.
+    // As written, such a stylesheet could style the host element, as well as children of the host.
+    // OTOH, this paves the way for a :bound-element implementation.
+    ContainerNode* parentOrShadowHost = parentOrShadowHostNode();
+    if (!parentOrShadowHost || !parentOrShadowHost->isElementNode())
+        return 0;
+
+    return toElement(parentOrShadowHost);
+}
+
+void HTMLStyleElement::dispatchPendingLoadEvents()
+{
+    styleLoadEventSender().dispatchPendingEvents();
+}
+
+void HTMLStyleElement::dispatchPendingEvent(StyleEventSender* eventSender)
+{
+    ASSERT_UNUSED(eventSender, eventSender == &styleLoadEventSender());
+    if (m_loadedSheet)
+        dispatchEvent(Event::create(eventNames().loadEvent, false, false));
+    else
+        dispatchEvent(Event::create(eventNames().errorEvent, false, false));
+}
+
+void HTMLStyleElement::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)
+{
+    if (m_firedLoad)
+        return;
+    m_loadedSheet = !errorOccurred;
+    styleLoadEventSender().dispatchEventSoon(this);
+    m_firedLoad = true;
+}
+
+void HTMLStyleElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{    
+    HTMLElement::addSubresourceAttributeURLs(urls);
+
+    if (CSSStyleSheet* styleSheet = const_cast<HTMLStyleElement*>(this)->sheet())
+        styleSheet->contents()->addSubresourceStyleURLs(urls);
+}
+
+bool HTMLStyleElement::disabled() const
+{
+    if (!m_sheet)
+        return false;
+
+    return m_sheet->disabled();
+}
+
+void HTMLStyleElement::setDisabled(bool setDisabled)
+{
+    if (CSSStyleSheet* styleSheet = sheet())
+        styleSheet->setDisabled(setDisabled);
+}
+
+}
diff --git a/Source/core/html/HTMLStyleElement.h b/Source/core/html/HTMLStyleElement.h
new file mode 100644
index 0000000..5fe275a
--- /dev/null
+++ b/Source/core/html/HTMLStyleElement.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLStyleElement_h
+#define HTMLStyleElement_h
+
+#include "core/dom/StyleElement.h"
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLStyleElement;
+class StyleSheet;
+
+template<typename T> class EventSender;
+typedef EventSender<HTMLStyleElement> StyleEventSender;
+
+class HTMLStyleElement FINAL : public HTMLElement, private StyleElement {
+public:
+    static PassRefPtr<HTMLStyleElement> create(const QualifiedName&, Document*, bool createdByParser);
+    virtual ~HTMLStyleElement();
+
+    void setType(const AtomicString&);
+
+    bool scoped() const;
+    void setScoped(bool);
+    Element* scopingElement() const;
+    bool isRegisteredAsScoped() const
+    {
+        // Note: We cannot rely on the 'scoped' attribute still being present when this method is invoked.
+        // Therefore we cannot rely on scoped()!
+        if (m_scopedStyleRegistrationState == NotRegistered)
+            return false;
+        return true;
+    }
+
+    using StyleElement::sheet;
+
+    bool disabled() const;
+    void setDisabled(bool);
+
+    void dispatchPendingEvent(StyleEventSender*);
+    static void dispatchPendingLoadEvents();
+
+private:
+    HTMLStyleElement(const QualifiedName&, Document*, bool createdByParser);
+
+    // overload from HTMLElement
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
+    virtual void finishParsingChildren();
+
+    virtual bool isLoading() const { return StyleElement::isLoading(); }
+    virtual bool sheetLoaded() { return StyleElement::sheetLoaded(document()); }
+    virtual void notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred);
+    virtual void startLoadingDynamicSheet() { StyleElement::startLoadingDynamicSheet(document()); }
+
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+
+    virtual const AtomicString& media() const;
+    virtual const AtomicString& type() const;
+
+    void scopedAttributeChanged(bool);
+    void registerWithScopingNode(bool);
+    void unregisterWithScopingNode(ContainerNode*);
+
+    bool m_firedLoad;
+    bool m_loadedSheet;
+
+    enum ScopedStyleRegistrationState {
+        NotRegistered,
+        RegisteredAsScoped,
+        RegisteredInShadowRoot
+    };
+    ScopedStyleRegistrationState m_scopedStyleRegistrationState;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLStyleElement.idl b/Source/core/html/HTMLStyleElement.idl
new file mode 100644
index 0000000..70efc26
--- /dev/null
+++ b/Source/core/html/HTMLStyleElement.idl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLStyleElement : HTMLElement {
+    attribute boolean disabled;
+    [EnabledAtRuntime=styleScoped] attribute boolean scoped;
+    [Reflect] attribute DOMString media;
+    [Reflect] attribute DOMString type;
+
+    // DOM Level 2 Style
+    readonly attribute StyleSheet sheet;
+};
+
diff --git a/Source/core/html/HTMLSummaryElement.cpp b/Source/core/html/HTMLSummaryElement.cpp
new file mode 100644
index 0000000..5f396a4
--- /dev/null
+++ b/Source/core/html/HTMLSummaryElement.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLSummaryElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/HTMLDetailsElement.h"
+#include "core/html/shadow/DetailsMarkerControl.h"
+#include "core/html/shadow/HTMLContentElement.h"
+#include "core/platform/PlatformMouseEvent.h"
+#include "core/rendering/RenderBlock.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+PassRefPtr<HTMLSummaryElement> HTMLSummaryElement::create(const QualifiedName& tagName, Document* document)
+{
+    RefPtr<HTMLSummaryElement> summary = adoptRef(new HTMLSummaryElement(tagName, document));
+    summary->ensureUserAgentShadowRoot();
+    return summary.release();
+}
+
+HTMLSummaryElement::HTMLSummaryElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(summaryTag));
+}
+
+RenderObject* HTMLSummaryElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderBlock(this);
+}
+
+bool HTMLSummaryElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
+{
+    if (childContext.node()->isPseudoElement())
+        return true;
+    return childContext.isOnEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext);
+}
+
+void HTMLSummaryElement::didAddUserAgentShadowRoot(ShadowRoot* root)
+{
+    root->appendChild(DetailsMarkerControl::create(document()), ASSERT_NO_EXCEPTION, AttachLazily);
+    root->appendChild(HTMLContentElement::create(document()), ASSERT_NO_EXCEPTION, AttachLazily);
+}
+
+HTMLDetailsElement* HTMLSummaryElement::detailsElement() const
+{
+    Node* mayDetails = const_cast<HTMLSummaryElement*>(this)->parentNodeForRenderingAndStyle();
+    if (!mayDetails || !mayDetails->hasTagName(detailsTag))
+        return 0;
+    return static_cast<HTMLDetailsElement*>(mayDetails);
+}
+
+bool HTMLSummaryElement::isMainSummary() const
+{
+    if (HTMLDetailsElement* details = detailsElement())
+        return details->findMainSummary() == this;
+
+    return false;
+}
+
+static bool isClickableControl(Node* node)
+{
+    if (!node->isElementNode())
+        return false;
+    Element* element = toElement(node);
+    if (element->isFormControlElement())
+        return true;
+    Element* host = element->shadowHost();
+    return host && host->isFormControlElement();
+}
+
+bool HTMLSummaryElement::supportsFocus() const
+{
+    return isMainSummary();
+}
+
+void HTMLSummaryElement::defaultEventHandler(Event* event)
+{
+    if (isMainSummary() && renderer()) {
+        if (event->type() == eventNames().DOMActivateEvent && !isClickableControl(event->target()->toNode())) {
+            if (HTMLDetailsElement* details = detailsElement())
+                details->toggleOpen();
+            event->setDefaultHandled();
+            return;
+        }
+
+        if (event->isKeyboardEvent()) {
+            if (event->type() == eventNames().keydownEvent && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "U+0020") {
+                setActive(true, true);
+                // No setDefaultHandled() - IE dispatches a keypress in this case.
+                return;
+            }
+            if (event->type() == eventNames().keypressEvent) {
+                switch (static_cast<KeyboardEvent*>(event)->charCode()) {
+                case '\r':
+                    dispatchSimulatedClick(event);
+                    event->setDefaultHandled();
+                    return;
+                case ' ':
+                    // Prevent scrolling down the page.
+                    event->setDefaultHandled();
+                    return;
+                }
+            }
+            if (event->type() == eventNames().keyupEvent && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "U+0020") {
+                if (active())
+                    dispatchSimulatedClick(event);
+                event->setDefaultHandled();
+                return;
+            }
+        }
+    }
+
+    HTMLElement::defaultEventHandler(event);
+}
+
+bool HTMLSummaryElement::willRespondToMouseClickEvents()
+{
+    if (isMainSummary() && renderer())
+        return true;
+
+    return HTMLElement::willRespondToMouseClickEvents();
+}
+
+}
diff --git a/Source/core/html/HTMLSummaryElement.h b/Source/core/html/HTMLSummaryElement.h
new file mode 100644
index 0000000..feaa019
--- /dev/null
+++ b/Source/core/html/HTMLSummaryElement.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLSummaryElement_h
+#define HTMLSummaryElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLDetailsElement;
+
+class HTMLSummaryElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLSummaryElement> create(const QualifiedName&, Document*);
+    bool isMainSummary() const;
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+private:
+    HTMLSummaryElement(const QualifiedName&, Document*);
+
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const OVERRIDE;
+    virtual void defaultEventHandler(Event*);
+
+    virtual void didAddUserAgentShadowRoot(ShadowRoot*) OVERRIDE;
+    HTMLDetailsElement* detailsElement() const;
+
+    bool supportsFocus() const OVERRIDE;
+};
+
+}
+
+#endif // HTMLSummaryElement_h
diff --git a/Source/core/html/HTMLTableCaptionElement.cpp b/Source/core/html/HTMLTableCaptionElement.cpp
new file mode 100644
index 0000000..6314448
--- /dev/null
+++ b/Source/core/html/HTMLTableCaptionElement.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLTableCaptionElement.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLTableCaptionElement::HTMLTableCaptionElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(captionTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLTableCaptionElement> HTMLTableCaptionElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLTableCaptionElement(tagName, document));
+}
+
+bool HTMLTableCaptionElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == alignAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLTableCaptionElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == alignAttr) {
+        if (!value.isEmpty())
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyCaptionSide, value);
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+}
diff --git a/Source/core/html/HTMLTableCaptionElement.h b/Source/core/html/HTMLTableCaptionElement.h
new file mode 100644
index 0000000..4601a7f
--- /dev/null
+++ b/Source/core/html/HTMLTableCaptionElement.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLTableCaptionElement_h
+#define HTMLTableCaptionElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLTableCaptionElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLTableCaptionElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLTableCaptionElement(const QualifiedName&, Document*);
+
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLTableCaptionElement.idl b/Source/core/html/HTMLTableCaptionElement.idl
new file mode 100644
index 0000000..e29f097
--- /dev/null
+++ b/Source/core/html/HTMLTableCaptionElement.idl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLTableCaptionElement : HTMLElement {
+    [Reflect] attribute DOMString align;
+};
+
diff --git a/Source/core/html/HTMLTableCellElement.cpp b/Source/core/html/HTMLTableCellElement.cpp
new file mode 100644
index 0000000..0c4b225
--- /dev/null
+++ b/Source/core/html/HTMLTableCellElement.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLTableCellElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/html/HTMLTableElement.h"
+#include "core/rendering/RenderTableCell.h"
+
+using std::max;
+using std::min;
+
+namespace WebCore {
+
+// Clamp rowspan at 8k to match Firefox.
+static const int maxRowspan = 8190;
+
+using namespace HTMLNames;
+
+inline HTMLTableCellElement::HTMLTableCellElement(const QualifiedName& tagName, Document* document)
+    : HTMLTablePartElement(tagName, document)
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLTableCellElement> HTMLTableCellElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLTableCellElement(tagName, document));
+}
+
+int HTMLTableCellElement::colSpan() const
+{
+    const AtomicString& colSpanValue = fastGetAttribute(colspanAttr);
+    return max(1, colSpanValue.toInt());
+}
+
+int HTMLTableCellElement::rowSpan() const
+{
+    const AtomicString& rowSpanValue = fastGetAttribute(rowspanAttr);
+    return max(1, min(rowSpanValue.toInt(), maxRowspan));
+}
+
+int HTMLTableCellElement::cellIndex() const
+{
+    int index = 0;
+    if (!parentElement() || !parentElement()->hasTagName(trTag))
+        return -1;
+
+    for (const Node * node = previousSibling(); node; node = node->previousSibling()) {
+        if (node->hasTagName(tdTag) || node->hasTagName(thTag))
+            index++;
+    }
+    
+    return index;
+}
+
+bool HTMLTableCellElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == nowrapAttr || name == widthAttr || name == heightAttr)
+        return true;
+    return HTMLTablePartElement::isPresentationAttribute(name);
+}
+
+void HTMLTableCellElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == nowrapAttr)
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyWhiteSpace, CSSValueWebkitNowrap);
+    else if (name == widthAttr) {
+        if (!value.isEmpty()) {
+            int widthInt = value.toInt();
+            if (widthInt > 0) // width="0" is ignored for compatibility with WinIE.
+                addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+        }
+    } else if (name == heightAttr) {
+        if (!value.isEmpty()) {
+            int heightInt = value.toInt();
+            if (heightInt > 0) // height="0" is ignored for compatibility with WinIE.
+                addHTMLLengthToStyle(style, CSSPropertyHeight, value);
+        }
+    } else
+        HTMLTablePartElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLTableCellElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == rowspanAttr) {
+        if (renderer() && renderer()->isTableCell())
+            toRenderTableCell(renderer())->colSpanOrRowSpanChanged();
+    } else if (name == colspanAttr) {
+        if (renderer() && renderer()->isTableCell())
+            toRenderTableCell(renderer())->colSpanOrRowSpanChanged();
+    } else
+        HTMLTablePartElement::parseAttribute(name, value);
+}
+
+const StylePropertySet* HTMLTableCellElement::additionalPresentationAttributeStyle()
+{
+    if (HTMLTableElement* table = findParentTable())
+        return table->additionalCellStyle();
+    return 0;
+}
+
+bool HTMLTableCellElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == backgroundAttr || HTMLTablePartElement::isURLAttribute(attribute);
+}
+
+String HTMLTableCellElement::abbr() const
+{
+    return getAttribute(abbrAttr);
+}
+
+String HTMLTableCellElement::axis() const
+{
+    return getAttribute(axisAttr);
+}
+
+void HTMLTableCellElement::setColSpan(int n)
+{
+    setAttribute(colspanAttr, String::number(n));
+}
+
+String HTMLTableCellElement::headers() const
+{
+    return getAttribute(headersAttr);
+}
+
+void HTMLTableCellElement::setRowSpan(int n)
+{
+    setAttribute(rowspanAttr, String::number(n));
+}
+
+String HTMLTableCellElement::scope() const
+{
+    return getAttribute(scopeAttr);
+}
+
+void HTMLTableCellElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLTablePartElement::addSubresourceAttributeURLs(urls);
+
+    addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr)));
+}
+
+HTMLTableCellElement* HTMLTableCellElement::cellAbove() const
+{
+    RenderObject* cellRenderer = renderer();
+    if (!cellRenderer)
+        return 0;
+    if (!cellRenderer->isTableCell())
+        return 0;
+
+    RenderTableCell* tableCellRenderer = toRenderTableCell(cellRenderer);
+    RenderTableCell* cellAboveRenderer = tableCellRenderer->table()->cellAbove(tableCellRenderer);
+    if (!cellAboveRenderer)
+        return 0;
+
+    return static_cast<HTMLTableCellElement*>(cellAboveRenderer->node());
+}
+
+#ifndef NDEBUG
+
+HTMLTableCellElement* toHTMLTableCellElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(HTMLNames::tdTag) || node->hasTagName(HTMLNames::thTag));
+    return static_cast<HTMLTableCellElement*>(node);
+}
+
+const HTMLTableCellElement* toHTMLTableCellElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(HTMLNames::tdTag) || node->hasTagName(HTMLNames::thTag));
+    return static_cast<const HTMLTableCellElement*>(node);
+}
+
+#endif
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLTableCellElement.h b/Source/core/html/HTMLTableCellElement.h
new file mode 100644
index 0000000..a5bf78c
--- /dev/null
+++ b/Source/core/html/HTMLTableCellElement.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLTableCellElement_h
+#define HTMLTableCellElement_h
+
+#include "core/html/HTMLTablePartElement.h"
+
+namespace WebCore {
+
+class HTMLTableCellElement FINAL : public HTMLTablePartElement {
+public:
+    static PassRefPtr<HTMLTableCellElement> create(const QualifiedName&, Document*);
+
+    int cellIndex() const;
+
+    int colSpan() const;
+    int rowSpan() const;
+
+    void setCellIndex(int);
+
+    String abbr() const;
+    String axis() const;
+    void setColSpan(int);
+    String headers() const;
+    void setRowSpan(int);
+    String scope() const;
+
+    HTMLTableCellElement* cellAbove() const;
+
+private:
+    HTMLTableCellElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+    virtual const StylePropertySet* additionalPresentationAttributeStyle() OVERRIDE;
+
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+};
+
+HTMLTableCellElement* toHTMLTableCellElement(Node* node);
+const HTMLTableCellElement* toHTMLTableCellElement(const Node* node);
+
+// This will catch anyone doing an unnecessary cast.
+void toHTMLTableCellElement(const HTMLTableCellElement*);
+
+#ifdef NDEBUG
+
+// The debug versions of these, with assertions, are not inlined.
+
+inline HTMLTableCellElement* toHTMLTableCellElement(Node* node)
+{
+    return static_cast<HTMLTableCellElement*>(node);
+}
+
+inline const HTMLTableCellElement* toHTMLTableCellElement(const Node* node)
+{
+    return static_cast<const HTMLTableCellElement*>(node);
+}
+#endif
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLTableCellElement.idl b/Source/core/html/HTMLTableCellElement.idl
new file mode 100644
index 0000000..3b949f3
--- /dev/null
+++ b/Source/core/html/HTMLTableCellElement.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLTableCellElement : HTMLElement {
+    readonly attribute long cellIndex;
+    [Reflect] attribute DOMString abbr;
+    [Reflect] attribute DOMString align;
+    [Reflect] attribute DOMString axis;
+    [Reflect] attribute DOMString bgColor;
+    [Reflect=char] attribute DOMString ch;
+    [Reflect=charoff] attribute DOMString chOff;
+    attribute long colSpan;
+    [Reflect] attribute DOMString headers;
+    [Reflect] attribute DOMString height;
+    [Reflect] attribute boolean noWrap;
+    attribute long rowSpan;
+    [Reflect] attribute DOMString scope;
+    [Reflect] attribute DOMString vAlign;
+    [Reflect] attribute DOMString width;
+};
+
diff --git a/Source/core/html/HTMLTableColElement.cpp b/Source/core/html/HTMLTableColElement.cpp
new file mode 100644
index 0000000..978ec17
--- /dev/null
+++ b/Source/core/html/HTMLTableColElement.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLTableColElement.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLTableElement.h"
+#include "core/rendering/RenderTableCol.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLTableColElement::HTMLTableColElement(const QualifiedName& tagName, Document* document)
+    : HTMLTablePartElement(tagName, document)
+    , m_span(1)
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLTableColElement> HTMLTableColElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLTableColElement(tagName, document));
+}
+
+bool HTMLTableColElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == widthAttr)
+        return true;
+    return HTMLTablePartElement::isPresentationAttribute(name);
+}
+
+void HTMLTableColElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == widthAttr)
+        addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+    else
+        HTMLTablePartElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLTableColElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == spanAttr) {
+        m_span = !value.isNull() ? value.toInt() : 1;
+        if (renderer() && renderer()->isRenderTableCol())
+            renderer()->updateFromElement();
+    } else if (name == widthAttr) {
+        if (!value.isEmpty()) {
+            if (renderer() && renderer()->isRenderTableCol()) {
+                RenderTableCol* col = toRenderTableCol(renderer());
+                int newWidth = width().toInt();
+                if (newWidth != col->width())
+                    col->setNeedsLayoutAndPrefWidthsRecalc();
+            }
+        }
+    } else
+        HTMLTablePartElement::parseAttribute(name, value);
+}
+
+const StylePropertySet* HTMLTableColElement::additionalPresentationAttributeStyle()
+{
+    if (!hasLocalName(colgroupTag))
+        return 0;
+    if (HTMLTableElement* table = findParentTable())
+        return table->additionalGroupStyle(false);
+    return 0;
+}
+
+void HTMLTableColElement::setSpan(int n)
+{
+    setAttribute(spanAttr, String::number(n));
+}
+
+String HTMLTableColElement::width() const
+{
+    return getAttribute(widthAttr);
+}
+
+}
diff --git a/Source/core/html/HTMLTableColElement.h b/Source/core/html/HTMLTableColElement.h
new file mode 100644
index 0000000..e6fba43
--- /dev/null
+++ b/Source/core/html/HTMLTableColElement.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLTableColElement_h
+#define HTMLTableColElement_h
+
+#include "core/html/HTMLTablePartElement.h"
+
+namespace WebCore {
+
+class HTMLTableColElement FINAL : public HTMLTablePartElement {
+public:
+    static PassRefPtr<HTMLTableColElement> create(const QualifiedName& tagName, Document*);
+
+    int span() const { return m_span; }
+    void setSpan(int);
+
+    String width() const;
+
+private:
+    HTMLTableColElement(const QualifiedName& tagName, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+    virtual const StylePropertySet* additionalPresentationAttributeStyle() OVERRIDE;
+
+    int m_span;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLTableColElement.idl b/Source/core/html/HTMLTableColElement.idl
new file mode 100644
index 0000000..725e05d
--- /dev/null
+++ b/Source/core/html/HTMLTableColElement.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLTableColElement : HTMLElement {
+    [Reflect] attribute DOMString align;
+    [Reflect=char] attribute DOMString ch;
+    [Reflect=charoff] attribute DOMString chOff;
+    attribute long span;
+    [Reflect] attribute DOMString vAlign;
+    [Reflect] attribute DOMString width;
+};
+
diff --git a/Source/core/html/HTMLTableElement.cpp b/Source/core/html/HTMLTableElement.cpp
new file mode 100644
index 0000000..8d38489
--- /dev/null
+++ b/Source/core/html/HTMLTableElement.cpp
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2010, 2011 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLTableElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/css/CSSImageValue.h"
+#include "core/css/CSSStyleSheet.h"
+#include "core/css/CSSValuePool.h"
+#include "core/css/StylePropertySet.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLTableCaptionElement.h"
+#include "core/html/HTMLTableRowElement.h"
+#include "core/html/HTMLTableRowsCollection.h"
+#include "core/html/HTMLTableSectionElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/rendering/RenderTable.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLTableElement::HTMLTableElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_borderAttr(false)
+    , m_borderColorAttr(false)
+    , m_frameAttr(false)
+    , m_rulesAttr(UnsetRules)
+    , m_padding(1)
+{
+    ASSERT(hasTagName(tableTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLTableElement> HTMLTableElement::create(Document* document)
+{
+    return adoptRef(new HTMLTableElement(tableTag, document));
+}
+
+PassRefPtr<HTMLTableElement> HTMLTableElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLTableElement(tagName, document));
+}
+
+HTMLTableCaptionElement* HTMLTableElement::caption() const
+{
+    for (Node* child = firstChild(); child; child = child->nextSibling()) {
+        if (child->hasTagName(captionTag))
+            return static_cast<HTMLTableCaptionElement*>(child);
+    }
+    return 0;
+}
+
+void HTMLTableElement::setCaption(PassRefPtr<HTMLTableCaptionElement> newCaption, ExceptionCode& ec)
+{
+    deleteCaption();
+    insertBefore(newCaption, firstChild(), ec);
+}
+
+HTMLTableSectionElement* HTMLTableElement::tHead() const
+{
+    for (Node* child = firstChild(); child; child = child->nextSibling()) {
+        if (child->hasTagName(theadTag))
+            return static_cast<HTMLTableSectionElement*>(child);
+    }
+    return 0;
+}
+
+void HTMLTableElement::setTHead(PassRefPtr<HTMLTableSectionElement> newHead, ExceptionCode& ec)
+{
+    deleteTHead();
+
+    Node* child;
+    for (child = firstChild(); child; child = child->nextSibling())
+        if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag))
+            break;
+
+    insertBefore(newHead, child, ec);
+}
+
+HTMLTableSectionElement* HTMLTableElement::tFoot() const
+{
+    for (Node* child = firstChild(); child; child = child->nextSibling()) {
+        if (child->hasTagName(tfootTag))
+            return static_cast<HTMLTableSectionElement*>(child);
+    }
+    return 0;
+}
+
+void HTMLTableElement::setTFoot(PassRefPtr<HTMLTableSectionElement> newFoot, ExceptionCode& ec)
+{
+    deleteTFoot();
+
+    Node* child;
+    for (child = firstChild(); child; child = child->nextSibling())
+        if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag) && !child->hasTagName(theadTag))
+            break;
+
+    insertBefore(newFoot, child, ec);
+}
+
+PassRefPtr<HTMLElement> HTMLTableElement::createTHead()
+{
+    if (HTMLTableSectionElement* existingHead = tHead())
+        return existingHead;
+    RefPtr<HTMLTableSectionElement> head = HTMLTableSectionElement::create(theadTag, document());
+    setTHead(head, IGNORE_EXCEPTION);
+    return head.release();
+}
+
+void HTMLTableElement::deleteTHead()
+{
+    removeChild(tHead(), IGNORE_EXCEPTION);
+}
+
+PassRefPtr<HTMLElement> HTMLTableElement::createTFoot()
+{
+    if (HTMLTableSectionElement* existingFoot = tFoot())
+        return existingFoot;
+    RefPtr<HTMLTableSectionElement> foot = HTMLTableSectionElement::create(tfootTag, document());
+    setTFoot(foot, IGNORE_EXCEPTION);
+    return foot.release();
+}
+
+void HTMLTableElement::deleteTFoot()
+{
+    removeChild(tFoot(), IGNORE_EXCEPTION);
+}
+
+PassRefPtr<HTMLElement> HTMLTableElement::createTBody()
+{
+    RefPtr<HTMLTableSectionElement> body = HTMLTableSectionElement::create(tbodyTag, document());
+    Node* referenceElement = lastBody() ? lastBody()->nextSibling() : 0;
+    insertBefore(body, referenceElement, ASSERT_NO_EXCEPTION);
+    return body.release();
+}
+
+PassRefPtr<HTMLElement> HTMLTableElement::createCaption()
+{
+    if (HTMLTableCaptionElement* existingCaption = caption())
+        return existingCaption;
+    RefPtr<HTMLTableCaptionElement> caption = HTMLTableCaptionElement::create(captionTag, document());
+    setCaption(caption, IGNORE_EXCEPTION);
+    return caption.release();
+}
+
+void HTMLTableElement::deleteCaption()
+{
+    removeChild(caption(), IGNORE_EXCEPTION);
+}
+
+HTMLTableSectionElement* HTMLTableElement::lastBody() const
+{
+    for (Node* child = lastChild(); child; child = child->previousSibling()) {
+        if (child->hasTagName(tbodyTag))
+            return static_cast<HTMLTableSectionElement*>(child);
+    }
+    return 0;
+}
+
+PassRefPtr<HTMLElement> HTMLTableElement::insertRow(int index, ExceptionCode& ec)
+{
+    if (index < -1) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }
+
+    RefPtr<Node> protectFromMutationEvents(this);
+
+    RefPtr<HTMLTableRowElement> lastRow = 0;
+    RefPtr<HTMLTableRowElement> row = 0;
+    if (index == -1)
+        lastRow = HTMLTableRowsCollection::lastRow(this);
+    else {
+        for (int i = 0; i <= index; ++i) {
+            row = HTMLTableRowsCollection::rowAfter(this, lastRow.get());
+            if (!row) {
+                if (i != index) {
+                    ec = INDEX_SIZE_ERR;
+                    return 0;
+                }
+                break;
+            }
+            lastRow = row;
+        }
+    }
+
+    RefPtr<ContainerNode> parent;
+    if (lastRow)
+        parent = row ? row->parentNode() : lastRow->parentNode();
+    else {
+        parent = lastBody();
+        if (!parent) {
+            RefPtr<HTMLTableSectionElement> newBody = HTMLTableSectionElement::create(tbodyTag, document());
+            RefPtr<HTMLTableRowElement> newRow = HTMLTableRowElement::create(document());
+            newBody->appendChild(newRow, ec);
+            appendChild(newBody.release(), ec);
+            return newRow.release();
+        }
+    }
+
+    RefPtr<HTMLTableRowElement> newRow = HTMLTableRowElement::create(document());
+    parent->insertBefore(newRow, row.get(), ec);
+    return newRow.release();
+}
+
+void HTMLTableElement::deleteRow(int index, ExceptionCode& ec)
+{
+    HTMLTableRowElement* row = 0;
+    if (index == -1)
+        row = HTMLTableRowsCollection::lastRow(this);
+    else {
+        for (int i = 0; i <= index; ++i) {
+            row = HTMLTableRowsCollection::rowAfter(this, row);
+            if (!row)
+                break;
+        }
+    }
+    if (!row) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+    row->remove(ec);
+}
+
+static inline bool isTableCellAncestor(Node* n)
+{
+    return n->hasTagName(theadTag) || n->hasTagName(tbodyTag) ||
+           n->hasTagName(tfootTag) || n->hasTagName(trTag) ||
+           n->hasTagName(thTag);
+}
+
+static bool setTableCellsChanged(Node* n)
+{
+    ASSERT(n);
+    bool cellChanged = false;
+
+    if (n->hasTagName(tdTag))
+        cellChanged = true;
+    else if (isTableCellAncestor(n)) {
+        for (Node* child = n->firstChild(); child; child = child->nextSibling())
+            cellChanged |= setTableCellsChanged(child);
+    }
+
+    if (cellChanged)
+       n->setNeedsStyleRecalc();
+
+    return cellChanged;
+}
+
+static bool getBordersFromFrameAttributeValue(const AtomicString& value, bool& borderTop, bool& borderRight, bool& borderBottom, bool& borderLeft)
+{
+    borderTop = false;
+    borderRight = false;
+    borderBottom = false;
+    borderLeft = false;
+
+    if (equalIgnoringCase(value, "above"))
+        borderTop = true;
+    else if (equalIgnoringCase(value, "below"))
+        borderBottom = true;
+    else if (equalIgnoringCase(value, "hsides"))
+        borderTop = borderBottom = true;
+    else if (equalIgnoringCase(value, "vsides"))
+        borderLeft = borderRight = true;
+    else if (equalIgnoringCase(value, "lhs"))
+        borderLeft = true;
+    else if (equalIgnoringCase(value, "rhs"))
+        borderRight = true;
+    else if (equalIgnoringCase(value, "box") || equalIgnoringCase(value, "border"))
+        borderTop = borderBottom = borderLeft = borderRight = true;
+    else if (!equalIgnoringCase(value, "void"))
+        return false;
+    return true;
+}
+
+void HTMLTableElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == widthAttr)
+        addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+    else if (name == heightAttr)
+        addHTMLLengthToStyle(style, CSSPropertyHeight, value);
+    else if (name == borderAttr) 
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderWidth, parseBorderWidthAttribute(value), CSSPrimitiveValue::CSS_PX);
+    else if (name == bordercolorAttr) {
+        if (!value.isEmpty())
+            addHTMLColorToStyle(style, CSSPropertyBorderColor, value);
+    } else if (name == bgcolorAttr)
+        addHTMLColorToStyle(style, CSSPropertyBackgroundColor, value);
+    else if (name == backgroundAttr) {
+        String url = stripLeadingAndTrailingHTMLSpaces(value);
+        if (!url.isEmpty())
+            style->setProperty(CSSProperty(CSSPropertyBackgroundImage, CSSImageValue::create(document()->completeURL(url).string())));
+    } else if (name == valignAttr) {
+        if (!value.isEmpty())
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, value);
+    } else if (name == cellspacingAttr) {
+        if (!value.isEmpty())
+            addHTMLLengthToStyle(style, CSSPropertyBorderSpacing, value);
+    } else if (name == vspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
+    } else if (name == hspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
+        addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
+    } else if (name == alignAttr) {
+        if (!value.isEmpty()) {
+            if (equalIgnoringCase(value, "center")) {
+                addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitMarginStart, CSSValueAuto);
+                addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitMarginEnd, CSSValueAuto);
+            } else
+                addPropertyToPresentationAttributeStyle(style, CSSPropertyFloat, value);
+        }
+    } else if (name == rulesAttr) {
+        // The presence of a valid rules attribute causes border collapsing to be enabled.
+        if (m_rulesAttr != UnsetRules)
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderCollapse, CSSValueCollapse);
+    } else if (name == frameAttr) {
+        bool borderTop;
+        bool borderRight;
+        bool borderBottom;
+        bool borderLeft;
+        if (getBordersFromFrameAttributeValue(value, borderTop, borderRight, borderBottom, borderLeft)) {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderWidth, CSSValueThin);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderTopStyle, borderTop ? CSSValueSolid : CSSValueHidden);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderBottomStyle, borderBottom ? CSSValueSolid : CSSValueHidden);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderLeftStyle, borderLeft ? CSSValueSolid : CSSValueHidden);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderRightStyle, borderRight ? CSSValueSolid : CSSValueHidden);
+        }
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+bool HTMLTableElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == widthAttr || name == heightAttr || name == bgcolorAttr || name == backgroundAttr || name == valignAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == cellspacingAttr || name == borderAttr || name == bordercolorAttr || name == frameAttr || name == rulesAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLTableElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    CellBorders bordersBefore = cellBorders();
+    unsigned short oldPadding = m_padding;
+
+    if (name == borderAttr)  {
+        // FIXME: This attribute is a mess.
+        m_borderAttr = parseBorderWidthAttribute(value);
+    } else if (name == bordercolorAttr) {
+        m_borderColorAttr = !value.isEmpty();
+    } else if (name == frameAttr) {
+        // FIXME: This attribute is a mess.
+        bool borderTop;
+        bool borderRight;
+        bool borderBottom;
+        bool borderLeft;
+        m_frameAttr = getBordersFromFrameAttributeValue(value, borderTop, borderRight, borderBottom, borderLeft);
+    } else if (name == rulesAttr) {
+        m_rulesAttr = UnsetRules;
+        if (equalIgnoringCase(value, "none"))
+            m_rulesAttr = NoneRules;
+        else if (equalIgnoringCase(value, "groups"))
+            m_rulesAttr = GroupsRules;
+        else if (equalIgnoringCase(value, "rows"))
+            m_rulesAttr = RowsRules;
+        else if (equalIgnoringCase(value, "cols"))
+            m_rulesAttr = ColsRules;
+        else if (equalIgnoringCase(value, "all"))
+            m_rulesAttr = AllRules;
+    } else if (name == cellpaddingAttr) {
+        if (!value.isEmpty())
+            m_padding = max(0, value.toInt());
+        else
+            m_padding = 1;
+    } else if (name == colsAttr) {
+        // ###
+    } else
+        HTMLElement::parseAttribute(name, value);
+
+    if (bordersBefore != cellBorders() || oldPadding != m_padding) {
+        m_sharedCellStyle = 0;
+        bool cellChanged = false;
+        for (Node* child = firstChild(); child; child = child->nextSibling())
+            cellChanged |= setTableCellsChanged(child);
+        if (cellChanged)
+            setNeedsStyleRecalc();
+    }
+}
+
+static StylePropertySet* leakBorderStyle(int value)
+{
+    RefPtr<StylePropertySet> style = StylePropertySet::create();
+    style->setProperty(CSSPropertyBorderTopStyle, value);
+    style->setProperty(CSSPropertyBorderBottomStyle, value);
+    style->setProperty(CSSPropertyBorderLeftStyle, value);
+    style->setProperty(CSSPropertyBorderRightStyle, value);
+    return style.release().leakRef();
+}
+
+const StylePropertySet* HTMLTableElement::additionalPresentationAttributeStyle()
+{
+    if (m_frameAttr)
+        return 0;
+    
+    if (!m_borderAttr && !m_borderColorAttr) {
+        // Setting the border to 'hidden' allows it to win over any border
+        // set on the table's cells during border-conflict resolution.
+        if (m_rulesAttr != UnsetRules) {
+            static StylePropertySet* solidBorderStyle = leakBorderStyle(CSSValueHidden);
+            return solidBorderStyle;
+        }
+        return 0;
+    }
+
+    if (m_borderColorAttr) {
+        static StylePropertySet* solidBorderStyle = leakBorderStyle(CSSValueSolid);
+        return solidBorderStyle;
+    }
+    static StylePropertySet* outsetBorderStyle = leakBorderStyle(CSSValueOutset);
+    return outsetBorderStyle;
+}
+
+HTMLTableElement::CellBorders HTMLTableElement::cellBorders() const
+{
+    switch (m_rulesAttr) {
+        case NoneRules:
+        case GroupsRules:
+            return NoBorders;
+        case AllRules:
+            return SolidBorders;
+        case ColsRules:
+            return SolidBordersColsOnly;
+        case RowsRules:
+            return SolidBordersRowsOnly;
+        case UnsetRules:
+            if (!m_borderAttr)
+                return NoBorders;
+            if (m_borderColorAttr)
+                return SolidBorders;
+            return InsetBorders;
+    }
+    ASSERT_NOT_REACHED();
+    return NoBorders;
+}
+
+PassRefPtr<StylePropertySet> HTMLTableElement::createSharedCellStyle()
+{
+    RefPtr<StylePropertySet> style = StylePropertySet::create();
+
+    switch (cellBorders()) {
+    case SolidBordersColsOnly:
+        style->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderRightWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
+        break;
+    case SolidBordersRowsOnly:
+        style->setProperty(CSSPropertyBorderTopWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
+        break;
+    case SolidBorders:
+        style->setProperty(CSSPropertyBorderWidth, cssValuePool().createValue(1, CSSPrimitiveValue::CSS_PX));
+        style->setProperty(CSSPropertyBorderStyle, cssValuePool().createIdentifierValue(CSSValueSolid));
+        style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
+        break;
+    case InsetBorders:
+        style->setProperty(CSSPropertyBorderWidth, cssValuePool().createValue(1, CSSPrimitiveValue::CSS_PX));
+        style->setProperty(CSSPropertyBorderStyle, cssValuePool().createIdentifierValue(CSSValueInset));
+        style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
+        break;
+    case NoBorders:
+        // If 'rules=none' then allow any borders set at cell level to take effect. 
+        break;
+    }
+
+    if (m_padding)
+        style->setProperty(CSSPropertyPadding, cssValuePool().createValue(m_padding, CSSPrimitiveValue::CSS_PX));
+
+    return style.release();
+}
+
+const StylePropertySet* HTMLTableElement::additionalCellStyle()
+{
+    if (!m_sharedCellStyle)
+        m_sharedCellStyle = createSharedCellStyle();
+    return m_sharedCellStyle.get();
+}
+
+static StylePropertySet* leakGroupBorderStyle(int rows)
+{
+    RefPtr<StylePropertySet> style = StylePropertySet::create();
+    if (rows) {
+        style->setProperty(CSSPropertyBorderTopWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid);
+    } else {
+        style->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderRightWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid);
+    }
+    return style.release().leakRef();
+}
+
+const StylePropertySet* HTMLTableElement::additionalGroupStyle(bool rows)
+{
+    if (m_rulesAttr != GroupsRules)
+        return 0;
+
+    if (rows) {
+        static StylePropertySet* rowBorderStyle = leakGroupBorderStyle(true);
+        return rowBorderStyle;
+    }
+    static StylePropertySet* columnBorderStyle = leakGroupBorderStyle(false);
+    return columnBorderStyle;
+}
+
+bool HTMLTableElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == backgroundAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+PassRefPtr<HTMLCollection> HTMLTableElement::rows()
+{
+    return ensureCachedHTMLCollection(TableRows);
+}
+
+PassRefPtr<HTMLCollection> HTMLTableElement::tBodies()
+{
+    return ensureCachedHTMLCollection(TableTBodies);
+}
+
+String HTMLTableElement::rules() const
+{
+    return getAttribute(rulesAttr);
+}
+
+String HTMLTableElement::summary() const
+{
+    return getAttribute(summaryAttr);
+}
+
+void HTMLTableElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
+{
+    HTMLElement::addSubresourceAttributeURLs(urls);
+
+    addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr)));
+}
+
+}
diff --git a/Source/core/html/HTMLTableElement.h b/Source/core/html/HTMLTableElement.h
new file mode 100644
index 0000000..73fee6b
--- /dev/null
+++ b/Source/core/html/HTMLTableElement.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLTableElement_h
+#define HTMLTableElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLCollection;
+class HTMLTableCaptionElement;
+class HTMLTableRowsCollection;
+class HTMLTableSectionElement;
+
+class HTMLTableElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLTableElement> create(Document*);
+    static PassRefPtr<HTMLTableElement> create(const QualifiedName&, Document*);
+
+    HTMLTableCaptionElement* caption() const;
+    void setCaption(PassRefPtr<HTMLTableCaptionElement>, ExceptionCode&);
+
+    HTMLTableSectionElement* tHead() const;
+    void setTHead(PassRefPtr<HTMLTableSectionElement>, ExceptionCode&);
+
+    HTMLTableSectionElement* tFoot() const;
+    void setTFoot(PassRefPtr<HTMLTableSectionElement>, ExceptionCode&);
+
+    PassRefPtr<HTMLElement> createTHead();
+    void deleteTHead();
+    PassRefPtr<HTMLElement> createTFoot();
+    void deleteTFoot();
+    PassRefPtr<HTMLElement> createTBody();
+    PassRefPtr<HTMLElement> createCaption();
+    void deleteCaption();
+    PassRefPtr<HTMLElement> insertRow(int index, ExceptionCode&);
+    void deleteRow(int index, ExceptionCode&);
+
+    PassRefPtr<HTMLCollection> rows();
+    PassRefPtr<HTMLCollection> tBodies();
+
+    String rules() const;
+    String summary() const;
+
+    const StylePropertySet* additionalCellStyle();
+    const StylePropertySet* additionalGroupStyle(bool rows);
+
+private:
+    HTMLTableElement(const QualifiedName&, Document*);
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+    // Used to obtain either a solid or outset border decl and to deal with the frame and rules attributes.
+    virtual const StylePropertySet* additionalPresentationAttributeStyle() OVERRIDE;
+
+    virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+
+    enum TableRules { UnsetRules, NoneRules, GroupsRules, RowsRules, ColsRules, AllRules };
+    enum CellBorders { NoBorders, SolidBorders, InsetBorders, SolidBordersColsOnly, SolidBordersRowsOnly };
+
+    CellBorders cellBorders() const;
+
+    PassRefPtr<StylePropertySet> createSharedCellStyle();
+
+    HTMLTableSectionElement* lastBody() const;
+
+    bool m_borderAttr;          // Sets a precise border width and creates an outset border for the table and for its cells.
+    bool m_borderColorAttr;     // Overrides the outset border and makes it solid for the table and cells instead.
+    bool m_frameAttr;           // Implies a thin border width if no border is set and then a certain set of solid/hidden borders based off the value.
+    TableRules m_rulesAttr;     // Implies a thin border width, a collapsing border model, and all borders on the table becoming set to hidden (if frame/border
+                                // are present, to none otherwise).
+
+    unsigned short m_padding;
+    RefPtr<StylePropertySet> m_sharedCellStyle;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLTableElement.idl b/Source/core/html/HTMLTableElement.idl
new file mode 100644
index 0000000..1881de3
--- /dev/null
+++ b/Source/core/html/HTMLTableElement.idl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLTableElement : HTMLElement {
+    [SetterRaisesException] attribute HTMLTableCaptionElement caption;
+    [SetterRaisesException] attribute HTMLTableSectionElement tHead;
+    [SetterRaisesException] attribute HTMLTableSectionElement tFoot;
+
+    readonly attribute HTMLCollection rows;
+    readonly attribute HTMLCollection tBodies;
+    [Reflect] attribute DOMString align;
+    [Reflect] attribute DOMString bgColor;
+    [Reflect] attribute DOMString border;
+    [Reflect] attribute DOMString cellPadding;
+    [Reflect] attribute DOMString cellSpacing;
+
+    [Reflect] attribute DOMString frame;
+
+    [Reflect] attribute DOMString rules;
+    [Reflect] attribute DOMString summary;
+    [Reflect] attribute DOMString width;
+
+    HTMLElement createTHead();
+    void deleteTHead();
+    HTMLElement createTFoot();
+    void deleteTFoot();
+    HTMLElement createTBody();
+    HTMLElement createCaption();
+    void deleteCaption();
+
+    [RaisesException] HTMLElement insertRow([Default=Undefined] optional long index);
+    [RaisesException] void deleteRow([Default=Undefined] optional long index);
+};
+
diff --git a/Source/core/html/HTMLTablePartElement.cpp b/Source/core/html/HTMLTablePartElement.cpp
new file mode 100644
index 0000000..2b8fbe0
--- /dev/null
+++ b/Source/core/html/HTMLTablePartElement.cpp
@@ -0,0 +1,94 @@
+/**
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLTablePartElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/css/CSSImageValue.h"
+#include "core/css/StylePropertySet.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/html/HTMLTableElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+bool HTMLTablePartElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == bgcolorAttr || name == backgroundAttr || name == valignAttr || name == alignAttr || name == heightAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLTablePartElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == bgcolorAttr)
+        addHTMLColorToStyle(style, CSSPropertyBackgroundColor, value);
+    else if (name == backgroundAttr) {
+        String url = stripLeadingAndTrailingHTMLSpaces(value);
+        if (!url.isEmpty())
+            style->setProperty(CSSProperty(CSSPropertyBackgroundImage, CSSImageValue::create(document()->completeURL(url).string())));
+    } else if (name == valignAttr) {
+        if (equalIgnoringCase(value, "top"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, CSSValueTop);
+        else if (equalIgnoringCase(value, "middle"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, CSSValueMiddle);
+        else if (equalIgnoringCase(value, "bottom"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, CSSValueBottom);
+        else if (equalIgnoringCase(value, "baseline"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, CSSValueBaseline);
+        else
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, value);
+    } else if (name == alignAttr) {
+        if (equalIgnoringCase(value, "middle") || equalIgnoringCase(value, "center"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueWebkitCenter);
+        else if (equalIgnoringCase(value, "absmiddle"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueCenter);
+        else if (equalIgnoringCase(value, "left"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueWebkitLeft);
+        else if (equalIgnoringCase(value, "right"))
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, CSSValueWebkitRight);
+        else
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyTextAlign, value);
+    } else if (name == heightAttr) {
+        if (!value.isEmpty())
+            addHTMLLengthToStyle(style, CSSPropertyHeight, value);
+    } else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+HTMLTableElement* HTMLTablePartElement::findParentTable() const
+{
+    ContainerNode* parent = parentNode();
+    while (parent && !parent->hasTagName(tableTag))
+        parent = parent->parentNode();
+    return static_cast<HTMLTableElement*>(parent);
+}
+
+}
diff --git a/Source/core/html/HTMLTablePartElement.h b/Source/core/html/HTMLTablePartElement.h
new file mode 100644
index 0000000..974228a
--- /dev/null
+++ b/Source/core/html/HTMLTablePartElement.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLTablePartElement_h
+#define HTMLTablePartElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLTableElement;
+
+class HTMLTablePartElement : public HTMLElement {
+protected:
+    HTMLTablePartElement(const QualifiedName& tagName, Document* document)
+        : HTMLElement(tagName, document)
+    {
+    }
+
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+
+    HTMLTableElement* findParentTable() const;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLTableRowElement.cpp b/Source/core/html/HTMLTableRowElement.cpp
new file mode 100644
index 0000000..80466fd
--- /dev/null
+++ b/Source/core/html/HTMLTableRowElement.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLTableRowElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLCollection.h"
+#include "core/html/HTMLTableCellElement.h"
+#include "core/html/HTMLTableElement.h"
+#include "core/html/HTMLTableSectionElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLTableRowElement::HTMLTableRowElement(const QualifiedName& tagName, Document* document)
+    : HTMLTablePartElement(tagName, document)
+{
+    ASSERT(hasTagName(trTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLTableRowElement> HTMLTableRowElement::create(Document* document)
+{
+    return adoptRef(new HTMLTableRowElement(trTag, document));
+}
+
+PassRefPtr<HTMLTableRowElement> HTMLTableRowElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLTableRowElement(tagName, document));
+}
+
+int HTMLTableRowElement::rowIndex() const
+{
+    ContainerNode* table = parentNode();
+    if (!table)
+        return -1;
+    table = table->parentNode();
+    if (!table || !table->hasTagName(tableTag))
+        return -1;
+
+    // To match Firefox, the row indices work like this:
+    //   Rows from the first <thead> are numbered before all <tbody> rows.
+    //   Rows from the first <tfoot> are numbered after all <tbody> rows.
+    //   Rows from other <thead> and <tfoot> elements don't get row indices at all.
+
+    int rIndex = 0;
+
+    if (HTMLTableSectionElement* head = static_cast<HTMLTableElement*>(table)->tHead()) {
+        for (Node *row = head->firstChild(); row; row = row->nextSibling()) {
+            if (row == this)
+                return rIndex;
+            if (row->hasTagName(trTag))
+                ++rIndex;
+        }
+    }
+    
+    for (Node *node = table->firstChild(); node; node = node->nextSibling()) {
+        if (node->hasTagName(tbodyTag)) {
+            HTMLTableSectionElement* section = static_cast<HTMLTableSectionElement*>(node);
+            for (Node* row = section->firstChild(); row; row = row->nextSibling()) {
+                if (row == this)
+                    return rIndex;
+                if (row->hasTagName(trTag))
+                    ++rIndex;
+            }
+        }
+    }
+
+    if (HTMLTableSectionElement* foot = static_cast<HTMLTableElement*>(table)->tFoot()) {
+        for (Node *row = foot->firstChild(); row; row = row->nextSibling()) {
+            if (row == this)
+                return rIndex;
+            if (row->hasTagName(trTag))
+                ++rIndex;
+        }
+    }
+
+    // We get here for rows that are in <thead> or <tfoot> sections other than the main header and footer.
+    return -1;
+}
+
+int HTMLTableRowElement::sectionRowIndex() const
+{
+    int rIndex = 0;
+    const Node *n = this;
+    do {
+        n = n->previousSibling();
+        if (n && n->hasTagName(trTag))
+            rIndex++;
+    }
+    while (n);
+
+    return rIndex;
+}
+
+PassRefPtr<HTMLElement> HTMLTableRowElement::insertCell(int index, ExceptionCode& ec)
+{
+    RefPtr<HTMLCollection> children = cells();
+    int numCells = children ? children->length() : 0;
+    if (index < -1 || index > numCells) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }
+
+    RefPtr<HTMLTableCellElement> cell = HTMLTableCellElement::create(tdTag, document());
+    if (index < 0 || index >= numCells)
+        appendChild(cell, ec);
+    else {
+        Node* n;
+        if (index < 1)
+            n = firstChild();
+        else
+            n = children->item(index);
+        insertBefore(cell, n, ec);
+    }
+    return cell.release();
+}
+
+void HTMLTableRowElement::deleteCell(int index, ExceptionCode& ec)
+{
+    RefPtr<HTMLCollection> children = cells();
+    int numCells = children ? children->length() : 0;
+    if (index == -1)
+        index = numCells-1;
+    if (index >= 0 && index < numCells) {
+        RefPtr<Node> cell = children->item(index);
+        HTMLElement::removeChild(cell.get(), ec);
+    } else
+        ec = INDEX_SIZE_ERR;
+}
+
+PassRefPtr<HTMLCollection> HTMLTableRowElement::cells()
+{
+    return ensureCachedHTMLCollection(TRCells);
+}
+
+void HTMLTableRowElement::setCells(HTMLCollection*, ExceptionCode& ec)
+{
+    ec = NO_MODIFICATION_ALLOWED_ERR;
+}
+
+}
diff --git a/Source/core/html/HTMLTableRowElement.h b/Source/core/html/HTMLTableRowElement.h
new file mode 100644
index 0000000..c50725b
--- /dev/null
+++ b/Source/core/html/HTMLTableRowElement.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLTableRowElement_h
+#define HTMLTableRowElement_h
+
+#include "core/html/HTMLTablePartElement.h"
+
+namespace WebCore {
+
+class HTMLTableRowElement FINAL : public HTMLTablePartElement {
+public:
+    static PassRefPtr<HTMLTableRowElement> create(Document*);
+    static PassRefPtr<HTMLTableRowElement> create(const QualifiedName&, Document*);
+
+    int rowIndex() const;
+    void setRowIndex(int);
+
+    int sectionRowIndex() const;
+    void setSectionRowIndex(int);
+
+    PassRefPtr<HTMLElement> insertCell(int index, ExceptionCode&);
+    void deleteCell(int index, ExceptionCode&);
+
+    PassRefPtr<HTMLCollection> cells();
+    void setCells(HTMLCollection *, ExceptionCode&);
+
+private:
+    HTMLTableRowElement(const QualifiedName&, Document*);
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLTableRowElement.idl b/Source/core/html/HTMLTableRowElement.idl
new file mode 100644
index 0000000..a56f70a
--- /dev/null
+++ b/Source/core/html/HTMLTableRowElement.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple Inc. ALl rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLTableRowElement : HTMLElement {
+    readonly attribute long rowIndex;
+    readonly attribute long sectionRowIndex;
+    readonly attribute HTMLCollection cells;
+    [Reflect] attribute DOMString align;
+    [Reflect] attribute DOMString bgColor;
+    [Reflect=char] attribute DOMString ch;
+    [Reflect=charoff] attribute DOMString chOff;
+    [Reflect] attribute DOMString vAlign;
+    [RaisesException] HTMLElement insertCell([Default=Undefined] optional long index);
+    [RaisesException] void deleteCell([Default=Undefined] optional long index);
+};
+
diff --git a/Source/core/html/HTMLTableRowsCollection.cpp b/Source/core/html/HTMLTableRowsCollection.cpp
new file mode 100644
index 0000000..128d3a9
--- /dev/null
+++ b/Source/core/html/HTMLTableRowsCollection.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008, 2011, 2012 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/html/HTMLTableRowsCollection.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLTableElement.h"
+#include "core/html/HTMLTableRowElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static bool isInHead(Element* row)
+{
+    return row->parentNode() && toElement(row->parentNode())->hasLocalName(theadTag);
+}
+
+static bool isInBody(Element* row)
+{
+    return row->parentNode() && toElement(row->parentNode())->hasLocalName(tbodyTag);
+}
+
+static bool isInFoot(Element* row)
+{
+    return row->parentNode() && toElement(row->parentNode())->hasLocalName(tfootTag);
+}
+
+HTMLTableRowElement* HTMLTableRowsCollection::rowAfter(HTMLTableElement* table, HTMLTableRowElement* previous)
+{
+    Node* child = 0;
+
+    // Start by looking for the next row in this section.
+    // Continue only if there is none.
+    if (previous && previous->parentNode() != table) {
+        for (child = previous->nextSibling(); child; child = child->nextSibling()) {
+            if (child->hasTagName(trTag))
+                return static_cast<HTMLTableRowElement*>(child);
+        }
+    }
+
+    // If still looking at head sections, find the first row in the next head section.
+    if (!previous)
+        child = table->firstChild();
+    else if (isInHead(previous))
+        child = previous->parentNode()->nextSibling();
+    for (; child; child = child->nextSibling()) {
+        if (child->hasTagName(theadTag)) {
+            for (Node* grandchild = child->firstChild(); grandchild; grandchild = grandchild->nextSibling()) {
+                if (grandchild->hasTagName(trTag))
+                    return static_cast<HTMLTableRowElement*>(grandchild);
+            }
+        }
+    }
+
+    // If still looking at top level and bodies, find the next row in top level or the first in the next body section.
+    if (!previous || isInHead(previous))
+        child = table->firstChild();
+    else if (previous->parentNode() == table)
+        child = previous->nextSibling();
+    else if (isInBody(previous))
+        child = previous->parentNode()->nextSibling();
+    for (; child; child = child->nextSibling()) {
+        if (child->hasTagName(trTag))
+            return static_cast<HTMLTableRowElement*>(child);
+        if (child->hasTagName(tbodyTag)) {
+            for (Node* grandchild = child->firstChild(); grandchild; grandchild = grandchild->nextSibling()) {
+                if (grandchild->hasTagName(trTag))
+                    return static_cast<HTMLTableRowElement*>(grandchild);
+            }
+        }
+    }
+
+    // Find the first row in the next foot section.
+    if (!previous || !isInFoot(previous))
+        child = table->firstChild();
+    else
+        child = previous->parentNode()->nextSibling();
+    for (; child; child = child->nextSibling()) {
+        if (child->hasTagName(tfootTag)) {
+            for (Node* grandchild = child->firstChild(); grandchild; grandchild = grandchild->nextSibling()) {
+                if (grandchild->hasTagName(trTag))
+                    return static_cast<HTMLTableRowElement*>(grandchild);
+            }
+        }
+    }
+
+    return 0;
+}
+
+HTMLTableRowElement* HTMLTableRowsCollection::lastRow(HTMLTableElement* table)
+{
+    for (Node* child = table->lastChild(); child; child = child->previousSibling()) {
+        if (child->hasTagName(tfootTag)) {
+            for (Node* grandchild = child->lastChild(); grandchild; grandchild = grandchild->previousSibling()) {
+                if (grandchild->hasTagName(trTag))
+                    return static_cast<HTMLTableRowElement*>(grandchild);
+            }
+        }
+    }
+
+    for (Node* child = table->lastChild(); child; child = child->previousSibling()) {
+        if (child->hasTagName(trTag))
+            return static_cast<HTMLTableRowElement*>(child);
+        if (child->hasTagName(tbodyTag)) {
+            for (Node* grandchild = child->lastChild(); grandchild; grandchild = grandchild->previousSibling()) {
+                if (grandchild->hasTagName(trTag))
+                    return static_cast<HTMLTableRowElement*>(grandchild);
+            }
+        }
+    }
+
+    for (Node* child = table->lastChild(); child; child = child->previousSibling()) {
+        if (child->hasTagName(theadTag)) {
+            for (Node* grandchild = child->lastChild(); grandchild; grandchild = grandchild->previousSibling()) {
+                if (grandchild->hasTagName(trTag))
+                    return static_cast<HTMLTableRowElement*>(grandchild);
+            }
+        }
+    }
+
+    return 0;
+}
+
+// Must call get() on the table in case that argument is compiled before dereferencing the
+// table to get at the collection cache. Order of argument evaluation is undefined and can
+// differ between compilers.
+HTMLTableRowsCollection::HTMLTableRowsCollection(Node* table)
+    : HTMLCollection(table, TableRows, OverridesItemAfter)
+{
+    ASSERT(table->hasTagName(tableTag));
+}
+
+PassRefPtr<HTMLTableRowsCollection> HTMLTableRowsCollection::create(Node* table, CollectionType)
+{
+    return adoptRef(new HTMLTableRowsCollection(table));
+}
+
+Element* HTMLTableRowsCollection::virtualItemAfter(unsigned& offsetInArray, Element* previous) const
+{
+    ASSERT_UNUSED(offsetInArray, !offsetInArray);
+    ASSERT(!previous || (previous->isHTMLElement() && toHTMLElement(previous)->hasLocalName(trTag)));
+    return rowAfter(static_cast<HTMLTableElement*>(ownerNode()), static_cast<HTMLTableRowElement*>(previous));
+}
+
+}
diff --git a/Source/core/html/HTMLTableRowsCollection.h b/Source/core/html/HTMLTableRowsCollection.h
new file mode 100644
index 0000000..e92500e
--- /dev/null
+++ b/Source/core/html/HTMLTableRowsCollection.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 HTMLTableRowsCollection_h
+#define HTMLTableRowsCollection_h
+
+#include "core/html/HTMLCollection.h"
+
+namespace WebCore {
+
+class HTMLTableElement;
+class HTMLTableRowElement;
+
+class HTMLTableRowsCollection : public HTMLCollection {
+public:
+    static PassRefPtr<HTMLTableRowsCollection> create(Node*, CollectionType);
+
+    static HTMLTableRowElement* rowAfter(HTMLTableElement*, HTMLTableRowElement*);
+    static HTMLTableRowElement* lastRow(HTMLTableElement*);
+
+private:
+    HTMLTableRowsCollection(Node*);
+
+    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLTableSectionElement.cpp b/Source/core/html/HTMLTableSectionElement.cpp
new file mode 100644
index 0000000..c1a8899
--- /dev/null
+++ b/Source/core/html/HTMLTableSectionElement.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLTableSectionElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLCollection.h"
+#include "core/html/HTMLTableElement.h"
+#include "core/html/HTMLTableRowElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLTableSectionElement::HTMLTableSectionElement(const QualifiedName& tagName, Document* document)
+    : HTMLTablePartElement(tagName, document)
+{
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLTableSectionElement> HTMLTableSectionElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLTableSectionElement(tagName, document));
+}
+
+const StylePropertySet* HTMLTableSectionElement::additionalPresentationAttributeStyle()
+{
+    if (HTMLTableElement* table = findParentTable())
+        return table->additionalGroupStyle(true);
+    return 0;
+}
+
+// these functions are rather slow, since we need to get the row at
+// the index... but they aren't used during usual HTML parsing anyway
+PassRefPtr<HTMLElement> HTMLTableSectionElement::insertRow(int index, ExceptionCode& ec)
+{
+    RefPtr<HTMLTableRowElement> row;
+    RefPtr<HTMLCollection> children = rows();
+    int numRows = children ? (int)children->length() : 0;
+    if (index < -1 || index > numRows)
+        ec = INDEX_SIZE_ERR; // per the DOM
+    else {
+        row = HTMLTableRowElement::create(trTag, document());
+        if (numRows == index || index == -1)
+            appendChild(row, ec);
+        else {
+            Node* n;
+            if (index < 1)
+                n = firstChild();
+            else
+                n = children->item(index);
+            insertBefore(row, n, ec);
+        }
+    }
+    return row.release();
+}
+
+void HTMLTableSectionElement::deleteRow(int index, ExceptionCode& ec)
+{
+    RefPtr<HTMLCollection> children = rows();
+    int numRows = children ? (int)children->length() : 0;
+    if (index == -1)
+        index = numRows - 1;
+    if (index >= 0 && index < numRows) {
+        RefPtr<Node> row = children->item(index);
+        HTMLElement::removeChild(row.get(), ec);
+    } else
+        ec = INDEX_SIZE_ERR;
+}
+
+int HTMLTableSectionElement::numRows() const
+{
+    int rows = 0;
+    const Node *n = firstChild();
+    while (n) {
+        if (n->hasTagName(trTag))
+            rows++;
+        n = n->nextSibling();
+    }
+
+    return rows;
+}
+
+String HTMLTableSectionElement::align() const
+{
+    return getAttribute(alignAttr);
+}
+
+void HTMLTableSectionElement::setAlign(const String &value)
+{
+    setAttribute(alignAttr, value);
+}
+
+String HTMLTableSectionElement::ch() const
+{
+    return getAttribute(charAttr);
+}
+
+void HTMLTableSectionElement::setCh(const String &value)
+{
+    setAttribute(charAttr, value);
+}
+
+String HTMLTableSectionElement::chOff() const
+{
+    return getAttribute(charoffAttr);
+}
+
+void HTMLTableSectionElement::setChOff(const String &value)
+{
+    setAttribute(charoffAttr, value);
+}
+
+String HTMLTableSectionElement::vAlign() const
+{
+    return getAttribute(valignAttr);
+}
+
+void HTMLTableSectionElement::setVAlign(const String &value)
+{
+    setAttribute(valignAttr, value);
+}
+
+PassRefPtr<HTMLCollection> HTMLTableSectionElement::rows()
+{
+    return ensureCachedHTMLCollection(TSectionRows);
+}
+
+}
diff --git a/Source/core/html/HTMLTableSectionElement.h b/Source/core/html/HTMLTableSectionElement.h
new file mode 100644
index 0000000..b0302be
--- /dev/null
+++ b/Source/core/html/HTMLTableSectionElement.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ *           (C) 1997 Torben Weis (weis@kde.org)
+ *           (C) 1998 Waldo Bastian (bastian@kde.org)
+ *           (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLTableSectionElement_h
+#define HTMLTableSectionElement_h
+
+#include "core/html/HTMLTablePartElement.h"
+
+namespace WebCore {
+
+class HTMLTableSectionElement FINAL : public HTMLTablePartElement {
+public:
+    static PassRefPtr<HTMLTableSectionElement> create(const QualifiedName&, Document*);
+
+    PassRefPtr<HTMLElement> insertRow(int index, ExceptionCode&);
+    void deleteRow(int index, ExceptionCode&);
+
+    int numRows() const;
+
+    String align() const;
+    void setAlign(const String&);
+
+    String ch() const;
+    void setCh(const String&);
+
+    String chOff() const;
+    void setChOff(const String&);
+
+    String vAlign() const;
+    void setVAlign(const String&);
+
+    PassRefPtr<HTMLCollection> rows();
+
+private:
+    HTMLTableSectionElement(const QualifiedName& tagName, Document*);
+
+    virtual const StylePropertySet* additionalPresentationAttributeStyle() OVERRIDE;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLTableSectionElement.idl b/Source/core/html/HTMLTableSectionElement.idl
new file mode 100644
index 0000000..3126d77
--- /dev/null
+++ b/Source/core/html/HTMLTableSectionElement.idl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLTableSectionElement : HTMLElement {
+    [Reflect] attribute DOMString align;
+    [Reflect=char] attribute DOMString ch;
+    [Reflect=charoff] attribute DOMString chOff;
+    [Reflect] attribute DOMString vAlign;
+    readonly attribute HTMLCollection rows;
+    [RaisesException] HTMLElement insertRow([Default=Undefined] optional long index);
+    [RaisesException] void deleteRow([Default=Undefined] optional long index);
+};
+
diff --git a/Source/core/html/HTMLTagNames.in b/Source/core/html/HTMLTagNames.in
new file mode 100644
index 0000000..88a754c
--- /dev/null
+++ b/Source/core/html/HTMLTagNames.in
@@ -0,0 +1,141 @@
+namespace="HTML"
+namespacePrefix="xhtml"
+namespaceURI="http://www.w3.org/1999/xhtml"
+fallbackInterfaceName="HTMLUnknownElement"
+
+a interfaceName=HTMLAnchorElement
+abbr interfaceName=HTMLElement
+acronym interfaceName=HTMLElement
+address interfaceName=HTMLElement
+applet constructorNeedsCreatedByParser
+area
+article interfaceName=HTMLElement
+aside interfaceName=HTMLElement
+audio wrapperOnlyIfMediaIsAvailable, constructorNeedsCreatedByParser
+b interfaceName=HTMLElement
+base
+basefont interfaceName=HTMLElement
+bdi interfaceName=HTMLBDIElement, JSInterfaceName=HTMLElement
+bdo interfaceName=HTMLElement
+bgsound interfaceName=HTMLElement
+big interfaceName=HTMLElement
+blockquote interfaceName=HTMLQuoteElement
+body
+br interfaceName=HTMLBRElement
+button constructorNeedsFormElement
+canvas
+caption interfaceName=HTMLTableCaptionElement
+center interfaceName=HTMLElement
+cite interfaceName=HTMLElement
+code interfaceName=HTMLElement
+col interfaceName=HTMLTableColElement
+colgroup interfaceName=HTMLTableColElement
+command interfaceName=HTMLElement
+content interfaceName=HTMLContentElement
+webkitShadowContent interfaceName=HTMLElement, noConstructor
+datalist interfaceName=HTMLDataListElement, conditional=DATALIST_ELEMENT
+dd interfaceName=HTMLElement
+del interfaceName=HTMLModElement
+details
+dfn interfaceName=HTMLElement
+dir interfaceName=HTMLDirectoryElement
+dialog contextConditional=dialogElement
+div
+dl interfaceName=HTMLDListElement
+dt interfaceName=HTMLElement
+em interfaceName=HTMLElement
+embed constructorNeedsCreatedByParser
+fieldset interfaceName=HTMLFieldSetElement, constructorNeedsFormElement
+figcaption interfaceName=HTMLElement
+figure interfaceName=HTMLElement
+font
+footer interfaceName=HTMLElement
+form
+frame
+frameset interfaceName=HTMLFrameSetElement
+h1 interfaceName=HTMLHeadingElement
+h2 interfaceName=HTMLHeadingElement
+h3 interfaceName=HTMLHeadingElement
+h4 interfaceName=HTMLHeadingElement
+h5 interfaceName=HTMLHeadingElement
+h6 interfaceName=HTMLHeadingElement
+head
+header interfaceName=HTMLElement
+hgroup interfaceName=HTMLElement
+hr interfaceName=HTMLHRElement
+html
+i interfaceName=HTMLElement
+iframe interfaceName=HTMLIFrameElement
+image mapToTagName=img
+img interfaceName=HTMLImageElement, constructorNeedsFormElement
+input constructorNeedsFormElement, constructorNeedsCreatedByParser
+ins interfaceName=HTMLModElement
+isindex interfaceName=HTMLUnknownElement
+kbd interfaceName=HTMLElement
+keygen constructorNeedsFormElement
+label
+layer interfaceName=HTMLElement
+legend
+li interfaceName=HTMLLIElement
+link constructorNeedsCreatedByParser
+listing interfaceName=HTMLPreElement
+main interfaceName=HTMLElement
+map
+mark interfaceName=HTMLElement
+marquee
+menu
+meta
+meter interfaceName=HTMLMeterElement
+nav interfaceName=HTMLElement
+nobr interfaceName=HTMLElement
+noembed interfaceName=HTMLElement
+noframes interfaceName=HTMLElement
+nolayer interfaceName=HTMLElement
+object constructorNeedsFormElement, constructorNeedsCreatedByParser
+ol interfaceName=HTMLOListElement
+optgroup interfaceName=HTMLOptGroupElement
+option
+output constructorNeedsFormElement
+shadow interfaceName=HTMLShadowElement
+p interfaceName=HTMLParagraphElement
+param
+plaintext interfaceName=HTMLElement
+pre
+progress interfaceName=HTMLProgressElement
+q interfaceName=HTMLQuoteElement
+rp interfaceName=HTMLElement
+rt interfaceName=HTMLElement
+ruby interfaceName=HTMLElement
+s interfaceName=HTMLElement
+samp interfaceName=HTMLElement
+script constructorNeedsCreatedByParser
+section interfaceName=HTMLElement
+select constructorNeedsFormElement, constructorNeedsCreatedByParser
+small interfaceName=HTMLElement
+source wrapperOnlyIfMediaIsAvailable
+span
+strike interfaceName=HTMLElement
+strong interfaceName=HTMLElement
+style constructorNeedsCreatedByParser
+sub interfaceName=HTMLElement
+summary interfaceName=HTMLSummaryElement, JSInterfaceName=HTMLElement
+sup interfaceName=HTMLElement
+table
+tbody interfaceName=HTMLTableSectionElement
+td interfaceName=HTMLTableCellElement
+template
+textarea interfaceName=HTMLTextAreaElement, constructorNeedsFormElement
+tfoot interfaceName=HTMLTableSectionElement
+th interfaceName=HTMLTableCellElement
+thead interfaceName=HTMLTableSectionElement
+title
+tr interfaceName=HTMLTableRowElement
+track wrapperOnlyIfMediaIsAvailable
+tt interfaceName=HTMLElement
+u interfaceName=HTMLElement
+ul interfaceName=HTMLUListElement
+var interfaceName=HTMLElement
+video wrapperOnlyIfMediaIsAvailable, constructorNeedsCreatedByParser
+wbr interfaceName=HTMLElement
+xmp interfaceName=HTMLPreElement
+noscript interfaceName=HTMLElement
diff --git a/Source/core/html/HTMLTemplateElement.cpp b/Source/core/html/HTMLTemplateElement.cpp
new file mode 100644
index 0000000..cdc0145
--- /dev/null
+++ b/Source/core/html/HTMLTemplateElement.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/HTMLTemplateElement.h"
+
+#include "core/dom/DOMImplementation.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/dom/TemplateContentDocumentFragment.h"
+#include "core/editing/markup.h"
+#include "core/html/HTMLDocument.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLTemplateElement::HTMLTemplateElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ScriptWrappable::init(this);
+}
+
+HTMLTemplateElement::~HTMLTemplateElement()
+{
+}
+
+PassRefPtr<HTMLTemplateElement> HTMLTemplateElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLTemplateElement(tagName, document));
+}
+
+DocumentFragment* HTMLTemplateElement::content() const
+{
+    if (!m_content)
+        m_content = TemplateContentDocumentFragment::create(document()->ensureTemplateDocument(), this);
+
+    return m_content.get();
+}
+
+PassRefPtr<Node> HTMLTemplateElement::cloneNode(bool deep)
+{
+    if (!deep)
+        return cloneElementWithoutChildren();
+
+    RefPtr<Node> clone = cloneElementWithChildren();
+    if (m_content)
+        content()->cloneChildNodes(toHTMLTemplateElement(clone.get())->content());
+    return clone.release();
+}
+
+void HTMLTemplateElement::didMoveToNewDocument(Document* oldDocument)
+{
+    HTMLElement::didMoveToNewDocument(oldDocument);
+    if (!m_content)
+        return;
+    document()->ensureTemplateDocument()->adoptIfNeeded(m_content.get());
+}
+
+#ifndef NDEBUG
+const HTMLTemplateElement* toHTMLTemplateElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || (node->isHTMLElement() && node->hasTagName(templateTag)));
+    return static_cast<const HTMLTemplateElement*>(node);
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/core/html/HTMLTemplateElement.h b/Source/core/html/HTMLTemplateElement.h
new file mode 100644
index 0000000..685d62a
--- /dev/null
+++ b/Source/core/html/HTMLTemplateElement.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 HTMLTemplateElement_h
+#define HTMLTemplateElement_h
+
+#include "core/dom/DocumentFragment.h"
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLTemplateElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLTemplateElement> create(const QualifiedName&, Document*);
+    virtual ~HTMLTemplateElement();
+
+    DocumentFragment* content() const;
+
+private:
+    virtual PassRefPtr<Node> cloneNode(bool deep) OVERRIDE;
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+
+    HTMLTemplateElement(const QualifiedName&, Document*);
+
+    mutable RefPtr<DocumentFragment> m_content;
+};
+
+const HTMLTemplateElement* toHTMLTemplateElement(const Node*);
+
+inline HTMLTemplateElement* toHTMLTemplateElement(Node* node)
+{
+    return const_cast<HTMLTemplateElement*>(toHTMLTemplateElement(static_cast<const Node*>(node)));
+}
+
+#ifdef NDEBUG
+
+// The debug version of this, with assertions, is not inlined.
+inline const HTMLTemplateElement* toHTMLTemplateElement(const Node* node)
+{
+    return static_cast<const HTMLTemplateElement*>(node);
+}
+#endif // NDEBUG
+
+} // namespace WebCore
+
+#endif // HTMLTemplateElement_h
diff --git a/Source/core/html/HTMLTemplateElement.idl b/Source/core/html/HTMLTemplateElement.idl
new file mode 100644
index 0000000..8e91f1c
--- /dev/null
+++ b/Source/core/html/HTMLTemplateElement.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2012, 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+interface HTMLTemplateElement : HTMLElement {
+    [CacheAttributeForGC] readonly attribute DocumentFragment content;
+};
+
diff --git a/Source/core/html/HTMLTextAreaElement.cpp b/Source/core/html/HTMLTextAreaElement.cpp
new file mode 100644
index 0000000..ab270f0
--- /dev/null
+++ b/Source/core/html/HTMLTextAreaElement.cpp
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLTextAreaElement.h"
+
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/BeforeTextInsertedEvent.h"
+#include "core/dom/Document.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/Text.h"
+#include "core/editing/Editor.h"
+#include "core/editing/FrameSelection.h"
+#include "core/editing/TextIterator.h"
+#include "core/html/FormController.h"
+#include "core/html/FormDataList.h"
+#include "core/html/shadow/TextControlInnerElements.h"
+#include "core/page/EventHandler.h"
+#include "core/page/Frame.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/rendering/RenderTextControlMultiLine.h"
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const int defaultRows = 2;
+static const int defaultCols = 20;
+
+// On submission, LF characters are converted into CRLF.
+// This function returns number of characters considering this.
+static inline unsigned computeLengthForSubmission(const String& text, unsigned numberOfLineBreaks)
+{
+    return numGraphemeClusters(text) + numberOfLineBreaks;
+}
+
+static unsigned numberOfLineBreaks(const String& text)
+{
+    unsigned length = text.length();
+    unsigned count = 0;
+    for (unsigned i = 0; i < length; i++) {
+        if (text[i] == '\n')
+            count++;
+    }
+    return count;
+}
+
+static inline unsigned computeLengthForSubmission(const String& text)
+{
+    return numGraphemeClusters(text) + numberOfLineBreaks(text);
+}
+
+static inline unsigned upperBoundForLengthForSubmission(const String& text, unsigned numberOfLineBreaks)
+{
+    return text.length() + numberOfLineBreaks;
+}
+
+HTMLTextAreaElement::HTMLTextAreaElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+    : HTMLTextFormControlElement(tagName, document, form)
+    , m_rows(defaultRows)
+    , m_cols(defaultCols)
+    , m_wrap(SoftWrap)
+    , m_placeholder(0)
+    , m_isDirty(false)
+    , m_wasModifiedByUser(false)
+{
+    ASSERT(hasTagName(textareaTag));
+    setFormControlValueMatchesRenderer(true);
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLTextAreaElement> HTMLTextAreaElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
+{
+    RefPtr<HTMLTextAreaElement> textArea = adoptRef(new HTMLTextAreaElement(tagName, document, form));
+    textArea->ensureUserAgentShadowRoot();
+    return textArea.release();
+}
+
+void HTMLTextAreaElement::didAddUserAgentShadowRoot(ShadowRoot* root)
+{
+    root->appendChild(TextControlInnerTextElement::create(document()), ASSERT_NO_EXCEPTION);
+}
+
+const AtomicString& HTMLTextAreaElement::formControlType() const
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, textarea, ("textarea", AtomicString::ConstructFromLiteral));
+    return textarea;
+}
+
+FormControlState HTMLTextAreaElement::saveFormControlState() const
+{
+    return m_isDirty ? FormControlState(value()) : FormControlState();
+}
+
+void HTMLTextAreaElement::restoreFormControlState(const FormControlState& state)
+{
+    setValue(state[0]);
+}
+
+void HTMLTextAreaElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+    setLastChangeWasNotUserEdit();
+    if (m_isDirty)
+        setInnerTextValue(value());
+    else
+        setNonDirtyValue(defaultValue());
+}
+
+bool HTMLTextAreaElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == alignAttr) {
+        // Don't map 'align' attribute.  This matches what Firefox, Opera and IE do.
+        // See http://bugs.webkit.org/show_bug.cgi?id=7075
+        return false;
+    }
+
+    if (name == wrapAttr)
+        return true;
+    return HTMLTextFormControlElement::isPresentationAttribute(name);
+}
+
+void HTMLTextAreaElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == wrapAttr) {
+        if (shouldWrapText()) {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWhiteSpace, CSSValuePreWrap);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWordWrap, CSSValueBreakWord);
+        } else {
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWhiteSpace, CSSValuePre);
+            addPropertyToPresentationAttributeStyle(style, CSSPropertyWordWrap, CSSValueNormal);
+        }
+    } else
+        HTMLTextFormControlElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+void HTMLTextAreaElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == rowsAttr) {
+        int rows = value.toInt();
+        if (rows <= 0)
+            rows = defaultRows;
+        if (m_rows != rows) {
+            m_rows = rows;
+            if (renderer())
+                renderer()->setNeedsLayoutAndPrefWidthsRecalc();
+        }
+    } else if (name == colsAttr) {
+        int cols = value.toInt();
+        if (cols <= 0)
+            cols = defaultCols;
+        if (m_cols != cols) {
+            m_cols = cols;
+            if (renderer())
+                renderer()->setNeedsLayoutAndPrefWidthsRecalc();
+        }
+    } else if (name == wrapAttr) {
+        // The virtual/physical values were a Netscape extension of HTML 3.0, now deprecated.
+        // The soft/hard /off values are a recommendation for HTML 4 extension by IE and NS 4.
+        WrapMethod wrap;
+        if (equalIgnoringCase(value, "physical") || equalIgnoringCase(value, "hard") || equalIgnoringCase(value, "on"))
+            wrap = HardWrap;
+        else if (equalIgnoringCase(value, "off"))
+            wrap = NoWrap;
+        else
+            wrap = SoftWrap;
+        if (wrap != m_wrap) {
+            m_wrap = wrap;
+            if (renderer())
+                renderer()->setNeedsLayoutAndPrefWidthsRecalc();
+        }
+    } else if (name == accesskeyAttr) {
+        // ignore for the moment
+    } else if (name == maxlengthAttr)
+        setNeedsValidityCheck();
+    else
+        HTMLTextFormControlElement::parseAttribute(name, value);
+}
+
+RenderObject* HTMLTextAreaElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderTextControlMultiLine(this);
+}
+
+bool HTMLTextAreaElement::appendFormData(FormDataList& encoding, bool)
+{
+    if (name().isEmpty())
+        return false;
+
+    document()->updateLayout();
+
+    const String& text = (m_wrap == HardWrap) ? valueWithHardLineBreaks() : value();
+    encoding.appendData(name(), text);
+
+    const AtomicString& dirnameAttrValue = fastGetAttribute(dirnameAttr);
+    if (!dirnameAttrValue.isNull())
+        encoding.appendData(dirnameAttrValue, directionForFormData());
+    return true;    
+}
+
+void HTMLTextAreaElement::reset()
+{
+    setNonDirtyValue(defaultValue());
+}
+
+bool HTMLTextAreaElement::hasCustomFocusLogic() const
+{
+    return true;
+}
+
+bool HTMLTextAreaElement::isKeyboardFocusable(KeyboardEvent*) const
+{
+    // If a given text area can be focused at all, then it will always be keyboard focusable.
+    return isFocusable();
+}
+
+bool HTMLTextAreaElement::isMouseFocusable() const
+{
+    return isFocusable();
+}
+
+void HTMLTextAreaElement::updateFocusAppearance(bool restorePreviousSelection)
+{
+    if (!restorePreviousSelection || !hasCachedSelection()) {
+        // If this is the first focus, set a caret at the beginning of the text.  
+        // This matches some browsers' behavior; see bug 11746 Comment #15.
+        // http://bugs.webkit.org/show_bug.cgi?id=11746#c15
+        setSelectionRange(0, 0);
+    } else
+        restoreCachedSelection();
+
+    if (document()->frame())
+        document()->frame()->selection()->revealSelection();
+}
+
+void HTMLTextAreaElement::defaultEventHandler(Event* event)
+{
+    if (renderer() && (event->isMouseEvent() || event->isDragEvent() || event->hasInterface(eventNames().interfaceForWheelEvent) || event->type() == eventNames().blurEvent))
+        forwardEvent(event);
+    else if (renderer() && event->isBeforeTextInsertedEvent())
+        handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(event));
+
+    HTMLTextFormControlElement::defaultEventHandler(event);
+}
+
+void HTMLTextAreaElement::subtreeHasChanged()
+{
+    setChangedSinceLastFormControlChangeEvent(true);
+    setFormControlValueMatchesRenderer(false);
+    setNeedsValidityCheck();
+
+    if (!focused())
+        return;
+
+    if (Frame* frame = document()->frame())
+        frame->editor()->textDidChangeInTextArea(this);
+    // When typing in a textarea, childrenChanged is not called, so we need to force the directionality check.
+    calculateAndAdjustDirectionality();
+}
+
+void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event) const
+{
+    ASSERT(event);
+    ASSERT(renderer());
+    int signedMaxLength = maxLength();
+    if (signedMaxLength < 0)
+        return;
+    unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength);
+
+    const String& currentValue = innerTextValue();
+    unsigned numberOfLineBreaksInCurrentValue = numberOfLineBreaks(currentValue);
+    if (upperBoundForLengthForSubmission(currentValue, numberOfLineBreaksInCurrentValue)
+        + upperBoundForLengthForSubmission(event->text(), numberOfLineBreaks(event->text())) < unsignedMaxLength)
+        return;
+
+    unsigned currentLength = computeLengthForSubmission(currentValue, numberOfLineBreaksInCurrentValue);
+    // selectionLength represents the selection length of this text field to be
+    // removed by this insertion.
+    // If the text field has no focus, we don't need to take account of the
+    // selection length. The selection is the source of text drag-and-drop in
+    // that case, and nothing in the text field will be removed.
+    unsigned selectionLength = focused() ? computeLengthForSubmission(plainText(document()->frame()->selection()->selection().toNormalizedRange().get())) : 0;
+    ASSERT(currentLength >= selectionLength);
+    unsigned baseLength = currentLength - selectionLength;
+    unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLength - baseLength : 0;
+    event->setText(sanitizeUserInputValue(event->text(), appendableLength));
+}
+
+String HTMLTextAreaElement::sanitizeUserInputValue(const String& proposedValue, unsigned maxLength)
+{
+    return proposedValue.left(numCharactersInGraphemeClusters(proposedValue, maxLength));
+}
+
+HTMLElement* HTMLTextAreaElement::innerTextElement() const
+{
+    Node* node = userAgentShadowRoot()->firstChild();
+    ASSERT(!node || node->hasTagName(divTag));
+    return toHTMLElement(node);
+}
+
+void HTMLTextAreaElement::rendererWillBeDestroyed()
+{
+    updateValue();
+}
+
+void HTMLTextAreaElement::updateValue() const
+{
+    if (formControlValueMatchesRenderer())
+        return;
+
+    ASSERT(renderer());
+    m_value = innerTextValue();
+    const_cast<HTMLTextAreaElement*>(this)->setFormControlValueMatchesRenderer(true);
+    const_cast<HTMLTextAreaElement*>(this)->notifyFormStateChanged();
+    m_isDirty = true;
+    m_wasModifiedByUser = true;
+    const_cast<HTMLTextAreaElement*>(this)->updatePlaceholderVisibility(false);
+}
+
+String HTMLTextAreaElement::value() const
+{
+    updateValue();
+    return m_value;
+}
+
+void HTMLTextAreaElement::setValue(const String& value)
+{
+    setValueCommon(value);
+    m_isDirty = true;
+    setNeedsValidityCheck();
+}
+
+void HTMLTextAreaElement::setNonDirtyValue(const String& value)
+{
+    setValueCommon(value);
+    m_isDirty = false;
+    setNeedsValidityCheck();
+}
+
+void HTMLTextAreaElement::setValueCommon(const String& newValue)
+{
+    m_wasModifiedByUser = false;
+    // Code elsewhere normalizes line endings added by the user via the keyboard or pasting.
+    // We normalize line endings coming from JavaScript here.
+    String normalizedValue = newValue.isNull() ? "" : newValue;
+    normalizedValue.replace("\r\n", "\n");
+    normalizedValue.replace('\r', '\n');
+
+    // Return early because we don't want to move the caret or trigger other side effects
+    // when the value isn't changing. This matches Firefox behavior, at least.
+    if (normalizedValue == value())
+        return;
+
+    m_value = normalizedValue;
+    setInnerTextValue(m_value);
+    setLastChangeWasNotUserEdit();
+    updatePlaceholderVisibility(false);
+    setNeedsStyleRecalc();
+    setFormControlValueMatchesRenderer(true);
+
+    // Set the caret to the end of the text value.
+    if (document()->focusedNode() == this) {
+        unsigned endOfString = m_value.length();
+        setSelectionRange(endOfString, endOfString);
+    }
+
+    notifyFormStateChanged();
+    setTextAsOfLastFormControlChangeEvent(normalizedValue);
+}
+
+String HTMLTextAreaElement::defaultValue() const
+{
+    StringBuilder value;
+
+    // Since there may be comments, ignore nodes other than text nodes.
+    for (Node* n = firstChild(); n; n = n->nextSibling()) {
+        if (n->isTextNode())
+            value.append(toText(n)->data());
+    }
+
+    return value.toString();
+}
+
+void HTMLTextAreaElement::setDefaultValue(const String& defaultValue)
+{
+    RefPtr<Node> protectFromMutationEvents(this);
+
+    // To preserve comments, remove only the text nodes, then add a single text node.
+    Vector<RefPtr<Node> > textNodes;
+    for (Node* n = firstChild(); n; n = n->nextSibling()) {
+        if (n->isTextNode())
+            textNodes.append(n);
+    }
+    size_t size = textNodes.size();
+    for (size_t i = 0; i < size; ++i)
+        removeChild(textNodes[i].get(), IGNORE_EXCEPTION);
+
+    // Normalize line endings.
+    String value = defaultValue;
+    value.replace("\r\n", "\n");
+    value.replace('\r', '\n');
+
+    insertBefore(document()->createTextNode(value), firstChild(), IGNORE_EXCEPTION);
+
+    if (!m_isDirty)
+        setNonDirtyValue(value);
+}
+
+int HTMLTextAreaElement::maxLength() const
+{
+    bool ok;
+    int value = getAttribute(maxlengthAttr).string().toInt(&ok);
+    return ok && value >= 0 ? value : -1;
+}
+
+void HTMLTextAreaElement::setMaxLength(int newValue, ExceptionCode& ec)
+{
+    if (newValue < 0)
+        ec = INDEX_SIZE_ERR;
+    else
+        setAttribute(maxlengthAttr, String::number(newValue));
+}
+
+String HTMLTextAreaElement::validationMessage() const
+{
+    if (!willValidate())
+        return String();
+
+    if (customError())
+        return customValidationMessage();
+
+    if (valueMissing())
+        return validationMessageValueMissingText();
+
+    if (tooLong())
+        return validationMessageTooLongText(computeLengthForSubmission(value()), maxLength());
+
+    return String();
+}
+
+bool HTMLTextAreaElement::valueMissing() const
+{
+    return willValidate() && valueMissing(value());
+}
+
+bool HTMLTextAreaElement::tooLong() const
+{
+    return willValidate() && tooLong(value(), CheckDirtyFlag);
+}
+
+bool HTMLTextAreaElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) const
+{
+    // Return false for the default value or value set by script even if it is
+    // longer than maxLength.
+    if (check == CheckDirtyFlag && !m_wasModifiedByUser)
+        return false;
+
+    int max = maxLength();
+    if (max < 0)
+        return false;
+    unsigned unsignedMax = static_cast<unsigned>(max);
+    unsigned numberOfLineBreaksInValue = numberOfLineBreaks(value);
+    return upperBoundForLengthForSubmission(value, numberOfLineBreaksInValue) > unsignedMax
+        && computeLengthForSubmission(value, numberOfLineBreaksInValue) > unsignedMax;
+}
+
+bool HTMLTextAreaElement::isValidValue(const String& candidate) const
+{
+    return !valueMissing(candidate) && !tooLong(candidate, IgnoreDirtyFlag);
+}
+
+void HTMLTextAreaElement::accessKeyAction(bool)
+{
+    focus();
+}
+
+void HTMLTextAreaElement::setCols(int cols)
+{
+    setAttribute(colsAttr, String::number(cols));
+}
+
+void HTMLTextAreaElement::setRows(int rows)
+{
+    setAttribute(rowsAttr, String::number(rows));
+}
+
+bool HTMLTextAreaElement::shouldUseInputMethod()
+{
+    return true;
+}
+
+HTMLElement* HTMLTextAreaElement::placeholderElement() const
+{
+    return m_placeholder;
+}
+
+void HTMLTextAreaElement::attach()
+{
+    HTMLTextFormControlElement::attach();
+    fixPlaceholderRenderer(m_placeholder, innerTextElement());
+}
+
+bool HTMLTextAreaElement::matchesReadOnlyPseudoClass() const
+{
+    return isReadOnly();
+}
+
+bool HTMLTextAreaElement::matchesReadWritePseudoClass() const
+{
+    return !isReadOnly();
+}
+
+void HTMLTextAreaElement::updatePlaceholderText()
+{
+    String placeholderText = strippedPlaceholder();
+    if (placeholderText.isEmpty()) {
+        if (m_placeholder) {
+            userAgentShadowRoot()->removeChild(m_placeholder, ASSERT_NO_EXCEPTION);
+            m_placeholder = 0;
+        }
+        return;
+    }
+    if (!m_placeholder) {
+        RefPtr<HTMLDivElement> placeholder = HTMLDivElement::create(document());
+        m_placeholder = placeholder.get();
+        m_placeholder->setPseudo(AtomicString("-webkit-input-placeholder", AtomicString::ConstructFromLiteral));
+        userAgentShadowRoot()->insertBefore(m_placeholder, innerTextElement()->nextSibling(), ASSERT_NO_EXCEPTION);
+    }
+    m_placeholder->setInnerText(placeholderText, ASSERT_NO_EXCEPTION);
+    fixPlaceholderRenderer(m_placeholder, innerTextElement());
+}
+
+}
diff --git a/Source/core/html/HTMLTextAreaElement.h b/Source/core/html/HTMLTextAreaElement.h
new file mode 100644
index 0000000..4857fdf
--- /dev/null
+++ b/Source/core/html/HTMLTextAreaElement.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLTextAreaElement_h
+#define HTMLTextAreaElement_h
+
+#include "core/html/HTMLTextFormControlElement.h"
+
+namespace WebCore {
+
+class BeforeTextInsertedEvent;
+class VisibleSelection;
+
+class HTMLTextAreaElement FINAL : public HTMLTextFormControlElement {
+public:
+    static PassRefPtr<HTMLTextAreaElement> create(const QualifiedName&, Document*, HTMLFormElement*);
+
+    int cols() const { return m_cols; }
+    int rows() const { return m_rows; }
+
+    bool shouldWrapText() const { return m_wrap != NoWrap; }
+
+    virtual String value() const;
+    void setValue(const String&);
+    String defaultValue() const;
+    void setDefaultValue(const String&);
+    int textLength() const { return value().length(); }
+    virtual int maxLength() const;
+    void setMaxLength(int, ExceptionCode&);
+    // For ValidityState
+    virtual String validationMessage() const OVERRIDE;
+    virtual bool valueMissing() const OVERRIDE;
+    virtual bool tooLong() const OVERRIDE;
+    bool isValidValue(const String&) const;
+    
+    virtual HTMLElement* innerTextElement() const;
+
+    void rendererWillBeDestroyed();
+
+    void setCols(int);
+    void setRows(int);
+
+private:
+    HTMLTextAreaElement(const QualifiedName&, Document*, HTMLFormElement*);
+
+    enum WrapMethod { NoWrap, SoftWrap, HardWrap };
+
+    virtual void didAddUserAgentShadowRoot(ShadowRoot*) OVERRIDE;
+    virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
+
+    void handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*) const;
+    static String sanitizeUserInputValue(const String&, unsigned maxLength);
+    void updateValue() const;
+    void setNonDirtyValue(const String&);
+    void setValueCommon(const String&);
+
+    virtual bool supportsPlaceholder() const { return true; }
+    virtual HTMLElement* placeholderElement() const;
+    virtual void updatePlaceholderText();
+    virtual bool isEmptyValue() const { return value().isEmpty(); }
+
+    virtual bool isOptionalFormControl() const { return !isRequiredFormControl(); }
+    virtual bool isRequiredFormControl() const { return isRequired(); }
+
+    virtual void defaultEventHandler(Event*);
+    
+    virtual void subtreeHasChanged();
+
+    virtual bool isEnumeratable() const { return true; }
+    virtual bool supportLabels() const OVERRIDE { return true; }
+
+    virtual const AtomicString& formControlType() const;
+
+    virtual FormControlState saveFormControlState() const OVERRIDE;
+    virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
+
+    virtual bool isTextFormControl() const { return true; }
+
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual bool appendFormData(FormDataList&, bool);
+    virtual void reset();
+    virtual bool hasCustomFocusLogic() const OVERRIDE;
+    virtual bool isMouseFocusable() const;
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual void updateFocusAppearance(bool restorePreviousSelection);
+
+    virtual void accessKeyAction(bool sendMouseEvents);
+
+    virtual bool shouldUseInputMethod();
+    virtual void attach() OVERRIDE;
+    virtual bool matchesReadOnlyPseudoClass() const OVERRIDE;
+    virtual bool matchesReadWritePseudoClass() const OVERRIDE;
+
+    bool valueMissing(const String& value) const { return isRequiredFormControl() && !isDisabledOrReadOnly() && value.isEmpty(); }
+    bool tooLong(const String&, NeedsToCheckDirtyFlag) const;
+
+    int m_rows;
+    int m_cols;
+    WrapMethod m_wrap;
+    HTMLElement* m_placeholder;
+    mutable String m_value;
+    mutable bool m_isDirty;
+    mutable bool m_wasModifiedByUser;
+};
+
+inline bool isHTMLTextAreaElement(Node* node)
+{
+    return node->hasTagName(HTMLNames::textareaTag);
+}
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLTextAreaElement.idl b/Source/core/html/HTMLTextAreaElement.idl
new file mode 100644
index 0000000..105683b
--- /dev/null
+++ b/Source/core/html/HTMLTextAreaElement.idl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ * Copyright (C) 2011 Motorola Mobility, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLTextAreaElement : HTMLElement {
+    [Reflect] attribute boolean autofocus;
+    attribute long cols;
+    [Reflect] attribute DOMString dirName;
+    [Reflect] attribute boolean disabled;
+    readonly attribute HTMLFormElement form;
+    [SetterRaisesException] attribute long maxLength;
+    [Reflect] attribute DOMString name;
+    [Reflect] attribute DOMString placeholder;
+    [Reflect] attribute boolean readOnly;
+    [Reflect] attribute boolean required;
+    attribute long rows;
+    [Reflect] attribute DOMString wrap;
+
+    readonly attribute DOMString type;
+    [TreatNullAs=NullString] attribute DOMString defaultValue;
+    [TreatNullAs=NullString] attribute DOMString value;
+    readonly attribute unsigned long textLength;
+
+    readonly attribute boolean willValidate;
+    readonly attribute ValidityState validity;
+    readonly attribute DOMString validationMessage;
+    boolean checkValidity();
+    void setCustomValidity([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString error);
+
+    readonly attribute NodeList labels;
+
+    void select();
+    attribute long selectionStart;
+    attribute long selectionEnd;
+    attribute DOMString selectionDirection;
+
+    [RaisesException] void setRangeText(DOMString replacement);
+    [RaisesException] void setRangeText(DOMString replacement,
+                        unsigned long start,
+                        unsigned long end,
+                        [Default=NullString] optional DOMString selectionMode);
+
+    void setSelectionRange([Default=Undefined] optional long start,
+                           [Default=Undefined] optional long end,
+                           optional DOMString direction);
+};
diff --git a/Source/core/html/HTMLTextFormControlElement.cpp b/Source/core/html/HTMLTextFormControlElement.cpp
new file mode 100644
index 0000000..cae2d79
--- /dev/null
+++ b/Source/core/html/HTMLTextFormControlElement.cpp
@@ -0,0 +1,693 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLTextFormControlElement.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/accessibility/AXObjectCache.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/Text.h"
+#include "core/editing/FrameSelection.h"
+#include "core/editing/TextIterator.h"
+#include "core/html/HTMLBRElement.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/Frame.h"
+#include "core/page/UseCounter.h"
+#include "core/rendering/RenderBox.h"
+#include "core/rendering/RenderTextControl.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace std;
+
+HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* form)
+    : HTMLFormControlElementWithState(tagName, doc, form)
+    , m_lastChangeWasUserEdit(false)
+    , m_cachedSelectionStart(-1)
+    , m_cachedSelectionEnd(-1)
+    , m_cachedSelectionDirection(SelectionHasNoDirection)
+{
+}
+
+HTMLTextFormControlElement::~HTMLTextFormControlElement()
+{
+}
+
+bool HTMLTextFormControlElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
+{
+    // FIXME: We shouldn't force the pseudo elements down into the shadow, but
+    // this perserves the current behavior of WebKit.
+    if (childContext.node()->isPseudoElement())
+        return HTMLFormControlElementWithState::childShouldCreateRenderer(childContext);
+    return childContext.isOnEncapsulationBoundary() && HTMLFormControlElementWithState::childShouldCreateRenderer(childContext);
+}
+
+Node::InsertionNotificationRequest HTMLTextFormControlElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLFormControlElement::insertedInto(insertionPoint);
+    if (!insertionPoint->inDocument())
+        return InsertionDone;
+    String initialValue = value();
+    setTextAsOfLastFormControlChangeEvent(initialValue.isNull() ? emptyString() : initialValue);
+    return InsertionDone;
+}
+
+void HTMLTextFormControlElement::dispatchFocusEvent(PassRefPtr<Node> oldFocusedNode, FocusDirection direction)
+{
+    if (supportsPlaceholder())
+        updatePlaceholderVisibility(false);
+    handleFocusEvent(oldFocusedNode.get(), direction);
+    HTMLFormControlElementWithState::dispatchFocusEvent(oldFocusedNode, direction);
+}
+
+void HTMLTextFormControlElement::dispatchBlurEvent(PassRefPtr<Node> newFocusedNode)
+{
+    if (supportsPlaceholder())
+        updatePlaceholderVisibility(false);
+    handleBlurEvent();
+    HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedNode);
+}
+
+void HTMLTextFormControlElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().webkitEditableContentChangedEvent && renderer() && renderer()->isTextControl()) {
+        m_lastChangeWasUserEdit = true;
+        subtreeHasChanged();
+        return;
+    }
+
+    HTMLFormControlElementWithState::defaultEventHandler(event);
+}
+
+void HTMLTextFormControlElement::forwardEvent(Event* event)
+{
+    if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)
+        return;
+    innerTextElement()->defaultEventHandler(event);
+}
+
+String HTMLTextFormControlElement::strippedPlaceholder() const
+{
+    // According to the HTML5 specification, we need to remove CR and LF from
+    // the attribute value.
+    const AtomicString& attributeValue = fastGetAttribute(placeholderAttr);
+    if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn))
+        return attributeValue;
+
+    StringBuilder stripped;
+    unsigned length = attributeValue.length();
+    stripped.reserveCapacity(length);
+    for (unsigned i = 0; i < length; ++i) {
+        UChar character = attributeValue[i];
+        if (character == newlineCharacter || character == carriageReturn)
+            continue;
+        stripped.append(character);
+    }
+    return stripped.toString();
+}
+
+static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
+
+bool HTMLTextFormControlElement::isPlaceholderEmpty() const
+{
+    const AtomicString& attributeValue = fastGetAttribute(placeholderAttr);
+    return attributeValue.string().find(isNotLineBreak) == notFound;
+}
+
+bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
+{
+    return supportsPlaceholder()
+        && isEmptyValue()
+        && isEmptySuggestedValue()
+        && !isPlaceholderEmpty()
+        && (document()->focusedNode() != this || (renderer() && renderer()->theme()->shouldShowPlaceholderWhenFocused()))
+        && (!renderer() || renderer()->style()->visibility() == VISIBLE);
+}
+
+void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged)
+{
+    if (!supportsPlaceholder())
+        return;
+    if (!placeholderElement() || placeholderValueChanged)
+        updatePlaceholderText();
+    HTMLElement* placeholder = placeholderElement();
+    if (!placeholder)
+        return;
+    placeholder->setInlineStyleProperty(CSSPropertyVisibility, placeholderShouldBeVisible() ? "visible" : "hidden");
+}
+
+void HTMLTextFormControlElement::fixPlaceholderRenderer(HTMLElement* placeholder, HTMLElement* siblingElement)
+{
+    // FIXME: We should change the order of DOM nodes. But it makes an assertion
+    // failure in editing code.
+    if (!placeholder || !placeholder->renderer())
+        return;
+    RenderObject* placeholderRenderer = placeholder->renderer();
+    RenderObject* siblingRenderer = siblingElement->renderer();
+    if (!siblingRenderer)
+        return;
+    if (placeholderRenderer->nextSibling() == siblingRenderer)
+        return;
+    RenderObject* parentRenderer = placeholderRenderer->parent();
+    ASSERT(siblingRenderer->parent() == parentRenderer);
+    parentRenderer->removeChild(placeholderRenderer);
+    parentRenderer->addChild(placeholderRenderer, siblingRenderer);
+}
+
+RenderTextControl* HTMLTextFormControlElement::textRendererAfterUpdateLayout()
+{
+    if (!isTextFormControl())
+        return 0;
+    document()->updateLayoutIgnorePendingStylesheets();
+    return toRenderTextControl(renderer());
+}
+
+void HTMLTextFormControlElement::setSelectionStart(int start)
+{
+    setSelectionRange(start, max(start, selectionEnd()), selectionDirection());
+}
+
+void HTMLTextFormControlElement::setSelectionEnd(int end)
+{
+    setSelectionRange(min(end, selectionStart()), end, selectionDirection());
+}
+
+void HTMLTextFormControlElement::setSelectionDirection(const String& direction)
+{
+    setSelectionRange(selectionStart(), selectionEnd(), direction);
+}
+
+void HTMLTextFormControlElement::select()
+{
+    setSelectionRange(0, numeric_limits<int>::max(), SelectionHasNoDirection);
+}
+
+String HTMLTextFormControlElement::selectedText() const
+{
+    if (!isTextFormControl())
+        return String();
+    return value().substring(selectionStart(), selectionEnd() - selectionStart());
+}
+
+void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
+{
+    if (m_textAsOfLastFormControlChangeEvent != value()) {
+        HTMLElement::dispatchChangeEvent();
+        setTextAsOfLastFormControlChangeEvent(value());
+    }
+    setChangedSinceLastFormControlChangeEvent(false);
+}
+
+static inline bool hasVisibleTextArea(RenderTextControl* textControl, HTMLElement* innerText)
+{
+    ASSERT(textControl);
+    return textControl->style()->visibility() != HIDDEN && innerText && innerText->renderer() && innerText->renderBox()->height();
+}
+
+
+void HTMLTextFormControlElement::setRangeText(const String& replacement, ExceptionCode& ec)
+{
+    setRangeText(replacement, selectionStart(), selectionEnd(), String(), ec);
+}
+
+void HTMLTextFormControlElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionCode& ec)
+{
+    if (start > end) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    String text = innerTextValue();
+    unsigned textLength = text.length();
+    unsigned replacementLength = replacement.length();
+    unsigned newSelectionStart = selectionStart();
+    unsigned newSelectionEnd = selectionEnd();
+
+    start = std::min(start, textLength);
+    end = std::min(end, textLength);
+
+    if (start < end)
+        text.replace(start, end - start, replacement);
+    else
+        text.insert(replacement, start);
+
+    setInnerTextValue(text);
+
+    // FIXME: What should happen to the value (as in value()) if there's no renderer?
+    if (!renderer())
+        return;
+
+    subtreeHasChanged();
+
+    if (equalIgnoringCase(selectionMode, "select")) {
+        newSelectionStart = start;
+        newSelectionEnd = start + replacementLength;
+    } else if (equalIgnoringCase(selectionMode, "start"))
+        newSelectionStart = newSelectionEnd = start;
+    else if (equalIgnoringCase(selectionMode, "end"))
+        newSelectionStart = newSelectionEnd = start + replacementLength;
+    else {
+        // Default is "preserve".
+        long delta = replacementLength - (end - start);
+
+        if (newSelectionStart > end)
+            newSelectionStart += delta;
+        else if (newSelectionStart > start)
+            newSelectionStart = start;
+
+        if (newSelectionEnd > end)
+            newSelectionEnd += delta;
+        else if (newSelectionEnd > start)
+            newSelectionEnd = start + replacementLength;
+    }
+
+    setSelectionRange(newSelectionStart, newSelectionEnd, SelectionHasNoDirection);
+}
+
+void HTMLTextFormControlElement::setSelectionRange(int start, int end, const String& directionString)
+{
+    TextFieldSelectionDirection direction = SelectionHasNoDirection;
+    if (directionString == "forward")
+        direction = SelectionHasForwardDirection;
+    else if (directionString == "backward")
+        direction = SelectionHasBackwardDirection;
+
+    return setSelectionRange(start, end, direction);
+}
+
+void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction)
+{
+    document()->updateLayoutIgnorePendingStylesheets();
+
+    if (!renderer() || !renderer()->isTextControl())
+        return;
+
+    end = max(end, 0);
+    start = min(max(start, 0), end);
+
+    if (!hasVisibleTextArea(toRenderTextControl(renderer()), innerTextElement())) {
+        cacheSelection(start, end, direction);
+        return;
+    }
+    VisiblePosition startPosition = visiblePositionForIndex(start);
+    VisiblePosition endPosition;
+    if (start == end)
+        endPosition = startPosition;
+    else
+        endPosition = visiblePositionForIndex(end);
+
+    // startPosition and endPosition can be null position for example when
+    // "-webkit-user-select: none" style attribute is specified.
+    if (startPosition.isNotNull() && endPosition.isNotNull()) {
+        ASSERT(startPosition.deepEquivalent().deprecatedNode()->shadowHost() == this
+            && endPosition.deepEquivalent().deprecatedNode()->shadowHost() == this);
+    }
+    VisibleSelection newSelection;
+    if (direction == SelectionHasBackwardDirection)
+        newSelection = VisibleSelection(endPosition, startPosition);
+    else
+        newSelection = VisibleSelection(startPosition, endPosition);
+    newSelection.setIsDirectional(direction != SelectionHasNoDirection);
+
+    if (Frame* frame = document()->frame())
+        frame->selection()->setSelection(newSelection);
+}
+
+VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const
+{
+    if (index <= 0)
+        return VisiblePosition(firstPositionInNode(innerTextElement()), DOWNSTREAM);
+    RefPtr<Range> range = Range::create(document());
+    range->selectNodeContents(innerTextElement(), ASSERT_NO_EXCEPTION);
+    CharacterIterator it(range.get());
+    it.advance(index - 1);
+    return VisiblePosition(it.range()->endPosition(), UPSTREAM);
+}
+
+int HTMLTextFormControlElement::indexForVisiblePosition(const VisiblePosition& pos) const
+{
+    Position indexPosition = pos.deepEquivalent().parentAnchoredEquivalent();
+    if (enclosingTextFormControl(indexPosition) != this)
+        return 0;
+    RefPtr<Range> range = Range::create(indexPosition.document());
+    range->setStart(innerTextElement(), 0, ASSERT_NO_EXCEPTION);
+    range->setEnd(indexPosition.containerNode(), indexPosition.offsetInContainerNode(), ASSERT_NO_EXCEPTION);
+    return TextIterator::rangeLength(range.get());
+}
+
+int HTMLTextFormControlElement::selectionStart() const
+{
+    if (!isTextFormControl())
+        return 0;
+    if (document()->focusedNode() != this && hasCachedSelection())
+        return m_cachedSelectionStart;
+
+    return computeSelectionStart();
+}
+
+int HTMLTextFormControlElement::computeSelectionStart() const
+{
+    ASSERT(isTextFormControl());
+    Frame* frame = document()->frame();
+    if (!frame)
+        return 0;
+
+    return indexForVisiblePosition(frame->selection()->start());
+}
+
+int HTMLTextFormControlElement::selectionEnd() const
+{
+    if (!isTextFormControl())
+        return 0;
+    if (document()->focusedNode() != this && hasCachedSelection())
+        return m_cachedSelectionEnd;
+    return computeSelectionEnd();
+}
+
+int HTMLTextFormControlElement::computeSelectionEnd() const
+{
+    ASSERT(isTextFormControl());
+    Frame* frame = document()->frame();
+    if (!frame)
+        return 0;
+
+    return indexForVisiblePosition(frame->selection()->end());
+}
+
+static const AtomicString& directionString(TextFieldSelectionDirection direction)
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(const AtomicString, forward, ("forward", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(const AtomicString, backward, ("backward", AtomicString::ConstructFromLiteral));
+
+    switch (direction) {
+    case SelectionHasNoDirection:
+        return none;
+    case SelectionHasForwardDirection:
+        return forward;
+    case SelectionHasBackwardDirection:
+        return backward;
+    }
+
+    ASSERT_NOT_REACHED();
+    return none;
+}
+
+const AtomicString& HTMLTextFormControlElement::selectionDirection() const
+{
+    if (!isTextFormControl())
+        return directionString(SelectionHasNoDirection);
+    if (document()->focusedNode() != this && hasCachedSelection())
+        return directionString(m_cachedSelectionDirection);
+
+    return directionString(computeSelectionDirection());
+}
+
+TextFieldSelectionDirection HTMLTextFormControlElement::computeSelectionDirection() const
+{
+    ASSERT(isTextFormControl());
+    Frame* frame = document()->frame();
+    if (!frame)
+        return SelectionHasNoDirection;
+
+    const VisibleSelection& selection = frame->selection()->selection();
+    return selection.isDirectional() ? (selection.isBaseFirst() ? SelectionHasForwardDirection : SelectionHasBackwardDirection) : SelectionHasNoDirection;
+}
+
+static inline void setContainerAndOffsetForRange(Node* node, int offset, Node*& containerNode, int& offsetInContainer)
+{
+    if (node->isTextNode()) {
+        containerNode = node;
+        offsetInContainer = offset;
+    } else {
+        containerNode = node->parentNode();
+        offsetInContainer = node->nodeIndex() + offset;
+    }
+}
+
+PassRefPtr<Range> HTMLTextFormControlElement::selection() const
+{
+    if (!renderer() || !isTextFormControl() || !hasCachedSelection())
+        return 0;
+
+    int start = m_cachedSelectionStart;
+    int end = m_cachedSelectionEnd;
+
+    ASSERT(start <= end);
+    HTMLElement* innerText = innerTextElement();
+    if (!innerText)
+        return 0;
+
+    if (!innerText->firstChild())
+        return Range::create(document(), innerText, 0, innerText, 0);
+
+    int offset = 0;
+    Node* startNode = 0;
+    Node* endNode = 0;
+    for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(node, innerText)) {
+        ASSERT(!node->firstChild());
+        ASSERT(node->isTextNode() || node->hasTagName(brTag));
+        int length = node->isTextNode() ? lastOffsetInNode(node) : 1;
+
+        if (offset <= start && start <= offset + length)
+            setContainerAndOffsetForRange(node, start - offset, startNode, start);
+
+        if (offset <= end && end <= offset + length) {
+            setContainerAndOffsetForRange(node, end - offset, endNode, end);
+            break;
+        }
+
+        offset += length;
+    }
+
+    if (!startNode || !endNode)
+        return 0;
+
+    return Range::create(document(), startNode, start, endNode, end);
+}
+
+void HTMLTextFormControlElement::restoreCachedSelection()
+{
+    setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, m_cachedSelectionDirection);
+}
+
+void HTMLTextFormControlElement::selectionChanged(bool userTriggered)
+{
+    if (!renderer() || !isTextFormControl())
+        return;
+
+    // selectionStart() or selectionEnd() will return cached selection when this node doesn't have focus
+    cacheSelection(computeSelectionStart(), computeSelectionEnd(), computeSelectionDirection());
+
+    if (Frame* frame = document()->frame()) {
+        if (frame->selection()->isRange() && userTriggered)
+            dispatchEvent(Event::create(eventNames().selectEvent, true, false));
+    }
+}
+
+void HTMLTextFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == placeholderAttr) {
+        updatePlaceholderVisibility(true);
+        UseCounter::count(document(), UseCounter::PlaceholderAttribute);
+    } else
+        HTMLFormControlElementWithState::parseAttribute(name, value);
+}
+
+bool HTMLTextFormControlElement::lastChangeWasUserEdit() const
+{
+    if (!isTextFormControl())
+        return false;
+    return m_lastChangeWasUserEdit;
+}
+
+void HTMLTextFormControlElement::setInnerTextValue(const String& value)
+{
+    if (!isTextFormControl())
+        return;
+
+    bool textIsChanged = value != innerTextValue();
+    if (textIsChanged || !innerTextElement()->hasChildNodes()) {
+        if (textIsChanged && document() && renderer()) {
+            if (AXObjectCache* cache = document()->existingAXObjectCache())
+                cache->postNotification(this, AXObjectCache::AXValueChanged, false);
+        }
+        innerTextElement()->setInnerText(value, ASSERT_NO_EXCEPTION);
+
+        if (value.endsWith('\n') || value.endsWith('\r'))
+            innerTextElement()->appendChild(HTMLBRElement::create(document()), ASSERT_NO_EXCEPTION);
+    }
+
+    setFormControlValueMatchesRenderer(true);
+}
+
+static String finishText(StringBuilder& result)
+{
+    // Remove one trailing newline; there's always one that's collapsed out by rendering.
+    size_t size = result.length();
+    if (size && result[size - 1] == '\n')
+        result.resize(--size);
+    return result.toString();
+}
+
+String HTMLTextFormControlElement::innerTextValue() const
+{
+    HTMLElement* innerText = innerTextElement();
+    if (!innerText || !isTextFormControl())
+        return emptyString();
+
+    StringBuilder result;
+    for (Node* node = innerText; node; node = NodeTraversal::next(node, innerText)) {
+        if (node->hasTagName(brTag))
+            result.append(newlineCharacter);
+        else if (node->isTextNode())
+            result.append(toText(node)->data());
+    }
+    return finishText(result);
+}
+
+static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
+{
+    RootInlineBox* next;
+    for (; line; line = next) {
+        next = line->nextRootBox();
+        if (next && !line->endsWithBreak()) {
+            ASSERT(line->lineBreakObj());
+            breakNode = line->lineBreakObj()->node();
+            breakOffset = line->lineBreakPos();
+            line = next;
+            return;
+        }
+    }
+    breakNode = 0;
+    breakOffset = 0;
+}
+
+String HTMLTextFormControlElement::valueWithHardLineBreaks() const
+{
+    // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer.
+    // While we have no evidence this has ever been a practical problem, it would be best to fix it some day.
+    HTMLElement* innerText = innerTextElement();
+    if (!innerText || !isTextFormControl())
+        return value();
+
+    RenderBlock* renderer = toRenderBlock(innerText->renderer());
+    if (!renderer)
+        return value();
+
+    Node* breakNode;
+    unsigned breakOffset;
+    RootInlineBox* line = renderer->firstRootBox();
+    if (!line)
+        return value();
+
+    getNextSoftBreak(line, breakNode, breakOffset);
+
+    StringBuilder result;
+    for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(node, innerText)) {
+        if (node->hasTagName(brTag))
+            result.append(newlineCharacter);
+        else if (node->isTextNode()) {
+            String data = toText(node)->data();
+            unsigned length = data.length();
+            unsigned position = 0;
+            while (breakNode == node && breakOffset <= length) {
+                if (breakOffset > position) {
+                    result.append(data.characters() + position, breakOffset - position);
+                    position = breakOffset;
+                    result.append(newlineCharacter);
+                }
+                getNextSoftBreak(line, breakNode, breakOffset);
+            }
+            result.append(data.characters() + position, length - position);
+        }
+        while (breakNode == node)
+            getNextSoftBreak(line, breakNode, breakOffset);
+    }
+    return finishText(result);
+}
+
+HTMLTextFormControlElement* enclosingTextFormControl(const Position& position)
+{
+    ASSERT(position.isNull() || position.anchorType() == Position::PositionIsOffsetInAnchor
+        || position.containerNode() || !position.anchorNode()->shadowHost()
+        || (position.anchorNode()->parentNode() && position.anchorNode()->parentNode()->isShadowRoot()));
+        
+    Node* container = position.containerNode();
+    if (!container)
+        return 0;
+    Element* ancestor = container->shadowHost();
+    return ancestor && isHTMLTextFormControlElement(ancestor) ? toHTMLTextFormControlElement(ancestor) : 0;
+}
+
+static const Element* parentHTMLElement(const Element* element)
+{
+    while (element) {
+        element = element->parentElement();
+        if (element && element->isHTMLElement())
+            return element;
+    }
+    return 0;
+}
+
+String HTMLTextFormControlElement::directionForFormData() const
+{
+    for (const Element* element = this; element; element = parentHTMLElement(element)) {
+        const AtomicString& dirAttributeValue = element->fastGetAttribute(dirAttr);
+        if (dirAttributeValue.isNull())
+            continue;
+
+        if (equalIgnoringCase(dirAttributeValue, "rtl") || equalIgnoringCase(dirAttributeValue, "ltr"))
+            return dirAttributeValue;
+
+        if (equalIgnoringCase(dirAttributeValue, "auto")) {
+            bool isAuto;
+            TextDirection textDirection = static_cast<const HTMLElement*>(element)->directionalityIfhasDirAutoAttribute(isAuto);
+            return textDirection == RTL ? "rtl" : "ltr";
+        }
+    }
+
+    return "ltr";
+}
+
+void HTMLTextFormControlElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
+    HTMLFormControlElementWithState::reportMemoryUsage(memoryObjectInfo);
+    info.addMember(m_textAsOfLastFormControlChangeEvent, "textAsOfLastFormControlChangeEvent");
+}
+
+} // namespace Webcore
diff --git a/Source/core/html/HTMLTextFormControlElement.h b/Source/core/html/HTMLTextFormControlElement.h
new file mode 100644
index 0000000..506380b
--- /dev/null
+++ b/Source/core/html/HTMLTextFormControlElement.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010, 2011 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLTextFormControlElement_h
+#define HTMLTextFormControlElement_h
+
+#include "core/html/HTMLFormControlElementWithState.h"
+
+namespace WebCore {
+
+class Position;
+class RenderTextControl;
+class VisiblePosition;
+
+enum TextFieldSelectionDirection { SelectionHasNoDirection, SelectionHasForwardDirection, SelectionHasBackwardDirection };
+enum TextFieldEventBehavior { DispatchNoEvent, DispatchChangeEvent, DispatchInputAndChangeEvent };
+
+class HTMLTextFormControlElement : public HTMLFormControlElementWithState {
+public:
+    // Common flag for HTMLInputElement::tooLong() and HTMLTextAreaElement::tooLong().
+    enum NeedsToCheckDirtyFlag {CheckDirtyFlag, IgnoreDirtyFlag};
+
+    virtual ~HTMLTextFormControlElement();
+
+    void forwardEvent(Event*);
+
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+
+    // The derived class should return true if placeholder processing is needed.
+    virtual bool supportsPlaceholder() const = 0;
+    String strippedPlaceholder() const;
+    bool placeholderShouldBeVisible() const;
+    virtual HTMLElement* placeholderElement() const = 0;
+    void updatePlaceholderVisibility(bool);
+    static void fixPlaceholderRenderer(HTMLElement* placeholder, HTMLElement* siblingElement);
+
+    VisiblePosition visiblePositionForIndex(int) const;
+    int indexForVisiblePosition(const VisiblePosition&) const;
+    int selectionStart() const;
+    int selectionEnd() const;
+    const AtomicString& selectionDirection() const;
+    void setSelectionStart(int);
+    void setSelectionEnd(int);
+    void setSelectionDirection(const String&);
+    void select();
+    virtual void setRangeText(const String& replacement, ExceptionCode&);
+    virtual void setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionCode&);
+    void setSelectionRange(int start, int end, const String& direction);
+    void setSelectionRange(int start, int end, TextFieldSelectionDirection = SelectionHasNoDirection);
+    PassRefPtr<Range> selection() const;
+    String selectedText() const;
+
+    virtual void dispatchFormControlChangeEvent();
+
+    virtual int maxLength() const = 0;
+    virtual String value() const = 0;
+
+    virtual HTMLElement* innerTextElement() const = 0;
+
+    void selectionChanged(bool userTriggered);
+    bool lastChangeWasUserEdit() const;
+    void setInnerTextValue(const String&);
+    String innerTextValue() const;
+
+    String directionForFormData() const;
+
+    void setTextAsOfLastFormControlChangeEvent(const String& text) { m_textAsOfLastFormControlChangeEvent = text; }
+
+    virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+
+protected:
+    HTMLTextFormControlElement(const QualifiedName&, Document*, HTMLFormElement*);
+    bool isPlaceholderEmpty() const;
+    virtual void updatePlaceholderText() = 0;
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    void cacheSelection(int start, int end, TextFieldSelectionDirection direction)
+    {
+        m_cachedSelectionStart = start;
+        m_cachedSelectionEnd = end;
+        m_cachedSelectionDirection = direction;
+    }
+
+    void restoreCachedSelection();
+    bool hasCachedSelection() const { return m_cachedSelectionStart >= 0; }
+
+    virtual void defaultEventHandler(Event*);
+    virtual void subtreeHasChanged() = 0;
+
+    void setLastChangeWasNotUserEdit() { m_lastChangeWasUserEdit = false; }
+
+    String valueWithHardLineBreaks() const;
+
+private:
+    int computeSelectionStart() const;
+    int computeSelectionEnd() const;
+    TextFieldSelectionDirection computeSelectionDirection() const;
+
+    virtual void dispatchFocusEvent(PassRefPtr<Node> oldFocusedNode, FocusDirection) OVERRIDE;
+    virtual void dispatchBlurEvent(PassRefPtr<Node> newFocusedNode);
+    virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const OVERRIDE;
+
+    // Returns true if user-editable value is empty. Used to check placeholder visibility.
+    virtual bool isEmptyValue() const = 0;
+    // Returns true if suggested value is empty. Used to check placeholder visibility.
+    virtual bool isEmptySuggestedValue() const { return true; }
+    // Called in dispatchFocusEvent(), after placeholder process, before calling parent's dispatchFocusEvent().
+    virtual void handleFocusEvent(Node* /* oldFocusedNode */, FocusDirection) { }
+    // Called in dispatchBlurEvent(), after placeholder process, before calling parent's dispatchBlurEvent().
+    virtual void handleBlurEvent() { }
+
+    RenderTextControl* textRendererAfterUpdateLayout();
+
+    String m_textAsOfLastFormControlChangeEvent;
+    bool m_lastChangeWasUserEdit;
+    
+    int m_cachedSelectionStart;
+    int m_cachedSelectionEnd;
+    TextFieldSelectionDirection m_cachedSelectionDirection;
+};
+
+inline bool isHTMLTextFormControlElement(const Node* node)
+{
+    return node->isElementNode() && toElement(node)->isTextFormControl();
+}
+
+inline HTMLTextFormControlElement* toHTMLTextFormControlElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLTextFormControlElement(node));
+    return static_cast<HTMLTextFormControlElement*>(node);
+}
+
+HTMLTextFormControlElement* enclosingTextFormControl(const Position&);
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLTitleElement.cpp b/Source/core/html/HTMLTitleElement.cpp
new file mode 100644
index 0000000..c161612
--- /dev/null
+++ b/Source/core/html/HTMLTitleElement.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/HTMLTitleElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Document.h"
+#include "core/dom/NodeRenderingContext.h"
+#include "core/dom/Text.h"
+#include "core/rendering/style/RenderStyle.h"
+#include "core/rendering/style/StyleInheritedData.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLTitleElement::HTMLTitleElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(titleTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLTitleElement> HTMLTitleElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLTitleElement(tagName, document));
+}
+
+Node::InsertionNotificationRequest HTMLTitleElement::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+    if (inDocument() && !isInShadowTree())
+        document()->setTitleElement(m_title, this);
+    return InsertionDone;
+}
+
+void HTMLTitleElement::removedFrom(ContainerNode* insertionPoint)
+{
+    HTMLElement::removedFrom(insertionPoint);
+    if (insertionPoint->inDocument() && !insertionPoint->isInShadowTree())
+        document()->removeTitle(this);
+}
+
+void HTMLTitleElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+    m_title = textWithDirection();
+    if (inDocument()) {
+        if (!isInShadowTree())
+            document()->setTitleElement(m_title, this);
+        else
+            document()->removeTitle(this);
+    }
+}
+
+String HTMLTitleElement::text() const
+{
+    StringBuilder result;
+
+    for (Node *n = firstChild(); n; n = n->nextSibling()) {
+        if (n->isTextNode())
+            result.append(toText(n)->data());
+    }
+
+    return result.toString();
+}
+
+StringWithDirection HTMLTitleElement::textWithDirection()
+{
+    TextDirection direction = LTR;
+    if (RenderStyle* style = computedStyle())
+        direction = style->direction();
+    else if (RefPtr<RenderStyle> style = styleForRenderer())
+        direction = style->direction();
+    return StringWithDirection(text(), direction);
+}
+
+void HTMLTitleElement::setText(const String &value)
+{
+    RefPtr<Node> protectFromMutationEvents(this);
+
+    int numChildren = childNodeCount();
+    
+    if (numChildren == 1 && firstChild()->isTextNode())
+        toText(firstChild())->setData(value, IGNORE_EXCEPTION);
+    else {
+        // We make a copy here because entity of "value" argument can be Document::m_title,
+        // which goes empty during removeChildren() invocation below,
+        // which causes HTMLTitleElement::childrenChanged(), which ends up Document::setTitle().
+        String valueCopy(value);
+
+        if (numChildren > 0)
+            removeChildren();
+
+        appendChild(document()->createTextNode(valueCopy.impl()), IGNORE_EXCEPTION);
+    }
+}
+
+}
diff --git a/Source/core/html/HTMLTitleElement.h b/Source/core/html/HTMLTitleElement.h
new file mode 100644
index 0000000..b80f598
--- /dev/null
+++ b/Source/core/html/HTMLTitleElement.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef HTMLTitleElement_h
+#define HTMLTitleElement_h
+
+#include "core/html/HTMLElement.h"
+#include "core/platform/text/StringWithDirection.h"
+
+namespace WebCore {
+
+class HTMLTitleElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLTitleElement> create(const QualifiedName&, Document*);
+
+    String text() const;
+    void setText(const String&);
+
+    StringWithDirection textWithDirection();
+
+private:
+    HTMLTitleElement(const QualifiedName&, Document*);
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
+    StringWithDirection m_title;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLTitleElement.idl b/Source/core/html/HTMLTitleElement.idl
new file mode 100644
index 0000000..f5639fe
--- /dev/null
+++ b/Source/core/html/HTMLTitleElement.idl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLTitleElement : HTMLElement {
+    [TreatNullAs=NullString] attribute DOMString            text;
+};
+
diff --git a/Source/core/html/HTMLTrackElement.cpp b/Source/core/html/HTMLTrackElement.cpp
new file mode 100644
index 0000000..d8a6ffe
--- /dev/null
+++ b/Source/core/html/HTMLTrackElement.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+#include "core/html/HTMLTrackElement.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Event.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/inspector/ScriptCallStack.h"
+#include "core/page/ContentSecurityPolicy.h"
+#include "RuntimeEnabledFeatures.h"
+#include "core/platform/Logging.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#if !LOG_DISABLED
+static String urlForLoggingTrack(const KURL& url)
+{
+    static const unsigned maximumURLLengthForLogging = 128;
+
+    if (url.string().length() < maximumURLLengthForLogging)
+        return url.string();
+    return url.string().substring(0, maximumURLLengthForLogging) + "...";
+}
+#endif
+
+inline HTMLTrackElement::HTMLTrackElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+    , m_loadTimer(this, &HTMLTrackElement::loadTimerFired)
+{
+    LOG(Media, "HTMLTrackElement::HTMLTrackElement - %p", this);
+    ASSERT(hasTagName(trackTag));
+    ScriptWrappable::init(this);
+}
+
+HTMLTrackElement::~HTMLTrackElement()
+{
+    if (m_track)
+        m_track->clearClient();
+}
+
+PassRefPtr<HTMLTrackElement> HTMLTrackElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLTrackElement(tagName, document));
+}
+
+Node::InsertionNotificationRequest HTMLTrackElement::insertedInto(ContainerNode* insertionPoint)
+{
+    // Since we've moved to a new parent, we may now be able to load.
+    scheduleLoad();
+
+    HTMLElement::insertedInto(insertionPoint);
+    HTMLMediaElement* parent = mediaElement();
+    if (insertionPoint == parent)
+        parent->didAddTrack(this);
+    return InsertionDone;
+}
+
+void HTMLTrackElement::removedFrom(ContainerNode* insertionPoint)
+{
+    if (!parentNode() && WebCore::isMediaElement(insertionPoint))
+        toMediaElement(insertionPoint)->didRemoveTrack(this);
+    HTMLElement::removedFrom(insertionPoint);
+}
+
+void HTMLTrackElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (RuntimeEnabledFeatures::webkitVideoTrackEnabled()) {
+        if (name == srcAttr) {
+            if (!value.isEmpty())
+                scheduleLoad();
+            else if (m_track)
+                m_track->removeAllCues();
+
+        // 4.8.10.12.3 Sourcing out-of-band text tracks
+        // As the kind, label, and srclang attributes are set, changed, or removed, the text track must update accordingly...
+        } else if (name == kindAttr)
+            track()->setKind(value.lower());
+        else if (name == labelAttr)
+            track()->setLabel(value);
+        else if (name == srclangAttr)
+            track()->setLanguage(value);
+        else if (name == defaultAttr)
+            track()->setIsDefault(!value.isNull());
+    }
+
+    HTMLElement::parseAttribute(name, value);
+}
+
+KURL HTMLTrackElement::src() const
+{
+    return document()->completeURL(getAttribute(srcAttr));
+}
+
+void HTMLTrackElement::setSrc(const String& url)
+{
+    setAttribute(srcAttr, url);
+}
+
+String HTMLTrackElement::kind()
+{
+    return track()->kind();
+}
+
+void HTMLTrackElement::setKind(const String& kind)
+{
+    setAttribute(kindAttr, kind);
+}
+
+String HTMLTrackElement::srclang() const
+{
+    return getAttribute(srclangAttr);
+}
+
+void HTMLTrackElement::setSrclang(const String& srclang)
+{
+    setAttribute(srclangAttr, srclang);
+}
+
+String HTMLTrackElement::label() const
+{
+    return getAttribute(labelAttr);
+}
+
+void HTMLTrackElement::setLabel(const String& label)
+{
+    setAttribute(labelAttr, label);
+}
+
+bool HTMLTrackElement::isDefault() const
+{
+    return fastHasAttribute(defaultAttr);
+}
+
+void HTMLTrackElement::setIsDefault(bool isDefault)
+{
+    setBooleanAttribute(defaultAttr, isDefault);
+}
+
+LoadableTextTrack* HTMLTrackElement::ensureTrack()
+{
+    if (!m_track) {
+        // The kind attribute is an enumerated attribute, limited only to know values. It defaults to 'subtitles' if missing or invalid.
+        String kind = getAttribute(kindAttr).lower();
+        if (!TextTrack::isValidKindKeyword(kind))
+            kind = TextTrack::subtitlesKeyword();
+        m_track = LoadableTextTrack::create(this, kind, label(), srclang());
+    }
+    return m_track.get();
+}
+
+TextTrack* HTMLTrackElement::track()
+{
+    return ensureTrack();
+}
+
+bool HTMLTrackElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == srcAttr || HTMLElement::isURLAttribute(attribute);
+}
+
+void HTMLTrackElement::scheduleLoad()
+{
+    // 1. If another occurrence of this algorithm is already running for this text track and its track element,
+    // abort these steps, letting that other algorithm take care of this element.
+    if (m_loadTimer.isActive())
+        return;
+
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return;
+
+    // 2. If the text track's text track mode is not set to one of hidden or showing, abort these steps.
+    if (ensureTrack()->mode() != TextTrack::hiddenKeyword() && ensureTrack()->mode() != TextTrack::showingKeyword())
+        return;
+
+    // 3. If the text track's track element does not have a media element as a parent, abort these steps.
+    if (!mediaElement())
+        return;
+
+    // 4. Run the remainder of these steps asynchronously, allowing whatever caused these steps to run to continue.
+    m_loadTimer.startOneShot(0);
+}
+
+void HTMLTrackElement::loadTimerFired(Timer<HTMLTrackElement>*)
+{
+    if (!fastHasAttribute(srcAttr))
+        return;
+
+    // 6. Set the text track readiness state to loading.
+    setReadyState(HTMLTrackElement::LOADING);
+
+    // 7. Let URL be the track URL of the track element.
+    KURL url = getNonEmptyURLAttribute(srcAttr);
+
+    // 8. If the track element's parent is a media element then let CORS mode be the state of the parent media
+    // element's crossorigin content attribute. Otherwise, let CORS mode be No CORS.
+    if (!canLoadUrl(url)) {
+        didCompleteLoad(ensureTrack(), HTMLTrackElement::Failure);
+        return;
+    }
+
+    ensureTrack()->scheduleLoad(url);
+}
+
+bool HTMLTrackElement::canLoadUrl(const KURL& url)
+{
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return false;
+
+    HTMLMediaElement* parent = mediaElement();
+    if (!parent)
+        return false;
+
+    // 4.8.10.12.3 Sourcing out-of-band text tracks
+
+    // 4. Download: If URL is not the empty string, perform a potentially CORS-enabled fetch of URL, with the
+    // mode being the state of the media element's crossorigin content attribute, the origin being the
+    // origin of the media element's Document, and the default origin behaviour set to fail.
+    if (url.isEmpty())
+        return false;
+
+    if (!document()->contentSecurityPolicy()->allowMediaFromSource(url)) {
+        LOG(Media, "HTMLTrackElement::canLoadUrl(%s) -> rejected by Content Security Policy", urlForLoggingTrack(url).utf8().data());
+        return false;
+    }
+
+    return dispatchBeforeLoadEvent(url.string());
+}
+
+void HTMLTrackElement::didCompleteLoad(LoadableTextTrack*, LoadStatus status)
+{
+    // 4.8.10.12.3 Sourcing out-of-band text tracks (continued)
+
+    // 4. Download: ...
+    // If the fetching algorithm fails for any reason (network error, the server returns an error
+    // code, a cross-origin check fails, etc), or if URL is the empty string or has the wrong origin
+    // as determined by the condition at the start of this step, or if the fetched resource is not in
+    // a supported format, then queue a task to first change the text track readiness state to failed
+    // to load and then fire a simple event named error at the track element; and then, once that task
+    // is queued, move on to the step below labeled monitoring.
+
+    if (status == Failure) {
+        setReadyState(HTMLTrackElement::TRACK_ERROR);
+        dispatchEvent(Event::create(eventNames().errorEvent, false, false), IGNORE_EXCEPTION);
+        return;
+    }
+
+    // If the fetching algorithm does not fail, then the final task that is queued by the networking
+    // task source must run the following steps:
+    //     1. Change the text track readiness state to loaded.
+    setReadyState(HTMLTrackElement::LOADED);
+
+    //     2. If the file was successfully processed, fire a simple event named load at the
+    //        track element.
+    dispatchEvent(Event::create(eventNames().loadEvent, false, false), IGNORE_EXCEPTION);
+}
+
+// NOTE: The values in the TextTrack::ReadinessState enum must stay in sync with those in HTMLTrackElement::ReadyState.
+COMPILE_ASSERT(HTMLTrackElement::NONE == static_cast<HTMLTrackElement::ReadyState>(TextTrack::NotLoaded), TextTrackEnumNotLoaded_Is_Wrong_Should_Be_HTMLTrackElementEnumNONE);
+COMPILE_ASSERT(HTMLTrackElement::LOADING == static_cast<HTMLTrackElement::ReadyState>(TextTrack::Loading), TextTrackEnumLoadingIsWrong_ShouldBe_HTMLTrackElementEnumLOADING);
+COMPILE_ASSERT(HTMLTrackElement::LOADED == static_cast<HTMLTrackElement::ReadyState>(TextTrack::Loaded), TextTrackEnumLoaded_Is_Wrong_Should_Be_HTMLTrackElementEnumLOADED);
+COMPILE_ASSERT(HTMLTrackElement::TRACK_ERROR == static_cast<HTMLTrackElement::ReadyState>(TextTrack::FailedToLoad), TextTrackEnumFailedToLoad_Is_Wrong_Should_Be_HTMLTrackElementEnumTRACK_ERROR);
+
+void HTMLTrackElement::setReadyState(ReadyState state)
+{
+    ensureTrack()->setReadinessState(static_cast<TextTrack::ReadinessState>(state));
+    if (HTMLMediaElement* parent = mediaElement())
+        return parent->textTrackReadyStateChanged(m_track.get());
+}
+
+HTMLTrackElement::ReadyState HTMLTrackElement::readyState()
+{
+    return static_cast<ReadyState>(ensureTrack()->readinessState());
+}
+
+const AtomicString& HTMLTrackElement::mediaElementCrossOriginAttribute() const
+{
+    if (HTMLMediaElement* parent = mediaElement())
+        return parent->fastGetAttribute(HTMLNames::crossoriginAttr);
+
+    return nullAtom;
+}
+
+void HTMLTrackElement::textTrackKindChanged(TextTrack* track)
+{
+    if (HTMLMediaElement* parent = mediaElement())
+        return parent->textTrackKindChanged(track);
+}
+
+void HTMLTrackElement::textTrackModeChanged(TextTrack* track)
+{
+    // Since we've moved to a new parent, we may now be able to load.
+    if (readyState() == HTMLTrackElement::NONE)
+        scheduleLoad();
+
+    if (HTMLMediaElement* parent = mediaElement())
+        return parent->textTrackModeChanged(track);
+}
+
+void HTMLTrackElement::textTrackAddCues(TextTrack* track, const TextTrackCueList* cues)
+{
+    if (HTMLMediaElement* parent = mediaElement())
+        return parent->textTrackAddCues(track, cues);
+}
+
+void HTMLTrackElement::textTrackRemoveCues(TextTrack* track, const TextTrackCueList* cues)
+{
+    if (HTMLMediaElement* parent = mediaElement())
+        return parent->textTrackRemoveCues(track, cues);
+}
+
+void HTMLTrackElement::textTrackAddCue(TextTrack* track, PassRefPtr<TextTrackCue> cue)
+{
+    if (HTMLMediaElement* parent = mediaElement())
+        return parent->textTrackAddCue(track, cue);
+}
+
+void HTMLTrackElement::textTrackRemoveCue(TextTrack* track, PassRefPtr<TextTrackCue> cue)
+{
+    if (HTMLMediaElement* parent = mediaElement())
+        return parent->textTrackRemoveCue(track, cue);
+}
+
+HTMLMediaElement* HTMLTrackElement::mediaElement() const
+{
+    Element* parent = parentElement();
+    if (parent && parent->isMediaElement())
+        return static_cast<HTMLMediaElement*>(parentNode());
+
+    return 0;
+}
+
+}
+
diff --git a/Source/core/html/HTMLTrackElement.h b/Source/core/html/HTMLTrackElement.h
new file mode 100644
index 0000000..c75cb69
--- /dev/null
+++ b/Source/core/html/HTMLTrackElement.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 HTMLTrackElement_h
+#define HTMLTrackElement_h
+
+#include "core/html/HTMLElement.h"
+#include "core/html/track/LoadableTextTrack.h"
+#include "core/html/track/TextTrack.h"
+
+namespace WebCore {
+
+class HTMLMediaElement;
+
+class HTMLTrackElement FINAL : public HTMLElement, public TextTrackClient {
+public:
+    static PassRefPtr<HTMLTrackElement> create(const QualifiedName&, Document*);
+
+    KURL src() const;
+    void setSrc(const String&);
+
+    String kind();
+    void setKind(const String&);
+
+    String srclang() const;
+    void setSrclang(const String&);
+
+    String label() const;
+    void setLabel(const String&);
+
+    bool isDefault() const;
+    void setIsDefault(bool);
+
+    enum ReadyState { NONE = 0, LOADING = 1, LOADED = 2, TRACK_ERROR = 3 };
+    ReadyState readyState();
+    void setReadyState(ReadyState);
+
+    TextTrack* track();
+
+    void scheduleLoad();
+
+    enum LoadStatus { Failure, Success };
+    virtual void didCompleteLoad(LoadableTextTrack*, LoadStatus);
+
+    const AtomicString& mediaElementCrossOriginAttribute() const;
+
+private:
+    HTMLTrackElement(const QualifiedName&, Document*);
+    virtual ~HTMLTrackElement();
+
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+
+    void loadTimerFired(Timer<HTMLTrackElement>*);
+
+    HTMLMediaElement* mediaElement() const;
+
+    // TextTrackClient
+    virtual void textTrackModeChanged(TextTrack*);
+    virtual void textTrackKindChanged(TextTrack*);
+    virtual void textTrackAddCues(TextTrack*, const TextTrackCueList*);
+    virtual void textTrackRemoveCues(TextTrack*, const TextTrackCueList*);
+    virtual void textTrackAddCue(TextTrack*, PassRefPtr<TextTrackCue>);
+    virtual void textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue>);
+
+    LoadableTextTrack* ensureTrack();
+    virtual bool canLoadUrl(const KURL&);
+
+    RefPtr<LoadableTextTrack> m_track;
+    Timer<HTMLTrackElement> m_loadTimer;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/HTMLTrackElement.idl b/Source/core/html/HTMLTrackElement.idl
new file mode 100644
index 0000000..f0d21f6
--- /dev/null
+++ b/Source/core/html/HTMLTrackElement.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+[
+    EnabledAtRuntime=webkitVideoTrack
+] interface HTMLTrackElement : HTMLElement {
+    attribute DOMString kind;
+    [Reflect, URL] attribute DOMString src;
+    attribute DOMString srclang;
+    attribute DOMString label;
+    [Reflect] attribute boolean default;
+
+    const unsigned short NONE = 0;
+    const unsigned short LOADING = 1;
+    const unsigned short LOADED = 2;
+    // Reflect is used for ERROR because it conflicts with a windows define.
+    [Reflect=TRACK_ERROR] const unsigned short ERROR = 3;
+    readonly attribute unsigned short readyState;
+
+    readonly attribute TextTrack track;
+};
diff --git a/Source/core/html/HTMLUListElement.cpp b/Source/core/html/HTMLUListElement.cpp
new file mode 100644
index 0000000..32b6813
--- /dev/null
+++ b/Source/core/html/HTMLUListElement.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/HTMLUListElement.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLUListElement::HTMLUListElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+    ASSERT(hasTagName(ulTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLUListElement> HTMLUListElement::create(Document* document)
+{
+    return adoptRef(new HTMLUListElement(ulTag, document));
+}
+
+PassRefPtr<HTMLUListElement> HTMLUListElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLUListElement(tagName, document));
+}
+
+bool HTMLUListElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == typeAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLUListElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == typeAttr)
+        addPropertyToPresentationAttributeStyle(style, CSSPropertyListStyleType, value);
+    else
+        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+}
diff --git a/Source/core/html/HTMLUListElement.h b/Source/core/html/HTMLUListElement.h
new file mode 100644
index 0000000..e2447d3
--- /dev/null
+++ b/Source/core/html/HTMLUListElement.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLUListElement_h
+#define HTMLUListElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLUListElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLUListElement> create(Document*);
+    static PassRefPtr<HTMLUListElement> create(const QualifiedName&, Document*);
+
+private:
+    HTMLUListElement(const QualifiedName&, Document*);
+
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLUListElement.idl b/Source/core/html/HTMLUListElement.idl
new file mode 100644
index 0000000..e40350d
--- /dev/null
+++ b/Source/core/html/HTMLUListElement.idl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+interface HTMLUListElement : HTMLElement {
+    [Reflect] attribute boolean compact;
+    [Reflect] attribute DOMString type;
+};
+
diff --git a/Source/core/html/HTMLUnknownElement.h b/Source/core/html/HTMLUnknownElement.h
new file mode 100644
index 0000000..4839654
--- /dev/null
+++ b/Source/core/html/HTMLUnknownElement.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER 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 HTMLUnknownElement_h
+#define HTMLUnknownElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLUnknownElement FINAL : public HTMLElement {
+public:
+    static PassRefPtr<HTMLUnknownElement> create(const QualifiedName& tagName, Document* document)
+    {
+        return adoptRef(new HTMLUnknownElement(tagName, document));
+    }
+
+    virtual bool isHTMLUnknownElement() const OVERRIDE { return true; }
+
+private:
+    HTMLUnknownElement(const QualifiedName& tagName, Document* document)
+        : HTMLElement(tagName, document)
+    {
+        ScriptWrappable::init(this);
+    }
+};
+
+inline HTMLUnknownElement* toHTMLUnknownElement(HTMLElement* element)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!element || element->isHTMLUnknownElement());
+    return static_cast<HTMLUnknownElement*>(element);
+}
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/HTMLUnknownElement.idl b/Source/core/html/HTMLUnknownElement.idl
new file mode 100644
index 0000000..7d7bbc3
--- /dev/null
+++ b/Source/core/html/HTMLUnknownElement.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2011 Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
+ */
+[
+    SkipVTableValidation
+] interface HTMLUnknownElement : HTMLElement {
+};
+
diff --git a/Source/core/html/HTMLVideoElement.cpp b/Source/core/html/HTMLVideoElement.cpp
new file mode 100644
index 0000000..82b8a9c
--- /dev/null
+++ b/Source/core/html/HTMLVideoElement.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+#include "core/html/HTMLVideoElement.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/Document.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/html/HTMLImageLoader.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/page/Chrome.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/rendering/RenderImage.h"
+#include "core/rendering/RenderVideo.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document* document, bool createdByParser)
+    : HTMLMediaElement(tagName, document, createdByParser)
+{
+    ASSERT(hasTagName(videoTag));
+    ScriptWrappable::init(this);
+    if (document->settings())
+        m_defaultPosterURL = document->settings()->defaultVideoPosterURL();
+}
+
+PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
+{
+    RefPtr<HTMLVideoElement> videoElement(adoptRef(new HTMLVideoElement(tagName, document, createdByParser)));
+    videoElement->suspendIfNeeded();
+    return videoElement.release();
+}
+
+bool HTMLVideoElement::rendererIsNeeded(const NodeRenderingContext& context) 
+{
+    return HTMLElement::rendererIsNeeded(context); 
+}
+
+RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderVideo(this);
+}
+
+void HTMLVideoElement::attach()
+{
+    HTMLMediaElement::attach();
+
+    updateDisplayState();
+    if (shouldDisplayPosterImage()) {
+        if (!m_imageLoader)
+            m_imageLoader = adoptPtr(new HTMLImageLoader(this));
+        m_imageLoader->updateFromElement();
+        if (renderer())
+            toRenderImage(renderer())->imageResource()->setCachedImage(m_imageLoader->image()); 
+    }
+}
+
+void HTMLVideoElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
+{
+    if (name == widthAttr)
+        addHTMLLengthToStyle(style, CSSPropertyWidth, value);
+    else if (name == heightAttr)
+        addHTMLLengthToStyle(style, CSSPropertyHeight, value);
+    else
+        HTMLMediaElement::collectStyleForPresentationAttribute(name, value, style);
+}
+
+bool HTMLVideoElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == widthAttr || name == heightAttr)
+        return true;
+    return HTMLMediaElement::isPresentationAttribute(name);
+}
+
+void HTMLVideoElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == posterAttr) {
+        // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.
+        HTMLMediaElement::setDisplayMode(Unknown);
+        updateDisplayState();
+        if (shouldDisplayPosterImage()) {
+            if (!m_imageLoader)
+                m_imageLoader = adoptPtr(new HTMLImageLoader(this));
+            m_imageLoader->updateFromElementIgnoringPreviousError();
+        } else {
+            if (renderer())
+                toRenderImage(renderer())->imageResource()->setCachedImage(0); 
+        }
+    } else
+        HTMLMediaElement::parseAttribute(name, value);
+}
+
+bool HTMLVideoElement::supportsFullscreen() const
+{
+    Page* page = document() ? document()->page() : 0;
+    if (!page) 
+        return false;
+
+    if (!player() || !player()->supportsFullscreen())
+        return false;
+
+    return true;
+}
+
+unsigned HTMLVideoElement::videoWidth() const
+{
+    if (!player())
+        return 0;
+    return player()->naturalSize().width();
+}
+
+unsigned HTMLVideoElement::videoHeight() const
+{
+    if (!player())
+        return 0;
+    return player()->naturalSize().height();
+}
+
+unsigned HTMLVideoElement::width() const
+{
+    bool ok;
+    unsigned w = getAttribute(widthAttr).string().toUInt(&ok);
+    return ok ? w : 0;
+}
+    
+unsigned HTMLVideoElement::height() const
+{
+    bool ok;
+    unsigned h = getAttribute(heightAttr).string().toUInt(&ok);
+    return ok ? h : 0;
+}
+    
+bool HTMLVideoElement::isURLAttribute(const Attribute& attribute) const
+{
+    return attribute.name() == posterAttr || HTMLMediaElement::isURLAttribute(attribute);
+}
+
+const AtomicString& HTMLVideoElement::imageSourceURL() const
+{
+    const AtomicString& url = getAttribute(posterAttr);
+    if (!stripLeadingAndTrailingHTMLSpaces(url).isEmpty())
+        return url;
+    return m_defaultPosterURL;
+}
+
+void HTMLVideoElement::setDisplayMode(DisplayMode mode)
+{
+    DisplayMode oldMode = displayMode();
+    KURL poster = posterImageURL();
+
+    if (!poster.isEmpty()) {
+        // We have a poster path, but only show it until the user triggers display by playing or seeking and the
+        // media engine has something to display.
+        if (mode == Video) {
+            if (oldMode != Video && player())
+                player()->prepareForRendering();
+            if (!hasAvailableVideoFrame())
+                mode = PosterWaitingForVideo;
+        }
+    } else if (oldMode != Video && player())
+        player()->prepareForRendering();
+
+    HTMLMediaElement::setDisplayMode(mode);
+
+    if (player() && player()->canLoadPoster()) {
+        bool canLoad = true;
+        if (!poster.isEmpty()) {
+            Frame* frame = document()->frame();
+            FrameLoader* loader = frame ? frame->loader() : 0;
+            canLoad = loader && loader->willLoadMediaElementURL(poster);
+        }
+        if (canLoad)
+            player()->setPoster(poster);
+    }
+
+    if (renderer() && displayMode() != oldMode)
+        renderer()->updateFromElement();
+}
+
+void HTMLVideoElement::updateDisplayState()
+{
+    if (posterImageURL().isEmpty())
+        setDisplayMode(Video);
+    else if (displayMode() < Poster)
+        setDisplayMode(Poster);
+}
+
+void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect)
+{
+    MediaPlayer* player = HTMLMediaElement::player();
+    if (!player)
+        return;
+    
+    player->setVisible(true); // Make player visible or it won't draw.
+    player->paintCurrentFrameInContext(context, destRect);
+}
+
+bool HTMLVideoElement::copyVideoTextureToPlatformTexture(GraphicsContext3D* context, Platform3DObject texture, GC3Dint level, GC3Denum type, GC3Denum internalFormat, bool premultiplyAlpha, bool flipY)
+{
+    if (!player())
+        return false;
+    return player()->copyVideoTextureToPlatformTexture(context, texture, level, type, internalFormat, premultiplyAlpha, flipY);
+}
+
+bool HTMLVideoElement::hasAvailableVideoFrame() const
+{
+    if (!player())
+        return false;
+    
+    return player()->hasVideo() && player()->hasAvailableVideoFrame();
+}
+
+void HTMLVideoElement::webkitEnterFullscreen(ExceptionCode& ec)
+{
+    if (isFullscreen())
+        return;
+
+    // Generate an exception if this isn't called in response to a user gesture, or if the 
+    // element does not support fullscreen.
+    if ((userGestureRequiredForFullscreen() && !ScriptController::processingUserGesture()) || !supportsFullscreen()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    enterFullscreen();
+}
+
+void HTMLVideoElement::webkitExitFullscreen()
+{
+    if (isFullscreen())
+        exitFullscreen();
+}
+
+bool HTMLVideoElement::webkitSupportsFullscreen()
+{
+    return supportsFullscreen();
+}
+
+bool HTMLVideoElement::webkitDisplayingFullscreen()
+{
+    return isFullscreen();
+}
+
+void HTMLVideoElement::didMoveToNewDocument(Document* oldDocument)
+{
+    if (m_imageLoader)
+        m_imageLoader->elementDidMoveToNewDocument();
+    HTMLMediaElement::didMoveToNewDocument(oldDocument);
+}
+
+unsigned HTMLVideoElement::webkitDecodedFrameCount() const
+{
+    if (!player())
+        return 0;
+
+    return player()->decodedFrameCount();
+}
+
+unsigned HTMLVideoElement::webkitDroppedFrameCount() const
+{
+    if (!player())
+        return 0;
+
+    return player()->droppedFrameCount();
+}
+
+KURL HTMLVideoElement::posterImageURL() const
+{
+    String url = stripLeadingAndTrailingHTMLSpaces(imageSourceURL());
+    if (url.isEmpty())
+        return KURL();
+    return document()->completeURL(url);
+}
+
+}
diff --git a/Source/core/html/HTMLVideoElement.h b/Source/core/html/HTMLVideoElement.h
new file mode 100644
index 0000000..63d42b7
--- /dev/null
+++ b/Source/core/html/HTMLVideoElement.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 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 COMPUTER, 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 COMPUTER, 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 HTMLVideoElement_h
+#define HTMLVideoElement_h
+
+#include "core/html/HTMLMediaElement.h"
+
+namespace WebCore {
+
+class HTMLImageLoader;
+
+class HTMLVideoElement FINAL : public HTMLMediaElement {
+public:
+    static PassRefPtr<HTMLVideoElement> create(const QualifiedName&, Document*, bool);
+
+    unsigned width() const;
+    unsigned height() const;
+    
+    unsigned videoWidth() const;
+    unsigned videoHeight() const;
+    
+    // Fullscreen
+    void webkitEnterFullscreen(ExceptionCode&);
+    void webkitExitFullscreen();
+    bool webkitSupportsFullscreen();
+    bool webkitDisplayingFullscreen();
+
+    // FIXME: Maintain "FullScreen" capitalization scheme for backwards compatibility.
+    // https://bugs.webkit.org/show_bug.cgi?id=36081
+    void webkitEnterFullScreen(ExceptionCode& ec) { webkitEnterFullscreen(ec); }
+    void webkitExitFullScreen() { webkitExitFullscreen(); }
+
+    // Statistics
+    unsigned webkitDecodedFrameCount() const;
+    unsigned webkitDroppedFrameCount() const;
+
+    // Used by canvas to gain raw pixel access
+    void paintCurrentFrameInContext(GraphicsContext*, const IntRect&);
+
+    // Used by WebGL to do GPU-GPU textures copy if possible.
+    // See more details at MediaPlayer::copyVideoTextureToPlatformTexture() defined in Source/WebCore/platform/graphics/MediaPlayer.h.
+    bool copyVideoTextureToPlatformTexture(GraphicsContext3D*, Platform3DObject texture, GC3Dint level, GC3Denum type, GC3Denum internalFormat, bool premultiplyAlpha, bool flipY);
+
+    bool shouldDisplayPosterImage() const { return displayMode() == Poster || displayMode() == PosterWaitingForVideo; }
+
+    KURL posterImageURL() const;
+
+private:
+    HTMLVideoElement(const QualifiedName&, Document*, bool);
+
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual void attach();
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
+    virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
+    virtual bool isVideo() const { return true; }
+    virtual bool hasVideo() const { return player() && player()->hasVideo(); }
+    virtual bool supportsFullscreen() const;
+    virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
+    virtual const AtomicString& imageSourceURL() const OVERRIDE;
+
+    virtual bool hasAvailableVideoFrame() const;
+    virtual void updateDisplayState();
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+    virtual void setDisplayMode(DisplayMode);
+
+    OwnPtr<HTMLImageLoader> m_imageLoader;
+
+    AtomicString m_defaultPosterURL;
+};
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/HTMLVideoElement.idl b/Source/core/html/HTMLVideoElement.idl
new file mode 100644
index 0000000..5b0cf38
--- /dev/null
+++ b/Source/core/html/HTMLVideoElement.idl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007, 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+interface HTMLVideoElement : HTMLMediaElement {
+    [Reflect] attribute unsigned long width;
+    [Reflect] attribute unsigned long height;
+    readonly attribute unsigned long videoWidth;
+    readonly attribute unsigned long videoHeight;
+    [Reflect, URL] attribute DOMString poster;
+
+    readonly attribute boolean webkitSupportsFullscreen;
+    readonly attribute boolean webkitDisplayingFullscreen;
+
+    [RaisesException] void webkitEnterFullscreen();
+    void webkitExitFullscreen();
+
+    // Note the different capitalization of the "S" in FullScreen.
+    [RaisesException] void webkitEnterFullScreen();
+    void webkitExitFullScreen();
+
+    // The number of frames that have been decoded and made available for
+    // playback.
+    readonly attribute unsigned long webkitDecodedFrameCount;
+
+    // The number of decoded frames that have been dropped by the player
+    // for performance reasons during playback.
+    readonly attribute unsigned long webkitDroppedFrameCount;
+};
diff --git a/Source/core/html/HTMLViewSourceDocument.cpp b/Source/core/html/HTMLViewSourceDocument.cpp
new file mode 100644
index 0000000..aee8471
--- /dev/null
+++ b/Source/core/html/HTMLViewSourceDocument.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2006, 2008, 2009, 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 "core/html/HTMLViewSourceDocument.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/DOMImplementation.h"
+#include "core/dom/DocumentStyleSheetCollection.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLAnchorElement.h"
+#include "core/html/HTMLBRElement.h"
+#include "core/html/HTMLBaseElement.h"
+#include "core/html/HTMLBodyElement.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLHtmlElement.h"
+#include "core/html/HTMLTableCellElement.h"
+#include "core/html/HTMLTableElement.h"
+#include "core/html/HTMLTableRowElement.h"
+#include "core/html/HTMLTableSectionElement.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/html/parser/HTMLViewSourceParser.h"
+#include "core/html/parser/TextViewSourceParser.h"
+#include "core/platform/text/SegmentedString.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLViewSourceDocument::HTMLViewSourceDocument(Frame* frame, const KURL& url, const String& mimeType)
+    : HTMLDocument(frame, url)
+    , m_type(mimeType)
+{
+    styleSheetCollection()->setUsesBeforeAfterRulesOverride(true);
+    setIsViewSource(true);
+
+    setCompatibilityMode(QuirksMode);
+    lockCompatibilityMode();
+}
+
+PassRefPtr<DocumentParser> HTMLViewSourceDocument::createParser()
+{
+    if (m_type == "text/html" || m_type == "application/xhtml+xml" || m_type == "image/svg+xml" || DOMImplementation::isXMLMIMEType(m_type))
+        return HTMLViewSourceParser::create(this);
+
+    return TextViewSourceParser::create(this);
+}
+
+void HTMLViewSourceDocument::createContainingTable()
+{
+    RefPtr<HTMLHtmlElement> html = HTMLHtmlElement::create(this);
+    parserAppendChild(html);
+    html->attach();
+    RefPtr<HTMLBodyElement> body = HTMLBodyElement::create(this);
+    html->parserAppendChild(body);
+    body->attach();
+
+    // Create a line gutter div that can be used to make sure the gutter extends down the height of the whole
+    // document.
+    RefPtr<HTMLDivElement> div = HTMLDivElement::create(this);
+    div->setAttribute(classAttr, "webkit-line-gutter-backdrop");
+    body->parserAppendChild(div);
+    div->attach();
+
+    RefPtr<HTMLTableElement> table = HTMLTableElement::create(this);
+    body->parserAppendChild(table);
+    table->attach();
+    m_tbody = HTMLTableSectionElement::create(tbodyTag, this);
+    table->parserAppendChild(m_tbody);
+    m_tbody->attach();
+    m_current = m_tbody;
+}
+
+void HTMLViewSourceDocument::addSource(const String& source, HTMLToken& token)
+{
+    if (!m_current)
+        createContainingTable();
+
+    switch (token.type()) {
+    case HTMLToken::Uninitialized:
+        ASSERT_NOT_REACHED();
+        break;
+    case HTMLToken::DOCTYPE:
+        processDoctypeToken(source, token);
+        break;
+    case HTMLToken::EndOfFile:
+        if (!m_tbody->hasChildNodes())
+            addLine(String());
+        break;
+    case HTMLToken::StartTag:
+    case HTMLToken::EndTag:
+        processTagToken(source, token);
+        break;
+    case HTMLToken::Comment:
+        processCommentToken(source, token);
+        break;
+    case HTMLToken::Character:
+        processCharacterToken(source, token);
+        break;
+    }
+}
+
+void HTMLViewSourceDocument::processDoctypeToken(const String& source, HTMLToken&)
+{
+    if (!m_current)
+        createContainingTable();
+    m_current = addSpanWithClassName("webkit-html-doctype");
+    addText(source, "webkit-html-doctype");
+    m_current = m_td;
+}
+
+void HTMLViewSourceDocument::processTagToken(const String& source, HTMLToken& token)
+{
+    m_current = addSpanWithClassName("webkit-html-tag");
+
+    AtomicString tagName(token.name());
+
+    unsigned index = 0;
+    HTMLToken::AttributeList::const_iterator iter = token.attributes().begin();
+    while (index < source.length()) {
+        if (iter == token.attributes().end()) {
+            // We want to show the remaining characters in the token.
+            index = addRange(source, index, source.length(), "");
+            ASSERT(index == source.length());
+            break;
+        }
+
+        AtomicString name(iter->name);
+        String value = StringImpl::create8BitIfPossible(iter->value);
+
+        index = addRange(source, index, iter->nameRange.start - token.startIndex(), "");
+        index = addRange(source, index, iter->nameRange.end - token.startIndex(), "webkit-html-attribute-name");
+
+        if (tagName == baseTag && name == hrefAttr)
+            m_current = addBase(value);
+
+        index = addRange(source, index, iter->valueRange.start - token.startIndex(), "");
+
+        bool isLink = name == srcAttr || name == hrefAttr;
+        index = addRange(source, index, iter->valueRange.end - token.startIndex(), "webkit-html-attribute-value", isLink, tagName == aTag, value);
+
+        ++iter;
+    }
+    m_current = m_td;
+}
+
+void HTMLViewSourceDocument::processCommentToken(const String& source, HTMLToken&)
+{
+    m_current = addSpanWithClassName("webkit-html-comment");
+    addText(source, "webkit-html-comment");
+    m_current = m_td;
+}
+
+void HTMLViewSourceDocument::processCharacterToken(const String& source, HTMLToken&)
+{
+    addText(source, "");
+}
+
+PassRefPtr<Element> HTMLViewSourceDocument::addSpanWithClassName(const AtomicString& className)
+{
+    if (m_current == m_tbody) {
+        addLine(className);
+        return m_current;
+    }
+
+    RefPtr<HTMLElement> span = HTMLElement::create(spanTag, this);
+    span->setAttribute(classAttr, className);
+    m_current->parserAppendChild(span);
+    span->attach();
+    return span.release();
+}
+
+void HTMLViewSourceDocument::addLine(const AtomicString& className)
+{
+    // Create a table row.
+    RefPtr<HTMLTableRowElement> trow = HTMLTableRowElement::create(this);
+    m_tbody->parserAppendChild(trow);
+    trow->attach();
+
+    // Create a cell that will hold the line number (it is generated in the stylesheet using counters).
+    RefPtr<HTMLTableCellElement> td = HTMLTableCellElement::create(tdTag, this);
+    td->setAttribute(classAttr, "webkit-line-number");
+    trow->parserAppendChild(td);
+    td->attach();
+
+    // Create a second cell for the line contents
+    td = HTMLTableCellElement::create(tdTag, this);
+    td->setAttribute(classAttr, "webkit-line-content");
+    trow->parserAppendChild(td);
+    td->attach();
+    m_current = m_td = td;
+
+#ifdef DEBUG_LINE_NUMBERS
+    RefPtr<Text> lineNumberText = Text::create(this, String::number(parser()->lineNumber() + 1) + " ");
+    td->addChild(lineNumberText);
+    lineNumberText->attach();
+#endif
+
+    // Open up the needed spans.
+    if (!className.isEmpty()) {
+        if (className == "webkit-html-attribute-name" || className == "webkit-html-attribute-value")
+            m_current = addSpanWithClassName("webkit-html-tag");
+        m_current = addSpanWithClassName(className);
+    }
+}
+
+void HTMLViewSourceDocument::finishLine()
+{
+    if (!m_current->hasChildNodes()) {
+        RefPtr<HTMLBRElement> br = HTMLBRElement::create(this);
+        m_current->parserAppendChild(br);
+        br->attach();
+    }
+    m_current = m_tbody;
+}
+
+void HTMLViewSourceDocument::addText(const String& text, const AtomicString& className)
+{
+    if (text.isEmpty())
+        return;
+
+    // Add in the content, splitting on newlines.
+    Vector<String> lines;
+    text.split('\n', true, lines);
+    unsigned size = lines.size();
+    for (unsigned i = 0; i < size; i++) {
+        String substring = lines[i];
+        if (m_current == m_tbody)
+            addLine(className);
+        if (substring.isEmpty()) {
+            if (i == size - 1)
+                break;
+            finishLine();
+            continue;
+        }
+        RefPtr<Text> t = Text::create(this, substring);
+        m_current->parserAppendChild(t);
+        t->attach();
+        if (i < size - 1)
+            finishLine();
+    }
+}
+
+int HTMLViewSourceDocument::addRange(const String& source, int start, int end, const String& className, bool isLink, bool isAnchor, const String& link)
+{
+    ASSERT(start <= end);
+    if (start == end)
+        return start;
+
+    String text = source.substring(start, end - start);
+    if (!className.isEmpty()) {
+        if (isLink)
+            m_current = addLink(link, isAnchor);
+        else
+            m_current = addSpanWithClassName(className);
+    }
+    addText(text, className);
+    if (!className.isEmpty() && m_current != m_tbody)
+        m_current = toElement(m_current->parentNode());
+    return end;
+}
+
+PassRefPtr<Element> HTMLViewSourceDocument::addBase(const AtomicString& href)
+{
+    RefPtr<HTMLBaseElement> base = HTMLBaseElement::create(baseTag, this);
+    base->setAttribute(hrefAttr, href);
+    m_current->parserAppendChild(base);
+    base->attach();
+    return base.release();
+}
+
+PassRefPtr<Element> HTMLViewSourceDocument::addLink(const AtomicString& url, bool isAnchor)
+{
+    if (m_current == m_tbody)
+        addLine("webkit-html-tag");
+
+    // Now create a link for the attribute value instead of a span.
+    RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::create(this);
+    const char* classValue;
+    if (isAnchor)
+        classValue = "webkit-html-attribute-value webkit-html-external-link";
+    else
+        classValue = "webkit-html-attribute-value webkit-html-resource-link";
+    anchor->setAttribute(classAttr, classValue);
+    anchor->setAttribute(targetAttr, "_blank");
+    anchor->setAttribute(hrefAttr, url);
+    m_current->parserAppendChild(anchor);
+    anchor->attach();
+    return anchor.release();
+}
+
+}
diff --git a/Source/core/html/HTMLViewSourceDocument.h b/Source/core/html/HTMLViewSourceDocument.h
new file mode 100644
index 0000000..c81953f
--- /dev/null
+++ b/Source/core/html/HTMLViewSourceDocument.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006, 2008, 2009 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 HTMLViewSourceDocument_h
+#define HTMLViewSourceDocument_h
+
+#include "core/html/HTMLDocument.h"
+
+namespace WebCore {
+
+class HTMLTableCellElement;
+class HTMLTableSectionElement;
+class HTMLToken;
+
+class HTMLViewSourceDocument FINAL : public HTMLDocument {
+public:
+    static PassRefPtr<HTMLViewSourceDocument> create(Frame* frame, const KURL& url, const String& mimeType)
+    {
+        return adoptRef(new HTMLViewSourceDocument(frame, url, mimeType));
+    }
+
+    void addSource(const String&, HTMLToken&);
+
+private:
+    HTMLViewSourceDocument(Frame*, const KURL&, const String& mimeType);
+
+    // Returns HTMLViewSourceParser or TextDocumentParser based on m_type.
+    virtual PassRefPtr<DocumentParser> createParser();
+
+    void processDoctypeToken(const String& source, HTMLToken&);
+    void processTagToken(const String& source, HTMLToken&);
+    void processCommentToken(const String& source, HTMLToken&);
+    void processCharacterToken(const String& source, HTMLToken&);
+
+    void createContainingTable();
+    PassRefPtr<Element> addSpanWithClassName(const AtomicString&);
+    void addLine(const AtomicString& className);
+    void finishLine();
+    void addText(const String& text, const AtomicString& className);
+    int addRange(const String& source, int start, int end, const String& className, bool isLink = false, bool isAnchor = false, const String& link = String());
+    PassRefPtr<Element> addLink(const AtomicString& url, bool isAnchor);
+    PassRefPtr<Element> addBase(const AtomicString& href);
+
+    String m_type;
+    RefPtr<Element> m_current;
+    RefPtr<HTMLTableSectionElement> m_tbody;
+    RefPtr<HTMLTableCellElement> m_td;
+};
+
+}
+
+#endif // HTMLViewSourceDocument_h
diff --git a/Source/core/html/HiddenInputType.cpp b/Source/core/html/HiddenInputType.cpp
new file mode 100644
index 0000000..b48060d
--- /dev/null
+++ b/Source/core/html/HiddenInputType.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/HiddenInputType.h"
+
+#include "HTMLNames.h"
+#include "core/html/FormController.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+PassOwnPtr<InputType> HiddenInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new HiddenInputType(element));
+}
+
+const AtomicString& HiddenInputType::formControlType() const
+{
+    return InputTypeNames::hidden();
+}
+
+FormControlState HiddenInputType::saveFormControlState() const
+{
+    // valueAttributeWasUpdatedAfterParsing() never be true for form
+    // controls create by createElement() or cloneNode(). It's ok for
+    // now because we restore values only to form controls created by
+    // parsing.
+    return element()->valueAttributeWasUpdatedAfterParsing() ? FormControlState(element()->value()) : FormControlState();
+}
+
+void HiddenInputType::restoreFormControlState(const FormControlState& state)
+{
+    element()->setAttribute(valueAttr, state[0]);
+}
+
+bool HiddenInputType::supportsValidation() const
+{
+    return false;
+}
+
+RenderObject* HiddenInputType::createRenderer(RenderArena*, RenderStyle*) const
+{
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+void HiddenInputType::accessKeyAction(bool)
+{
+}
+
+bool HiddenInputType::rendererIsNeeded()
+{
+    return false;
+}
+
+bool HiddenInputType::storesValueSeparateFromAttribute()
+{
+    return false;
+}
+
+void HiddenInputType::setValue(const String& sanitizedValue, bool, TextFieldEventBehavior)
+{
+    element()->setAttribute(valueAttr, sanitizedValue);
+}
+
+bool HiddenInputType::isHiddenType() const
+{
+    return true;
+}
+
+bool HiddenInputType::appendFormData(FormDataList& encoding, bool isMultipartForm) const
+{
+    if (equalIgnoringCase(element()->name(), "_charset_")) {
+        encoding.appendData(element()->name(), String(encoding.encoding().name()));
+        return true;
+    }
+    return InputType::appendFormData(encoding, isMultipartForm);
+}
+
+bool HiddenInputType::shouldRespectHeightAndWidthAttributes()
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/HiddenInputType.h b/Source/core/html/HiddenInputType.h
new file mode 100644
index 0000000..d6af8c2
--- /dev/null
+++ b/Source/core/html/HiddenInputType.h
@@ -0,0 +1,61 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 HiddenInputType_h
+#define HiddenInputType_h
+
+#include "core/html/InputType.h"
+
+namespace WebCore {
+
+class HiddenInputType : public InputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    HiddenInputType(HTMLInputElement* element) : InputType(element) { }
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual FormControlState saveFormControlState() const OVERRIDE;
+    virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
+    virtual bool supportsValidation() const OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
+    virtual void accessKeyAction(bool sendMouseEvents) OVERRIDE;
+    virtual bool rendererIsNeeded() OVERRIDE;
+    virtual bool storesValueSeparateFromAttribute() OVERRIDE;
+    virtual bool isHiddenType() const OVERRIDE;
+    virtual bool supportLabels() const OVERRIDE { return false; }
+    virtual bool shouldRespectHeightAndWidthAttributes() OVERRIDE;
+    virtual void setValue(const String&, bool, TextFieldEventBehavior) OVERRIDE;
+    virtual bool appendFormData(FormDataList&, bool) const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // HiddenInputType_h
diff --git a/Source/core/html/ImageData.cpp b/Source/core/html/ImageData.cpp
new file mode 100644
index 0000000..eae5ed6
--- /dev/null
+++ b/Source/core/html/ImageData.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/html/ImageData.h"
+
+namespace WebCore {
+
+PassRefPtr<ImageData> ImageData::create(const IntSize& size)
+{
+    Checked<int, RecordOverflow> dataSize = 4;
+    dataSize *= size.width();
+    dataSize *= size.height();
+    if (dataSize.hasOverflowed())
+        return 0;
+
+    return adoptRef(new ImageData(size));
+}
+
+PassRefPtr<ImageData> ImageData::create(const IntSize& size, PassRefPtr<Uint8ClampedArray> byteArray)
+{
+    Checked<int, RecordOverflow> dataSize = 4;
+    dataSize *= size.width();
+    dataSize *= size.height();
+    if (dataSize.hasOverflowed())
+        return 0;
+
+    if (dataSize.unsafeGet() < 0
+        || static_cast<unsigned>(dataSize.unsafeGet()) > byteArray->length())
+        return 0;
+
+    return adoptRef(new ImageData(size, byteArray));
+}
+
+ImageData::ImageData(const IntSize& size)
+    : m_size(size)
+    , m_data(Uint8ClampedArray::createUninitialized(size.width() * size.height() * 4))
+{
+}
+
+ImageData::ImageData(const IntSize& size, PassRefPtr<Uint8ClampedArray> byteArray)
+    : m_size(size)
+    , m_data(byteArray)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(static_cast<unsigned>(size.width() * size.height() * 4) <= m_data->length());
+}
+
+}
+
diff --git a/Source/core/html/ImageData.h b/Source/core/html/ImageData.h
new file mode 100644
index 0000000..6e3b13d
--- /dev/null
+++ b/Source/core/html/ImageData.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008, 2009 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 ImageData_h
+#define ImageData_h
+
+#include "core/platform/graphics/IntSize.h"
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Uint8ClampedArray.h>
+
+namespace WebCore {
+
+class ImageData : public RefCounted<ImageData> {
+public:
+    static PassRefPtr<ImageData> create(const IntSize&);
+    static PassRefPtr<ImageData> create(const IntSize&, PassRefPtr<Uint8ClampedArray>);
+
+    IntSize size() const { return m_size; }
+    int width() const { return m_size.width(); }
+    int height() const { return m_size.height(); }
+    Uint8ClampedArray* data() const { return m_data.get(); }
+
+private:
+    ImageData(const IntSize&);
+    ImageData(const IntSize&, PassRefPtr<Uint8ClampedArray>);
+
+    IntSize m_size;
+    RefPtr<Uint8ClampedArray> m_data;
+};
+
+} // namespace WebCore
+
+#endif // ImageData_h
diff --git a/Source/core/html/ImageData.idl b/Source/core/html/ImageData.idl
new file mode 100644
index 0000000..180eb78
--- /dev/null
+++ b/Source/core/html/ImageData.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008, 2009 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+[
+    CustomToV8,
+    ImplementationLacksVTable
+] interface ImageData {
+    readonly attribute long width;
+    readonly attribute long height;
+};
+
diff --git a/Source/core/html/ImageDocument.cpp b/Source/core/html/ImageDocument.cpp
new file mode 100644
index 0000000..0d7e79d
--- /dev/null
+++ b/Source/core/html/ImageDocument.cpp
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 "core/html/ImageDocument.h"
+
+#include "HTMLNames.h"
+#include "core/dom/EventListener.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/RawDataDocumentParser.h"
+#include "core/html/HTMLHtmlElement.h"
+#include "core/html/HTMLImageElement.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/loader/cache/CachedImage.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/NotImplemented.h"
+
+using std::min;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+class ImageEventListener : public EventListener {
+public:
+    static PassRefPtr<ImageEventListener> create(ImageDocument* document) { return adoptRef(new ImageEventListener(document)); }
+    static const ImageEventListener* cast(const EventListener* listener)
+    {
+        return listener->type() == ImageEventListenerType
+            ? static_cast<const ImageEventListener*>(listener)
+            : 0;
+    }
+
+    virtual bool operator==(const EventListener& other);
+
+private:
+    ImageEventListener(ImageDocument* document)
+        : EventListener(ImageEventListenerType)
+        , m_doc(document)
+    {
+    }
+
+    virtual void handleEvent(ScriptExecutionContext*, Event*);
+
+    ImageDocument* m_doc;
+};
+    
+class ImageDocumentParser : public RawDataDocumentParser {
+public:
+    static PassRefPtr<ImageDocumentParser> create(ImageDocument* document)
+    {
+        return adoptRef(new ImageDocumentParser(document));
+    }
+
+    ImageDocument* document() const
+    {
+        return toImageDocument(RawDataDocumentParser::document());
+    }
+    
+private:
+    ImageDocumentParser(ImageDocument* document)
+        : RawDataDocumentParser(document)
+    {
+    }
+
+    virtual void appendBytes(DocumentWriter*, const char*, size_t);
+    virtual void finish();
+};
+
+class ImageDocumentElement FINAL : public HTMLImageElement {
+public:
+    static PassRefPtr<ImageDocumentElement> create(ImageDocument*);
+
+private:
+    ImageDocumentElement(ImageDocument* document)
+        : HTMLImageElement(imgTag, document)
+        , m_imageDocument(document)
+    {
+    }
+
+    virtual ~ImageDocumentElement();
+    virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
+
+    ImageDocument* m_imageDocument;
+};
+
+inline PassRefPtr<ImageDocumentElement> ImageDocumentElement::create(ImageDocument* document)
+{
+    return adoptRef(new ImageDocumentElement(document));
+}
+
+// --------
+
+static float pageZoomFactor(const Document* document)
+{
+    Frame* frame = document->frame();
+    return frame ? frame->pageZoomFactor() : 1;
+}
+
+void ImageDocumentParser::appendBytes(DocumentWriter*, const char* data, size_t length)
+{
+    Frame* frame = document()->frame();
+    Settings* settings = frame->settings();
+    if (!frame->loader()->client()->allowImage(!settings || settings->areImagesEnabled(), document()->url()))
+        return;
+
+    document()->cachedImage()->appendData(data, length);
+    document()->imageUpdated();
+}
+
+void ImageDocumentParser::finish()
+{
+    if (!isStopped() && document()->imageElement()) {
+        CachedImage* cachedImage = document()->cachedImage();
+        cachedImage->finish();
+        cachedImage->setResponse(document()->frame()->loader()->documentLoader()->response());
+
+        // Report the natural image size in the page title, regardless of zoom level.
+        // At a zoom level of 1 the image is guaranteed to have an integer size.
+        IntSize size = flooredIntSize(cachedImage->imageSizeForRenderer(document()->imageElement()->renderer(), 1.0f));
+        if (size.width()) {
+            // Compute the title, we use the decoded filename of the resource, falling
+            // back on the (decoded) hostname if there is no path.
+            String fileName = decodeURLEscapeSequences(document()->url().lastPathComponent());
+            if (fileName.isEmpty())
+                fileName = document()->url().host();
+            document()->setTitle(imageTitle(fileName, size));
+        }
+
+        document()->imageUpdated();
+    }
+
+    document()->finishedParsing();
+}
+    
+// --------
+
+ImageDocument::ImageDocument(Frame* frame, const KURL& url)
+    : HTMLDocument(frame, url)
+    , m_imageElement(0)
+    , m_imageSizeIsKnown(false)
+    , m_didShrinkImage(false)
+    , m_shouldShrinkImage(shouldShrinkToFit())
+{
+    setCompatibilityMode(QuirksMode);
+    lockCompatibilityMode();
+}
+    
+PassRefPtr<DocumentParser> ImageDocument::createParser()
+{
+    return ImageDocumentParser::create(this);
+}
+
+void ImageDocument::createDocumentStructure()
+{
+    RefPtr<Element> rootElement = Document::createElement(htmlTag, false);
+    appendChild(rootElement, IGNORE_EXCEPTION);
+    static_cast<HTMLHtmlElement*>(rootElement.get())->insertedByParser();
+
+    if (frame() && frame()->loader())
+        frame()->loader()->dispatchDocumentElementAvailable();
+    
+    RefPtr<Element> body = Document::createElement(bodyTag, false);
+    body->setAttribute(styleAttr, "margin: 0px;");
+    
+    rootElement->appendChild(body, IGNORE_EXCEPTION);
+    
+    RefPtr<ImageDocumentElement> imageElement = ImageDocumentElement::create(this);
+    
+    imageElement->setAttribute(styleAttr, "-webkit-user-select: none");        
+    imageElement->setLoadManually(true);
+    imageElement->setSrc(url().string());
+    
+    body->appendChild(imageElement, IGNORE_EXCEPTION);
+    
+    if (shouldShrinkToFit()) {
+        // Add event listeners
+        RefPtr<EventListener> listener = ImageEventListener::create(this);
+        if (DOMWindow* domWindow = this->domWindow())
+            domWindow->addEventListener("resize", listener, false);
+        imageElement->addEventListener("click", listener.release(), false);
+    }
+
+    m_imageElement = imageElement.get();
+}
+
+float ImageDocument::scale() const
+{
+    if (!m_imageElement)
+        return 1.0f;
+
+    FrameView* view = frame()->view();
+    if (!view)
+        return 1;
+
+    LayoutSize imageSize = m_imageElement->cachedImage()->imageSizeForRenderer(m_imageElement->renderer(), pageZoomFactor(this));
+    LayoutSize windowSize = LayoutSize(view->width(), view->height());
+    
+    float widthScale = (float)windowSize.width() / imageSize.width();
+    float heightScale = (float)windowSize.height() / imageSize.height();
+
+    return min(widthScale, heightScale);
+}
+
+void ImageDocument::resizeImageToFit()
+{
+    if (!m_imageElement)
+        return;
+
+    LayoutSize imageSize = m_imageElement->cachedImage()->imageSizeForRenderer(m_imageElement->renderer(), pageZoomFactor(this));
+
+    float scale = this->scale();
+    m_imageElement->setWidth(static_cast<int>(imageSize.width() * scale));
+    m_imageElement->setHeight(static_cast<int>(imageSize.height() * scale));
+    
+    m_imageElement->setInlineStyleProperty(CSSPropertyCursor, "-webkit-zoom-in", false);
+}
+
+void ImageDocument::imageClicked(int x, int y)
+{
+    if (!m_imageSizeIsKnown || imageFitsInWindow())
+        return;
+
+    m_shouldShrinkImage = !m_shouldShrinkImage;
+    
+    if (m_shouldShrinkImage)
+        windowSizeChanged();
+    else {
+        restoreImageSize();
+        
+        updateLayout();
+        
+        float scale = this->scale();
+        
+        int scrollX = static_cast<int>(x / scale - (float)frame()->view()->width() / 2);
+        int scrollY = static_cast<int>(y / scale - (float)frame()->view()->height() / 2);
+        
+        frame()->view()->setScrollPosition(IntPoint(scrollX, scrollY));
+    }
+}
+
+void ImageDocument::imageUpdated()
+{
+    ASSERT(m_imageElement);
+    
+    if (m_imageSizeIsKnown)
+        return;
+
+    if (m_imageElement->cachedImage()->imageSizeForRenderer(m_imageElement->renderer(), pageZoomFactor(this)).isEmpty())
+        return;
+    
+    m_imageSizeIsKnown = true;
+    
+    if (shouldShrinkToFit()) {
+        // Force resizing of the image
+        windowSizeChanged();
+    }
+}
+
+void ImageDocument::restoreImageSize()
+{
+    if (!m_imageElement || !m_imageSizeIsKnown)
+        return;
+    
+    LayoutSize imageSize = m_imageElement->cachedImage()->imageSizeForRenderer(m_imageElement->renderer(), 1.0f);
+    m_imageElement->setWidth(imageSize.width());
+    m_imageElement->setHeight(imageSize.height());
+    
+    if (imageFitsInWindow())
+        m_imageElement->removeInlineStyleProperty(CSSPropertyCursor);
+    else
+        m_imageElement->setInlineStyleProperty(CSSPropertyCursor, "-webkit-zoom-out", false);
+        
+    m_didShrinkImage = false;
+}
+
+bool ImageDocument::imageFitsInWindow() const
+{
+    if (!m_imageElement)
+        return true;
+
+    FrameView* view = frame()->view();
+    if (!view)
+        return true;
+
+    LayoutSize imageSize = m_imageElement->cachedImage()->imageSizeForRenderer(m_imageElement->renderer(), pageZoomFactor(this));
+    LayoutSize windowSize = LayoutSize(view->width(), view->height());
+    
+    return imageSize.width() <= windowSize.width() && imageSize.height() <= windowSize.height();    
+}
+
+void ImageDocument::windowSizeChanged()
+{
+    if (!m_imageElement || !m_imageSizeIsKnown)
+        return;
+
+    bool fitsInWindow = imageFitsInWindow();
+    
+    // If the image has been explicitly zoomed in, restore the cursor if the image fits
+    // and set it to a zoom out cursor if the image doesn't fit
+    if (!m_shouldShrinkImage) {
+        if (fitsInWindow)
+            m_imageElement->removeInlineStyleProperty(CSSPropertyCursor);
+        else
+            m_imageElement->setInlineStyleProperty(CSSPropertyCursor, "-webkit-zoom-out", false);
+        return;
+    }
+    
+    if (m_didShrinkImage) {
+        // If the window has been resized so that the image fits, restore the image size
+        // otherwise update the restored image size.
+        if (fitsInWindow)
+            restoreImageSize();
+        else
+            resizeImageToFit();
+    } else {
+        // If the image isn't resized but needs to be, then resize it.
+        if (!fitsInWindow) {
+            resizeImageToFit();
+            m_didShrinkImage = true;
+        }
+    }
+}
+
+CachedImage* ImageDocument::cachedImage()
+{ 
+    if (!m_imageElement)
+        createDocumentStructure();
+    
+    return m_imageElement->cachedImage();
+}
+
+bool ImageDocument::shouldShrinkToFit() const
+{
+    return frame()->page()->settings()->shrinksStandaloneImagesToFit() &&
+        frame()->page()->mainFrame() == frame();
+}
+
+// --------
+
+void ImageEventListener::handleEvent(ScriptExecutionContext*, Event* event)
+{
+    if (event->type() == eventNames().resizeEvent)
+        m_doc->windowSizeChanged();
+    else if (event->type() == eventNames().clickEvent && event->isMouseEvent()) {
+        MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+        m_doc->imageClicked(mouseEvent->x(), mouseEvent->y());
+    }
+}
+
+bool ImageEventListener::operator==(const EventListener& listener)
+{
+    if (const ImageEventListener* imageEventListener = ImageEventListener::cast(&listener))
+        return m_doc == imageEventListener->m_doc;
+    return false;
+}
+
+// --------
+
+ImageDocumentElement::~ImageDocumentElement()
+{
+    if (m_imageDocument)
+        m_imageDocument->disconnectImageElement();
+}
+
+void ImageDocumentElement::didMoveToNewDocument(Document* oldDocument)
+{
+    if (m_imageDocument) {
+        m_imageDocument->disconnectImageElement();
+        m_imageDocument = 0;
+    }
+    HTMLImageElement::didMoveToNewDocument(oldDocument);
+}
+
+}
diff --git a/Source/core/html/ImageDocument.h b/Source/core/html/ImageDocument.h
new file mode 100644
index 0000000..6f94404
--- /dev/null
+++ b/Source/core/html/ImageDocument.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 ImageDocument_h
+#define ImageDocument_h
+
+#include "core/html/HTMLDocument.h"
+
+namespace WebCore {
+
+class CachedImage;
+class ImageDocumentElement;
+
+class ImageDocument FINAL : public HTMLDocument {
+public:
+    static PassRefPtr<ImageDocument> create(Frame* frame, const KURL& url)
+    {
+        return adoptRef(new ImageDocument(frame, url));
+    }
+
+    CachedImage* cachedImage();
+    ImageDocumentElement* imageElement() const { return m_imageElement; }
+    void disconnectImageElement() { m_imageElement = 0; }
+    
+    void windowSizeChanged();
+    void imageUpdated();
+    void imageClicked(int x, int y);
+
+private:
+    ImageDocument(Frame*, const KURL&);
+
+    virtual PassRefPtr<DocumentParser> createParser();
+    virtual bool isImageDocument() const { return true; }
+    
+    void createDocumentStructure();
+    void resizeImageToFit();
+    void restoreImageSize();
+    bool imageFitsInWindow() const;
+    bool shouldShrinkToFit() const;
+    float scale() const;
+    
+    ImageDocumentElement* m_imageElement;
+    
+    // Whether enough of the image has been loaded to determine its size
+    bool m_imageSizeIsKnown;
+    
+    // Whether the image is shrunk to fit or not
+    bool m_didShrinkImage;
+    
+    // Whether the image should be shrunk or not
+    bool m_shouldShrinkImage;
+};
+
+inline ImageDocument* toImageDocument(Document* document)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!document || document->isImageDocument());
+    return static_cast<ImageDocument*>(document);
+}
+
+inline const ImageDocument* toImageDocument(const Document* document)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!document || document->isImageDocument());
+    return static_cast<const ImageDocument*>(document);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toImageDocument(const ImageDocument*);
+
+}
+
+#endif // ImageDocument_h
diff --git a/Source/core/html/ImageInputType.cpp b/Source/core/html/ImageInputType.cpp
new file mode 100644
index 0000000..eef34da
--- /dev/null
+++ b/Source/core/html/ImageInputType.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2012 Samsung Electronics. 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/ImageInputType.h"
+
+#include "HTMLNames.h"
+#include "core/dom/MouseEvent.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLImageLoader.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/cache/CachedImage.h"
+#include "core/rendering/RenderImage.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline ImageInputType::ImageInputType(HTMLInputElement* element)
+    : BaseButtonInputType(element)
+{
+}
+
+PassOwnPtr<InputType> ImageInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new ImageInputType(element));
+}
+
+const AtomicString& ImageInputType::formControlType() const
+{
+    return InputTypeNames::image();
+}
+
+bool ImageInputType::isFormDataAppendable() const
+{
+    return true;
+}
+
+bool ImageInputType::appendFormData(FormDataList& encoding, bool) const
+{
+    if (!element()->isActivatedSubmit())
+        return false;
+    const AtomicString& name = element()->name();
+    if (name.isEmpty()) {
+        encoding.appendData("x", m_clickLocation.x());
+        encoding.appendData("y", m_clickLocation.y());
+        return true;
+    }
+
+    DEFINE_STATIC_LOCAL(String, dotXString, (ASCIILiteral(".x")));
+    DEFINE_STATIC_LOCAL(String, dotYString, (ASCIILiteral(".y")));
+    encoding.appendData(name + dotXString, m_clickLocation.x());
+    encoding.appendData(name + dotYString, m_clickLocation.y());
+
+    if (!element()->value().isEmpty())
+        encoding.appendData(name, element()->value());
+    return true;
+}
+
+bool ImageInputType::supportsValidation() const
+{
+    return false;
+}
+
+void ImageInputType::handleDOMActivateEvent(Event* event)
+{
+    RefPtr<HTMLInputElement> element = this->element();
+    if (element->isDisabledFormControl() || !element->form())
+        return;
+    element->setActivatedSubmit(true);
+    if (event->underlyingEvent() && event->underlyingEvent()->isMouseEvent()) {
+        MouseEvent* mouseEvent = static_cast<MouseEvent*>(event->underlyingEvent());
+        m_clickLocation = IntPoint(mouseEvent->offsetX(), mouseEvent->offsetY());
+    } else
+        m_clickLocation = IntPoint();
+    element->form()->prepareForSubmission(event); // Event handlers can run.
+    element->setActivatedSubmit(false);
+    event->setDefaultHandled();
+}
+
+RenderObject* ImageInputType::createRenderer(RenderArena* arena, RenderStyle*) const
+{
+    RenderImage* image = new (arena) RenderImage(element());
+    image->setImageResource(RenderImageResource::create());
+    return image;
+}
+
+void ImageInputType::altAttributeChanged()
+{
+    RenderImage* image = toRenderImage(element()->renderer());
+    if (!image)
+        return;
+    image->updateAltText();
+}
+
+void ImageInputType::srcAttributeChanged()
+{
+    if (!element()->renderer())
+        return;
+    element()->imageLoader()->updateFromElementIgnoringPreviousError();
+}
+
+void ImageInputType::attach()
+{
+    BaseButtonInputType::attach();
+
+    HTMLImageLoader* imageLoader = element()->imageLoader();
+    imageLoader->updateFromElement();
+
+    RenderImage* renderer = toRenderImage(element()->renderer());
+    if (!renderer)
+        return;
+
+    if (imageLoader->hasPendingBeforeLoadEvent())
+        return;
+
+    RenderImageResource* imageResource = renderer->imageResource();
+    imageResource->setCachedImage(imageLoader->image()); 
+
+    // If we have no image at all because we have no src attribute, set
+    // image height and width for the alt text instead.
+    if (!imageLoader->image() && !imageResource->cachedImage())
+        renderer->setImageSizeForAltText();
+}
+
+bool ImageInputType::shouldRespectAlignAttribute()
+{
+    return true;
+}
+
+bool ImageInputType::canBeSuccessfulSubmitButton()
+{
+    return true;
+}
+
+bool ImageInputType::isImageButton() const
+{
+    return true;
+}
+
+bool ImageInputType::isEnumeratable()
+{
+    return false;
+}
+
+bool ImageInputType::shouldRespectHeightAndWidthAttributes()
+{
+    return true;
+}
+
+unsigned ImageInputType::height() const
+{
+    RefPtr<HTMLInputElement> element = this->element();
+
+    if (!element->renderer()) {
+        // Check the attribute first for an explicit pixel value.
+        unsigned height;
+        if (parseHTMLNonNegativeInteger(element->fastGetAttribute(heightAttr), height))
+            return height;
+
+        // If the image is available, use its height.
+        if (element->hasImageLoader()) {
+            HTMLImageLoader* imageLoader = element->imageLoader();
+            if (imageLoader->image())
+                return imageLoader->image()->imageSizeForRenderer(element->renderer(), 1).height();
+        }
+    }
+
+    element->document()->updateLayout();
+
+    RenderBox* box = element->renderBox();
+    return box ? adjustForAbsoluteZoom(box->contentHeight(), box) : 0;
+}
+
+unsigned ImageInputType::width() const
+{
+    RefPtr<HTMLInputElement> element = this->element();
+
+    if (!element->renderer()) {
+        // Check the attribute first for an explicit pixel value.
+        unsigned width;
+        if (parseHTMLNonNegativeInteger(element->fastGetAttribute(widthAttr), width))
+            return width;
+
+        // If the image is available, use its width.
+        if (element->hasImageLoader()) {
+            HTMLImageLoader* imageLoader = element->imageLoader();
+            if (imageLoader->image())
+                return imageLoader->image()->imageSizeForRenderer(element->renderer(), 1).width();
+        }
+    }
+
+    element->document()->updateLayout();
+
+    RenderBox* box = element->renderBox();
+    return box ? adjustForAbsoluteZoom(box->contentWidth(), box) : 0;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/ImageInputType.h b/Source/core/html/ImageInputType.h
new file mode 100644
index 0000000..ebaca90
--- /dev/null
+++ b/Source/core/html/ImageInputType.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Samsung Electronics. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 ImageInputType_h
+#define ImageInputType_h
+
+#include "core/html/BaseButtonInputType.h"
+#include "core/platform/graphics/IntPoint.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class ImageInputType : public BaseButtonInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    ImageInputType(HTMLInputElement*);
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool isFormDataAppendable() const OVERRIDE;
+    virtual bool appendFormData(FormDataList&, bool) const OVERRIDE;
+    virtual bool supportsValidation() const OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
+    virtual void handleDOMActivateEvent(Event*) OVERRIDE;
+    virtual void altAttributeChanged() OVERRIDE;
+    virtual void srcAttributeChanged() OVERRIDE;
+    virtual void attach() OVERRIDE;
+    virtual bool shouldRespectAlignAttribute() OVERRIDE;
+    virtual bool canBeSuccessfulSubmitButton() OVERRIDE;
+    virtual bool isImageButton() const OVERRIDE;
+    virtual bool isEnumeratable() OVERRIDE;
+    virtual bool shouldRespectHeightAndWidthAttributes() OVERRIDE;
+    virtual unsigned height() const OVERRIDE;
+    virtual unsigned width() const OVERRIDE;
+
+    IntPoint m_clickLocation; // Valid only during HTMLFormElement::prepareForSubmission().
+};
+
+} // namespace WebCore
+
+#endif // ImageInputType_h
diff --git a/Source/core/html/InputType.cpp b/Source/core/html/InputType.cpp
new file mode 100644
index 0000000..2458eaf
--- /dev/null
+++ b/Source/core/html/InputType.cpp
@@ -0,0 +1,1126 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
+ * Copyright (C) 2009, 2010, 2011, 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2012 Samsung Electronics. 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/InputType.h"
+
+#include <limits>
+#include "HTMLNames.h"
+#include "core/accessibility/AXObjectCache.h"
+#include "core/dom/BeforeTextInsertedEvent.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/NodeRenderStyle.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/fileapi/FileList.h"
+#include "core/html/ButtonInputType.h"
+#include "core/html/CheckboxInputType.h"
+#include "core/html/ColorInputType.h"
+#include "core/html/DateInputType.h"
+#include "core/html/DateTimeInputType.h"
+#include "core/html/DateTimeLocalInputType.h"
+#include "core/html/EmailInputType.h"
+#include "core/html/FileInputType.h"
+#include "core/html/FormController.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/HiddenInputType.h"
+#include "core/html/ImageInputType.h"
+#include "core/html/InputTypeNames.h"
+#include "core/html/MonthInputType.h"
+#include "core/html/NumberInputType.h"
+#include "core/html/PasswordInputType.h"
+#include "core/html/RadioInputType.h"
+#include "core/html/RangeInputType.h"
+#include "core/html/ResetInputType.h"
+#include "core/html/SearchInputType.h"
+#include "core/html/SubmitInputType.h"
+#include "core/html/TelephoneInputType.h"
+#include "core/html/TextInputType.h"
+#include "core/html/TimeInputType.h"
+#include "core/html/URLInputType.h"
+#include "core/html/WeekInputType.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/shadow/HTMLShadowElement.h"
+#include "core/page/Page.h"
+#include "RuntimeEnabledFeatures.h"
+#include "core/platform/DateComponents.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/text/TextBreakIterator.h"
+#include "core/rendering/RenderObject.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace std;
+
+typedef PassOwnPtr<InputType> (*InputTypeFactoryFunction)(HTMLInputElement*);
+typedef HashMap<AtomicString, InputTypeFactoryFunction, CaseFoldingHash> InputTypeFactoryMap;
+
+static PassOwnPtr<InputTypeFactoryMap> createInputTypeFactoryMap()
+{
+    OwnPtr<InputTypeFactoryMap> map = adoptPtr(new InputTypeFactoryMap);
+    map->add(InputTypeNames::button(), ButtonInputType::create);
+    map->add(InputTypeNames::checkbox(), CheckboxInputType::create);
+#if ENABLE(INPUT_TYPE_COLOR)
+    map->add(InputTypeNames::color(), ColorInputType::create);
+#endif
+    map->add(InputTypeNames::date(), DateInputType::create);
+#if ENABLE(INPUT_TYPE_DATETIME_INCOMPLETE)
+    if (RuntimeEnabledFeatures::inputTypeDateTimeEnabled())
+        map->add(InputTypeNames::datetime(), DateTimeInputType::create);
+#endif
+    map->add(InputTypeNames::datetimelocal(), DateTimeLocalInputType::create);
+    map->add(InputTypeNames::email(), EmailInputType::create);
+    map->add(InputTypeNames::file(), FileInputType::create);
+    map->add(InputTypeNames::hidden(), HiddenInputType::create);
+    map->add(InputTypeNames::image(), ImageInputType::create);
+    map->add(InputTypeNames::month(), MonthInputType::create);
+    map->add(InputTypeNames::number(), NumberInputType::create);
+    map->add(InputTypeNames::password(), PasswordInputType::create);
+    map->add(InputTypeNames::radio(), RadioInputType::create);
+    map->add(InputTypeNames::range(), RangeInputType::create);
+    map->add(InputTypeNames::reset(), ResetInputType::create);
+    map->add(InputTypeNames::search(), SearchInputType::create);
+    map->add(InputTypeNames::submit(), SubmitInputType::create);
+    map->add(InputTypeNames::telephone(), TelephoneInputType::create);
+    map->add(InputTypeNames::time(), TimeInputType::create);
+    map->add(InputTypeNames::url(), URLInputType::create);
+    if (RuntimeEnabledFeatures::inputTypeWeekEnabled())
+        map->add(InputTypeNames::week(), WeekInputType::create);
+    // No need to register "text" because it is the default type.
+    return map.release();
+}
+
+PassOwnPtr<InputType> InputType::create(HTMLInputElement* element, const AtomicString& typeName)
+{
+    static const InputTypeFactoryMap* factoryMap = createInputTypeFactoryMap().leakPtr();
+    PassOwnPtr<InputType> (*factory)(HTMLInputElement*) = typeName.isEmpty() ? 0 : factoryMap->get(typeName);
+    if (!factory)
+        factory = TextInputType::create;
+    return factory(element);
+}
+
+PassOwnPtr<InputType> InputType::createText(HTMLInputElement* element)
+{
+    return TextInputType::create(element);
+}
+
+InputType::~InputType()
+{
+}
+
+bool InputType::themeSupportsDataListUI(InputType* type)
+{
+    Document* document = type->element()->document();
+    RefPtr<RenderTheme> theme = document->page() ? document->page()->theme() : RenderTheme::defaultTheme();
+    return theme->supportsDataListUI(type->formControlType());
+}
+
+bool InputType::isTextField() const
+{
+    return false;
+}
+
+bool InputType::isTextType() const
+{
+    return false;
+}
+
+bool InputType::isRangeControl() const
+{
+    return false;
+}
+
+bool InputType::shouldSaveAndRestoreFormControlState() const
+{
+    return true;
+}
+
+FormControlState InputType::saveFormControlState() const
+{
+    String currentValue = element()->value();
+    if (currentValue == element()->defaultValue())
+        return FormControlState();
+    return FormControlState(currentValue);
+}
+
+void InputType::restoreFormControlState(const FormControlState& state)
+{
+    element()->setValue(state[0]);
+}
+
+bool InputType::isFormDataAppendable() const
+{
+    // There is no form data unless there's a name for non-image types.
+    return !element()->name().isEmpty();
+}
+
+bool InputType::appendFormData(FormDataList& encoding, bool) const
+{
+    // Always successful.
+    encoding.appendData(element()->name(), element()->value());
+    return true;
+}
+
+double InputType::valueAsDate() const
+{
+    return DateComponents::invalidMilliseconds();
+}
+
+void InputType::setValueAsDate(double, ExceptionCode& ec) const
+{
+    ec = INVALID_STATE_ERR;
+}
+
+double InputType::valueAsDouble() const
+{
+    return numeric_limits<double>::quiet_NaN();
+}
+
+void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
+{
+    setValueAsDecimal(Decimal::fromDouble(doubleValue), eventBehavior, ec);
+}
+
+void InputType::setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode& ec) const
+{
+    ec = INVALID_STATE_ERR;
+}
+
+bool InputType::supportsValidation() const
+{
+    return true;
+}
+
+bool InputType::typeMismatchFor(const String&) const
+{
+    return false;
+}
+
+bool InputType::typeMismatch() const
+{
+    return false;
+}
+
+bool InputType::supportsRequired() const
+{
+    // Almost all validatable types support @required.
+    return supportsValidation();
+}
+
+bool InputType::valueMissing(const String&) const
+{
+    return false;
+}
+
+bool InputType::hasBadInput() const
+{
+    return false;
+}
+
+bool InputType::patternMismatch(const String&) const
+{
+    return false;
+}
+
+bool InputType::rangeUnderflow(const String& value) const
+{
+    if (!isSteppable())
+        return false;
+
+    const Decimal numericValue = parseToNumberOrNaN(value);
+    if (!numericValue.isFinite())
+        return false;
+
+    return numericValue < createStepRange(RejectAny).minimum();
+}
+
+bool InputType::rangeOverflow(const String& value) const
+{
+    if (!isSteppable())
+        return false;
+
+    const Decimal numericValue = parseToNumberOrNaN(value);
+    if (!numericValue.isFinite())
+        return false;
+
+    return numericValue > createStepRange(RejectAny).maximum();
+}
+
+Decimal InputType::defaultValueForStepUp() const
+{
+    return 0;
+}
+
+double InputType::minimum() const
+{
+    return createStepRange(RejectAny).minimum().toDouble();
+}
+
+double InputType::maximum() const
+{
+    return createStepRange(RejectAny).maximum().toDouble();
+}
+
+bool InputType::sizeShouldIncludeDecoration(int, int& preferredSize) const
+{
+    preferredSize = element()->size();
+    return false;
+}
+
+bool InputType::isInRange(const String& value) const
+{
+    if (!isSteppable())
+        return false;
+
+    const Decimal numericValue = parseToNumberOrNaN(value);
+    if (!numericValue.isFinite())
+        return true;
+
+    StepRange stepRange(createStepRange(RejectAny));
+    return numericValue >= stepRange.minimum() && numericValue <= stepRange.maximum();
+}
+
+bool InputType::isOutOfRange(const String& value) const
+{
+    if (!isSteppable())
+        return false;
+
+    const Decimal numericValue = parseToNumberOrNaN(value);
+    if (!numericValue.isFinite())
+        return true;
+
+    StepRange stepRange(createStepRange(RejectAny));
+    return numericValue < stepRange.minimum() || numericValue > stepRange.maximum();
+}
+
+bool InputType::stepMismatch(const String& value) const
+{
+    if (!isSteppable())
+        return false;
+
+    const Decimal numericValue = parseToNumberOrNaN(value);
+    if (!numericValue.isFinite())
+        return false;
+
+    return createStepRange(RejectAny).stepMismatch(numericValue);
+}
+
+String InputType::badInputText() const
+{
+    ASSERT_NOT_REACHED();
+    return validationMessageTypeMismatchText();
+}
+
+String InputType::typeMismatchText() const
+{
+    return validationMessageTypeMismatchText();
+}
+
+String InputType::valueMissingText() const
+{
+    return validationMessageValueMissingText();
+}
+
+String InputType::validationMessage() const
+{
+    const String value = element()->value();
+
+    // The order of the following checks is meaningful. e.g. We'd like to show the
+    // badInput message even if the control has other validation errors.
+    if (hasBadInput())
+        return badInputText();
+
+    if (valueMissing(value))
+        return valueMissingText();
+
+    if (typeMismatch())
+        return typeMismatchText();
+
+    if (patternMismatch(value))
+        return validationMessagePatternMismatchText();
+
+    if (element()->tooLong())
+        return validationMessageTooLongText(numGraphemeClusters(value), element()->maxLength());
+
+    if (!isSteppable())
+        return emptyString();
+
+    const Decimal numericValue = parseToNumberOrNaN(value);
+    if (!numericValue.isFinite())
+        return emptyString();
+
+    StepRange stepRange(createStepRange(RejectAny));
+
+    if (numericValue < stepRange.minimum())
+        return validationMessageRangeUnderflowText(serialize(stepRange.minimum()));
+
+    if (numericValue > stepRange.maximum())
+        return validationMessageRangeOverflowText(serialize(stepRange.maximum()));
+
+    if (stepRange.stepMismatch(numericValue)) {
+        const String stepString = stepRange.hasStep() ? serializeForNumberType(stepRange.step() / stepRange.stepScaleFactor()) : emptyString();
+        return validationMessageStepMismatchText(serialize(stepRange.stepBase()), stepString);
+    }
+
+    return emptyString();
+}
+
+void InputType::handleClickEvent(MouseEvent*)
+{
+}
+
+void InputType::handleMouseDownEvent(MouseEvent*)
+{
+}
+
+void InputType::handleDOMActivateEvent(Event*)
+{
+}
+
+void InputType::handleKeydownEvent(KeyboardEvent*)
+{
+}
+
+void InputType::handleKeypressEvent(KeyboardEvent*)
+{
+}
+
+void InputType::handleKeyupEvent(KeyboardEvent*)
+{
+}
+
+void InputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*)
+{
+}
+
+void InputType::handleTouchEvent(TouchEvent*)
+{
+}
+
+void InputType::forwardEvent(Event*)
+{
+}
+
+bool InputType::shouldSubmitImplicitly(Event* event)
+{
+    return event->isKeyboardEvent() && event->type() == eventNames().keypressEvent && static_cast<KeyboardEvent*>(event)->charCode() == '\r';
+}
+
+PassRefPtr<HTMLFormElement> InputType::formForSubmission() const
+{
+    return element()->form();
+}
+
+RenderObject* InputType::createRenderer(RenderArena*, RenderStyle* style) const
+{
+    return RenderObject::createObject(element(), style);
+}
+
+PassRefPtr<RenderStyle> InputType::customStyleForRenderer(PassRefPtr<RenderStyle> originalStyle)
+{
+    return originalStyle;
+}
+
+void InputType::blur()
+{
+    element()->defaultBlur();
+}
+
+void InputType::createShadowSubtree()
+{
+}
+
+void InputType::destroyShadowSubtree()
+{
+    ShadowRoot* root = element()->userAgentShadowRoot();
+    if (!root)
+        return;
+
+    root->removeChildren();
+
+    // It's ok to clear contents of all other ShadowRoots because they must have
+    // been created by TextFieldDecorationElement, and we don't allow adding
+    // AuthorShadowRoot to HTMLInputElement.
+    while ((root = root->youngerShadowRoot())) {
+        root->removeChildren();
+        root->appendChild(HTMLShadowElement::create(shadowTag, element()->document()));
+    }
+}
+
+Decimal InputType::parseToNumber(const String&, const Decimal& defaultValue) const
+{
+    ASSERT_NOT_REACHED();
+    return defaultValue;
+}
+
+Decimal InputType::parseToNumberOrNaN(const String& string) const
+{
+    return parseToNumber(string, Decimal::nan());
+}
+
+bool InputType::parseToDateComponents(const String&, DateComponents*) const
+{
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+String InputType::serialize(const Decimal&) const
+{
+    ASSERT_NOT_REACHED();
+    return String();
+}
+
+void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const
+{
+    if (element()->active())
+        element()->dispatchSimulatedClick(event);
+    event->setDefaultHandled();
+}
+
+Chrome* InputType::chrome() const
+{
+    if (Page* page = element()->document()->page())
+        return page->chrome();
+    return 0;
+}
+
+bool InputType::canSetStringValue() const
+{
+    return true;
+}
+
+bool InputType::hasCustomFocusLogic() const
+{
+    return true;
+}
+
+bool InputType::isKeyboardFocusable(KeyboardEvent* event) const
+{
+    return element()->isTextFormControlKeyboardFocusable(event);
+}
+
+bool InputType::isMouseFocusable() const
+{
+    return element()->isTextFormControlMouseFocusable();
+}
+
+bool InputType::shouldUseInputMethod() const
+{
+    return false;
+}
+
+void InputType::handleFocusEvent(Node*, FocusDirection)
+{
+}
+
+void InputType::handleBlurEvent()
+{
+}
+
+void InputType::accessKeyAction(bool)
+{
+    element()->focus(false);
+}
+
+void InputType::addSearchResult()
+{
+}
+
+void InputType::attach()
+{
+}
+
+void InputType::detach()
+{
+}
+
+void InputType::altAttributeChanged()
+{
+}
+
+void InputType::srcAttributeChanged()
+{
+}
+
+bool InputType::shouldRespectAlignAttribute()
+{
+    return false;
+}
+
+bool InputType::canChangeFromAnotherType() const
+{
+    return true;
+}
+
+void InputType::minOrMaxAttributeChanged()
+{
+}
+
+void InputType::stepAttributeChanged()
+{
+}
+
+bool InputType::canBeSuccessfulSubmitButton()
+{
+    return false;
+}
+
+HTMLElement* InputType::placeholderElement() const
+{
+    return 0;
+}
+
+bool InputType::rendererIsNeeded()
+{
+    return true;
+}
+
+FileList* InputType::files()
+{
+    return 0;
+}
+
+void InputType::setFiles(PassRefPtr<FileList>)
+{
+}
+
+bool InputType::getTypeSpecificValue(String&)
+{
+    return false;
+}
+
+String InputType::fallbackValue() const
+{
+    return String();
+}
+
+String InputType::defaultValue() const
+{
+    return String();
+}
+
+bool InputType::canSetSuggestedValue()
+{
+    return false;
+}
+
+bool InputType::shouldSendChangeEventAfterCheckedChanged()
+{
+    return true;
+}
+
+bool InputType::storesValueSeparateFromAttribute()
+{
+    return true;
+}
+
+void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
+{
+    element()->setValueInternal(sanitizedValue, eventBehavior);
+    element()->setNeedsStyleRecalc();
+    if (!valueChanged)
+        return;
+    switch (eventBehavior) {
+    case DispatchChangeEvent:
+        element()->dispatchFormControlChangeEvent();
+        break;
+    case DispatchInputAndChangeEvent:
+        element()->dispatchFormControlInputEvent();
+        element()->dispatchFormControlChangeEvent();
+        break;
+    case DispatchNoEvent:
+        break;
+    }
+}
+
+bool InputType::canSetValue(const String&)
+{
+    return true;
+}
+
+PassOwnPtr<ClickHandlingState> InputType::willDispatchClick()
+{
+    return nullptr;
+}
+
+void InputType::didDispatchClick(Event*, const ClickHandlingState&)
+{
+}
+
+String InputType::localizeValue(const String& proposedValue) const
+{
+    return proposedValue;
+}
+
+String InputType::visibleValue() const
+{
+    return element()->value();
+}
+
+String InputType::sanitizeValue(const String& proposedValue) const
+{
+    return proposedValue;
+}
+
+bool InputType::receiveDroppedFiles(const DragData*)
+{
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+String InputType::droppedFileSystemId()
+{
+    ASSERT_NOT_REACHED();
+    return String();
+}
+
+Icon* InputType::icon() const
+{
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+bool InputType::shouldResetOnDocumentActivation()
+{
+    return false;
+}
+
+bool InputType::shouldRespectListAttribute()
+{
+    return false;
+}
+
+bool InputType::shouldRespectSpeechAttribute()
+{
+    return false;
+}
+
+bool InputType::isTextButton() const
+{
+    return false;
+}
+
+bool InputType::isRadioButton() const
+{
+    return false;
+}
+
+bool InputType::isSearchField() const
+{
+    return false;
+}
+
+bool InputType::isHiddenType() const
+{
+    return false;
+}
+
+bool InputType::isPasswordField() const
+{
+    return false;
+}
+
+bool InputType::isCheckbox() const
+{
+    return false;
+}
+
+bool InputType::isEmailField() const
+{
+    return false;
+}
+
+bool InputType::isFileUpload() const
+{
+    return false;
+}
+
+bool InputType::isImageButton() const
+{
+    return false;
+}
+
+bool InputType::supportLabels() const
+{
+    return true;
+}
+
+bool InputType::isNumberField() const
+{
+    return false;
+}
+
+bool InputType::isSubmitButton() const
+{
+    return false;
+}
+
+bool InputType::isTelephoneField() const
+{
+    return false;
+}
+
+bool InputType::isURLField() const
+{
+    return false;
+}
+
+bool InputType::isDateField() const
+{
+    return false;
+}
+
+bool InputType::isDateTimeField() const
+{
+    return false;
+}
+
+bool InputType::isDateTimeLocalField() const
+{
+    return false;
+}
+
+bool InputType::isMonthField() const
+{
+    return false;
+}
+
+bool InputType::isTimeField() const
+{
+    return false;
+}
+
+bool InputType::isWeekField() const
+{
+    return false;
+}
+
+bool InputType::isEnumeratable()
+{
+    return true;
+}
+
+bool InputType::isCheckable()
+{
+    return false;
+}
+
+bool InputType::isSteppable() const
+{
+    return false;
+}
+
+#if ENABLE(INPUT_TYPE_COLOR)
+bool InputType::isColorControl() const
+{
+    return false;
+}
+#endif
+
+bool InputType::shouldRespectHeightAndWidthAttributes()
+{
+    return false;
+}
+
+bool InputType::supportsPlaceholder() const
+{
+    return false;
+}
+
+bool InputType::supportsReadOnly() const
+{
+    return false;
+}
+
+void InputType::updateInnerTextValue()
+{
+}
+
+void InputType::updatePlaceholderText()
+{
+}
+
+void InputType::attributeChanged()
+{
+}
+
+void InputType::multipleAttributeChanged()
+{
+}
+
+void InputType::disabledAttributeChanged()
+{
+}
+
+void InputType::readonlyAttributeChanged()
+{
+}
+
+void InputType::requiredAttributeChanged()
+{
+}
+
+void InputType::valueAttributeChanged()
+{
+}
+
+void InputType::subtreeHasChanged()
+{
+    ASSERT_NOT_REACHED();
+}
+
+bool InputType::hasTouchEventHandler() const
+{
+    return false;
+}
+
+String InputType::defaultToolTip() const
+{
+    return String();
+}
+
+#if ENABLE(DATALIST_ELEMENT)
+void InputType::listAttributeTargetChanged()
+{
+}
+
+Decimal InputType::findClosestTickMarkValue(const Decimal&)
+{
+    ASSERT_NOT_REACHED();
+    return Decimal::nan();
+}
+#endif
+
+void InputType::updateClearButtonVisibility()
+{
+}
+
+bool InputType::supportsIndeterminateAppearance() const
+{
+    return false;
+}
+
+bool InputType::supportsSelectionAPI() const
+{
+    return false;
+}
+
+unsigned InputType::height() const
+{
+    return 0;
+}
+
+unsigned InputType::width() const
+{
+    return 0;
+}
+
+void InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionCode& ec)
+{
+    StepRange stepRange(createStepRange(anyStepHandling));
+    if (!stepRange.hasStep()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    const Decimal current = parseToNumberOrNaN(element()->value());
+    if (!current.isFinite()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    Decimal newValue = current + stepRange.step() * count;
+    if (!newValue.isFinite()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    const Decimal acceptableErrorValue = stepRange.acceptableError();
+    if (newValue - stepRange.minimum() < -acceptableErrorValue) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    if (newValue < stepRange.minimum())
+        newValue = stepRange.minimum();
+
+    const AtomicString& stepString = element()->fastGetAttribute(stepAttr);
+    if (!equalIgnoringCase(stepString, "any"))
+        newValue = stepRange.alignValueForStep(current, newValue);
+
+    if (newValue - stepRange.maximum() > acceptableErrorValue) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    if (newValue > stepRange.maximum())
+        newValue = stepRange.maximum();
+
+    setValueAsDecimal(newValue, eventBehavior, ec);
+
+    if (AXObjectCache* cache = element()->document()->existingAXObjectCache())
+        cache->postNotification(element(), AXObjectCache::AXValueChanged, true);
+}
+
+bool InputType::getAllowedValueStep(Decimal* step) const
+{
+    StepRange stepRange(createStepRange(RejectAny));
+    *step = stepRange.step();
+    return stepRange.hasStep();
+}
+
+StepRange InputType::createStepRange(AnyStepHandling) const
+{
+    ASSERT_NOT_REACHED();
+    return StepRange();
+}
+
+void InputType::stepUp(int n, ExceptionCode& ec)
+{
+    if (!isSteppable()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    applyStep(n, RejectAny, DispatchNoEvent, ec);
+}
+
+void InputType::stepUpFromRenderer(int n)
+{
+    // The differences from stepUp()/stepDown():
+    //
+    // Difference 1: the current value
+    // If the current value is not a number, including empty, the current value is assumed as 0.
+    //   * If 0 is in-range, and matches to step value
+    //     - The value should be the +step if n > 0
+    //     - The value should be the -step if n < 0
+    //     If -step or +step is out of range, new value should be 0.
+    //   * If 0 is smaller than the minimum value
+    //     - The value should be the minimum value for any n
+    //   * If 0 is larger than the maximum value
+    //     - The value should be the maximum value for any n
+    //   * If 0 is in-range, but not matched to step value
+    //     - The value should be the larger matched value nearest to 0 if n > 0
+    //       e.g. <input type=number min=-100 step=3> -> 2
+    //     - The value should be the smaler matched value nearest to 0 if n < 0
+    //       e.g. <input type=number min=-100 step=3> -> -1
+    //   As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time".
+    //   As for datetime type, the current value is assumed as "the current date/time in UTC".
+    // If the current value is smaller than the minimum value:
+    //  - The value should be the minimum value if n > 0
+    //  - Nothing should happen if n < 0
+    // If the current value is larger than the maximum value:
+    //  - The value should be the maximum value if n < 0
+    //  - Nothing should happen if n > 0
+    //
+    // Difference 2: clamping steps
+    // If the current value is not matched to step value:
+    // - The value should be the larger matched value nearest to 0 if n > 0
+    //   e.g. <input type=number value=3 min=-100 step=3> -> 5
+    // - The value should be the smaler matched value nearest to 0 if n < 0
+    //   e.g. <input type=number value=3 min=-100 step=3> -> 2
+    //
+    // n is assumed as -n if step < 0.
+
+    ASSERT(isSteppable());
+    if (!isSteppable())
+        return;
+    ASSERT(n);
+    if (!n)
+        return;
+
+    StepRange stepRange(createStepRange(AnyIsDefaultStep));
+
+    // FIXME: Not any changes after stepping, even if it is an invalid value, may be better.
+    // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo")
+    if (!stepRange.hasStep())
+      return;
+
+    const Decimal step = stepRange.step();
+
+    int sign;
+    if (step > 0)
+        sign = n;
+    else if (step < 0)
+        sign = -n;
+    else
+        sign = 0;
+
+    String currentStringValue = element()->value();
+    Decimal current = parseToNumberOrNaN(currentStringValue);
+    if (!current.isFinite()) {
+        current = defaultValueForStepUp();
+        const Decimal nextDiff = step * n;
+        if (current < stepRange.minimum() - nextDiff)
+            current = stepRange.minimum() - nextDiff;
+        if (current > stepRange.maximum() - nextDiff)
+            current = stepRange.maximum() - nextDiff;
+        setValueAsDecimal(current, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+    }
+    if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum()))
+        setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+    else {
+        if (stepMismatch(element()->value())) {
+            ASSERT(!step.isZero());
+            const Decimal base = stepRange.stepBase();
+            Decimal newValue;
+            if (sign < 0)
+                newValue = base + ((current - base) / step).floor() * step;
+            else if (sign > 0)
+                newValue = base + ((current - base) / step).ceiling() * step;
+            else
+                newValue = current;
+
+            if (newValue < stepRange.minimum())
+                newValue = stepRange.minimum();
+            if (newValue > stepRange.maximum())
+                newValue = stepRange.maximum();
+
+            setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
+            if (n > 1)
+                applyStep(n - 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+            else if (n < -1)
+                applyStep(n + 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+        } else
+            applyStep(n, AnyIsDefaultStep, DispatchInputAndChangeEvent, IGNORE_EXCEPTION);
+    }
+}
+
+void InputType::observeFeatureIfVisible(UseCounter::Feature feature) const
+{
+    if (RenderStyle* style = element()->renderStyle()) {
+        if (style->visibility() != HIDDEN)
+            UseCounter::count(element()->document(), feature);
+    }
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/InputType.h b/Source/core/html/InputType.h
new file mode 100644
index 0000000..0d35e1b
--- /dev/null
+++ b/Source/core/html/InputType.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Samsung Electronics. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 InputType_h
+#define InputType_h
+
+#include "core/html/HTMLTextFormControlElement.h"
+#include "core/html/StepRange.h"
+#include "core/page/UseCounter.h"
+#include <wtf/FastAllocBase.h>
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class BeforeTextInsertedEvent;
+class Chrome;
+class Color;
+class DateComponents;
+class DragData;
+class Event;
+class FileList;
+class FormDataList;
+class HTMLElement;
+class HTMLFormElement;
+class HTMLInputElement;
+class Icon;
+class KeyboardEvent;
+class MouseEvent;
+class Node;
+class RenderArena;
+class RenderObject;
+class RenderStyle;
+class TouchEvent;
+
+typedef int ExceptionCode;
+
+struct ClickHandlingState {
+    WTF_MAKE_FAST_ALLOCATED;
+  
+public:
+    bool checked;
+    bool indeterminate;
+    RefPtr<HTMLInputElement> checkedRadioButton;
+};
+
+// An InputType object represents the type-specific part of an HTMLInputElement.
+// Do not expose instances of InputType and classes derived from it to classes
+// other than HTMLInputElement.
+class InputType {
+    WTF_MAKE_NONCOPYABLE(InputType);
+    WTF_MAKE_FAST_ALLOCATED;
+
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*, const AtomicString&);
+    static PassOwnPtr<InputType> createText(HTMLInputElement*);
+    virtual ~InputType();
+
+    static bool themeSupportsDataListUI(InputType*);
+
+    virtual const AtomicString& formControlType() const = 0;
+    virtual bool canChangeFromAnotherType() const;
+
+    // Type query functions
+
+    // Any time we are using one of these functions it's best to refactor
+    // to add a virtual function to allow the input type object to do the
+    // work instead, or at least make a query function that asks a higher
+    // level question. These functions make the HTMLInputElement class
+    // inflexible because it's harder to add new input types if there is
+    // scattered code with special cases for various types.
+
+#if ENABLE(INPUT_TYPE_COLOR)
+    virtual bool isColorControl() const;
+#endif
+    virtual bool isCheckbox() const;
+    virtual bool isDateField() const;
+    virtual bool isDateTimeField() const;
+    virtual bool isDateTimeLocalField() const;
+    virtual bool isEmailField() const;
+    virtual bool isFileUpload() const;
+    virtual bool isHiddenType() const;
+    virtual bool isImageButton() const;
+    virtual bool supportLabels() const;
+    virtual bool isMonthField() const;
+    virtual bool isNumberField() const;
+    virtual bool isPasswordField() const;
+    virtual bool isRadioButton() const;
+    virtual bool isRangeControl() const;
+    virtual bool isSearchField() const;
+    virtual bool isSubmitButton() const;
+    virtual bool isTelephoneField() const;
+    virtual bool isTextButton() const;
+    virtual bool isTextField() const;
+    virtual bool isTextType() const;
+    virtual bool isTimeField() const;
+    virtual bool isURLField() const;
+    virtual bool isWeekField() const;
+
+    // Form value functions
+
+    virtual bool shouldSaveAndRestoreFormControlState() const;
+    virtual FormControlState saveFormControlState() const;
+    virtual void restoreFormControlState(const FormControlState&);
+    virtual bool isFormDataAppendable() const;
+    virtual bool appendFormData(FormDataList&, bool multipart) const;
+
+    // DOM property functions
+
+    virtual bool getTypeSpecificValue(String&); // Checked first, before internal storage or the value attribute.
+    virtual String fallbackValue() const; // Checked last, if both internal storage and value attribute are missing.
+    virtual String defaultValue() const; // Checked after even fallbackValue, only when the valueWithDefault function is called.
+    virtual double valueAsDate() const;
+    virtual void setValueAsDate(double, ExceptionCode&) const;
+    virtual double valueAsDouble() const;
+    virtual void setValueAsDouble(double, TextFieldEventBehavior, ExceptionCode&) const;
+    virtual void setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode&) const;
+
+    // Validation functions
+    virtual String validationMessage() const;
+    virtual bool supportsValidation() const;
+    virtual bool typeMismatchFor(const String&) const;
+    // Type check for the current input value. We do nothing for some types
+    // though typeMismatchFor() does something for them because of value
+    // sanitization.
+    virtual bool typeMismatch() const;
+    virtual bool supportsRequired() const;
+    virtual bool valueMissing(const String&) const;
+    virtual bool hasBadInput() const;
+    virtual bool patternMismatch(const String&) const;
+    bool rangeUnderflow(const String&) const;
+    bool rangeOverflow(const String&) const;
+    bool isInRange(const String&) const;
+    bool isOutOfRange(const String&) const;
+    virtual Decimal defaultValueForStepUp() const;
+    double minimum() const;
+    double maximum() const;
+    virtual bool sizeShouldIncludeDecoration(int defaultSize, int& preferredSize) const;
+    bool stepMismatch(const String&) const;
+    virtual bool getAllowedValueStep(Decimal*) const;
+    virtual StepRange createStepRange(AnyStepHandling) const;
+    virtual void stepUp(int, ExceptionCode&);
+    virtual void stepUpFromRenderer(int);
+    virtual String badInputText() const;
+    virtual String typeMismatchText() const;
+    virtual String valueMissingText() const;
+    virtual bool canSetStringValue() const;
+    virtual String localizeValue(const String&) const;
+    virtual String visibleValue() const;
+    // Returing the null string means "use the default value."
+    // This function must be called only by HTMLInputElement::sanitizeValue().
+    virtual String sanitizeValue(const String&) const;
+
+    // Event handlers
+
+    virtual void handleClickEvent(MouseEvent*);
+    virtual void handleMouseDownEvent(MouseEvent*);
+    virtual PassOwnPtr<ClickHandlingState> willDispatchClick();
+    virtual void didDispatchClick(Event*, const ClickHandlingState&);
+    virtual void handleDOMActivateEvent(Event*);
+    virtual void handleKeydownEvent(KeyboardEvent*);
+    virtual void handleKeypressEvent(KeyboardEvent*);
+    virtual void handleKeyupEvent(KeyboardEvent*);
+    virtual void handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*);
+    virtual void handleTouchEvent(TouchEvent*);
+    virtual void forwardEvent(Event*);
+    // Helpers for event handlers.
+    virtual bool shouldSubmitImplicitly(Event*);
+    virtual PassRefPtr<HTMLFormElement> formForSubmission() const;
+    virtual bool hasCustomFocusLogic() const;
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+    virtual bool isMouseFocusable() const;
+    virtual bool shouldUseInputMethod() const;
+    virtual void handleFocusEvent(Node* oldFocusedNode, FocusDirection);
+    virtual void handleBlurEvent();
+    virtual void accessKeyAction(bool sendMouseEvents);
+    virtual bool canBeSuccessfulSubmitButton();
+    virtual void subtreeHasChanged();
+    virtual bool hasTouchEventHandler() const;
+
+    virtual void blur();
+
+    // Shadow tree handling
+
+    virtual void createShadowSubtree();
+    virtual void destroyShadowSubtree();
+
+    virtual HTMLElement* containerElement() const { return 0; }
+    virtual HTMLElement* innerBlockElement() const { return 0; }
+    virtual HTMLElement* innerTextElement() const { return 0; }
+    virtual HTMLElement* innerSpinButtonElement() const { return 0; }
+    virtual HTMLElement* resultsButtonElement() const { return 0; }
+    virtual HTMLElement* cancelButtonElement() const { return 0; }
+#if ENABLE(INPUT_SPEECH)
+    virtual HTMLElement* speechButtonElement() const { return 0; }
+#endif
+    virtual HTMLElement* sliderThumbElement() const { return 0; }
+    virtual HTMLElement* sliderTrackElement() const { return 0; }
+    virtual HTMLElement* placeholderElement() const;
+
+    // Miscellaneous functions
+
+    virtual bool rendererIsNeeded();
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer(PassRefPtr<RenderStyle>);
+    virtual void addSearchResult();
+    virtual void attach();
+    virtual void detach();
+    virtual void minOrMaxAttributeChanged();
+    virtual void stepAttributeChanged();
+    virtual void altAttributeChanged();
+    virtual void srcAttributeChanged();
+    virtual bool shouldRespectAlignAttribute();
+    virtual FileList* files();
+    virtual void setFiles(PassRefPtr<FileList>);
+    // Should return true if the given DragData has more than one dropped files.
+    virtual bool receiveDroppedFiles(const DragData*);
+    virtual String droppedFileSystemId();
+    virtual Icon* icon() const;
+    // Should return true if the corresponding renderer for a type can display a suggested value.
+    virtual bool canSetSuggestedValue();
+    virtual bool shouldSendChangeEventAfterCheckedChanged();
+    virtual bool canSetValue(const String&);
+    virtual bool storesValueSeparateFromAttribute();
+    virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior);
+    virtual bool shouldResetOnDocumentActivation();
+    virtual bool shouldRespectListAttribute();
+    virtual bool shouldRespectSpeechAttribute();
+    virtual bool isEnumeratable();
+    virtual bool isCheckable();
+    virtual bool isSteppable() const;
+    virtual bool shouldRespectHeightAndWidthAttributes();
+    virtual bool supportsPlaceholder() const;
+    virtual bool supportsReadOnly() const;
+    virtual void updateInnerTextValue();
+    virtual void updatePlaceholderText();
+    virtual void attributeChanged();
+    virtual void multipleAttributeChanged();
+    virtual void disabledAttributeChanged();
+    virtual void readonlyAttributeChanged();
+    virtual void requiredAttributeChanged();
+    virtual void valueAttributeChanged();
+    virtual String defaultToolTip() const;
+#if ENABLE(DATALIST_ELEMENT)
+    virtual void listAttributeTargetChanged();
+    virtual Decimal findClosestTickMarkValue(const Decimal&);
+#endif
+    virtual void updateClearButtonVisibility();
+
+    // Parses the specified string for the type, and return
+    // the Decimal value for the parsing result if the parsing
+    // succeeds; Returns defaultValue otherwise. This function can
+    // return NaN or Infinity only if defaultValue is NaN or Infinity.
+    virtual Decimal parseToNumber(const String&, const Decimal& defaultValue) const;
+
+    // Parses the specified string for this InputType, 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.
+    virtual bool parseToDateComponents(const String&, DateComponents*) const;
+
+    // Create a string representation of the specified Decimal value for the
+    // input type. If NaN or Infinity is specified, this returns an empty
+    // string. This should not be called for types without valueAsNumber.
+    virtual String serialize(const Decimal&) const;
+
+    virtual bool supportsIndeterminateAppearance() const;
+
+    virtual bool supportsSelectionAPI() const;
+
+    // Gets width and height of the input element if the type of the
+    // element is image. It returns 0 if the element is not image type.
+    virtual unsigned height() const;
+    virtual unsigned width() const;
+
+    void dispatchSimulatedClickIfActive(KeyboardEvent*) const;
+
+protected:
+    InputType(HTMLInputElement* element) : m_element(element) { }
+    HTMLInputElement* element() const { return m_element; }
+    Chrome* chrome() const;
+    Decimal parseToNumberOrNaN(const String&) const;
+    void observeFeatureIfVisible(UseCounter::Feature) const;
+
+private:
+    // Helper for stepUp()/stepDown(). Adds step value * count to the current value.
+    void applyStep(int count, AnyStepHandling, TextFieldEventBehavior, ExceptionCode&);
+
+    // Raw pointer because the HTMLInputElement object owns this InputType object.
+    HTMLInputElement* m_element;
+};
+
+} // namespace WebCore
+#endif
diff --git a/Source/core/html/InputTypeNames.cpp b/Source/core/html/InputTypeNames.cpp
new file mode 100644
index 0000000..cefdac8
--- /dev/null
+++ b/Source/core/html/InputTypeNames.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2012 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/InputTypeNames.h"
+
+namespace WebCore {
+
+namespace InputTypeNames {
+
+// The type names must be lowercased because they will be the return values of
+// input.type and input.type must be lowercase according to DOM Level 2.
+
+const AtomicString& button()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("button", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& checkbox()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("checkbox", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& color()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("color", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& date()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("date", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& datetime()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("datetime", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& datetimelocal()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("datetime-local", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& email()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("email", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& file()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("file", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& hidden()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("hidden", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& image()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("image", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& month()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("month", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& number()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("number", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& password()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("password", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& radio()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("radio", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& range()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("range", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& reset()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("reset", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& search()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("search", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& submit()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("submit", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& telephone()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("tel", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& text()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("text", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& time()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("time", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& url()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("url", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+const AtomicString& week()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("week", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+} // namespace WebCore::InputTypeNames
+
+} // namespace WebCore
diff --git a/Source/core/html/InputTypeNames.h b/Source/core/html/InputTypeNames.h
new file mode 100644
index 0000000..0a94c8b
--- /dev/null
+++ b/Source/core/html/InputTypeNames.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010, 2012 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef InputTypeNames_h
+#define InputTypeNames_h
+
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+namespace InputTypeNames {
+
+const AtomicString& button();
+const AtomicString& checkbox();
+const AtomicString& color();
+const AtomicString& date();
+const AtomicString& datetime();
+const AtomicString& datetimelocal();
+const AtomicString& email();
+const AtomicString& file();
+const AtomicString& hidden();
+const AtomicString& image();
+const AtomicString& month();
+const AtomicString& number();
+const AtomicString& password();
+const AtomicString& radio();
+const AtomicString& range();
+const AtomicString& reset();
+const AtomicString& search();
+const AtomicString& submit();
+const AtomicString& telephone();
+const AtomicString& text();
+const AtomicString& time();
+const AtomicString& url();
+const AtomicString& week();
+
+}
+
+} // namespace WebCore
+
+#endif // InputTypeNames_h
diff --git a/Source/core/html/LabelableElement.cpp b/Source/core/html/LabelableElement.cpp
new file mode 100644
index 0000000..4d2d529
--- /dev/null
+++ b/Source/core/html/LabelableElement.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/LabelableElement.h"
+
+#include "core/dom/NodeRareData.h"
+#include "core/html/LabelsNodeList.h"
+#include "core/rendering/style/RenderStyle.h"
+
+namespace WebCore {
+
+LabelableElement::LabelableElement(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document)
+{
+}
+
+LabelableElement::~LabelableElement()
+{
+}
+
+PassRefPtr<NodeList> LabelableElement::labels()
+{
+    if (!supportLabels())
+        return 0;
+    if (!document())
+        return 0;
+
+    return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<LabelsNodeList>(this, LabelsNodeListType, starAtom);
+}
+
+} // namespace Webcore
diff --git a/Source/core/html/LabelableElement.h b/Source/core/html/LabelableElement.h
new file mode 100644
index 0000000..ce7a2cf
--- /dev/null
+++ b/Source/core/html/LabelableElement.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 LabelableElement_h
+#define LabelableElement_h
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+// LabelableElement represents "labelable element" defined in the HTML
+// specification, and provides the implementation of the "labels" attribute.
+class LabelableElement : public HTMLElement {
+public:
+    virtual ~LabelableElement();
+    PassRefPtr<NodeList> labels();
+    virtual bool supportLabels() const { return false; }
+
+protected:
+    LabelableElement(const QualifiedName& tagName, Document*);
+
+private:
+    virtual bool isLabelable() const OVERRIDE FINAL { return true; }
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/LabelsNodeList.cpp b/Source/core/html/LabelsNodeList.cpp
new file mode 100644
index 0000000..f925e9f
--- /dev/null
+++ b/Source/core/html/LabelsNodeList.cpp
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/html/LabelsNodeList.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Element.h"
+#include "core/dom/NodeRareData.h"
+#include "core/html/HTMLLabelElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+LabelsNodeList::LabelsNodeList(Node* forNode)
+    : LiveNodeList(forNode, LabelsNodeListType, InvalidateOnForAttrChange, NodeListIsRootedAtDocument)
+{
+}
+
+LabelsNodeList::~LabelsNodeList()
+{
+    ownerNode()->nodeLists()->removeCacheWithAtomicName(this, LabelsNodeListType, starAtom);
+} 
+    
+bool LabelsNodeList::nodeMatches(Element* testNode) const
+{
+    return testNode->hasTagName(labelTag) && static_cast<HTMLLabelElement*>(testNode)->control() == ownerNode();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/LabelsNodeList.h b/Source/core/html/LabelsNodeList.h
new file mode 100644
index 0000000..8c7f211
--- /dev/null
+++ b/Source/core/html/LabelsNodeList.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef LabelsNodeList_h
+#define LabelsNodeList_h
+
+#include "core/dom/LiveNodeList.h"
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class LabelsNodeList : public LiveNodeList {
+public:
+    static PassRefPtr<LabelsNodeList> create(Node* forNode, CollectionType type, const AtomicString&)
+    {
+        ASSERT_UNUSED(type, type == LabelsNodeListType);
+        return adoptRef(new LabelsNodeList(forNode));
+    }
+    ~LabelsNodeList();
+
+protected:
+    LabelsNodeList(Node* forNode);
+
+    virtual bool nodeMatches(Element*) const;
+};
+
+} // namespace WebCore
+
+#endif // LabelsNodeList_h
diff --git a/Source/core/html/LinkRelAttribute.cpp b/Source/core/html/LinkRelAttribute.cpp
new file mode 100644
index 0000000..272d294
--- /dev/null
+++ b/Source/core/html/LinkRelAttribute.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ *
+ */
+
+#include "config.h"
+#include "core/html/LinkRelAttribute.h"
+
+namespace WebCore {
+
+LinkRelAttribute::LinkRelAttribute()
+    : m_isStyleSheet(false)
+    , m_iconType(InvalidIcon)
+    , m_isAlternate(false)
+    , m_isDNSPrefetch(false)
+    , m_isLinkPrefetch(false)
+    , m_isLinkSubresource(false)
+    , m_isLinkPrerender(false)
+{
+}
+
+LinkRelAttribute::LinkRelAttribute(const String& rel)
+    : m_isStyleSheet(false)
+    , m_iconType(InvalidIcon)
+    , m_isAlternate(false)
+    , m_isDNSPrefetch(false)
+    , m_isLinkPrefetch(false)
+    , m_isLinkSubresource(false)
+    , m_isLinkPrerender(false)
+{
+    if (equalIgnoringCase(rel, "stylesheet"))
+        m_isStyleSheet = true;
+    else if (equalIgnoringCase(rel, "icon") || equalIgnoringCase(rel, "shortcut icon"))
+        m_iconType = Favicon;
+#if ENABLE(TOUCH_ICON_LOADING)
+    else if (equalIgnoringCase(rel, "apple-touch-icon"))
+        m_iconType = TouchIcon;
+    else if (equalIgnoringCase(rel, "apple-touch-icon-precomposed"))
+        m_iconType = TouchPrecomposedIcon;
+#endif
+    else if (equalIgnoringCase(rel, "dns-prefetch"))
+        m_isDNSPrefetch = true;
+    else if (equalIgnoringCase(rel, "alternate stylesheet") || equalIgnoringCase(rel, "stylesheet alternate")) {
+        m_isStyleSheet = true;
+        m_isAlternate = true;
+    } else {
+        // Tokenize the rel attribute and set bits based on specific keywords that we find.
+        String relCopy = rel;
+        relCopy.replace('\n', ' ');
+        Vector<String> list;
+        relCopy.split(' ', list);
+        Vector<String>::const_iterator end = list.end();
+        for (Vector<String>::const_iterator it = list.begin(); it != end; ++it) {
+            if (equalIgnoringCase(*it, "stylesheet"))
+                m_isStyleSheet = true;
+            else if (equalIgnoringCase(*it, "alternate"))
+                m_isAlternate = true;
+            else if (equalIgnoringCase(*it, "icon"))
+                m_iconType = Favicon;
+#if ENABLE(TOUCH_ICON_LOADING)
+            else if (equalIgnoringCase(*it, "apple-touch-icon"))
+                m_iconType = TouchIcon;
+            else if (equalIgnoringCase(*it, "apple-touch-icon-precomposed"))
+                m_iconType = TouchPrecomposedIcon;
+#endif
+            else if (equalIgnoringCase(*it, "prefetch"))
+              m_isLinkPrefetch = true;
+            else if (equalIgnoringCase(*it, "subresource"))
+              m_isLinkSubresource = true;
+            else if (equalIgnoringCase(*it, "prerender"))
+              m_isLinkPrerender = true;
+        }
+    }
+}
+
+}
diff --git a/Source/core/html/LinkRelAttribute.h b/Source/core/html/LinkRelAttribute.h
new file mode 100644
index 0000000..1856fc4
--- /dev/null
+++ b/Source/core/html/LinkRelAttribute.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 LinkRelAttribute_h
+#define LinkRelAttribute_h
+
+#include "core/dom/IconURL.h"
+
+namespace WebCore {
+
+class LinkRelAttribute {
+public:
+    LinkRelAttribute();
+    explicit LinkRelAttribute(const String&);
+
+    bool isStyleSheet() const { return m_isStyleSheet; }
+    IconType iconType() const { return m_iconType; }
+    bool isAlternate() const { return m_isAlternate; }
+    bool isDNSPrefetch() const { return m_isDNSPrefetch; }
+    bool isLinkPrefetch() const { return m_isLinkPrefetch; }
+    bool isLinkSubresource() const { return m_isLinkSubresource; }
+    bool isLinkPrerender() const { return m_isLinkPrerender; }
+
+private:
+    bool m_isStyleSheet;
+    IconType m_iconType;
+    bool m_isAlternate;
+    bool m_isDNSPrefetch;
+    bool m_isLinkPrefetch;
+    bool m_isLinkSubresource;
+    bool m_isLinkPrerender;
+
+};
+    
+}
+
+#endif
+
diff --git a/Source/core/html/MediaController.cpp b/Source/core/html/MediaController.cpp
new file mode 100644
index 0000000..a68a725
--- /dev/null
+++ b/Source/core/html/MediaController.cpp
@@ -0,0 +1,684 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/MediaController.h"
+
+#include "core/dom/ExceptionCode.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/html/TimeRanges.h"
+#include "core/platform/Clock.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/AtomicString.h>
+
+using namespace WebCore;
+using namespace std;
+
+PassRefPtr<MediaController> MediaController::create(ScriptExecutionContext* context)
+{
+    return adoptRef(new MediaController(context));
+}
+
+MediaController::MediaController(ScriptExecutionContext* context)
+    : m_paused(false)
+    , m_defaultPlaybackRate(1)
+    , m_volume(1)
+    , m_position(MediaPlayer::invalidTime())
+    , m_muted(false)
+    , m_readyState(HAVE_NOTHING)
+    , m_playbackState(WAITING)
+    , m_asyncEventTimer(this, &MediaController::asyncEventTimerFired)
+    , m_clearPositionTimer(this, &MediaController::clearPositionTimerFired)
+    , m_closedCaptionsVisible(false)
+    , m_clock(Clock::create())
+    , m_scriptExecutionContext(context)
+    , m_timeupdateTimer(this, &MediaController::timeupdateTimerFired)
+    , m_previousTimeupdateTime(0)
+{
+}
+
+MediaController::~MediaController()
+{
+}
+
+void MediaController::addMediaElement(HTMLMediaElement* element)
+{
+    ASSERT(element);
+    ASSERT(!m_mediaElements.contains(element));
+
+    m_mediaElements.append(element);
+    bringElementUpToSpeed(element);
+}
+
+void MediaController::removeMediaElement(HTMLMediaElement* element)
+{
+    ASSERT(element);
+    ASSERT(m_mediaElements.contains(element));
+    m_mediaElements.remove(m_mediaElements.find(element));
+}
+
+bool MediaController::containsMediaElement(HTMLMediaElement* element) const
+{
+    return m_mediaElements.contains(element);
+}
+
+PassRefPtr<TimeRanges> MediaController::buffered() const
+{
+    if (m_mediaElements.isEmpty())
+        return TimeRanges::create();
+
+    // The buffered attribute must return a new static normalized TimeRanges object that represents 
+    // the intersection of the ranges of the media resources of the slaved media elements that the 
+    // user agent has buffered, at the time the attribute is evaluated.
+    RefPtr<TimeRanges> bufferedRanges = m_mediaElements.first()->buffered();
+    for (size_t index = 1; index < m_mediaElements.size(); ++index)
+        bufferedRanges->intersectWith(m_mediaElements[index]->buffered().get());
+    return bufferedRanges;
+}
+
+PassRefPtr<TimeRanges> MediaController::seekable() const
+{
+    if (m_mediaElements.isEmpty())
+        return TimeRanges::create();
+
+    // The seekable attribute must return a new static normalized TimeRanges object that represents
+    // the intersection of the ranges of the media resources of the slaved media elements that the
+    // user agent is able to seek to, at the time the attribute is evaluated.
+    RefPtr<TimeRanges> seekableRanges = m_mediaElements.first()->seekable();
+    for (size_t index = 1; index < m_mediaElements.size(); ++index)
+        seekableRanges->intersectWith(m_mediaElements[index]->seekable().get());
+    return seekableRanges;
+}
+
+PassRefPtr<TimeRanges> MediaController::played()
+{
+    if (m_mediaElements.isEmpty())
+        return TimeRanges::create();
+
+    // The played attribute must return a new static normalized TimeRanges object that represents 
+    // the union of the ranges of the media resources of the slaved media elements that the 
+    // user agent has so far rendered, at the time the attribute is evaluated.
+    RefPtr<TimeRanges> playedRanges = m_mediaElements.first()->played();
+    for (size_t index = 1; index < m_mediaElements.size(); ++index)
+        playedRanges->unionWith(m_mediaElements[index]->played().get());
+    return playedRanges;
+}
+
+double MediaController::duration() const
+{
+    // FIXME: Investigate caching the maximum duration and only updating the cached value
+    // when the slaved media elements' durations change.
+    double maxDuration = 0;
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        double duration = m_mediaElements[index]->duration();
+        if (std::isnan(duration))
+            continue;
+        maxDuration = max(maxDuration, duration);
+    }
+    return maxDuration;
+}
+
+double MediaController::currentTime() const
+{
+    if (m_mediaElements.isEmpty())
+        return 0;
+
+    if (m_position == MediaPlayer::invalidTime()) {
+        // Some clocks may return times outside the range of [0..duration].
+        m_position = max(0.0, min(duration(), m_clock->currentTime()));
+        m_clearPositionTimer.startOneShot(0);
+    }
+
+    return m_position;
+}
+
+void MediaController::setCurrentTime(double time, ExceptionCode& code)
+{
+    // When the user agent is to seek the media controller to a particular new playback position, 
+    // it must follow these steps:
+    // If the new playback position is less than zero, then set it to zero.
+    time = max(0.0, time);
+    
+    // If the new playback position is greater than the media controller duration, then set it 
+    // to the media controller duration.
+    time = min(time, duration());
+    
+    // Set the media controller position to the new playback position.
+    m_clock->setCurrentTime(time);
+    
+    // Seek each slaved media element to the new playback position relative to the media element timeline.
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->seek(time, code);
+
+    scheduleTimeupdateEvent();
+}
+
+void MediaController::unpause()
+{
+    // When the unpause() method is invoked, if the MediaController is a paused media controller,
+    if (!m_paused)
+        return;
+
+    // the user agent must change the MediaController into a playing media controller,
+    m_paused = false;
+    // queue a task to fire a simple event named play at the MediaController,
+    scheduleEvent(eventNames().playEvent);
+    // and then report the controller state of the MediaController.
+    reportControllerState();
+}
+
+void MediaController::play()
+{
+    // When the play() method is invoked, the user agent must invoke the play method of each
+    // slaved media element in turn,
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->play();
+
+    // and then invoke the unpause method of the MediaController.
+    unpause();
+}
+
+void MediaController::pause()
+{
+    // When the pause() method is invoked, if the MediaController is a playing media controller,
+    if (m_paused)
+        return;
+
+    // then the user agent must change the MediaController into a paused media controller,
+    m_paused = true;
+    // queue a task to fire a simple event named pause at the MediaController,
+    scheduleEvent(eventNames().pauseEvent);
+    // and then report the controller state of the MediaController.
+    reportControllerState();
+}
+
+void MediaController::setDefaultPlaybackRate(double rate)
+{
+    if (m_defaultPlaybackRate == rate)
+        return;
+
+    // The defaultPlaybackRate attribute, on setting, must set the MediaController's media controller
+    // default playback rate to the new value,
+    m_defaultPlaybackRate = rate;
+
+    // then queue a task to fire a simple event named ratechange at the MediaController.
+    scheduleEvent(eventNames().ratechangeEvent);
+}
+
+double MediaController::playbackRate() const
+{
+    return m_clock->playRate();
+}
+
+void MediaController::setPlaybackRate(double rate)
+{
+    if (m_clock->playRate() == rate)
+        return;
+
+    // The playbackRate attribute, on setting, must set the MediaController's media controller 
+    // playback rate to the new value,
+    m_clock->setPlayRate(rate);
+
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->updatePlaybackRate();
+
+    // then queue a task to fire a simple event named ratechange at the MediaController.
+    scheduleEvent(eventNames().ratechangeEvent);
+}
+
+void MediaController::setVolume(double level, ExceptionCode& code)
+{
+    if (m_volume == level)
+        return;
+
+    // If the new value is outside the range 0.0 to 1.0 inclusive, then, on setting, an 
+    // IndexSizeError exception must be raised instead.
+    if (level < 0 || level > 1) {
+        code = INDEX_SIZE_ERR;
+        return;
+    }
+        
+    // The volume attribute, on setting, if the new value is in the range 0.0 to 1.0 inclusive,
+    // must set the MediaController's media controller volume multiplier to the new value
+    m_volume = level;
+
+    // and queue a task to fire a simple event named volumechange at the MediaController.
+    scheduleEvent(eventNames().volumechangeEvent);
+
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->updateVolume();
+}
+
+void MediaController::setMuted(bool flag)
+{
+    if (m_muted == flag)
+        return;
+
+    // The muted attribute, on setting, must set the MediaController's media controller mute override
+    // to the new value
+    m_muted = flag;
+
+    // and queue a task to fire a simple event named volumechange at the MediaController.
+    scheduleEvent(eventNames().volumechangeEvent);
+
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->updateVolume();
+}
+
+static const AtomicString& playbackStateWaiting()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, waiting, ("waiting", AtomicString::ConstructFromLiteral));
+    return waiting;
+}
+
+static const AtomicString& playbackStatePlaying()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, playing, ("playing", AtomicString::ConstructFromLiteral));
+    return playing;
+}
+
+static const AtomicString& playbackStateEnded()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, ended, ("ended", AtomicString::ConstructFromLiteral));
+    return ended;
+}
+
+const AtomicString& MediaController::playbackState() const
+{
+    switch (m_playbackState) {
+    case WAITING:
+        return playbackStateWaiting();
+    case PLAYING:
+        return playbackStatePlaying();
+    case ENDED:
+        return playbackStateEnded();
+    default:
+        ASSERT_NOT_REACHED();
+        return nullAtom;
+    }
+}
+
+void MediaController::reportControllerState()
+{
+    updateReadyState();
+    updatePlaybackState();
+}
+
+static AtomicString eventNameForReadyState(MediaControllerInterface::ReadyState state)
+{
+    switch (state) {
+    case MediaControllerInterface::HAVE_NOTHING:
+        return eventNames().emptiedEvent;
+    case MediaControllerInterface::HAVE_METADATA:
+        return eventNames().loadedmetadataEvent;
+    case MediaControllerInterface::HAVE_CURRENT_DATA:
+        return eventNames().loadeddataEvent;
+    case MediaControllerInterface::HAVE_FUTURE_DATA:
+        return eventNames().canplayEvent;
+    case MediaControllerInterface::HAVE_ENOUGH_DATA:
+        return eventNames().canplaythroughEvent;
+    default:
+        ASSERT_NOT_REACHED();
+        return nullAtom;
+    }
+}
+
+void MediaController::updateReadyState()
+{
+    ReadyState oldReadyState = m_readyState;
+    ReadyState newReadyState;
+    
+    if (m_mediaElements.isEmpty()) {
+        // If the MediaController has no slaved media elements, let new readiness state be 0.
+        newReadyState = HAVE_NOTHING;
+    } else {
+        // Otherwise, let it have the lowest value of the readyState IDL attributes of all of its
+        // slaved media elements.
+        newReadyState = m_mediaElements.first()->readyState();
+        for (size_t index = 1; index < m_mediaElements.size(); ++index)
+            newReadyState = min(newReadyState, m_mediaElements[index]->readyState());
+    }
+
+    if (newReadyState == oldReadyState) 
+        return;
+
+    // If the MediaController's most recently reported readiness state is greater than new readiness 
+    // state then queue a task to fire a simple event at the MediaController object, whose name is the
+    // event name corresponding to the value of new readiness state given in the table below. [omitted]
+    if (oldReadyState > newReadyState) {
+        scheduleEvent(eventNameForReadyState(newReadyState));
+        return;
+    }
+
+    // If the MediaController's most recently reported readiness state is less than the new readiness
+    // state, then run these substeps:
+    // 1. Let next state be the MediaController's most recently reported readiness state.
+    ReadyState nextState = oldReadyState;
+    do {
+        // 2. Loop: Increment next state by one.
+        nextState = static_cast<ReadyState>(nextState + 1);
+        // 3. Queue a task to fire a simple event at the MediaController object, whose name is the
+        // event name corresponding to the value of next state given in the table below. [omitted]
+        scheduleEvent(eventNameForReadyState(nextState));        
+        // If next state is less than new readiness state, then return to the step labeled loop
+    } while (nextState < newReadyState);
+
+    // Let the MediaController's most recently reported readiness state be new readiness state.
+    m_readyState = newReadyState;
+}
+
+void MediaController::updatePlaybackState()
+{
+    PlaybackState oldPlaybackState = m_playbackState;
+    PlaybackState newPlaybackState;
+
+    // Initialize new playback state by setting it to the state given for the first matching 
+    // condition from the following list:
+    if (m_mediaElements.isEmpty()) {
+        // If the MediaController has no slaved media elements
+        // Let new playback state be waiting.
+        newPlaybackState = WAITING;
+    } else if (hasEnded()) {
+        // If all of the MediaController's slaved media elements have ended playback and the media
+        // controller playback rate is positive or zero
+        // Let new playback state be ended.
+        newPlaybackState = ENDED;
+    } else if (isBlocked()) {
+        // If the MediaController is a blocked media controller
+        // Let new playback state be waiting.
+        newPlaybackState = WAITING;
+    } else {
+        // Otherwise
+        // Let new playback state be playing.
+        newPlaybackState = PLAYING;
+    }
+
+    // If the MediaController's most recently reported playback state is not equal to new playback state
+    if (newPlaybackState == oldPlaybackState)
+        return;
+
+    // and the new playback state is ended,
+    if (newPlaybackState == ENDED) {
+        // then queue a task that, if the MediaController object is a playing media controller, and 
+        // all of the MediaController's slaved media elements have still ended playback, and the 
+        // media controller playback rate is still positive or zero, 
+        if (!m_paused && hasEnded()) {
+            // changes the MediaController object to a paused media controller
+            m_paused = true;
+
+            // and then fires a simple event named pause at the MediaController object.
+            scheduleEvent(eventNames().pauseEvent);
+        }
+    }
+
+    // If the MediaController's most recently reported playback state is not equal to new playback state
+    // then queue a task to fire a simple event at the MediaController object, whose name is playing 
+    // if new playback state is playing, ended if new playback state is ended, and waiting otherwise.
+    AtomicString eventName;
+    switch (newPlaybackState) {
+    case WAITING:
+        eventName = eventNames().waitingEvent;
+        m_clock->stop();
+        m_timeupdateTimer.stop();
+        break;
+    case ENDED:
+        eventName = eventNames().endedEvent;
+        m_clock->stop();
+        m_timeupdateTimer.stop();
+        break;
+    case PLAYING:
+        eventName = eventNames().playingEvent;
+        m_clock->start();
+        startTimeupdateTimer();
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+    scheduleEvent(eventName);
+
+    // Let the MediaController's most recently reported playback state be new playback state.
+    m_playbackState = newPlaybackState;
+
+    updateMediaElements();
+}
+
+void MediaController::updateMediaElements()
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->updatePlayState();
+}
+
+void MediaController::bringElementUpToSpeed(HTMLMediaElement* element)
+{
+    ASSERT(element);
+    ASSERT(m_mediaElements.contains(element));
+
+    // When the user agent is to bring a media element up to speed with its new media controller,
+    // it must seek that media element to the MediaController's media controller position relative
+    // to the media element's timeline.
+    element->seek(currentTime(), IGNORE_EXCEPTION);
+}
+
+bool MediaController::isBlocked() const
+{
+    // A MediaController is a blocked media controller if the MediaController is a paused media 
+    // controller,
+    if (m_paused)
+        return true;
+    
+    if (m_mediaElements.isEmpty())
+        return false;
+    
+    bool allPaused = true;
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        HTMLMediaElement* element = m_mediaElements[index];
+        //  or if any of its slaved media elements are blocked media elements,
+        if (element->isBlocked())
+            return true;
+        
+        // or if any of its slaved media elements whose autoplaying flag is true still have their 
+        // paused attribute set to true,
+        if (element->isAutoplaying() && element->paused())
+            return true;
+        
+        if (!element->paused())
+            allPaused = false;
+    }
+    
+    // or if all of its slaved media elements have their paused attribute set to true.
+    return allPaused;
+}
+
+bool MediaController::hasEnded() const
+{
+    // If the ... media controller playback rate is positive or zero
+    if (m_clock->playRate() < 0)
+        return false;
+
+    // [and] all of the MediaController's slaved media elements have ended playback ... let new
+    // playback state be ended.
+    if (m_mediaElements.isEmpty())
+        return false;
+    
+    bool allHaveEnded = true;
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        if (!m_mediaElements[index]->ended())
+            allHaveEnded = false;
+    }
+    return allHaveEnded;
+}
+
+void MediaController::scheduleEvent(const AtomicString& eventName)
+{
+    m_pendingEvents.append(Event::create(eventName, false, true));
+    if (!m_asyncEventTimer.isActive())
+        m_asyncEventTimer.startOneShot(0);
+}
+
+void MediaController::asyncEventTimerFired(Timer<MediaController>*)
+{
+    Vector<RefPtr<Event> > pendingEvents;
+
+    m_pendingEvents.swap(pendingEvents);
+    size_t count = pendingEvents.size();
+    for (size_t index = 0; index < count; ++index)
+        dispatchEvent(pendingEvents[index].release(), IGNORE_EXCEPTION);
+}
+
+void MediaController::clearPositionTimerFired(Timer<MediaController>*)
+{
+    m_position = MediaPlayer::invalidTime();
+}
+
+bool MediaController::hasAudio() const
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        if (m_mediaElements[index]->hasAudio())
+            return true;
+    }
+    return false;
+}
+
+bool MediaController::hasVideo() const
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        if (m_mediaElements[index]->hasVideo())
+            return true;
+    }
+    return false;
+}
+
+bool MediaController::hasClosedCaptions() const
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        if (m_mediaElements[index]->hasClosedCaptions())
+            return true;
+    }
+    return false;
+}
+
+void MediaController::setClosedCaptionsVisible(bool visible)
+{
+    m_closedCaptionsVisible = visible;
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->setClosedCaptionsVisible(visible);
+}
+
+bool MediaController::supportsScanning() const
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        if (!m_mediaElements[index]->supportsScanning())
+            return false;
+    }
+    return true;
+}
+
+void MediaController::beginScrubbing()
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->beginScrubbing();
+    if (m_playbackState == PLAYING)
+        m_clock->stop();
+}
+
+void MediaController::endScrubbing()
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->endScrubbing();
+    if (m_playbackState == PLAYING)
+        m_clock->start();
+}
+
+bool MediaController::canPlay() const
+{
+    if (m_paused)
+        return true;
+
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        if (!m_mediaElements[index]->canPlay())
+            return false;
+    }
+    return true;
+}
+
+bool MediaController::isLiveStream() const
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        if (!m_mediaElements[index]->isLiveStream())
+            return false;
+    }
+    return true;
+}
+
+bool MediaController::hasCurrentSrc() const
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index) {
+        if (!m_mediaElements[index]->hasCurrentSrc())
+            return false;
+    }
+    return true;
+}
+
+void MediaController::returnToRealtime()
+{
+    for (size_t index = 0; index < m_mediaElements.size(); ++index)
+        m_mediaElements[index]->returnToRealtime();
+}
+
+const AtomicString& MediaController::interfaceName() const
+{
+    return eventNames().interfaceForMediaController;
+}
+
+// The spec says to fire periodic timeupdate events (those sent while playing) every
+// "15 to 250ms", we choose the slowest frequency
+static const double maxTimeupdateEventFrequency = 0.25;
+
+void MediaController::startTimeupdateTimer()
+{
+    if (m_timeupdateTimer.isActive())
+        return;
+
+    m_timeupdateTimer.startRepeating(maxTimeupdateEventFrequency);
+}
+
+void MediaController::timeupdateTimerFired(Timer<MediaController>*)
+{
+    scheduleTimeupdateEvent();
+}
+
+void MediaController::scheduleTimeupdateEvent()
+{
+    double now = WTF::currentTime();
+    double timedelta = now - m_previousTimeupdateTime;
+
+    if (timedelta < maxTimeupdateEventFrequency)
+        return;
+
+    scheduleEvent(eventNames().timeupdateEvent);
+    m_previousTimeupdateTime = now;
+}
diff --git a/Source/core/html/MediaController.h b/Source/core/html/MediaController.h
new file mode 100644
index 0000000..4785673
--- /dev/null
+++ b/Source/core/html/MediaController.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 MediaController_h
+#define MediaController_h
+
+#include "core/dom/ActiveDOMObject.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventListener.h"
+#include "core/dom/EventTarget.h"
+#include "core/html/MediaControllerInterface.h"
+#include "core/platform/Timer.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Clock;
+class HTMLMediaElement;
+class Event;
+class ScriptExecutionContext;
+
+class MediaController : public RefCounted<MediaController>, public MediaControllerInterface, public EventTarget {
+public:
+    static PassRefPtr<MediaController> create(ScriptExecutionContext*);
+    virtual ~MediaController();
+
+    void addMediaElement(HTMLMediaElement*);
+    void removeMediaElement(HTMLMediaElement*);
+    bool containsMediaElement(HTMLMediaElement*) const;
+
+    const String& mediaGroup() const { return m_mediaGroup; }
+    
+    virtual PassRefPtr<TimeRanges> buffered() const;
+    virtual PassRefPtr<TimeRanges> seekable() const;
+    virtual PassRefPtr<TimeRanges> played();
+    
+    virtual double duration() const;
+    virtual double currentTime() const;
+    virtual void setCurrentTime(double, ExceptionCode&);
+    
+    virtual bool paused() const { return m_paused; }
+    virtual void play();
+    virtual void pause();
+    void unpause();
+    
+    virtual double defaultPlaybackRate() const { return m_defaultPlaybackRate; }
+    virtual void setDefaultPlaybackRate(double);
+    
+    virtual double playbackRate() const;
+    virtual void setPlaybackRate(double);
+    
+    virtual double volume() const { return m_volume; }
+    virtual void setVolume(double, ExceptionCode&);
+    
+    virtual bool muted() const { return m_muted; }
+    virtual void setMuted(bool);
+    
+    virtual ReadyState readyState() const { return m_readyState; }
+
+    enum PlaybackState { WAITING, PLAYING, ENDED };
+    const AtomicString& playbackState() const;
+
+    virtual bool supportsFullscreen() const { return false; }
+    virtual bool isFullscreen() const { return false; }
+    virtual void enterFullscreen() { }
+
+    virtual bool hasAudio() const;
+    virtual bool hasVideo() const;
+    virtual bool hasClosedCaptions() const;
+    virtual void setClosedCaptionsVisible(bool);
+    virtual bool closedCaptionsVisible() const { return m_closedCaptionsVisible; }
+    
+    virtual bool supportsScanning() const;
+    
+    virtual void beginScrubbing();
+    virtual void endScrubbing();
+    
+    virtual bool canPlay() const;
+    
+    virtual bool isLiveStream() const;
+    
+    virtual bool hasCurrentSrc() const;
+    
+    virtual void returnToRealtime();
+
+    bool isBlocked() const;
+
+    // EventTarget
+    using RefCounted<MediaController>::ref;
+    using RefCounted<MediaController>::deref;
+
+private:
+    MediaController(ScriptExecutionContext*);
+    void reportControllerState();
+    void updateReadyState();
+    void updatePlaybackState();
+    void updateMediaElements();
+    void bringElementUpToSpeed(HTMLMediaElement*);
+    void scheduleEvent(const AtomicString& eventName);
+    void asyncEventTimerFired(Timer<MediaController>*);
+    void clearPositionTimerFired(Timer<MediaController>*);
+    bool hasEnded() const;
+    void scheduleTimeupdateEvent();
+    void timeupdateTimerFired(Timer<MediaController>*);
+    void startTimeupdateTimer();
+
+    // EventTarget
+    virtual void refEventTarget() { ref(); }
+    virtual void derefEventTarget() { deref(); }
+    virtual const AtomicString& interfaceName() const;
+    virtual ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext; };
+    virtual EventTargetData* eventTargetData() { return &m_eventTargetData; }
+    virtual EventTargetData* ensureEventTargetData() { return &m_eventTargetData; }
+    EventTargetData m_eventTargetData;
+
+    friend class HTMLMediaElement;
+    friend class MediaControllerEventListener;
+    Vector<HTMLMediaElement*> m_mediaElements;
+    bool m_paused;
+    double m_defaultPlaybackRate;
+    double m_volume;
+    mutable double m_position;
+    bool m_muted;
+    ReadyState m_readyState;
+    PlaybackState m_playbackState;
+    Vector<RefPtr<Event> > m_pendingEvents;
+    Timer<MediaController> m_asyncEventTimer;
+    mutable Timer<MediaController> m_clearPositionTimer;
+    String m_mediaGroup;
+    bool m_closedCaptionsVisible;
+    PassRefPtr<Clock> m_clock;
+    ScriptExecutionContext* m_scriptExecutionContext;
+    Timer<MediaController> m_timeupdateTimer;
+    double m_previousTimeupdateTime;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/MediaController.idl b/Source/core/html/MediaController.idl
new file mode 100644
index 0000000..675cc4d
--- /dev/null
+++ b/Source/core/html/MediaController.idl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Constructor,
+    CallWith=ScriptExecutionContext,
+    EventTarget
+] interface MediaController {
+    readonly attribute TimeRanges buffered;
+    readonly attribute TimeRanges seekable;
+
+    readonly attribute double duration;
+    [SetterRaisesException] attribute double currentTime;
+
+    readonly attribute boolean paused;
+    readonly attribute TimeRanges played;
+    readonly attribute DOMString playbackState;
+    void play();
+    void pause();
+    void unpause();
+
+    attribute double defaultPlaybackRate;
+    attribute double playbackRate;
+
+    [SetterRaisesException] attribute double volume;
+    attribute boolean muted;
+
+    // EventTarget interface
+    void addEventListener(DOMString type, 
+                          EventListener listener, 
+                          optional boolean useCapture);
+    void removeEventListener(DOMString type, 
+                             EventListener listener, 
+                             optional boolean useCapture);
+    [RaisesException] boolean dispatchEvent(Event evt);
+};
diff --git a/Source/core/html/MediaControllerInterface.h b/Source/core/html/MediaControllerInterface.h
new file mode 100644
index 0000000..a291bbc
--- /dev/null
+++ b/Source/core/html/MediaControllerInterface.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 MediaControllerInterface_h
+#define MediaControllerInterface_h
+
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class TimeRanges;
+
+typedef int ExceptionCode;
+
+class MediaControllerInterface {
+public:
+    virtual ~MediaControllerInterface() { };
+    
+    // MediaController IDL:
+    virtual PassRefPtr<TimeRanges> buffered() const = 0;
+    virtual PassRefPtr<TimeRanges> seekable() const = 0;
+    virtual PassRefPtr<TimeRanges> played() = 0;
+    
+    virtual double duration() const = 0;
+    virtual double currentTime() const = 0;
+    virtual void setCurrentTime(double, ExceptionCode&) = 0;
+    
+    virtual bool paused() const = 0;
+    virtual void play() = 0;
+    virtual void pause() = 0;
+    
+    virtual double defaultPlaybackRate() const = 0;
+    virtual void setDefaultPlaybackRate(double) = 0;
+    
+    virtual double playbackRate() const = 0;
+    virtual void setPlaybackRate(double) = 0;
+    
+    virtual double volume() const = 0;
+    virtual void setVolume(double, ExceptionCode&) = 0;
+    
+    virtual bool muted() const = 0;
+    virtual void setMuted(bool) = 0;
+    
+    enum ReadyState { HAVE_NOTHING, HAVE_METADATA, HAVE_CURRENT_DATA, HAVE_FUTURE_DATA, HAVE_ENOUGH_DATA };
+    virtual ReadyState readyState() const = 0;
+
+    // MediaControlElements:
+    virtual bool supportsFullscreen() const = 0;
+    virtual bool isFullscreen() const = 0;
+    virtual void enterFullscreen() = 0;
+
+    virtual bool hasAudio() const = 0;
+    virtual bool hasVideo() const = 0;
+    virtual bool hasClosedCaptions() const = 0;
+    virtual void setClosedCaptionsVisible(bool) = 0;
+    virtual bool closedCaptionsVisible() const = 0;
+
+    virtual bool supportsScanning() const = 0;
+
+    virtual void beginScrubbing() = 0;
+    virtual void endScrubbing() = 0;
+
+    virtual bool canPlay() const = 0;
+
+    virtual bool isLiveStream() const = 0;
+
+    virtual bool hasCurrentSrc() const = 0;
+
+    virtual void returnToRealtime() = 0;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/MediaDocument.cpp b/Source/core/html/MediaDocument.cpp
new file mode 100644
index 0000000..c2326e5
--- /dev/null
+++ b/Source/core/html/MediaDocument.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2008 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. ``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. 
+ */
+
+#include "config.h"
+
+#include "core/html/MediaDocument.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/RawDataDocumentParser.h"
+#include "core/html/HTMLEmbedElement.h"
+#include "core/html/HTMLHtmlElement.h"
+#include "core/html/HTMLSourceElement.h"
+#include "core/html/HTMLVideoElement.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/page/Frame.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// FIXME: Share more code with PluginDocumentParser.
+class MediaDocumentParser : public RawDataDocumentParser {
+public:
+    static PassRefPtr<MediaDocumentParser> create(MediaDocument* document)
+    {
+        return adoptRef(new MediaDocumentParser(document));
+    }
+    
+private:
+    MediaDocumentParser(Document* document)
+        : RawDataDocumentParser(document)
+        , m_mediaElement(0)
+    {
+    }
+
+    virtual void appendBytes(DocumentWriter*, const char*, size_t);
+
+    void createDocumentStructure();
+
+    HTMLMediaElement* m_mediaElement;
+};
+    
+void MediaDocumentParser::createDocumentStructure()
+{
+    RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
+    document()->appendChild(rootElement, IGNORE_EXCEPTION);
+    document()->setCSSTarget(rootElement.get());
+    static_cast<HTMLHtmlElement*>(rootElement.get())->insertedByParser();
+
+    if (document()->frame())
+        document()->frame()->loader()->dispatchDocumentElementAvailable();
+        
+    RefPtr<Element> body = document()->createElement(bodyTag, false);
+    rootElement->appendChild(body, IGNORE_EXCEPTION);
+
+    RefPtr<Element> mediaElement = document()->createElement(videoTag, false);
+
+    m_mediaElement = static_cast<HTMLVideoElement*>(mediaElement.get());
+    m_mediaElement->setAttribute(controlsAttr, "");
+    m_mediaElement->setAttribute(autoplayAttr, "");
+
+    m_mediaElement->setAttribute(nameAttr, "media");
+
+    RefPtr<Element> sourceElement = document()->createElement(sourceTag, false);
+    HTMLSourceElement* source = static_cast<HTMLSourceElement*>(sourceElement.get());
+    source->setSrc(document()->url());
+
+    if (DocumentLoader* loader = document()->loader())
+        source->setType(loader->responseMIMEType());
+
+    m_mediaElement->appendChild(sourceElement, IGNORE_EXCEPTION);
+    body->appendChild(mediaElement, IGNORE_EXCEPTION);
+
+    Frame* frame = document()->frame();
+    if (!frame)
+        return;
+
+    frame->loader()->activeDocumentLoader()->setMainResourceDataBufferingPolicy(DoNotBufferData);
+}
+
+void MediaDocumentParser::appendBytes(DocumentWriter*, const char*, size_t)
+{
+    if (m_mediaElement)
+        return;
+
+    createDocumentStructure();
+    finish();
+}
+    
+MediaDocument::MediaDocument(Frame* frame, const KURL& url)
+    : HTMLDocument(frame, url)
+    , m_replaceMediaElementTimer(this, &MediaDocument::replaceMediaElementTimerFired)
+{
+    setCompatibilityMode(QuirksMode);
+    lockCompatibilityMode();
+}
+
+MediaDocument::~MediaDocument()
+{
+    ASSERT(!m_replaceMediaElementTimer.isActive());
+}
+
+PassRefPtr<DocumentParser> MediaDocument::createParser()
+{
+    return MediaDocumentParser::create(this);
+}
+
+static inline HTMLVideoElement* descendentVideoElement(Node* node)
+{
+    ASSERT(node);
+
+    if (node->hasTagName(videoTag))
+        return static_cast<HTMLVideoElement*>(node);
+
+    RefPtr<NodeList> nodeList = node->getElementsByTagNameNS(videoTag.namespaceURI(), videoTag.localName());
+   
+    if (nodeList.get()->length() > 0)
+        return static_cast<HTMLVideoElement*>(nodeList.get()->item(0));
+
+    return 0;
+}
+
+static inline HTMLVideoElement* ancestorVideoElement(Node* node)
+{
+    while (node && !node->hasTagName(videoTag))
+        node = node->parentOrShadowHostNode();
+
+    return static_cast<HTMLVideoElement*>(node);
+}
+
+void MediaDocument::defaultEventHandler(Event* event)
+{
+    // Match the default Quicktime plugin behavior to allow 
+    // clicking and double-clicking to pause and play the media.
+    Node* targetNode = event->target()->toNode();
+    if (!targetNode)
+        return;
+
+    if (event->type() == eventNames().keydownEvent && event->isKeyboardEvent()) {
+        HTMLVideoElement* video = descendentVideoElement(targetNode);
+        if (!video)
+            return;
+
+        KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event);
+        if (keyboardEvent->keyIdentifier() == "U+0020") { // space
+            if (video->paused()) {
+                if (video->canPlay())
+                    video->play();
+            } else
+                video->pause();
+            event->setDefaultHandled();
+        }
+    }
+}
+
+void MediaDocument::mediaElementSawUnsupportedTracks()
+{
+    // The HTMLMediaElement was told it has something that the underlying 
+    // MediaPlayer cannot handle so we should switch from <video> to <embed> 
+    // and let the plugin handle this. Don't do it immediately as this 
+    // function may be called directly from a media engine callback, and 
+    // replaceChild will destroy the element, media player, and media engine.
+    m_replaceMediaElementTimer.startOneShot(0);
+}
+
+void MediaDocument::replaceMediaElementTimerFired(Timer<MediaDocument>*)
+{
+    HTMLElement* htmlBody = body();
+    if (!htmlBody)
+        return;
+
+    // Set body margin width and height to 0 as that is what a PluginDocument uses.
+    htmlBody->setAttribute(marginwidthAttr, "0");
+    htmlBody->setAttribute(marginheightAttr, "0");
+
+    if (HTMLVideoElement* videoElement = descendentVideoElement(htmlBody)) {
+        RefPtr<Element> element = Document::createElement(embedTag, false);
+        HTMLEmbedElement* embedElement = static_cast<HTMLEmbedElement*>(element.get());
+
+        embedElement->setAttribute(widthAttr, "100%");
+        embedElement->setAttribute(heightAttr, "100%");
+        embedElement->setAttribute(nameAttr, "plugin");
+        embedElement->setAttribute(srcAttr, url().string());
+
+        DocumentLoader* documentLoader = loader();
+        ASSERT(documentLoader);
+        if (documentLoader)
+            embedElement->setAttribute(typeAttr, documentLoader->writer()->mimeType());
+
+        videoElement->parentNode()->replaceChild(embedElement, videoElement, IGNORE_EXCEPTION);
+    }
+}
+
+}
diff --git a/Source/core/html/MediaDocument.h b/Source/core/html/MediaDocument.h
new file mode 100644
index 0000000..101264d
--- /dev/null
+++ b/Source/core/html/MediaDocument.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008,2009 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. ``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 MediaDocument_h
+#define MediaDocument_h
+
+#include "core/html/HTMLDocument.h"
+
+namespace WebCore {
+
+class MediaDocument FINAL : public HTMLDocument {
+public:
+    static PassRefPtr<MediaDocument> create(Frame* frame, const KURL& url)
+    {
+        return adoptRef(new MediaDocument(frame, url));
+    }
+    virtual ~MediaDocument();
+
+    void mediaElementSawUnsupportedTracks();
+
+private:
+    MediaDocument(Frame*, const KURL&);
+
+    virtual bool isMediaDocument() const { return true; }        
+    virtual PassRefPtr<DocumentParser> createParser();
+
+    virtual void defaultEventHandler(Event*);
+
+    void replaceMediaElementTimerFired(Timer<MediaDocument>*);
+
+    Timer<MediaDocument> m_replaceMediaElementTimer;
+};
+
+inline MediaDocument* toMediaDocument(Document* document)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!document || document->isMediaDocument());
+    return static_cast<MediaDocument*>(document);
+}
+
+inline const MediaDocument* toMediaDocument(const Document* document)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!document || document->isMediaDocument());
+    return static_cast<const MediaDocument*>(document);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toMediaDocument(const MediaDocument*);
+
+}
+
+#endif
diff --git a/Source/core/html/MediaError.h b/Source/core/html/MediaError.h
new file mode 100644
index 0000000..63ed525
--- /dev/null
+++ b/Source/core/html/MediaError.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 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 COMPUTER, 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 COMPUTER, 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 MediaError_h
+#define MediaError_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class MediaError : public RefCounted<MediaError> {
+public:
+    enum Code {
+        MEDIA_ERR_ABORTED = 1,
+        MEDIA_ERR_NETWORK,
+        MEDIA_ERR_DECODE,
+        MEDIA_ERR_SRC_NOT_SUPPORTED
+#if ENABLE(ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA_V2)
+        , MEDIA_ERR_ENCRYPTED
+#endif
+    };
+
+    static PassRefPtr<MediaError> create(Code code) { return adoptRef(new MediaError(code)); }
+
+    Code code() const { return m_code; }
+
+private:
+    MediaError(Code code) : m_code(code) { }
+
+    Code m_code;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/MediaError.idl b/Source/core/html/MediaError.idl
new file mode 100644
index 0000000..cbc4eb2
--- /dev/null
+++ b/Source/core/html/MediaError.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    ImplementationLacksVTable
+] interface MediaError {
+      const unsigned short MEDIA_ERR_ABORTED = 1;
+      const unsigned short MEDIA_ERR_NETWORK = 2;
+      const unsigned short MEDIA_ERR_DECODE = 3;
+      const unsigned short MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
+#if (defined(ENABLE_ENCRYPTED_MEDIA) && ENABLE_ENCRYPTED_MEDIA) || (defined(ENABLE_ENCRYPTED_MEDIA_V2) && ENABLE_ENCRYPTED_MEDIA_V2)
+      const unsigned short MEDIA_ERR_ENCRYPTED = 5;
+#endif
+      readonly attribute unsigned short code;
+};
diff --git a/Source/core/html/MediaFragmentURIParser.cpp b/Source/core/html/MediaFragmentURIParser.cpp
new file mode 100644
index 0000000..a62b6bc
--- /dev/null
+++ b/Source/core/html/MediaFragmentURIParser.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2011, 2012 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/MediaFragmentURIParser.h"
+
+#include "core/dom/ProcessingInstruction.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLElement.h"
+#include "core/platform/graphics/MediaPlayer.h"
+#include "core/platform/text/SegmentedString.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+const int secondsPerHour = 3600;
+const int secondsPerMinute = 60;
+const unsigned nptIdentiferLength = 4; // "npt:"
+
+static String collectDigits(const LChar* input, unsigned length, unsigned& position)
+{
+    StringBuilder digits;
+
+    // http://www.ietf.org/rfc/rfc2326.txt
+    // DIGIT ; any positive number
+    while (position < length && isASCIIDigit(input[position]))
+        digits.append(input[position++]);
+    return digits.toString();
+}
+
+static String collectFraction(const LChar* input, unsigned length, unsigned& position)
+{
+    StringBuilder digits;
+
+    // http://www.ietf.org/rfc/rfc2326.txt
+    // [ "." *DIGIT ]
+    if (input[position] != '.')
+        return String();
+
+    digits.append(input[position++]);
+    while (position < length && isASCIIDigit(input[position]))
+        digits.append(input[position++]);
+    return digits.toString();
+}
+
+double MediaFragmentURIParser::invalidTimeValue()
+{
+    return MediaPlayer::invalidTime();
+}
+
+MediaFragmentURIParser::MediaFragmentURIParser(const KURL& url)
+    : m_url(url)
+    , m_timeFormat(None)
+    , m_startTime(MediaPlayer::invalidTime())
+    , m_endTime(MediaPlayer::invalidTime())
+{
+}
+
+double MediaFragmentURIParser::startTime()
+{
+    if (!m_url.isValid())
+        return MediaPlayer::invalidTime();
+    if (m_timeFormat == None)
+        parseTimeFragment();
+    return m_startTime;
+}
+
+double MediaFragmentURIParser::endTime()
+{
+    if (!m_url.isValid())
+        return MediaPlayer::invalidTime();
+    if (m_timeFormat == None)
+        parseTimeFragment();
+    return m_endTime;
+}
+
+void MediaFragmentURIParser::parseFragments()
+{
+    if (!m_url.hasFragmentIdentifier())
+        return;
+    String fragmentString = m_url.fragmentIdentifier();
+    if (fragmentString.isEmpty())
+        return;
+
+    unsigned offset = 0;
+    unsigned end = fragmentString.length();
+    while (offset < end) {
+        // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#processing-name-value-components
+        // 1. Parse the octet string according to the namevalues syntax, yielding a list of 
+        //    name-value pairs, where name and value are both octet string. In accordance 
+        //    with RFC 3986, the name and value components must be parsed and separated before
+        //    percent-encoded octets are decoded.
+        size_t parameterStart = offset;
+        size_t parameterEnd = fragmentString.find('&', offset);
+        if (parameterEnd == notFound)
+            parameterEnd = end;
+
+        size_t equalOffset = fragmentString.find('=', offset);
+        if (equalOffset == notFound || equalOffset > parameterEnd) {
+            offset = parameterEnd + 1;
+            continue;
+        }
+
+        // 2. For each name-value pair:
+        //  a. Decode percent-encoded octets in name and value as defined by RFC 3986. If either
+        //     name or value are not valid percent-encoded strings, then remove the name-value pair
+        //     from the list.
+        const UChar* fragmentStart = fragmentString.characters();
+        String name = decodeURLEscapeSequences(String(fragmentStart + parameterStart, equalOffset - parameterStart));
+        String value;
+        if (equalOffset != parameterEnd)
+            value = decodeURLEscapeSequences(String(fragmentStart + equalOffset + 1, parameterEnd - equalOffset - 1));
+        
+        //  b. Convert name and value to Unicode strings by interpreting them as UTF-8. If either
+        //     name or value are not valid UTF-8 strings, then remove the name-value pair from the list.
+        bool validUTF8 = true;
+        if (!name.isEmpty()) {
+            name = name.utf8(String::StrictConversion).data();
+            validUTF8 = !name.isEmpty();
+        }
+        if (validUTF8 && !value.isEmpty()) {
+            value = value.utf8(String::StrictConversion).data();
+            validUTF8 = !value.isEmpty();
+        }
+        
+        if (validUTF8)
+            m_fragments.append(std::make_pair(name, value));
+
+        offset = parameterEnd + 1;
+    }
+}
+
+void MediaFragmentURIParser::parseTimeFragment()
+{
+    ASSERT(m_timeFormat == None);
+
+    if (m_fragments.isEmpty())
+        parseFragments();
+
+    m_timeFormat = Invalid;
+
+    for (unsigned i = 0; i < m_fragments.size(); ++i) {
+        pair<String, String>& fragment = m_fragments[i];
+
+        ASSERT(fragment.first.is8Bit());
+        ASSERT(fragment.second.is8Bit());
+
+        // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#naming-time
+        // Temporal clipping is denoted by the name t, and specified as an interval with a begin 
+        // time and an end time
+        if (fragment.first != "t")
+            continue;
+
+        // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#npt-time
+        // Temporal clipping can be specified either as Normal Play Time (npt) RFC 2326, as SMPTE timecodes,
+        // SMPTE, or as real-world clock time (clock) RFC 2326. Begin and end times are always specified
+        // in the same format. The format is specified by name, followed by a colon (:), with npt: being
+        // the default.
+        
+        double start = MediaPlayer::invalidTime();
+        double end = MediaPlayer::invalidTime();
+        if (parseNPTFragment(fragment.second.characters8(), fragment.second.length(), start, end)) {
+            m_startTime = start;
+            m_endTime = end;
+            m_timeFormat = NormalPlayTime;
+
+            // Although we have a valid fragment, don't return yet because when a fragment dimensions
+            // occurs multiple times, only the last occurrence of that dimension is used:
+            // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#error-uri-general
+            // Multiple occurrences of the same dimension: only the last valid occurrence of a dimension
+            // (e.g., t=10 in #t=2&t=10) is interpreted, all previous occurrences (valid or invalid) 
+            // SHOULD be ignored by the UA. 
+        }
+    }
+    m_fragments.clear();
+}
+
+bool MediaFragmentURIParser::parseNPTFragment(const LChar* timeString, unsigned length, double& startTime, double& endTime)
+{
+    unsigned offset = 0;
+    if (length >= nptIdentiferLength && timeString[0] == 'n' && timeString[1] == 'p' && timeString[2] == 't' && timeString[3] == ':')
+            offset += nptIdentiferLength;
+
+    if (offset == length)
+        return false;
+    
+    // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#naming-time
+    // If a single number only is given, this corresponds to the begin time except if it is preceded
+    // by a comma that would in this case indicate the end time.
+    if (timeString[offset] == ',')
+        startTime = 0;
+    else {
+        if (!parseNPTTime(timeString, length, offset, startTime))
+            return false;
+    }
+
+    if (offset == length)
+        return true;
+
+    if (timeString[offset] != ',')
+        return false;
+    if (++offset == length)
+        return false;
+
+    if (!parseNPTTime(timeString, length, offset, endTime))
+        return false;
+
+    if (offset != length)
+        return false;
+    
+    if (startTime >= endTime)
+        return false;
+
+    return true;
+}
+
+bool MediaFragmentURIParser::parseNPTTime(const LChar* timeString, unsigned length, unsigned& offset, double& time)
+{
+    enum Mode { minutes, hours };
+    Mode mode = minutes;
+
+    if (offset >= length || !isASCIIDigit(timeString[offset]))
+        return false;
+
+    // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#npttimedef
+    // Normal Play Time can either be specified as seconds, with an optional
+    // fractional part to indicate miliseconds, or as colon-separated hours,
+    // minutes and seconds (again with an optional fraction). Minutes and
+    // seconds must be specified as exactly two digits, hours and fractional
+    // seconds can be any number of digits. The hours, minutes and seconds
+    // specification for NPT is a convenience only, it does not signal frame
+    // accuracy. The specification of the "npt:" identifier is optional since
+    // NPT is the default time scheme. This specification builds on the RTSP
+    // specification of NPT RFC 2326.
+    //
+    // ; defined in RFC 2326
+    // npt-sec       = 1*DIGIT [ "." *DIGIT ]                     ; definitions taken
+    // npt-hhmmss    = npt-hh ":" npt-mm ":" npt-ss [ "." *DIGIT] ; from RFC 2326
+    // npt-mmss      = npt-mm ":" npt-ss [ "." *DIGIT] 
+    // npt-hh        =   1*DIGIT     ; any positive number
+    // npt-mm        =   2DIGIT      ; 0-59
+    // npt-ss        =   2DIGIT      ; 0-59
+
+    String digits1 = collectDigits(timeString, length, offset);
+    int value1 = digits1.toInt();
+    if (offset >= length || timeString[offset] == ',') {
+        time = value1;
+        return true;
+    }
+
+    double fraction = 0;
+    if (timeString[offset] == '.') {
+        if (offset == length)
+            return true;
+        String digits = collectFraction(timeString, length, offset);
+        fraction = digits.toDouble();
+        time = value1 + fraction;
+        return true;
+    }
+    
+    if (digits1.length() < 2)
+        return false;
+    if (digits1.length() > 2)
+        mode = hours;
+
+    // Collect the next sequence of 0-9 after ':'
+    if (offset >= length || timeString[offset++] != ':')
+        return false;
+    if (offset >= length || !isASCIIDigit(timeString[(offset)]))
+        return false;
+    String digits2 = collectDigits(timeString, length, offset);
+    int value2 = digits2.toInt();
+    if (digits2.length() != 2)
+        return false;
+
+    // Detect whether this timestamp includes hours.
+    int value3;
+    if (mode == hours || (offset < length && timeString[offset] == ':')) {
+        if (offset >= length || timeString[offset++] != ':')
+            return false;
+        if (offset >= length || !isASCIIDigit(timeString[offset]))
+            return false;
+        String digits3 = collectDigits(timeString, length, offset);
+        if (digits3.length() != 2)
+            return false;
+        value3 = digits3.toInt();
+    } else {
+        value3 = value2;
+        value2 = value1;
+        value1 = 0;
+    }
+
+    if (offset < length && timeString[offset] == '.')
+        fraction = collectFraction(timeString, length, offset).toDouble();
+    
+    time = (value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3 + fraction;
+    return true;
+}
+
+}
diff --git a/Source/core/html/MediaFragmentURIParser.h b/Source/core/html/MediaFragmentURIParser.h
new file mode 100644
index 0000000..509adb9
--- /dev/null
+++ b/Source/core/html/MediaFragmentURIParser.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011, 2012 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 COMPUTER, 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 COMPUTER, 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 MediaFragmentURIParser_h
+#define MediaFragmentURIParser_h
+
+#include "core/platform/KURL.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class KURL;
+
+class MediaFragmentURIParser FINAL {
+public:
+    
+    MediaFragmentURIParser(const KURL&);
+
+    double startTime();
+    double endTime();
+
+    static double invalidTimeValue();
+
+private:
+
+    void parseFragments();
+    
+    enum TimeFormat { None, Invalid, NormalPlayTime, SMPTETimeCode, WallClockTimeCode };
+    void parseTimeFragment();
+    bool parseNPTFragment(const LChar*, unsigned length, double& startTime, double& endTime);
+    bool parseNPTTime(const LChar*, unsigned length, unsigned& offset, double& time);
+
+    KURL m_url;
+    TimeFormat m_timeFormat;
+    double m_startTime;
+    double m_endTime;
+    Vector<std::pair<String, String> > m_fragments;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/MediaKeyError.h b/Source/core/html/MediaKeyError.h
new file mode 100644
index 0000000..49e3843
--- /dev/null
+++ b/Source/core/html/MediaKeyError.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 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 COMPUTER, 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 COMPUTER, 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 MediaKeyError_h
+#define MediaKeyError_h
+
+#if ENABLE(ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA_V2)
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class MediaKeyError : public RefCounted<MediaKeyError> {
+public:
+    enum {
+        MEDIA_KEYERR_UNKNOWN = 1,
+        MEDIA_KEYERR_CLIENT,
+        MEDIA_KEYERR_SERVICE,
+        MEDIA_KEYERR_OUTPUT,
+        MEDIA_KEYERR_HARDWARECHANGE,
+        MEDIA_KEYERR_DOMAIN
+    };
+    typedef unsigned short Code;
+
+    static PassRefPtr<MediaKeyError> create(Code code, unsigned long systemCode = 0) { return adoptRef(new MediaKeyError(code, systemCode)); }
+
+    Code code() const { return m_code; }
+    unsigned long systemCode() { return m_systemCode; }
+
+private:
+    explicit MediaKeyError(Code code, unsigned long systemCode) : m_code(code), m_systemCode(systemCode) { }
+
+    Code m_code;
+    unsigned long m_systemCode;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/MediaKeyError.idl b/Source/core/html/MediaKeyError.idl
new file mode 100644
index 0000000..597bfea
--- /dev/null
+++ b/Source/core/html/MediaKeyError.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=ENCRYPTED_MEDIA|ENCRYPTED_MEDIA_V2,
+    EnabledAtRuntime=encryptedMedia, 
+    ImplementationLacksVTable
+] interface MediaKeyError {
+    const unsigned short MEDIA_KEYERR_UNKNOWN = 1;
+    const unsigned short MEDIA_KEYERR_CLIENT = 2;
+    const unsigned short MEDIA_KEYERR_SERVICE = 3;
+    const unsigned short MEDIA_KEYERR_OUTPUT = 4;
+    const unsigned short MEDIA_KEYERR_HARDWARECHANGE = 5;
+    const unsigned short MEDIA_KEYERR_DOMAIN = 6;
+    readonly attribute unsigned short code;
+    [Conditional=ENCRYPTED_MEDIA_V2] readonly attribute unsigned long systemCode;
+};
diff --git a/Source/core/html/MediaKeyEvent.cpp b/Source/core/html/MediaKeyEvent.cpp
new file mode 100644
index 0000000..a420128
--- /dev/null
+++ b/Source/core/html/MediaKeyEvent.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#if ENABLE(ENCRYPTED_MEDIA)
+
+#include "core/html/MediaKeyEvent.h"
+
+#include "core/dom/EventNames.h"
+#include <wtf/Uint8Array.h>
+
+namespace WebCore {
+
+MediaKeyEventInit::MediaKeyEventInit()
+    : systemCode(0)
+{
+}
+
+MediaKeyEvent::MediaKeyEvent()
+{
+    ScriptWrappable::init(this);
+}
+
+MediaKeyEvent::MediaKeyEvent(const AtomicString& type, const MediaKeyEventInit& initializer)
+    : Event(type, initializer)
+    , m_keySystem(initializer.keySystem)
+    , m_sessionId(initializer.sessionId)
+    , m_initData(initializer.initData)
+    , m_message(initializer.message)
+    , m_defaultURL(initializer.defaultURL)
+    , m_errorCode(initializer.errorCode)
+    , m_systemCode(initializer.systemCode)
+{
+    ScriptWrappable::init(this);
+}
+
+MediaKeyEvent::~MediaKeyEvent()
+{
+}
+
+const AtomicString& MediaKeyEvent::interfaceName() const
+{
+    return eventNames().interfaceForMediaKeyEvent;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/MediaKeyEvent.h b/Source/core/html/MediaKeyEvent.h
new file mode 100644
index 0000000..cab4eef
--- /dev/null
+++ b/Source/core/html/MediaKeyEvent.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 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 COMPUTER, 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 COMPUTER, 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 MediaKeyEvent_h
+#define MediaKeyEvent_h
+
+#if ENABLE(ENCRYPTED_MEDIA)
+
+#include "core/dom/Event.h"
+#include "core/html/MediaKeyError.h"
+
+namespace WebCore {
+
+struct MediaKeyEventInit : public EventInit {
+    MediaKeyEventInit();
+
+    String keySystem;
+    String sessionId;
+    RefPtr<Uint8Array> initData;
+    RefPtr<Uint8Array> message;
+    String defaultURL;
+    RefPtr<MediaKeyError> errorCode;
+    unsigned short systemCode;
+};
+
+class MediaKeyEvent : public Event {
+public:
+    virtual ~MediaKeyEvent();
+
+    static PassRefPtr<MediaKeyEvent> create()
+    {
+        return adoptRef(new MediaKeyEvent);
+    }
+
+    static PassRefPtr<MediaKeyEvent> create(const AtomicString& type, const MediaKeyEventInit& initializer)
+    {
+        return adoptRef(new MediaKeyEvent(type, initializer));
+    }
+
+    virtual const AtomicString& interfaceName() const;
+
+    String keySystem() const { return m_keySystem; }
+    String sessionId() const { return m_sessionId; }
+    Uint8Array* initData() const { return m_initData.get(); }
+    Uint8Array* message() const { return m_message.get(); }
+    String defaultURL() const { return m_defaultURL; }
+    MediaKeyError* errorCode() const { return m_errorCode.get(); }
+    unsigned short systemCode() const { return m_systemCode; }
+
+private:
+    MediaKeyEvent();
+    MediaKeyEvent(const AtomicString& type, const MediaKeyEventInit& initializer);
+
+    String m_keySystem;
+    String m_sessionId;
+    RefPtr<Uint8Array> m_initData;
+    RefPtr<Uint8Array> m_message;
+    String m_defaultURL;
+    RefPtr<MediaKeyError> m_errorCode;
+    unsigned short m_systemCode;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/MediaKeyEvent.idl b/Source/core/html/MediaKeyEvent.idl
new file mode 100644
index 0000000..546a93b
--- /dev/null
+++ b/Source/core/html/MediaKeyEvent.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=ENCRYPTED_MEDIA,
+    EnabledAtRuntime=encryptedMedia,
+    ConstructorTemplate=Event 
+] interface MediaKeyEvent : Event {
+    [InitializedByEventConstructor] readonly attribute DOMString keySystem;
+    [InitializedByEventConstructor] readonly attribute DOMString sessionId;
+    [InitializedByEventConstructor] readonly attribute Uint8Array initData;
+    [InitializedByEventConstructor] readonly attribute Uint8Array message;
+    [InitializedByEventConstructor] readonly attribute DOMString defaultURL;
+    [InitializedByEventConstructor] readonly attribute MediaKeyError errorCode;
+    [InitializedByEventConstructor] readonly attribute unsigned short systemCode;
+};
+
diff --git a/Source/core/html/MonthInputType.cpp b/Source/core/html/MonthInputType.cpp
new file mode 100644
index 0000000..c7d9d6a
--- /dev/null
+++ b/Source/core/html/MonthInputType.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/MonthInputType.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/platform/DateComponents.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/DateMath.h>
+#include <wtf/MathExtras.h>
+#include <wtf/PassOwnPtr.h>
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/DateTimeFieldsState.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/text/PlatformLocale.h"
+#include <wtf/text/WTFString.h>
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const int monthDefaultStep = 1;
+static const int monthDefaultStepBase = 0;
+static const int monthStepScaleFactor = 1;
+
+PassOwnPtr<InputType> MonthInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new MonthInputType(element));
+}
+
+void MonthInputType::attach()
+{
+    observeFeatureIfVisible(UseCounter::InputTypeMonth);
+}
+
+const AtomicString& MonthInputType::formControlType() const
+{
+    return InputTypeNames::month();
+}
+
+DateComponents::Type MonthInputType::dateType() const
+{
+    return DateComponents::Month;
+}
+
+double MonthInputType::valueAsDate() const
+{
+    DateComponents date;
+    if (!parseToDateComponents(element()->value(), &date))
+        return DateComponents::invalidMilliseconds();
+    double msec = date.millisecondsSinceEpoch();
+    ASSERT(std::isfinite(msec));
+    return msec;
+}
+
+String MonthInputType::serializeWithMilliseconds(double value) const
+{
+    DateComponents date;
+    if (!date.setMillisecondsSinceEpochForMonth(value))
+        return String();
+    return serializeWithComponents(date);
+}
+
+Decimal MonthInputType::defaultValueForStepUp() const
+{
+    double current = currentTimeMS();
+    double utcOffset = calculateUTCOffset();
+    double dstOffset = calculateDSTOffset(current, utcOffset);
+    int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+    current += offset * msPerMinute;
+
+    DateComponents date;
+    date.setMillisecondsSinceEpochForMonth(current);
+    double months = date.monthsSinceEpoch();
+    ASSERT(std::isfinite(months));
+    return Decimal::fromDouble(months);
+}
+
+StepRange MonthInputType::createStepRange(AnyStepHandling anyStepHandling) const
+{
+    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (monthDefaultStep, monthDefaultStepBase, monthStepScaleFactor, StepRange::ParsedStepValueShouldBeInteger));
+
+    const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(monthDefaultStepBase));
+    const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumMonth()));
+    const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumMonth()));
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+    return StepRange(stepBase, minimum, maximum, step, stepDescription);
+}
+
+Decimal MonthInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
+{
+    DateComponents date;
+    if (!parseToDateComponents(src, &date))
+        return defaultValue;
+    double months = date.monthsSinceEpoch();
+    ASSERT(std::isfinite(months));
+    return Decimal::fromDouble(months);
+}
+
+bool MonthInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const
+{
+    ASSERT(out);
+    unsigned end;
+    return out->parseMonth(characters, length, 0, end) && end == length;
+}
+
+bool MonthInputType::setMillisecondToDateComponents(double value, DateComponents* date) const
+{
+    ASSERT(date);
+    return date->setMonthsSinceEpoch(value);
+}
+
+bool MonthInputType::isMonthField() const
+{
+    return true;
+}
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+String MonthInputType::formatDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) const
+{
+    if (!dateTimeFieldsState.hasMonth() || !dateTimeFieldsState.hasYear())
+        return emptyString();
+    return String::format("%04u-%02u", dateTimeFieldsState.year(), dateTimeFieldsState.month());
+}
+
+void MonthInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& date) const
+{
+    layoutParameters.dateTimeFormat = layoutParameters.locale.monthFormat();
+    layoutParameters.fallbackDateTimeFormat = "yyyy-MM";
+    if (!parseToDateComponents(element()->fastGetAttribute(minAttr), &layoutParameters.minimum))
+        layoutParameters.minimum = DateComponents();
+    if (!parseToDateComponents(element()->fastGetAttribute(maxAttr), &layoutParameters.maximum))
+        layoutParameters.maximum = DateComponents();
+    layoutParameters.placeholderForMonth = "--";
+    layoutParameters.placeholderForYear = "----";
+}
+
+bool MonthInputType::isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const
+{
+    return hasYear && hasMonth;
+}
+#endif
+} // namespace WebCore
diff --git a/Source/core/html/MonthInputType.h b/Source/core/html/MonthInputType.h
new file mode 100644
index 0000000..2e11cd4
--- /dev/null
+++ b/Source/core/html/MonthInputType.h
@@ -0,0 +1,73 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 MonthInputType_h
+#define MonthInputType_h
+
+#include "core/html/BaseChooserOnlyDateAndTimeInputType.h"
+#include "core/html/BaseMultipleFieldsDateAndTimeInputType.h"
+
+namespace WebCore {
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+typedef BaseMultipleFieldsDateAndTimeInputType BaseMonthInputType;
+#else
+typedef BaseChooserOnlyDateAndTimeInputType BaseMonthInputType;
+#endif
+
+class MonthInputType : public BaseMonthInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    MonthInputType(HTMLInputElement* element) : BaseMonthInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual DateComponents::Type dateType() const OVERRIDE;
+    virtual double valueAsDate() const OVERRIDE;
+    virtual String serializeWithMilliseconds(double) const OVERRIDE;
+    virtual Decimal parseToNumber(const String&, const Decimal&) const OVERRIDE;
+    virtual Decimal defaultValueForStepUp() const OVERRIDE;
+    virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
+    virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
+    virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
+    virtual bool isMonthField() const OVERRIDE;
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+    // BaseMultipleFieldsDateAndTimeInputType functions
+    virtual String formatDateTimeFieldsState(const DateTimeFieldsState&) const OVERRIDE FINAL;
+    virtual void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const OVERRIDE FINAL;
+    virtual bool isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // MonthInputType_h
diff --git a/Source/core/html/NumberInputType.cpp b/Source/core/html/NumberInputType.cpp
new file mode 100644
index 0000000..e66394b
--- /dev/null
+++ b/Source/core/html/NumberInputType.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/NumberInputType.h"
+
+#include <limits>
+#include "HTMLNames.h"
+#include "core/dom/BeforeTextInsertedEvent.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/text/PlatformLocale.h"
+#include "core/rendering/RenderTextControl.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/MathExtras.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace std;
+
+static const int numberDefaultStep = 1;
+static const int numberDefaultStepBase = 0;
+static const int numberStepScaleFactor = 1;
+
+struct RealNumberRenderSize
+{
+    unsigned sizeBeforeDecimalPoint;
+    unsigned sizeAfteDecimalPoint;
+
+    RealNumberRenderSize(unsigned before, unsigned after)
+        : sizeBeforeDecimalPoint(before)
+        , sizeAfteDecimalPoint(after)
+    {
+    }
+
+    RealNumberRenderSize max(const RealNumberRenderSize& other) const
+    {
+        return RealNumberRenderSize(
+            std::max(sizeBeforeDecimalPoint, other.sizeBeforeDecimalPoint),
+            std::max(sizeAfteDecimalPoint, other.sizeAfteDecimalPoint));
+    }
+};
+
+static RealNumberRenderSize calculateRenderSize(const Decimal& value)
+{
+    ASSERT(value.isFinite());
+    const unsigned sizeOfDigits = String::number(value.value().coefficient()).length();
+    const unsigned sizeOfSign = value.isNegative() ? 1 : 0;
+    const int exponent = value.exponent();
+    if (exponent >= 0)
+        return RealNumberRenderSize(sizeOfSign + sizeOfDigits, 0);
+
+    const int sizeBeforeDecimalPoint = exponent + sizeOfDigits;
+    if (sizeBeforeDecimalPoint > 0) {
+        // In case of "123.456"
+        return RealNumberRenderSize(sizeOfSign + sizeBeforeDecimalPoint, sizeOfDigits - sizeBeforeDecimalPoint);
+    }
+
+    // In case of "0.00012345"
+    const unsigned sizeOfZero = 1;
+    const unsigned numberOfZeroAfterDecimalPoint = -sizeBeforeDecimalPoint;
+    return RealNumberRenderSize(sizeOfSign + sizeOfZero , numberOfZeroAfterDecimalPoint + sizeOfDigits);
+}
+
+PassOwnPtr<InputType> NumberInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new NumberInputType(element));
+}
+
+void NumberInputType::attach()
+{
+    TextFieldInputType::attach();
+    observeFeatureIfVisible(UseCounter::InputTypeNumber);
+}
+
+const AtomicString& NumberInputType::formControlType() const
+{
+    return InputTypeNames::number();
+}
+
+void NumberInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
+{
+    if (!valueChanged && sanitizedValue.isEmpty() && !element()->innerTextValue().isEmpty())
+        updateInnerTextValue();
+    TextFieldInputType::setValue(sanitizedValue, valueChanged, eventBehavior);
+}
+
+double NumberInputType::valueAsDouble() const
+{
+    return parseToDoubleForNumberType(element()->value());
+}
+
+void NumberInputType::setValueAsDouble(double newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
+{
+    // FIXME: We should use numeric_limits<double>::max for number input type.
+    const double floatMax = numeric_limits<float>::max();
+    if (newValue < -floatMax) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    if (newValue > floatMax) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    element()->setValue(serializeForNumberType(newValue), eventBehavior);
+}
+
+void NumberInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
+{
+    // FIXME: We should use numeric_limits<double>::max for number input type.
+    const Decimal floatMax = Decimal::fromDouble(numeric_limits<float>::max());
+    if (newValue < -floatMax) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    if (newValue > floatMax) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    element()->setValue(serializeForNumberType(newValue), eventBehavior);
+}
+
+bool NumberInputType::typeMismatchFor(const String& value) const
+{
+    return !value.isEmpty() && !std::isfinite(parseToDoubleForNumberType(value));
+}
+
+bool NumberInputType::typeMismatch() const
+{
+    ASSERT(!typeMismatchFor(element()->value()));
+    return false;
+}
+
+StepRange NumberInputType::createStepRange(AnyStepHandling anyStepHandling) const
+{
+    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (numberDefaultStep, numberDefaultStepBase, numberStepScaleFactor));
+    const Decimal stepBase = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr), numberDefaultStepBase);
+    // FIXME: We should use numeric_limits<double>::max for number input type.
+    const Decimal floatMax = Decimal::fromDouble(numeric_limits<float>::max());
+    const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), -floatMax);
+    const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), floatMax);
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+    return StepRange(stepBase, minimum, maximum, step, stepDescription);
+}
+
+bool NumberInputType::sizeShouldIncludeDecoration(int defaultSize, int& preferredSize) const
+{
+    preferredSize = defaultSize;
+
+    const String stepString = element()->fastGetAttribute(stepAttr);
+    if (equalIgnoringCase(stepString, "any"))
+        return false;
+
+    const Decimal minimum = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr));
+    if (!minimum.isFinite())
+        return false;
+
+    const Decimal maximum = parseToDecimalForNumberType(element()->fastGetAttribute(maxAttr));
+    if (!maximum.isFinite())
+        return false;
+
+    const Decimal step = parseToDecimalForNumberType(stepString, 1);
+    ASSERT(step.isFinite());
+
+    RealNumberRenderSize size = calculateRenderSize(minimum).max(calculateRenderSize(maximum).max(calculateRenderSize(step)));
+
+    preferredSize = size.sizeBeforeDecimalPoint + size.sizeAfteDecimalPoint + (size.sizeAfteDecimalPoint ? 1 : 0);
+
+    return true;
+}
+
+bool NumberInputType::isSteppable() const
+{
+    return true;
+}
+
+void NumberInputType::handleKeydownEvent(KeyboardEvent* event)
+{
+    handleKeydownEventForSpinButton(event);
+    if (!event->defaultHandled())
+        TextFieldInputType::handleKeydownEvent(event);
+}
+
+Decimal NumberInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
+{
+    return parseToDecimalForNumberType(src, defaultValue);
+}
+
+String NumberInputType::serialize(const Decimal& value) const
+{
+    if (!value.isFinite())
+        return String();
+    return serializeForNumberType(value);
+}
+
+static bool isE(UChar ch)
+{
+    return ch == 'e' || ch == 'E';
+}
+
+String NumberInputType::localizeValue(const String& proposedValue) const
+{
+    if (proposedValue.isEmpty())
+        return proposedValue;
+    // We don't localize scientific notations.
+    if (proposedValue.find(isE) != notFound)
+        return proposedValue;
+    return element()->locale().convertToLocalizedNumber(proposedValue);
+}
+
+String NumberInputType::visibleValue() const
+{
+    return localizeValue(element()->value());
+}
+
+String NumberInputType::convertFromVisibleValue(const String& visibleValue) const
+{
+    if (visibleValue.isEmpty())
+        return visibleValue;
+    // We don't localize scientific notations.
+    if (visibleValue.find(isE) != notFound)
+        return visibleValue;
+    return element()->locale().convertFromLocalizedNumber(visibleValue);
+}
+
+String NumberInputType::sanitizeValue(const String& proposedValue) const
+{
+    if (proposedValue.isEmpty())
+        return proposedValue;
+    return std::isfinite(parseToDoubleForNumberType(proposedValue)) ? proposedValue : emptyString();
+}
+
+bool NumberInputType::hasBadInput() const
+{
+    String standardValue = convertFromVisibleValue(element()->innerTextValue());
+    return !standardValue.isEmpty() && !std::isfinite(parseToDoubleForNumberType(standardValue));
+}
+
+String NumberInputType::badInputText() const
+{
+    return validationMessageBadInputForNumberText();
+}
+
+bool NumberInputType::shouldRespectSpeechAttribute()
+{
+    return true;
+}
+
+bool NumberInputType::supportsPlaceholder() const
+{
+    return true;
+}
+
+bool NumberInputType::isNumberField() const
+{
+    return true;
+}
+
+void NumberInputType::minOrMaxAttributeChanged()
+{
+    InputType::minOrMaxAttributeChanged();
+
+    if (element()->renderer())
+        element()->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+void NumberInputType::stepAttributeChanged()
+{
+    InputType::stepAttributeChanged();
+
+    if (element()->renderer())
+        element()->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/NumberInputType.h b/Source/core/html/NumberInputType.h
new file mode 100644
index 0000000..e5ed8e5
--- /dev/null
+++ b/Source/core/html/NumberInputType.h
@@ -0,0 +1,73 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 NumberInputType_h
+#define NumberInputType_h
+
+#include "core/html/TextFieldInputType.h"
+
+namespace WebCore {
+
+class NumberInputType : public TextFieldInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    NumberInputType(HTMLInputElement* element) : TextFieldInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE;
+    virtual double valueAsDouble() const OVERRIDE;
+    virtual void setValueAsDouble(double, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
+    virtual void setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
+    virtual bool typeMismatchFor(const String&) const OVERRIDE;
+    virtual bool typeMismatch() const OVERRIDE;
+    virtual bool sizeShouldIncludeDecoration(int defaultSize, int& preferredSize) const OVERRIDE;
+    virtual bool isSteppable() const OVERRIDE;
+    virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
+    virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
+    virtual Decimal parseToNumber(const String&, const Decimal&) const OVERRIDE;
+    virtual String serialize(const Decimal&) const OVERRIDE;
+    virtual String localizeValue(const String&) const OVERRIDE;
+    virtual String visibleValue() const OVERRIDE;
+    virtual String convertFromVisibleValue(const String&) const OVERRIDE;
+    virtual String sanitizeValue(const String&) const OVERRIDE;
+    virtual bool hasBadInput() const OVERRIDE;
+    virtual String badInputText() const OVERRIDE;
+    virtual bool shouldRespectSpeechAttribute() OVERRIDE;
+    virtual bool supportsPlaceholder() const OVERRIDE;
+    virtual bool isNumberField() const OVERRIDE;
+    virtual void minOrMaxAttributeChanged() OVERRIDE;
+    virtual void stepAttributeChanged() OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // NumberInputType_h
diff --git a/Source/core/html/PasswordInputType.cpp b/Source/core/html/PasswordInputType.cpp
new file mode 100644
index 0000000..b56e423
--- /dev/null
+++ b/Source/core/html/PasswordInputType.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/PasswordInputType.h"
+
+#include "core/html/FormController.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include <wtf/Assertions.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<InputType> PasswordInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new PasswordInputType(element));
+}
+
+const AtomicString& PasswordInputType::formControlType() const
+{
+    return InputTypeNames::password();
+}
+
+bool PasswordInputType::shouldSaveAndRestoreFormControlState() const
+{
+    return false;
+}
+
+FormControlState PasswordInputType::saveFormControlState() const
+{
+    // Should never save/restore password fields.
+    ASSERT_NOT_REACHED();
+    return FormControlState();
+}
+
+void PasswordInputType::restoreFormControlState(const FormControlState&)
+{
+    // Should never save/restore password fields.
+    ASSERT_NOT_REACHED();
+}
+
+bool PasswordInputType::shouldUseInputMethod() const
+{
+    // Input methods are disabled for the password field because otherwise
+    // anyone can access the underlying password and display it in clear text.
+    return false;
+}
+
+bool PasswordInputType::shouldResetOnDocumentActivation()
+{
+    return true;
+}
+
+bool PasswordInputType::shouldRespectListAttribute()
+{
+    return false;
+}
+
+bool PasswordInputType::shouldRespectSpeechAttribute()
+{
+    return true;
+}
+
+bool PasswordInputType::isPasswordField() const
+{
+    return true;
+}
+
+void PasswordInputType::handleFocusEvent(Node* oldFocusedNode, FocusDirection direction)
+{
+    BaseTextInputType::handleFocusEvent(oldFocusedNode, direction);
+    if (element()->document()->frame())
+        element()->document()->setUseSecureKeyboardEntryWhenActive(true);
+}
+
+void PasswordInputType::handleBlurEvent()
+{
+    if (element()->document()->frame())
+        element()->document()->setUseSecureKeyboardEntryWhenActive(false);
+    BaseTextInputType::handleBlurEvent();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/PasswordInputType.h b/Source/core/html/PasswordInputType.h
new file mode 100644
index 0000000..96afdb5
--- /dev/null
+++ b/Source/core/html/PasswordInputType.h
@@ -0,0 +1,59 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 PasswordInputType_h
+#define PasswordInputType_h
+
+#include "core/html/BaseTextInputType.h"
+
+namespace WebCore {
+
+class PasswordInputType : public BaseTextInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    PasswordInputType(HTMLInputElement* element) : BaseTextInputType(element) { }
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool shouldSaveAndRestoreFormControlState() const OVERRIDE;
+    virtual FormControlState saveFormControlState() const OVERRIDE;
+    virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
+    virtual bool shouldUseInputMethod() const OVERRIDE;
+    virtual bool shouldResetOnDocumentActivation() OVERRIDE;
+    virtual bool shouldRespectListAttribute() OVERRIDE;
+    virtual bool shouldRespectSpeechAttribute() OVERRIDE;
+    virtual bool isPasswordField() const OVERRIDE;
+    virtual void handleFocusEvent(Node* oldFocusedNode, FocusDirection) OVERRIDE;
+    virtual void handleBlurEvent() OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // PasswordInputType_h
diff --git a/Source/core/html/PluginDocument.cpp b/Source/core/html/PluginDocument.cpp
new file mode 100644
index 0000000..06b42f2
--- /dev/null
+++ b/Source/core/html/PluginDocument.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2006, 2008 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 "core/html/PluginDocument.h"
+
+#include "HTMLNames.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/RawDataDocumentParser.h"
+#include "core/html/HTMLEmbedElement.h"
+#include "core/html/HTMLHtmlElement.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/rendering/RenderEmbeddedObject.h"
+
+namespace WebCore {
+    
+using namespace HTMLNames;
+
+// FIXME: Share more code with MediaDocumentParser.
+class PluginDocumentParser : public RawDataDocumentParser {
+public:
+    static PassRefPtr<PluginDocumentParser> create(PluginDocument* document)
+    {
+        return adoptRef(new PluginDocumentParser(document));
+    }
+
+private:
+    PluginDocumentParser(Document* document)
+        : RawDataDocumentParser(document)
+        , m_embedElement(0)
+    {
+    }
+
+    virtual void appendBytes(DocumentWriter*, const char*, size_t);
+
+    void createDocumentStructure();
+
+    HTMLEmbedElement* m_embedElement;
+};
+
+void PluginDocumentParser::createDocumentStructure()
+{
+    RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
+    document()->appendChild(rootElement, IGNORE_EXCEPTION);
+    static_cast<HTMLHtmlElement*>(rootElement.get())->insertedByParser();
+
+    if (document()->frame() && document()->frame()->loader())
+        document()->frame()->loader()->dispatchDocumentElementAvailable();
+
+    RefPtr<Element> body = document()->createElement(bodyTag, false);
+    body->setAttribute(marginwidthAttr, "0");
+    body->setAttribute(marginheightAttr, "0");
+    body->setAttribute(styleAttr, "background-color: rgb(38,38,38)");
+
+    rootElement->appendChild(body, IGNORE_EXCEPTION);
+        
+    RefPtr<Element> embedElement = document()->createElement(embedTag, false);
+        
+    m_embedElement = static_cast<HTMLEmbedElement*>(embedElement.get());
+    m_embedElement->setAttribute(widthAttr, "100%");
+    m_embedElement->setAttribute(heightAttr, "100%");
+    
+    m_embedElement->setAttribute(nameAttr, "plugin");
+    m_embedElement->setAttribute(srcAttr, document()->url().string());
+    
+    DocumentLoader* loader = document()->loader();
+    ASSERT(loader);
+    if (loader)
+        m_embedElement->setAttribute(typeAttr, loader->writer()->mimeType());
+
+    toPluginDocument(document())->setPluginNode(m_embedElement);
+
+    body->appendChild(embedElement, IGNORE_EXCEPTION);
+}
+
+void PluginDocumentParser::appendBytes(DocumentWriter*, const char*, size_t)
+{
+    if (m_embedElement)
+        return;
+
+    createDocumentStructure();
+
+    Frame* frame = document()->frame();
+    if (!frame)
+        return;
+    Settings* settings = frame->settings();
+    if (!settings || !frame->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
+        return;
+
+    document()->updateLayout();
+
+    // Below we assume that renderer->widget() to have been created by
+    // document()->updateLayout(). However, in some cases, updateLayout() will 
+    // recurse too many times and delay its post-layout tasks (such as creating
+    // the widget). Here we kick off the pending post-layout tasks so that we
+    // can synchronously redirect data to the plugin.
+    frame->view()->flushAnyPendingPostLayoutTasks();
+
+    if (RenderPart* renderer = m_embedElement->renderPart()) {
+        if (Widget* widget = renderer->widget()) {
+            frame->loader()->client()->redirectDataToPlugin(widget);
+            // In a plugin document, the main resource is the plugin. If we have a null widget, that means
+            // the loading of the plugin was cancelled, which gives us a null mainResourceLoader(), so we
+            // need to have this call in a null check of the widget or of mainResourceLoader().
+            frame->loader()->activeDocumentLoader()->setMainResourceDataBufferingPolicy(DoNotBufferData);
+        }
+    }
+}
+
+PluginDocument::PluginDocument(Frame* frame, const KURL& url)
+    : HTMLDocument(frame, url)
+    , m_shouldLoadPluginManually(true)
+{
+    setCompatibilityMode(QuirksMode);
+    lockCompatibilityMode();
+}
+
+PassRefPtr<DocumentParser> PluginDocument::createParser()
+{
+    return PluginDocumentParser::create(this);
+}
+
+Widget* PluginDocument::pluginWidget()
+{
+    if (m_pluginNode && m_pluginNode->renderer()) {
+        ASSERT(m_pluginNode->renderer()->isEmbeddedObject());
+        return toRenderEmbeddedObject(m_pluginNode->renderer())->widget();
+    }
+    return 0;
+}
+
+Node* PluginDocument::pluginNode()
+{
+    return m_pluginNode.get();
+}
+
+void PluginDocument::detach()
+{
+    // Release the plugin node so that we don't have a circular reference.
+    m_pluginNode = 0;
+    if (FrameLoader* loader = frame()->loader())
+        loader->client()->redirectDataToPlugin(0);
+    HTMLDocument::detach();
+}
+
+void PluginDocument::cancelManualPluginLoad()
+{
+    // PluginDocument::cancelManualPluginLoad should only be called once, but there are issues
+    // with how many times we call beforeload on object elements. <rdar://problem/8441094>.
+    if (!shouldLoadPluginManually())
+        return;
+
+    DocumentLoader* documentLoader = frame()->loader()->activeDocumentLoader();
+    documentLoader->cancelMainResourceLoad(frame()->loader()->cancelledError(documentLoader->request()));
+    setShouldLoadPluginManually(false);
+}
+
+}
diff --git a/Source/core/html/PluginDocument.h b/Source/core/html/PluginDocument.h
new file mode 100644
index 0000000..49175dc
--- /dev/null
+++ b/Source/core/html/PluginDocument.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006, 2008, 2009 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 PluginDocument_h
+#define PluginDocument_h
+
+#include "core/html/HTMLDocument.h"
+
+namespace WebCore {
+
+class Node;
+class Widget;
+
+class PluginDocument FINAL : public HTMLDocument {
+public:
+    static PassRefPtr<PluginDocument> create(Frame* frame, const KURL& url)
+    {
+        return adoptRef(new PluginDocument(frame, url));
+    }
+
+    void setPluginNode(Node* pluginNode) { m_pluginNode = pluginNode; }
+
+    Widget* pluginWidget();
+    Node* pluginNode();
+
+    virtual void detach() OVERRIDE;
+
+    void cancelManualPluginLoad();
+
+    bool shouldLoadPluginManually() { return m_shouldLoadPluginManually; }
+
+private:
+    PluginDocument(Frame*, const KURL&);
+
+    virtual PassRefPtr<DocumentParser> createParser() OVERRIDE;
+    virtual bool isPluginDocument() const OVERRIDE { return true; }    
+        
+    void setShouldLoadPluginManually(bool loadManually) { m_shouldLoadPluginManually = loadManually; }
+
+    bool m_shouldLoadPluginManually;
+    RefPtr<Node> m_pluginNode;
+};
+
+inline PluginDocument* toPluginDocument(Document* document)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!document || document->isPluginDocument());
+    return static_cast<PluginDocument*>(document);
+}
+
+inline const PluginDocument* toPluginDocument(const Document* document)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!document || document->isPluginDocument());
+    return static_cast<const PluginDocument*>(document);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toPluginDocument(const PluginDocument*);
+    
+}
+
+#endif // PluginDocument_h
diff --git a/Source/core/html/PublicURLManager.h b/Source/core/html/PublicURLManager.h
new file mode 100644
index 0000000..dfdf533
--- /dev/null
+++ b/Source/core/html/PublicURLManager.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 Motorola Mobility Inc.
+ *
+ * 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 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 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 PublicURLManager_h
+#define PublicURLManager_h
+
+#include "core/dom/ScriptExecutionContext.h"
+#include "core/fileapi/ThreadableBlobRegistry.h"
+#include <wtf/HashSet.h>
+#include <wtf/text/WTFString.h>
+
+#include "modules/mediastream/MediaStream.h"
+#include "modules/mediastream/MediaStreamRegistry.h"
+#include "modules/mediasource/MediaSource.h"
+#include "modules/mediasource/MediaSourceRegistry.h"
+
+namespace WebCore {
+
+class ScriptExecutionContext;
+
+class PublicURLManager {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<PublicURLManager> create() { return adoptPtr(new PublicURLManager); }
+    void contextDestroyed()
+    {
+        HashSet<String>::iterator blobURLsEnd = m_blobURLs.end();
+        for (HashSet<String>::iterator iter = m_blobURLs.begin(); iter != blobURLsEnd; ++iter)
+            ThreadableBlobRegistry::unregisterBlobURL(KURL(ParsedURLString, *iter));
+
+        HashSet<String>::iterator streamURLsEnd = m_streamURLs.end();
+        for (HashSet<String>::iterator iter = m_streamURLs.begin(); iter != streamURLsEnd; ++iter)
+            MediaStreamRegistry::registry().unregisterMediaStreamURL(KURL(ParsedURLString, *iter));
+        HashSet<String>::iterator sourceURLsEnd = m_sourceURLs.end();
+        for (HashSet<String>::iterator iter = m_sourceURLs.begin(); iter != sourceURLsEnd; ++iter)
+            MediaSourceRegistry::registry().unregisterMediaSourceURL(KURL(ParsedURLString, *iter));
+    }
+
+    HashSet<String>& blobURLs() { return m_blobURLs; }
+    HashSet<String>& streamURLs() { return m_streamURLs; }
+    HashSet<String>& sourceURLs() { return m_sourceURLs; }
+
+private:
+    HashSet<String> m_blobURLs;
+    HashSet<String> m_streamURLs;
+    HashSet<String> m_sourceURLs;
+};
+
+} // namespace WebCore
+
+#endif // PUBLICURLMANAGER_h
diff --git a/Source/core/html/RadioInputType.cpp b/Source/core/html/RadioInputType.cpp
new file mode 100644
index 0000000..10c1c2c
--- /dev/null
+++ b/Source/core/html/RadioInputType.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2005, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/RadioInputType.h"
+
+#include "HTMLNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/page/Frame.h"
+#include "core/page/Settings.h"
+#include "core/page/SpatialNavigation.h"
+#include "core/platform/LocalizedStrings.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+PassOwnPtr<InputType> RadioInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new RadioInputType(element));
+}
+
+const AtomicString& RadioInputType::formControlType() const
+{
+    return InputTypeNames::radio();
+}
+
+bool RadioInputType::valueMissing(const String&) const
+{
+    return element()->isInRequiredRadioButtonGroup() && !element()->checkedRadioButtonForGroup();
+}
+
+String RadioInputType::valueMissingText() const
+{
+    return validationMessageValueMissingForRadioText();
+}
+
+void RadioInputType::handleClickEvent(MouseEvent* event)
+{
+    event->setDefaultHandled();
+}
+
+void RadioInputType::handleKeydownEvent(KeyboardEvent* event)
+{
+    BaseCheckableInputType::handleKeydownEvent(event);
+    if (event->defaultHandled())
+        return;
+    const String& key = event->keyIdentifier();
+    if (key != "Up" && key != "Down" && key != "Left" && key != "Right")
+        return;
+
+    // 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
+    // to the right).  Seems strange, but we'll match it.
+    // However, when using Spatial Navigation, we need to be able to navigate without changing the selection.
+    Document* document = element()->document();
+    if (isSpatialNavigationEnabled(document->frame()))
+        return;
+    bool forward = (key == "Down" || key == "Right");
+
+    // We can only stay within the form's children if the form hasn't been demoted to a leaf because
+    // of malformed HTML.
+    Node* node = element();
+    while ((node = (forward ? NodeTraversal::next(node) : NodeTraversal::previous(node)))) {
+        // Once we encounter a form element, we know we're through.
+        if (node->hasTagName(formTag))
+            break;
+        // Look for more radio buttons.
+        if (!node->hasTagName(inputTag))
+            continue;
+        HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node);
+        if (inputElement->form() != element()->form())
+            break;
+        if (inputElement->isRadioButton() && inputElement->name() == element()->name() && inputElement->isFocusable()) {
+            document->setFocusedNode(inputElement);
+            inputElement->dispatchSimulatedClick(event, SendNoEvents, DoNotShowPressedLook);
+            event->setDefaultHandled();
+            return;
+        }
+    }
+}
+
+void RadioInputType::handleKeyupEvent(KeyboardEvent* event)
+{
+    const String& key = event->keyIdentifier();
+    if (key != "U+0020")
+        return;
+    // If an unselected radio is tabbed into (because the entire group has nothing
+    // checked, or because of some explicit .focus() call), then allow space to check it.
+    if (element()->checked())
+        return;
+    dispatchSimulatedClickIfActive(event);
+}
+
+bool RadioInputType::isKeyboardFocusable(KeyboardEvent* event) const
+{
+    if (!InputType::isKeyboardFocusable(event))
+        return false;
+
+    // When using Spatial Navigation, every radio button should be focusable.
+    if (isSpatialNavigationEnabled(element()->document()->frame()))
+        return true;
+
+    // Never allow keyboard tabbing to leave you in the same radio group.  Always
+    // skip any other elements in the group.
+    Node* currentFocusedNode = element()->document()->focusedNode();
+    if (currentFocusedNode && currentFocusedNode->hasTagName(inputTag)) {
+        HTMLInputElement* focusedInput = static_cast<HTMLInputElement*>(currentFocusedNode);
+        if (focusedInput->isRadioButton() && focusedInput->form() == element()->form() && focusedInput->name() == element()->name())
+            return false;
+    }
+
+    // Allow keyboard focus if we're checked or if nothing in the group is checked.
+    return element()->checked() || !element()->checkedRadioButtonForGroup();
+}
+
+bool RadioInputType::shouldSendChangeEventAfterCheckedChanged()
+{
+    // Don't send a change event for a radio button that's getting unchecked.
+    // This was done to match the behavior of other browsers.
+    return element()->checked();
+}
+
+PassOwnPtr<ClickHandlingState> RadioInputType::willDispatchClick()
+{
+    // An event handler can use preventDefault or "return false" to reverse the selection we do here.
+    // The ClickHandlingState object contains what we need to undo what we did here in didDispatchClick.
+
+    // We want radio groups to end up in sane states, i.e., to have something checked.
+    // Therefore if nothing is currently selected, we won't allow the upcoming action to be "undone", since
+    // we want some object in the radio group to actually get selected.
+
+    OwnPtr<ClickHandlingState> state = adoptPtr(new ClickHandlingState);
+
+    state->checked = element()->checked();
+    state->checkedRadioButton = element()->checkedRadioButtonForGroup();
+    element()->setChecked(true, DispatchChangeEvent);
+
+    return state.release();
+}
+
+void RadioInputType::didDispatchClick(Event* event, const ClickHandlingState& state)
+{
+    if (event->defaultPrevented() || event->defaultHandled()) {
+        // Restore the original selected radio button if possible.
+        // Make sure it is still a radio button and only do the restoration if it still belongs to our group.
+        HTMLInputElement* checkedRadioButton = state.checkedRadioButton.get();
+        if (checkedRadioButton
+                && checkedRadioButton->isRadioButton()
+                && checkedRadioButton->form() == element()->form()
+                && checkedRadioButton->name() == element()->name()) {
+            checkedRadioButton->setChecked(true);
+        }
+    }
+
+    // The work we did in willDispatchClick was default handling.
+    event->setDefaultHandled();
+}
+
+bool RadioInputType::isRadioButton() const
+{
+    return true;
+}
+
+bool RadioInputType::supportsIndeterminateAppearance() const
+{
+    return false;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/RadioInputType.h b/Source/core/html/RadioInputType.h
new file mode 100644
index 0000000..a5a9696
--- /dev/null
+++ b/Source/core/html/RadioInputType.h
@@ -0,0 +1,60 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 RadioInputType_h
+#define RadioInputType_h
+
+#include "core/html/BaseCheckableInputType.h"
+
+namespace WebCore {
+
+class RadioInputType : public BaseCheckableInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    RadioInputType(HTMLInputElement* element) : BaseCheckableInputType(element) { }
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool valueMissing(const String&) const OVERRIDE;
+    virtual String valueMissingText() const OVERRIDE;
+    virtual void handleClickEvent(MouseEvent*) OVERRIDE;
+    virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
+    virtual void handleKeyupEvent(KeyboardEvent*) OVERRIDE;
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const OVERRIDE;
+    virtual bool shouldSendChangeEventAfterCheckedChanged() OVERRIDE;
+    virtual PassOwnPtr<ClickHandlingState> willDispatchClick() OVERRIDE;
+    virtual void didDispatchClick(Event*, const ClickHandlingState&) OVERRIDE;
+    virtual bool isRadioButton() const OVERRIDE;
+    virtual bool supportsIndeterminateAppearance() const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // RadioInputType_h
diff --git a/Source/core/html/RadioNodeList.cpp b/Source/core/html/RadioNodeList.cpp
new file mode 100644
index 0000000..9e0b10b
--- /dev/null
+++ b/Source/core/html/RadioNodeList.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2012 Motorola Mobility, 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 MOTOROLA MOBILITY, 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 MOTOROLA MOBILITY, 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 "core/html/RadioNodeList.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Element.h"
+#include "core/dom/NodeRareData.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLObjectElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RadioNodeList::RadioNodeList(Node* rootNode, const AtomicString& name)
+    : LiveNodeList(rootNode, RadioNodeListType, InvalidateForFormControls, rootNode->hasTagName(formTag) ? NodeListIsRootedAtDocument : NodeListIsRootedAtNode)
+    , m_name(name)
+{
+    ScriptWrappable::init(this);
+}
+
+RadioNodeList::~RadioNodeList()
+{
+    ownerNode()->nodeLists()->removeCacheWithAtomicName(this, RadioNodeListType, m_name);
+}
+
+static inline HTMLInputElement* toRadioButtonInputElement(Node* node)
+{
+    ASSERT(node->isElementNode());
+    HTMLInputElement* inputElement = node->toInputElement();
+    if (!inputElement || !inputElement->isRadioButton() || inputElement->value().isEmpty())
+        return 0;
+    return inputElement;
+}
+
+String RadioNodeList::value() const
+{
+    for (unsigned i = 0; i < length(); ++i) {
+        Node* node = item(i);
+        const HTMLInputElement* inputElement = toRadioButtonInputElement(node);
+        if (!inputElement || !inputElement->checked())
+            continue;
+        return inputElement->value();
+    }
+    return String();
+}
+
+void RadioNodeList::setValue(const String& value)
+{
+    for (unsigned i = 0; i < length(); ++i) {
+        Node* node = item(i);
+        HTMLInputElement* inputElement = toRadioButtonInputElement(node);
+        if (!inputElement || inputElement->value() != value)
+            continue;
+        inputElement->setChecked(true);
+        return;
+    }
+}
+
+bool RadioNodeList::checkElementMatchesRadioNodeListFilter(Element* testElement) const
+{
+    ASSERT(testElement->hasTagName(objectTag) || testElement->isFormControlElement());
+    if (ownerNode()->hasTagName(formTag)) {
+        HTMLFormElement* formElement = 0;
+        if (testElement->hasTagName(objectTag))
+            formElement = static_cast<HTMLObjectElement*>(testElement)->form();
+        else
+            formElement = static_cast<HTMLFormControlElement*>(testElement)->form();
+        if (!formElement || formElement != ownerNode())
+            return false;
+    }
+
+    return testElement->getIdAttribute() == m_name || testElement->getNameAttribute() == m_name;
+}
+
+bool RadioNodeList::nodeMatches(Element* testElement) const
+{
+    if (!testElement->hasTagName(objectTag) && !testElement->isFormControlElement())
+        return false;
+
+    if (HTMLInputElement* inputElement = testElement->toInputElement()) {
+        if (inputElement->isImageButton())
+            return false;
+    }
+
+    return checkElementMatchesRadioNodeListFilter(testElement);
+}
+
+} // namspace
+
diff --git a/Source/core/html/RadioNodeList.h b/Source/core/html/RadioNodeList.h
new file mode 100644
index 0000000..85a5dfd
--- /dev/null
+++ b/Source/core/html/RadioNodeList.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012 Motorola Mobility, 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 MOTOROLA MOBILITY, 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 MOTOROLA MOBILITY, 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 RadioNodeList_h
+#define RadioNodeList_h
+
+#include "core/dom/LiveNodeList.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class RadioNodeList : public LiveNodeList {
+public:
+    static PassRefPtr<RadioNodeList> create(Node* rootNode, CollectionType type, const AtomicString& name)
+    {
+        ASSERT_UNUSED(type, type == RadioNodeListType);
+        return adoptRef(new RadioNodeList(rootNode, name));
+    }
+
+    ~RadioNodeList();
+
+    String value() const;
+    void setValue(const String&);
+
+protected:
+    virtual bool nodeMatches(Element*) const;
+
+private:
+    RadioNodeList(Node*, const AtomicString& name);
+    bool checkElementMatchesRadioNodeListFilter(Element*) const;
+
+    AtomicString m_name;
+};
+
+} // namepsace
+
+#endif
+
diff --git a/Source/core/html/RadioNodeList.idl b/Source/core/html/RadioNodeList.idl
new file mode 100644
index 0000000..d3132f0
--- /dev/null
+++ b/Source/core/html/RadioNodeList.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012 Motorola Mobility, 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 MOTOROLA MOBILITY, 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 MOTOROLA MOBILITY, 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.
+ */
+
+[
+] interface RadioNodeList : NodeList {
+    attribute DOMString value;
+};
diff --git a/Source/core/html/RangeInputType.cpp b/Source/core/html/RangeInputType.cpp
new file mode 100644
index 0000000..75ebd80
--- /dev/null
+++ b/Source/core/html/RangeInputType.cpp
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/RangeInputType.h"
+
+#include <limits>
+#include "HTMLNames.h"
+#include "core/accessibility/AXObjectCache.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/ScopedEventQueue.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/Touch.h"
+#include "core/dom/TouchEvent.h"
+#include "core/dom/TouchList.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/html/StepRange.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/shadow/SliderThumbElement.h"
+#include "core/platform/PlatformMouseEvent.h"
+#include "core/rendering/RenderSlider.h"
+#include <wtf/MathExtras.h>
+#include <wtf/PassOwnPtr.h>
+
+#if ENABLE(DATALIST_ELEMENT)
+#include "core/html/HTMLDataListElement.h"
+#include "core/html/HTMLOptionElement.h"
+#include <wtf/NonCopyingSort.h>
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace std;
+
+static const int rangeDefaultMinimum = 0;
+static const int rangeDefaultMaximum = 100;
+static const int rangeDefaultStep = 1;
+static const int rangeDefaultStepBase = 0;
+static const int rangeStepScaleFactor = 1;
+
+static Decimal ensureMaximum(const Decimal& proposedValue, const Decimal& minimum, const Decimal& fallbackValue)
+{
+    return proposedValue >= minimum ? proposedValue : std::max(minimum, fallbackValue);
+}
+
+PassOwnPtr<InputType> RangeInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new RangeInputType(element));
+}
+
+RangeInputType::RangeInputType(HTMLInputElement* element)
+    : InputType(element)
+#if ENABLE(DATALIST_ELEMENT)
+    , m_tickMarkValuesDirty(true)
+#endif
+{
+}
+
+void RangeInputType::attach()
+{
+    observeFeatureIfVisible(UseCounter::InputTypeRange);
+}
+
+bool RangeInputType::isRangeControl() const
+{
+    return true;
+}
+
+const AtomicString& RangeInputType::formControlType() const
+{
+    return InputTypeNames::range();
+}
+
+double RangeInputType::valueAsDouble() const
+{
+    return parseToDoubleForNumberType(element()->value());
+}
+
+void RangeInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode&) const
+{
+    element()->setValue(serialize(newValue), eventBehavior);
+}
+
+bool RangeInputType::typeMismatchFor(const String& value) const
+{
+    return !value.isEmpty() && !std::isfinite(parseToDoubleForNumberType(value));
+}
+
+bool RangeInputType::supportsRequired() const
+{
+    return false;
+}
+
+StepRange RangeInputType::createStepRange(AnyStepHandling anyStepHandling) const
+{
+    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (rangeDefaultStep, rangeDefaultStepBase, rangeStepScaleFactor));
+
+    const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), rangeDefaultMinimum);
+    const Decimal maximum = ensureMaximum(parseToNumber(element()->fastGetAttribute(maxAttr), rangeDefaultMaximum), minimum, rangeDefaultMaximum);
+
+    const AtomicString& precisionValue = element()->fastGetAttribute(precisionAttr);
+    if (!precisionValue.isNull()) {
+        const Decimal step = equalIgnoringCase(precisionValue, "float") ? Decimal::nan() : 1;
+        return StepRange(minimum, minimum, maximum, step, stepDescription);
+    }
+
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+    return StepRange(minimum, minimum, maximum, step, stepDescription);
+}
+
+bool RangeInputType::isSteppable() const
+{
+    return true;
+}
+
+void RangeInputType::handleMouseDownEvent(MouseEvent* event)
+{
+    if (element()->isDisabledOrReadOnly())
+        return;
+
+    Node* targetNode = event->target()->toNode();
+    if (event->button() != LeftButton || !targetNode)
+        return;
+    ASSERT(element()->shadow());
+    if (targetNode != element() && !targetNode->isDescendantOf(element()->userAgentShadowRoot()))
+        return;
+    SliderThumbElement* thumb = sliderThumbElementOf(element());
+    if (targetNode == thumb)
+        return;
+    thumb->dragFrom(event->absoluteLocation());
+}
+
+void RangeInputType::handleTouchEvent(TouchEvent* event)
+{
+    if (element()->isDisabledOrReadOnly())
+        return;
+
+    if (event->type() == eventNames().touchendEvent) {
+        event->setDefaultHandled();
+        return;
+    }
+
+    TouchList* touches = event->targetTouches();
+    if (touches->length() == 1) {
+        Touch* touch = touches->item(0);
+        SliderThumbElement* thumb = sliderThumbElementOf(element());
+        thumb->setPositionFromPoint(touch->absoluteLocation());
+        event->setDefaultHandled();
+    }
+}
+
+bool RangeInputType::hasTouchEventHandler() const
+{
+    return true;
+}
+
+void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
+{
+    if (element()->isDisabledOrReadOnly())
+        return;
+
+    const String& key = event->keyIdentifier();
+
+    const Decimal current = parseToNumberOrNaN(element()->value());
+    ASSERT(current.isFinite());
+
+    StepRange stepRange(createStepRange(RejectAny));
+
+
+    // FIXME: We can't use stepUp() for the step value "any". So, we increase
+    // or decrease the value by 1/100 of the value range. Is it reasonable?
+    const Decimal step = equalIgnoringCase(element()->fastGetAttribute(stepAttr), "any") ? (stepRange.maximum() - stepRange.minimum()) / 100 : stepRange.step();
+    const Decimal bigStep = max((stepRange.maximum() - stepRange.minimum()) / 10, step);
+
+    bool isVertical = false;
+    if (element()->renderer()) {
+        ControlPart part = element()->renderer()->style()->appearance();
+        isVertical = part == SliderVerticalPart || part == MediaVolumeSliderPart;
+    }
+
+    Decimal newValue;
+    if (key == "Up")
+        newValue = current + step;
+    else if (key == "Down")
+        newValue = current - step;
+    else if (key == "Left")
+        newValue = isVertical ? current + step : current - step;
+    else if (key == "Right")
+        newValue = isVertical ? current - step : current + step;
+    else if (key == "PageUp")
+        newValue = current + bigStep;
+    else if (key == "PageDown")
+        newValue = current - bigStep;
+    else if (key == "Home")
+        newValue = isVertical ? stepRange.maximum() : stepRange.minimum();
+    else if (key == "End")
+        newValue = isVertical ? stepRange.minimum() : stepRange.maximum();
+    else
+        return; // Did not match any key binding.
+
+    newValue = stepRange.clampValue(newValue);
+
+    if (newValue != current) {
+        EventQueueScope scope;
+        TextFieldEventBehavior eventBehavior = DispatchChangeEvent;
+        setValueAsDecimal(newValue, eventBehavior, IGNORE_EXCEPTION);
+
+        if (AXObjectCache* cache = element()->document()->existingAXObjectCache())
+            cache->postNotification(element(), AXObjectCache::AXValueChanged, true);
+        element()->dispatchFormControlChangeEvent();
+    }
+
+    event->setDefaultHandled();
+}
+
+void RangeInputType::createShadowSubtree()
+{
+    ASSERT(element()->shadow());
+
+    Document* document = element()->document();
+    RefPtr<HTMLDivElement> track = HTMLDivElement::create(document);
+    track->setPseudo(AtomicString("-webkit-slider-runnable-track", AtomicString::ConstructFromLiteral));
+    track->appendChild(SliderThumbElement::create(document), IGNORE_EXCEPTION);
+    RefPtr<HTMLElement> container = SliderContainerElement::create(document);
+    container->appendChild(track.release(), IGNORE_EXCEPTION);
+    element()->userAgentShadowRoot()->appendChild(container.release(), IGNORE_EXCEPTION);
+}
+
+RenderObject* RangeInputType::createRenderer(RenderArena* arena, RenderStyle*) const
+{
+    return new (arena) RenderSlider(element());
+}
+
+Decimal RangeInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
+{
+    return parseToDecimalForNumberType(src, defaultValue);
+}
+
+String RangeInputType::serialize(const Decimal& value) const
+{
+    if (!value.isFinite())
+        return String();
+    return serializeForNumberType(value);
+}
+
+// FIXME: Could share this with BaseClickableWithKeyInputType and BaseCheckableInputType if we had a common base class.
+void RangeInputType::accessKeyAction(bool sendMouseEvents)
+{
+    InputType::accessKeyAction(sendMouseEvents);
+
+    element()->dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
+}
+
+void RangeInputType::minOrMaxAttributeChanged()
+{
+    InputType::minOrMaxAttributeChanged();
+
+    // Sanitize the value.
+    if (element()->hasDirtyValue())
+        element()->setValue(element()->value());
+    element()->setNeedsStyleRecalc();
+}
+
+void RangeInputType::setValue(const String& value, bool valueChanged, TextFieldEventBehavior eventBehavior)
+{
+    InputType::setValue(value, valueChanged, eventBehavior);
+
+    if (!valueChanged)
+        return;
+
+    sliderThumbElementOf(element())->setPositionFromValue();
+}
+
+String RangeInputType::fallbackValue() const
+{
+    return serializeForNumberType(createStepRange(RejectAny).defaultValue());
+}
+
+String RangeInputType::sanitizeValue(const String& proposedValue) const
+{
+    StepRange stepRange(createStepRange(RejectAny));
+    const Decimal proposedNumericValue = parseToNumber(proposedValue, stepRange.defaultValue());
+    return serializeForNumberType(stepRange.clampValue(proposedNumericValue));
+}
+
+bool RangeInputType::shouldRespectListAttribute()
+{
+    return InputType::themeSupportsDataListUI(this);
+}
+
+HTMLElement* RangeInputType::sliderThumbElement() const
+{
+    return sliderThumbElementOf(element());
+}
+
+HTMLElement* RangeInputType::sliderTrackElement() const
+{
+    return sliderTrackElementOf(element());
+}
+
+#if ENABLE(DATALIST_ELEMENT)
+void RangeInputType::listAttributeTargetChanged()
+{
+    m_tickMarkValuesDirty = true;
+    HTMLElement* sliderTrackElement = sliderTrackElementOf(element());
+    if (sliderTrackElement->renderer())
+        sliderTrackElement->renderer()->setNeedsLayout(true);
+}
+
+static bool decimalCompare(const Decimal& a, const Decimal& b)
+{
+    return a < b;
+}
+
+void RangeInputType::updateTickMarkValues()
+{
+    if (!m_tickMarkValuesDirty)
+        return;
+    m_tickMarkValues.clear();
+    m_tickMarkValuesDirty = false;
+    HTMLDataListElement* dataList = element()->dataList();
+    if (!dataList)
+        return;
+    RefPtr<HTMLCollection> options = dataList->options();
+    m_tickMarkValues.reserveCapacity(options->length());
+    for (unsigned i = 0; i < options->length(); ++i) {
+        Node* node = options->item(i);
+        HTMLOptionElement* optionElement = toHTMLOptionElement(node);
+        String optionValue = optionElement->value();
+        if (!element()->isValidValue(optionValue))
+            continue;
+        m_tickMarkValues.append(parseToNumber(optionValue, Decimal::nan()));
+    }
+    m_tickMarkValues.shrinkToFit();
+    nonCopyingSort(m_tickMarkValues.begin(), m_tickMarkValues.end(), decimalCompare);
+}
+
+Decimal RangeInputType::findClosestTickMarkValue(const Decimal& value)
+{
+    updateTickMarkValues();
+    if (!m_tickMarkValues.size())
+        return Decimal::nan();
+
+    size_t left = 0;
+    size_t right = m_tickMarkValues.size();
+    size_t middle;
+    while (true) {
+        ASSERT(left <= right);
+        middle = left + (right - left) / 2;
+        if (!middle)
+            break;
+        if (middle == m_tickMarkValues.size() - 1 && m_tickMarkValues[middle] < value) {
+            middle++;
+            break;
+        }
+        if (m_tickMarkValues[middle - 1] <= value && m_tickMarkValues[middle] >= value)
+            break;
+
+        if (m_tickMarkValues[middle] < value)
+            left = middle;
+        else
+            right = middle;
+    }
+    const Decimal closestLeft = middle ? m_tickMarkValues[middle - 1] : Decimal::infinity(Decimal::Negative);
+    const Decimal closestRight = middle != m_tickMarkValues.size() ? m_tickMarkValues[middle] : Decimal::infinity(Decimal::Positive);
+    if (closestRight - value < value - closestLeft)
+        return closestRight;
+    return closestLeft;
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/core/html/RangeInputType.h b/Source/core/html/RangeInputType.h
new file mode 100644
index 0000000..10f6cbe
--- /dev/null
+++ b/Source/core/html/RangeInputType.h
@@ -0,0 +1,83 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 RangeInputType_h
+#define RangeInputType_h
+
+#include "core/html/InputType.h"
+
+namespace WebCore {
+
+class SliderThumbElement;
+
+class RangeInputType : public InputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    RangeInputType(HTMLInputElement*);
+    virtual void attach() OVERRIDE;
+    virtual bool isRangeControl() const OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual double valueAsDouble() const OVERRIDE;
+    virtual void setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
+    virtual bool typeMismatchFor(const String&) const OVERRIDE;
+    virtual bool supportsRequired() const OVERRIDE;
+    virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
+    virtual bool isSteppable() const OVERRIDE;
+    virtual void handleMouseDownEvent(MouseEvent*) OVERRIDE;
+    virtual void handleTouchEvent(TouchEvent*) OVERRIDE;
+    virtual bool hasTouchEventHandler() const OVERRIDE;
+    virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
+    virtual void createShadowSubtree() OVERRIDE;
+    virtual Decimal parseToNumber(const String&, const Decimal&) const OVERRIDE;
+    virtual String serialize(const Decimal&) const OVERRIDE;
+    virtual void accessKeyAction(bool sendMouseEvents) OVERRIDE;
+    virtual void minOrMaxAttributeChanged() OVERRIDE;
+    virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE;
+    virtual String fallbackValue() const OVERRIDE;
+    virtual String sanitizeValue(const String& proposedValue) const OVERRIDE;
+    virtual bool shouldRespectListAttribute() OVERRIDE;
+    virtual HTMLElement* sliderThumbElement() const OVERRIDE;
+    virtual HTMLElement* sliderTrackElement() const OVERRIDE;
+#if ENABLE(DATALIST_ELEMENT)
+    virtual void listAttributeTargetChanged() OVERRIDE;
+    void updateTickMarkValues();
+    virtual Decimal findClosestTickMarkValue(const Decimal&) OVERRIDE;
+
+    bool m_tickMarkValuesDirty;
+    Vector<Decimal> m_tickMarkValues;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // RangeInputType_h
diff --git a/Source/core/html/ResetInputType.cpp b/Source/core/html/ResetInputType.cpp
new file mode 100644
index 0000000..332e3ed
--- /dev/null
+++ b/Source/core/html/ResetInputType.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/ResetInputType.h"
+
+#include "core/dom/Event.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/platform/LocalizedStrings.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<InputType> ResetInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new ResetInputType(element));
+}
+
+const AtomicString& ResetInputType::formControlType() const
+{
+    return InputTypeNames::reset();
+}
+
+bool ResetInputType::supportsValidation() const
+{
+    return false;
+}
+
+void ResetInputType::handleDOMActivateEvent(Event* event)
+{
+    if (element()->isDisabledFormControl() || !element()->form())
+        return;
+    element()->form()->reset();
+    event->setDefaultHandled();
+}
+
+String ResetInputType::defaultValue() const
+{
+    return resetButtonDefaultLabel();
+}
+
+bool ResetInputType::isTextButton() const
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/ResetInputType.h b/Source/core/html/ResetInputType.h
new file mode 100644
index 0000000..40d9c02
--- /dev/null
+++ b/Source/core/html/ResetInputType.h
@@ -0,0 +1,53 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 ResetInputType_h
+#define ResetInputType_h
+
+#include "core/html/BaseButtonInputType.h"
+
+namespace WebCore {
+
+class ResetInputType : public BaseButtonInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    ResetInputType(HTMLInputElement* element) : BaseButtonInputType(element) { }
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool supportsValidation() const OVERRIDE;
+    virtual void handleDOMActivateEvent(Event*) OVERRIDE;
+    virtual String defaultValue() const OVERRIDE;
+    virtual bool isTextButton() const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // ResetInputType_h
diff --git a/Source/core/html/SearchInputType.cpp b/Source/core/html/SearchInputType.cpp
new file mode 100644
index 0000000..18fc880
--- /dev/null
+++ b/Source/core/html/SearchInputType.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/SearchInputType.h"
+
+#include "HTMLNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/html/shadow/TextControlInnerElements.h"
+#include "core/rendering/RenderSearchField.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline SearchInputType::SearchInputType(HTMLInputElement* element)
+    : BaseTextInputType(element)
+    , m_resultsButton(0)
+    , m_cancelButton(0)
+    , m_searchEventTimer(this, &SearchInputType::searchEventTimerFired)
+{
+}
+
+PassOwnPtr<InputType> SearchInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new SearchInputType(element));
+}
+
+void SearchInputType::attach()
+{
+    TextFieldInputType::attach();
+    observeFeatureIfVisible(UseCounter::InputTypeSearch);
+}
+
+void SearchInputType::addSearchResult()
+{
+    if (RenderObject* renderer = element()->renderer())
+        toRenderSearchField(renderer)->addSearchResult();
+}
+
+RenderObject* SearchInputType::createRenderer(RenderArena* arena, RenderStyle*) const
+{
+    return new (arena) RenderSearchField(element());
+}
+
+const AtomicString& SearchInputType::formControlType() const
+{
+    return InputTypeNames::search();
+}
+
+bool SearchInputType::shouldRespectSpeechAttribute()
+{
+    return true;
+}
+
+bool SearchInputType::isSearchField() const
+{
+    return true;
+}
+
+bool SearchInputType::needsContainer() const
+{
+    return true;
+}
+
+void SearchInputType::createShadowSubtree()
+{
+    ASSERT(!m_resultsButton);
+    ASSERT(!m_cancelButton);
+
+    TextFieldInputType::createShadowSubtree();
+    HTMLElement* container = containerElement();
+    HTMLElement* textWrapper = innerBlockElement();
+    ASSERT(container);
+    ASSERT(textWrapper);
+
+    RefPtr<SearchFieldResultsButtonElement> resultsButton = SearchFieldResultsButtonElement::create(element()->document());
+    m_resultsButton = resultsButton.get();
+    container->insertBefore(m_resultsButton, textWrapper, IGNORE_EXCEPTION);
+
+    RefPtr<SearchFieldCancelButtonElement> cancelButton = SearchFieldCancelButtonElement::create(element()->document());
+    m_cancelButton = cancelButton.get();
+    container->insertBefore(m_cancelButton, textWrapper->nextSibling(), IGNORE_EXCEPTION);
+}
+
+HTMLElement* SearchInputType::resultsButtonElement() const
+{
+    return m_resultsButton;
+}
+
+HTMLElement* SearchInputType::cancelButtonElement() const
+{
+    return m_cancelButton;
+}
+
+void SearchInputType::handleKeydownEvent(KeyboardEvent* event)
+{
+    if (element()->isDisabledOrReadOnly()) {
+        TextFieldInputType::handleKeydownEvent(event);
+        return;
+    }
+
+    const String& key = event->keyIdentifier();
+    if (key == "U+001B") {
+        RefPtr<HTMLInputElement> input = element();
+        input->setValueForUser("");
+        input->onSearch();
+        event->setDefaultHandled();
+        return;
+    }
+    TextFieldInputType::handleKeydownEvent(event);
+}
+
+void SearchInputType::destroyShadowSubtree()
+{
+    TextFieldInputType::destroyShadowSubtree();
+    m_resultsButton = 0;
+    m_cancelButton = 0;
+}
+
+void SearchInputType::startSearchEventTimer()
+{
+    ASSERT(element()->renderer());
+    unsigned length = element()->innerTextValue().length();
+
+    if (!length) {
+        stopSearchEventTimer();
+        element()->onSearch();
+        return;
+    }
+
+    // After typing the first key, we wait 0.5 seconds.
+    // After the second key, 0.4 seconds, then 0.3, then 0.2 from then on.
+    m_searchEventTimer.startOneShot(max(0.2, 0.6 - 0.1 * length));
+}
+
+void SearchInputType::stopSearchEventTimer()
+{
+    m_searchEventTimer.stop();
+}
+
+void SearchInputType::searchEventTimerFired(Timer<SearchInputType>*)
+{
+    element()->onSearch();
+}
+
+bool SearchInputType::searchEventsShouldBeDispatched() const
+{
+    return element()->hasAttribute(incrementalAttr);
+}
+
+void SearchInputType::didSetValueByUserEdit(ValueChangeState state)
+{
+    if (m_cancelButton)
+        toRenderSearchField(element()->renderer())->updateCancelButtonVisibility();
+
+    // If the incremental attribute is set, then dispatch the search event
+    if (searchEventsShouldBeDispatched())
+        startSearchEventTimer();
+
+    TextFieldInputType::didSetValueByUserEdit(state);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/SearchInputType.h b/Source/core/html/SearchInputType.h
new file mode 100644
index 0000000..de1b2c9
--- /dev/null
+++ b/Source/core/html/SearchInputType.h
@@ -0,0 +1,75 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 SearchInputType_h
+#define SearchInputType_h
+
+#include "core/html/BaseTextInputType.h"
+#include "core/platform/Timer.h"
+
+namespace WebCore {
+
+class SearchFieldCancelButtonElement;
+class SearchFieldResultsButtonElement;
+
+class SearchInputType : public BaseTextInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+    void stopSearchEventTimer();
+
+private:
+    SearchInputType(HTMLInputElement*);
+    virtual void attach() OVERRIDE;
+    virtual void addSearchResult() OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool shouldRespectSpeechAttribute() OVERRIDE;
+    virtual bool isSearchField() const OVERRIDE;
+    virtual bool needsContainer() const OVERRIDE;
+    virtual void createShadowSubtree() OVERRIDE;
+    virtual void destroyShadowSubtree() OVERRIDE;
+    virtual HTMLElement* resultsButtonElement() const OVERRIDE;
+    virtual HTMLElement* cancelButtonElement() const OVERRIDE;
+    virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
+    virtual void didSetValueByUserEdit(ValueChangeState) OVERRIDE;
+
+    void searchEventTimerFired(Timer<SearchInputType>*);
+    bool searchEventsShouldBeDispatched() const;
+    void startSearchEventTimer();
+
+    HTMLElement* m_resultsButton;
+    HTMLElement* m_cancelButton;
+    Timer<SearchInputType> m_searchEventTimer;
+};
+
+} // namespace WebCore
+
+#endif // SearchInputType_h
diff --git a/Source/core/html/StepRange.cpp b/Source/core/html/StepRange.cpp
new file mode 100644
index 0000000..fd51d03
--- /dev/null
+++ b/Source/core/html/StepRange.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/StepRange.h"
+
+#include "HTMLNames.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include <wtf/MathExtras.h>
+#include <wtf/text/WTFString.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+StepRange::StepRange()
+    : m_maximum(100)
+    , m_minimum(0)
+    , m_step(1)
+    , m_stepBase(0)
+    , m_hasStep(false)
+{
+}
+
+StepRange::StepRange(const StepRange& stepRange)
+    : m_maximum(stepRange.m_maximum)
+    , m_minimum(stepRange.m_minimum)
+    , m_step(stepRange.m_step)
+    , m_stepBase(stepRange.m_stepBase)
+    , m_stepDescription(stepRange.m_stepDescription)
+    , m_hasStep(stepRange.m_hasStep)
+{
+}
+
+StepRange::StepRange(const Decimal& stepBase, const Decimal& minimum, const Decimal& maximum, const Decimal& step, const StepDescription& stepDescription)
+    : m_maximum(maximum)
+    , m_minimum(minimum)
+    , m_step(step.isFinite() ? step : 1)
+    , m_stepBase(stepBase.isFinite() ? stepBase : 1)
+    , m_stepDescription(stepDescription)
+    , m_hasStep(step.isFinite())
+{
+    ASSERT(m_maximum.isFinite());
+    ASSERT(m_minimum.isFinite());
+    ASSERT(m_step.isFinite());
+    ASSERT(m_stepBase.isFinite());
+}
+
+Decimal StepRange::acceptableError() const
+{
+    // FIXME: We should use DBL_MANT_DIG instead of FLT_MANT_DIG regarding to HTML5 specification.
+    DEFINE_STATIC_LOCAL(const Decimal, twoPowerOfFloatMantissaBits, (Decimal::Positive, 0, UINT64_C(1) << FLT_MANT_DIG));
+    return m_stepDescription.stepValueShouldBe == StepValueShouldBeReal ? m_step / twoPowerOfFloatMantissaBits : Decimal(0);
+}
+
+Decimal StepRange::alignValueForStep(const Decimal& currentValue, const Decimal& newValue) const
+{
+    DEFINE_STATIC_LOCAL(const Decimal, tenPowerOf21, (Decimal::Positive, 21, 1));
+    if (newValue >= tenPowerOf21)
+        return newValue;
+
+    return stepMismatch(currentValue) ? newValue : roundByStep(newValue, m_stepBase);
+}
+
+Decimal StepRange::clampValue(const Decimal& value) const
+{
+    const Decimal inRangeValue = max(m_minimum, min(value, m_maximum));
+    if (!m_hasStep)
+        return inRangeValue;
+    // Rounds inRangeValue to minimum + N * step.
+    const Decimal roundedValue = roundByStep(inRangeValue, m_minimum);
+    const Decimal clampedValue = roundedValue > m_maximum ? roundedValue - m_step : roundedValue;
+    ASSERT(clampedValue >= m_minimum);
+    ASSERT(clampedValue <= m_maximum);
+    return clampedValue;
+}
+
+Decimal StepRange::parseStep(AnyStepHandling anyStepHandling, const StepDescription& stepDescription, const String& stepString)
+{
+    if (stepString.isEmpty())
+        return stepDescription.defaultValue();
+
+    if (equalIgnoringCase(stepString, "any")) {
+        switch (anyStepHandling) {
+        case RejectAny:
+            return Decimal::nan();
+        case AnyIsDefaultStep:
+            return stepDescription.defaultValue();
+        default:
+            ASSERT_NOT_REACHED();
+        }
+    }
+
+    Decimal step = parseToDecimalForNumberType(stepString);
+    if (!step.isFinite() || step <= 0)
+        return stepDescription.defaultValue();
+
+    switch (stepDescription.stepValueShouldBe) {
+    case StepValueShouldBeReal:
+        step *= stepDescription.stepScaleFactor;
+        break;
+    case ParsedStepValueShouldBeInteger:
+        // For date, month, and week, the parsed value should be an integer for some types.
+        step = max(step.round(), Decimal(1));
+        step *= stepDescription.stepScaleFactor;
+        break;
+    case ScaledStepValueShouldBeInteger:
+        // For datetime, datetime-local, time, the result should be an integer.
+        step *= stepDescription.stepScaleFactor;
+        step = max(step.round(), Decimal(1));
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    ASSERT(step > 0);
+    return step;
+}
+
+Decimal StepRange::roundByStep(const Decimal& value, const Decimal& base) const
+{
+    return base + ((value - base) / m_step).round() * m_step;
+}
+
+bool StepRange::stepMismatch(const Decimal& valueForCheck) const
+{
+    if (!m_hasStep)
+        return false;
+    if (!valueForCheck.isFinite())
+        return false;
+    const Decimal value = (valueForCheck - m_stepBase).abs();
+    if (!value.isFinite())
+        return false;
+    // Decimal's fractional part size is DBL_MAN_DIG-bit. If the current value
+    // is greater than step*2^DBL_MANT_DIG, the following computation for
+    // remainder makes no sense.
+    DEFINE_STATIC_LOCAL(const Decimal, twoPowerOfDoubleMantissaBits, (Decimal::Positive, 0, UINT64_C(1) << DBL_MANT_DIG));
+    if (value / twoPowerOfDoubleMantissaBits > m_step)
+        return false;
+    // The computation follows HTML5 4.10.7.2.10 `The step attribute' :
+    // ... that number subtracted from the step base is not an integral multiple
+    // of the allowed value step, the element is suffering from a step mismatch.
+    const Decimal remainder = (value - m_step * (value / m_step).round()).abs();
+    // Accepts erros in lower fractional part which IEEE 754 single-precision
+    // can't represent.
+    const Decimal computedAcceptableError = acceptableError();
+    return computedAcceptableError < remainder && remainder < (m_step - computedAcceptableError);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/StepRange.h b/Source/core/html/StepRange.h
new file mode 100644
index 0000000..4aa5cae
--- /dev/null
+++ b/Source/core/html/StepRange.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2006, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef StepRange_h
+#define StepRange_h
+
+#include "core/platform/Decimal.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class HTMLInputElement;
+
+enum AnyStepHandling { RejectAny, AnyIsDefaultStep };
+
+class StepRange {
+public:
+    enum StepValueShouldBe {
+        StepValueShouldBeReal,
+        ParsedStepValueShouldBeInteger,
+        ScaledStepValueShouldBeInteger,
+    };
+
+    struct StepDescription {
+        WTF_MAKE_FAST_ALLOCATED;
+    public:
+        int defaultStep;
+        int defaultStepBase;
+        int stepScaleFactor;
+        StepValueShouldBe stepValueShouldBe;
+
+        StepDescription(int defaultStep, int defaultStepBase, int stepScaleFactor, StepValueShouldBe stepValueShouldBe = StepValueShouldBeReal)
+            : defaultStep(defaultStep)
+            , defaultStepBase(defaultStepBase)
+            , stepScaleFactor(stepScaleFactor)
+            , stepValueShouldBe(stepValueShouldBe)
+        {
+        }
+
+        StepDescription()
+            : defaultStep(1)
+            , defaultStepBase(0)
+            , stepScaleFactor(1)
+            , stepValueShouldBe(StepValueShouldBeReal)
+        {
+        }
+
+        Decimal defaultValue() const
+        {
+            return defaultStep * stepScaleFactor;
+        }
+    };
+
+    StepRange();
+    StepRange(const StepRange&);
+    StepRange(const Decimal& stepBase, const Decimal& minimum, const Decimal& maximum, const Decimal& step, const StepDescription&);
+    Decimal acceptableError() const;
+    Decimal alignValueForStep(const Decimal& currentValue, const Decimal& newValue) const;
+    Decimal clampValue(const Decimal& value) const;
+    bool hasStep() const { return m_hasStep; }
+    Decimal maximum() const { return m_maximum; }
+    Decimal minimum() const { return m_minimum; }
+    static Decimal parseStep(AnyStepHandling, const StepDescription&, const String&);
+    Decimal step() const { return m_step; }
+    Decimal stepBase() const { return m_stepBase; }
+    int stepScaleFactor() const { return m_stepDescription.stepScaleFactor; }
+    bool stepMismatch(const Decimal&) const;
+
+    // Clamp the middle value according to the step
+    Decimal defaultValue() const
+    {
+        return clampValue((m_minimum + m_maximum) / 2);
+    }
+
+    // Map value into 0-1 range
+    Decimal proportionFromValue(const Decimal& value) const
+    {
+        if (m_minimum == m_maximum)
+            return 0;
+
+        return (value - m_minimum) / (m_maximum - m_minimum);
+    }
+
+    // Map from 0-1 range to value
+    Decimal valueFromProportion(const Decimal& proportion) const
+    {
+        return m_minimum + proportion * (m_maximum - m_minimum);
+    }
+
+private:
+    StepRange& operator =(const StepRange&);
+    Decimal roundByStep(const Decimal& value, const Decimal& base) const;
+
+    const Decimal m_maximum; // maximum must be >= minimum.
+    const Decimal m_minimum;
+    const Decimal m_step;
+    const Decimal m_stepBase;
+    const StepDescription m_stepDescription;
+    const bool m_hasStep;
+};
+
+}
+
+#endif // StepRange_h
diff --git a/Source/core/html/SubmitInputType.cpp b/Source/core/html/SubmitInputType.cpp
new file mode 100644
index 0000000..1cb2c63
--- /dev/null
+++ b/Source/core/html/SubmitInputType.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/SubmitInputType.h"
+
+#include "core/dom/Event.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/platform/LocalizedStrings.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<InputType> SubmitInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new SubmitInputType(element));
+}
+
+const AtomicString& SubmitInputType::formControlType() const
+{
+    return InputTypeNames::submit();
+}
+
+bool SubmitInputType::appendFormData(FormDataList& encoding, bool) const
+{
+    if (!element()->isActivatedSubmit())
+        return false;
+    encoding.appendData(element()->name(), element()->valueWithDefault());
+    return true;
+}
+
+bool SubmitInputType::supportsRequired() const
+{
+    return false;
+}
+
+void SubmitInputType::handleDOMActivateEvent(Event* event)
+{
+    RefPtr<HTMLInputElement> element = this->element();
+    if (element->isDisabledFormControl() || !element->form())
+        return;
+    element->setActivatedSubmit(true);
+    element->form()->prepareForSubmission(event); // Event handlers can run.
+    element->setActivatedSubmit(false);
+    event->setDefaultHandled();
+}
+
+bool SubmitInputType::canBeSuccessfulSubmitButton()
+{
+    return true;
+}
+
+String SubmitInputType::defaultValue() const
+{
+    return submitButtonDefaultLabel();
+}
+
+bool SubmitInputType::isSubmitButton() const
+{
+    return true;
+}
+
+bool SubmitInputType::isTextButton() const
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/SubmitInputType.h b/Source/core/html/SubmitInputType.h
new file mode 100644
index 0000000..596920c
--- /dev/null
+++ b/Source/core/html/SubmitInputType.h
@@ -0,0 +1,56 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 SubmitInputType_h
+#define SubmitInputType_h
+
+#include "core/html/BaseButtonInputType.h"
+
+namespace WebCore {
+
+class SubmitInputType : public BaseButtonInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    SubmitInputType(HTMLInputElement* element) : BaseButtonInputType(element) { }
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool appendFormData(FormDataList&, bool) const OVERRIDE;
+    virtual bool supportsRequired() const OVERRIDE;
+    virtual void handleDOMActivateEvent(Event*) OVERRIDE;
+    virtual bool canBeSuccessfulSubmitButton() OVERRIDE;
+    virtual String defaultValue() const OVERRIDE;
+    virtual bool isSubmitButton() const OVERRIDE;
+    virtual bool isTextButton() const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // SubmitInputType_h
diff --git a/Source/core/html/TelephoneInputType.cpp b/Source/core/html/TelephoneInputType.cpp
new file mode 100644
index 0000000..6a17c7d
--- /dev/null
+++ b/Source/core/html/TelephoneInputType.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/TelephoneInputType.h"
+
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<InputType> TelephoneInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new TelephoneInputType(element));
+}
+
+void TelephoneInputType::attach()
+{
+    TextFieldInputType::attach();
+    observeFeatureIfVisible(UseCounter::InputTypeTel);
+}
+
+const AtomicString& TelephoneInputType::formControlType() const
+{
+    return InputTypeNames::telephone();
+}
+
+bool TelephoneInputType::shouldRespectSpeechAttribute()
+{
+    return true;
+}
+
+bool TelephoneInputType::isTelephoneField() const
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/TelephoneInputType.h b/Source/core/html/TelephoneInputType.h
new file mode 100644
index 0000000..264d5a9
--- /dev/null
+++ b/Source/core/html/TelephoneInputType.h
@@ -0,0 +1,52 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 TelephoneInputType_h
+#define TelephoneInputType_h
+
+#include "core/html/BaseTextInputType.h"
+
+namespace WebCore {
+
+class TelephoneInputType : public BaseTextInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    TelephoneInputType(HTMLInputElement* element) : BaseTextInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool shouldRespectSpeechAttribute() OVERRIDE;
+    virtual bool isTelephoneField() const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // TelephoneInputType_h
diff --git a/Source/core/html/TextDocument.cpp b/Source/core/html/TextDocument.cpp
new file mode 100644
index 0000000..83caa01
--- /dev/null
+++ b/Source/core/html/TextDocument.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 "core/html/TextDocument.h"
+
+#include "core/html/parser/TextDocumentParser.h"
+
+namespace WebCore {
+
+TextDocument::TextDocument(Frame* frame, const KURL& url)
+    : HTMLDocument(frame, url)
+{
+    setCompatibilityMode(QuirksMode);
+    lockCompatibilityMode();
+}
+
+PassRefPtr<DocumentParser> TextDocument::createParser()
+{
+    return TextDocumentParser::create(this);
+}
+
+}
diff --git a/Source/core/html/TextDocument.h b/Source/core/html/TextDocument.h
new file mode 100644
index 0000000..c0d3384
--- /dev/null
+++ b/Source/core/html/TextDocument.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2006, 2008, 2009 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 TextDocument_h
+#define TextDocument_h
+
+#include "core/html/HTMLDocument.h"
+
+namespace WebCore {
+
+class TextDocument FINAL : public HTMLDocument {
+public:
+    static PassRefPtr<TextDocument> create(Frame* frame, const KURL& url)
+    {
+        return adoptRef(new TextDocument(frame, url));
+    }
+
+private:
+    TextDocument(Frame*, const KURL&);
+    
+    virtual PassRefPtr<DocumentParser> createParser();
+};
+
+}
+
+#endif
diff --git a/Source/core/html/TextFieldInputType.cpp b/Source/core/html/TextFieldInputType.cpp
new file mode 100644
index 0000000..9cfb9d3
--- /dev/null
+++ b/Source/core/html/TextFieldInputType.cpp
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/TextFieldInputType.h"
+
+#include "HTMLNames.h"
+#include "core/dom/BeforeTextInsertedEvent.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/NodeRenderStyle.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/TextEvent.h"
+#include "core/dom/WheelEvent.h"
+#include "core/editing/Editor.h"
+#include "core/editing/FrameSelection.h"
+#include "core/editing/TextIterator.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/shadow/TextControlInnerElements.h"
+#include "core/page/Chrome.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/rendering/RenderLayer.h"
+#include "core/rendering/RenderTextControlSingleLine.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+TextFieldInputType::TextFieldInputType(HTMLInputElement* element)
+    : InputType(element)
+{
+}
+
+TextFieldInputType::~TextFieldInputType()
+{
+    if (m_innerSpinButton)
+        m_innerSpinButton->removeSpinButtonOwner();
+}
+
+bool TextFieldInputType::isKeyboardFocusable(KeyboardEvent*) const
+{
+    return element()->isFocusable();
+}
+
+bool TextFieldInputType::isMouseFocusable() const
+{
+    return element()->isFocusable();
+}
+
+bool TextFieldInputType::isTextField() const
+{
+    return true;
+}
+
+bool TextFieldInputType::valueMissing(const String& value) const
+{
+    return element()->isRequired() && value.isEmpty();
+}
+
+bool TextFieldInputType::canSetSuggestedValue()
+{
+    return true;
+}
+
+void TextFieldInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
+{
+    // Grab this input element to keep reference even if JS event handler
+    // changes input type.
+    RefPtr<HTMLInputElement> input(element());
+
+    // We don't ask InputType::setValue to dispatch events because
+    // TextFieldInputType dispatches events different way from InputType.
+    InputType::setValue(sanitizedValue, valueChanged, DispatchNoEvent);
+
+    if (valueChanged)
+        updateInnerTextValue();
+
+    unsigned max = visibleValue().length();
+    if (input->focused())
+        input->setSelectionRange(max, max);
+    else
+        input->cacheSelectionInResponseToSetValue(max);
+
+    if (!valueChanged)
+        return;
+
+    switch (eventBehavior) {
+    case DispatchChangeEvent:
+        // If the user is still editing this field, dispatch an input event rather than a change event.
+        // The change event will be dispatched when editing finishes.
+        if (input->focused())
+            input->dispatchFormControlInputEvent();
+        else
+            input->dispatchFormControlChangeEvent();
+        break;
+
+    case DispatchInputAndChangeEvent: {
+        input->dispatchFormControlInputEvent();
+        input->dispatchFormControlChangeEvent();
+        break;
+    }
+
+    case DispatchNoEvent:
+        break;
+    }
+
+    // FIXME: Why do we do this when eventBehavior == DispatchNoEvent
+    if (!input->focused() || eventBehavior == DispatchNoEvent)
+        input->setTextAsOfLastFormControlChangeEvent(sanitizedValue);
+}
+
+void TextFieldInputType::handleKeydownEvent(KeyboardEvent* event)
+{
+    if (!element()->focused())
+        return;
+    Frame* frame = element()->document()->frame();
+    if (!frame || !frame->editor()->doTextFieldCommandFromEvent(element(), event))
+        return;
+    event->setDefaultHandled();
+}
+
+void TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent* event)
+{
+    if (element()->isDisabledOrReadOnly())
+        return;
+    const String& key = event->keyIdentifier();
+    if (key == "Up")
+        spinButtonStepUp();
+    else if (key == "Down")
+        spinButtonStepDown();
+    else
+        return;
+    event->setDefaultHandled();
+}
+
+void TextFieldInputType::forwardEvent(Event* event)
+{
+    if (m_innerSpinButton) {
+        m_innerSpinButton->forwardEvent(event);
+        if (event->defaultHandled())
+            return;
+    }
+
+    if (element()->renderer() && (event->isMouseEvent() || event->isDragEvent() || event->hasInterface(eventNames().interfaceForWheelEvent) || event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)) {
+        RenderTextControlSingleLine* renderTextControl = toRenderTextControlSingleLine(element()->renderer());
+        if (event->type() == eventNames().blurEvent) {
+            if (RenderBox* innerTextRenderer = innerTextElement()->renderBox()) {
+                if (RenderLayer* innerLayer = innerTextRenderer->layer()) {
+                    IntSize scrollOffset(!renderTextControl->style()->isLeftToRightDirection() ? innerLayer->scrollWidth() : 0, 0);
+                    innerLayer->scrollToOffset(scrollOffset, RenderLayer::ScrollOffsetClamped);
+                }
+            }
+
+            renderTextControl->capsLockStateMayHaveChanged();
+        } else if (event->type() == eventNames().focusEvent)
+            renderTextControl->capsLockStateMayHaveChanged();
+
+        element()->forwardEvent(event);
+    }
+}
+
+void TextFieldInputType::handleBlurEvent()
+{
+    InputType::handleBlurEvent();
+    element()->endEditing();
+}
+
+bool TextFieldInputType::shouldSubmitImplicitly(Event* event)
+{
+    return (event->type() == eventNames().textInputEvent && event->hasInterface(eventNames().interfaceForTextEvent) && static_cast<TextEvent*>(event)->data() == "\n") || InputType::shouldSubmitImplicitly(event);
+}
+
+RenderObject* TextFieldInputType::createRenderer(RenderArena* arena, RenderStyle*) const
+{
+    return new (arena) RenderTextControlSingleLine(element());
+}
+
+bool TextFieldInputType::needsContainer() const
+{
+#if ENABLE(INPUT_SPEECH)
+    return element()->isSpeechEnabled();
+#else
+    return false;
+#endif
+}
+
+bool TextFieldInputType::shouldHaveSpinButton() const
+{
+    Document* document = element()->document();
+    RefPtr<RenderTheme> theme = document->page() ? document->page()->theme() : RenderTheme::defaultTheme();
+    return theme->shouldHaveSpinButton(element());
+}
+
+void TextFieldInputType::createShadowSubtree()
+{
+    ASSERT(element()->shadow());
+
+    ASSERT(!m_innerText);
+    ASSERT(!m_innerBlock);
+    ASSERT(!m_innerSpinButton);
+
+    Document* document = element()->document();
+    ChromeClient* chromeClient = document->page() ? document->page()->chrome()->client() : 0;
+    bool shouldAddDecorations = chromeClient && chromeClient->willAddTextFieldDecorationsTo(element());
+    bool shouldHaveSpinButton = this->shouldHaveSpinButton();
+    bool createsContainer = shouldHaveSpinButton || needsContainer() || shouldAddDecorations;
+
+    m_innerText = TextControlInnerTextElement::create(document);
+    if (!createsContainer) {
+        element()->userAgentShadowRoot()->appendChild(m_innerText, IGNORE_EXCEPTION);
+        return;
+    }
+
+    ShadowRoot* shadowRoot = element()->userAgentShadowRoot();
+    m_container = TextControlInnerContainer::create(document);
+    m_container->setPseudo(AtomicString("-webkit-textfield-decoration-container", AtomicString::ConstructFromLiteral));
+    shadowRoot->appendChild(m_container, IGNORE_EXCEPTION);
+
+    m_innerBlock = TextControlInnerElement::create(document);
+    m_innerBlock->appendChild(m_innerText, IGNORE_EXCEPTION);
+    m_container->appendChild(m_innerBlock, IGNORE_EXCEPTION);
+
+#if ENABLE(INPUT_SPEECH)
+    ASSERT(!m_speechButton);
+    if (element()->isSpeechEnabled()) {
+        m_speechButton = InputFieldSpeechButtonElement::create(document);
+        m_container->appendChild(m_speechButton, IGNORE_EXCEPTION);
+    }
+#endif
+
+    if (shouldHaveSpinButton) {
+        m_innerSpinButton = SpinButtonElement::create(document, *this);
+        m_container->appendChild(m_innerSpinButton, IGNORE_EXCEPTION);
+    }
+
+    if (shouldAddDecorations)
+        chromeClient->addTextFieldDecorationsTo(element());
+}
+
+HTMLElement* TextFieldInputType::containerElement() const
+{
+    return m_container.get();
+}
+
+HTMLElement* TextFieldInputType::innerBlockElement() const
+{
+    return m_innerBlock.get();
+}
+
+HTMLElement* TextFieldInputType::innerTextElement() const
+{
+    ASSERT(m_innerText);
+    return m_innerText.get();
+}
+
+HTMLElement* TextFieldInputType::innerSpinButtonElement() const
+{
+    return m_innerSpinButton.get();
+}
+
+#if ENABLE(INPUT_SPEECH)
+HTMLElement* TextFieldInputType::speechButtonElement() const
+{
+    return m_speechButton.get();
+}
+#endif
+
+HTMLElement* TextFieldInputType::placeholderElement() const
+{
+    return m_placeholder.get();
+}
+
+void TextFieldInputType::destroyShadowSubtree()
+{
+    InputType::destroyShadowSubtree();
+    m_innerText.clear();
+    m_placeholder.clear();
+    m_innerBlock.clear();
+#if ENABLE(INPUT_SPEECH)
+    m_speechButton.clear();
+#endif
+    if (m_innerSpinButton)
+        m_innerSpinButton->removeSpinButtonOwner();
+    m_innerSpinButton.clear();
+    m_container.clear();
+}
+
+void TextFieldInputType::attributeChanged()
+{
+    // FIXME: Updating the inner text on any attribute update should
+    // be unnecessary. We should figure out what attributes affect.
+    updateInnerTextValue();
+}
+
+void TextFieldInputType::disabledAttributeChanged()
+{
+    if (m_innerSpinButton)
+        m_innerSpinButton->releaseCapture();
+}
+
+void TextFieldInputType::readonlyAttributeChanged()
+{
+    if (m_innerSpinButton)
+        m_innerSpinButton->releaseCapture();
+}
+
+bool TextFieldInputType::supportsReadOnly() const
+{
+    return true;
+}
+
+bool TextFieldInputType::shouldUseInputMethod() const
+{
+    return true;
+}
+
+static bool isASCIILineBreak(UChar c)
+{
+    return c == '\r' || c == '\n';
+}
+
+static String limitLength(const String& string, int maxLength)
+{
+    unsigned newLength = numCharactersInGraphemeClusters(string, maxLength);
+    for (unsigned i = 0; i < newLength; ++i) {
+        const UChar current = string[i];
+        if (current < ' ' && current != '\t') {
+            newLength = i;
+            break;
+        }
+    }
+    return string.left(newLength);
+}
+
+String TextFieldInputType::sanitizeValue(const String& proposedValue) const
+{
+    return limitLength(proposedValue.removeCharacters(isASCIILineBreak), HTMLInputElement::maximumLength);
+}
+
+void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event)
+{
+    // Make sure that the text to be inserted will not violate the maxLength.
+
+    // We use RenderTextControlSingleLine::text() instead of InputElement::value()
+    // because they can be mismatched by sanitizeValue() in
+    // HTMLInputElement::subtreeHasChanged() in some cases.
+    unsigned oldLength = numGraphemeClusters(element()->innerTextValue());
+
+    // selectionLength represents the selection length of this text field to be
+    // removed by this insertion.
+    // If the text field has no focus, we don't need to take account of the
+    // selection length. The selection is the source of text drag-and-drop in
+    // that case, and nothing in the text field will be removed.
+    unsigned selectionLength = element()->focused() ? numGraphemeClusters(plainText(element()->document()->frame()->selection()->selection().toNormalizedRange().get())) : 0;
+    ASSERT(oldLength >= selectionLength);
+
+    // Selected characters will be removed by the next text event.
+    unsigned baseLength = oldLength - selectionLength;
+    unsigned maxLength = static_cast<unsigned>(isTextType() ? element()->maxLength() : HTMLInputElement::maximumLength); // maxLength can never be negative.
+    unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
+
+    // Truncate the inserted text to avoid violating the maxLength and other constraints.
+    String eventText = event->text();
+    unsigned textLength = eventText.length();
+    while (textLength > 0 && isASCIILineBreak(eventText[textLength - 1]))
+        textLength--;
+    eventText.truncate(textLength);
+    eventText.replace("\r\n", " ");
+    eventText.replace('\r', ' ');
+    eventText.replace('\n', ' ');
+
+    event->setText(limitLength(eventText, appendableLength));
+}
+
+bool TextFieldInputType::shouldRespectListAttribute()
+{
+    return InputType::themeSupportsDataListUI(this);
+}
+
+void TextFieldInputType::updatePlaceholderText()
+{
+    if (!supportsPlaceholder())
+        return;
+    String placeholderText = element()->strippedPlaceholder();
+    if (placeholderText.isEmpty()) {
+        if (m_placeholder) {
+            m_placeholder->parentNode()->removeChild(m_placeholder.get(), ASSERT_NO_EXCEPTION);
+            m_placeholder.clear();
+        }
+        return;
+    }
+    if (!m_placeholder) {
+        m_placeholder = HTMLDivElement::create(element()->document());
+        m_placeholder->setPseudo(AtomicString("-webkit-input-placeholder", AtomicString::ConstructFromLiteral));
+        element()->userAgentShadowRoot()->insertBefore(m_placeholder, m_container ? m_container->nextSibling() : innerTextElement()->nextSibling(), ASSERT_NO_EXCEPTION);
+    }
+    m_placeholder->setInnerText(placeholderText, ASSERT_NO_EXCEPTION);
+    element()->fixPlaceholderRenderer(m_placeholder.get(), m_container ? m_container.get() : m_innerText.get());
+}
+
+void TextFieldInputType::attach()
+{
+    InputType::attach();
+    // If container exists, the container should not have any content data.
+    ASSERT(!m_container || !m_container->renderStyle() || !m_container->renderStyle()->hasContent());
+
+    element()->fixPlaceholderRenderer(m_placeholder.get(), m_container ? m_container.get() : m_innerText.get());
+}
+
+bool TextFieldInputType::appendFormData(FormDataList& list, bool multipart) const
+{
+    InputType::appendFormData(list, multipart);
+    const AtomicString& dirnameAttrValue = element()->fastGetAttribute(dirnameAttr);
+    if (!dirnameAttrValue.isNull())
+        list.appendData(dirnameAttrValue, element()->directionForFormData());
+    return true;
+}
+
+String TextFieldInputType::convertFromVisibleValue(const String& visibleValue) const
+{
+    return visibleValue;
+}
+
+void TextFieldInputType::subtreeHasChanged()
+{
+    ASSERT(element()->renderer());
+
+    bool wasChanged = element()->wasChangedSinceLastFormControlChangeEvent();
+    element()->setChangedSinceLastFormControlChangeEvent(true);
+
+    // We don't need to call sanitizeUserInputValue() function here because
+    // HTMLInputElement::handleBeforeTextInsertedEvent() has already called
+    // sanitizeUserInputValue().
+    // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
+    element()->setValueFromRenderer(sanitizeValue(convertFromVisibleValue(element()->innerTextValue())));
+    element()->updatePlaceholderVisibility(false);
+    // Recalc for :invalid change.
+    element()->setNeedsStyleRecalc();
+
+    didSetValueByUserEdit(wasChanged ? ValueChangeStateChanged : ValueChangeStateNone);
+}
+
+void TextFieldInputType::didSetValueByUserEdit(ValueChangeState state)
+{
+    if (!element()->focused())
+        return;
+    if (Frame* frame = element()->document()->frame()) {
+        if (state == ValueChangeStateNone)
+            frame->editor()->textFieldDidBeginEditing(element());
+        frame->editor()->textDidChangeInTextField(element());
+    }
+}
+
+void TextFieldInputType::spinButtonStepDown()
+{
+    stepUpFromRenderer(-1);
+}
+
+void TextFieldInputType::spinButtonStepUp()
+{
+    stepUpFromRenderer(1);
+}
+
+void TextFieldInputType::updateInnerTextValue()
+{
+    if (!element()->suggestedValue().isNull()) {
+        element()->setInnerTextValue(element()->suggestedValue());
+        element()->updatePlaceholderVisibility(false);
+    } else if (!element()->formControlValueMatchesRenderer()) {
+        // Update the renderer value if the formControlValueMatchesRenderer() flag is false.
+        // It protects an unacceptable renderer value from being overwritten with the DOM value.
+        element()->setInnerTextValue(visibleValue());
+        element()->updatePlaceholderVisibility(false);
+    }
+}
+
+void TextFieldInputType::focusAndSelectSpinButtonOwner()
+{
+    RefPtr<HTMLInputElement> input(element());
+    input->focus();
+    input->select();
+}
+
+bool TextFieldInputType::shouldSpinButtonRespondToMouseEvents()
+{
+    return !element()->isDisabledOrReadOnly();
+}
+
+bool TextFieldInputType::shouldSpinButtonRespondToWheelEvents()
+{
+    return shouldSpinButtonRespondToMouseEvents() && element()->focused();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/TextFieldInputType.h b/Source/core/html/TextFieldInputType.h
new file mode 100644
index 0000000..48e06fc
--- /dev/null
+++ b/Source/core/html/TextFieldInputType.h
@@ -0,0 +1,117 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 TextFieldInputType_h
+#define TextFieldInputType_h
+
+#include "core/html/InputType.h"
+#include "core/html/shadow/SpinButtonElement.h"
+#include "core/html/shadow/TextControlInnerElements.h"
+
+namespace WebCore {
+
+class FormDataList; 
+
+// The class represents types of which UI contain text fields.
+// It supports not only the types for BaseTextInputType but also type=number.
+class TextFieldInputType : public InputType, protected SpinButtonElement::SpinButtonOwner {
+protected:
+    TextFieldInputType(HTMLInputElement*);
+    virtual ~TextFieldInputType();
+    virtual bool canSetSuggestedValue() OVERRIDE;
+    virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
+    void handleKeydownEventForSpinButton(KeyboardEvent*);
+
+    virtual HTMLElement* containerElement() const OVERRIDE;
+    virtual HTMLElement* innerBlockElement() const OVERRIDE;
+    virtual HTMLElement* innerTextElement() const OVERRIDE;
+    virtual HTMLElement* innerSpinButtonElement() const OVERRIDE;
+#if ENABLE(INPUT_SPEECH)
+    virtual HTMLElement* speechButtonElement() const OVERRIDE;
+#endif
+
+protected:
+    virtual void attach() OVERRIDE;
+    virtual bool needsContainer() const;
+    virtual bool shouldHaveSpinButton() const;
+    virtual void createShadowSubtree() OVERRIDE;
+    virtual void destroyShadowSubtree() OVERRIDE;
+    virtual void attributeChanged() OVERRIDE;
+    virtual void disabledAttributeChanged() OVERRIDE;
+    virtual void readonlyAttributeChanged() OVERRIDE;
+    virtual bool supportsReadOnly() const OVERRIDE;
+    virtual void handleBlurEvent() OVERRIDE;
+    virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE;
+    virtual void updateInnerTextValue() OVERRIDE;
+
+    virtual String convertFromVisibleValue(const String&) const;
+    enum ValueChangeState {
+        ValueChangeStateNone,
+        ValueChangeStateChanged
+    };
+    virtual void didSetValueByUserEdit(ValueChangeState);
+
+private:
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const OVERRIDE;
+    virtual bool isMouseFocusable() const OVERRIDE;
+    virtual bool isTextField() const OVERRIDE;
+    virtual bool valueMissing(const String&) const OVERRIDE;
+    virtual void handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*) OVERRIDE;
+    virtual void forwardEvent(Event*) OVERRIDE;
+    virtual bool shouldSubmitImplicitly(Event*) OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
+    virtual bool shouldUseInputMethod() const OVERRIDE;
+    virtual String sanitizeValue(const String&) const OVERRIDE;
+    virtual bool shouldRespectListAttribute() OVERRIDE;
+    virtual HTMLElement* placeholderElement() const OVERRIDE;
+    virtual void updatePlaceholderText() OVERRIDE;
+    virtual bool appendFormData(FormDataList&, bool multipart) const OVERRIDE;
+    virtual void subtreeHasChanged() OVERRIDE;
+
+    // SpinButtonElement::SpinButtonOwner functions.
+    virtual void focusAndSelectSpinButtonOwner() OVERRIDE;
+    virtual bool shouldSpinButtonRespondToMouseEvents() OVERRIDE;
+    virtual bool shouldSpinButtonRespondToWheelEvents() OVERRIDE;
+    virtual void spinButtonStepDown() OVERRIDE;
+    virtual void spinButtonStepUp() OVERRIDE;
+
+    RefPtr<HTMLElement> m_container;
+    RefPtr<HTMLElement> m_innerBlock;
+    RefPtr<HTMLElement> m_innerText;
+    RefPtr<HTMLElement> m_placeholder;
+    RefPtr<SpinButtonElement> m_innerSpinButton;
+#if ENABLE(INPUT_SPEECH)
+    RefPtr<HTMLElement> m_speechButton;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // TextFieldInputType_h
diff --git a/Source/core/html/TextInputType.cpp b/Source/core/html/TextInputType.cpp
new file mode 100644
index 0000000..ff8d2bf
--- /dev/null
+++ b/Source/core/html/TextInputType.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/TextInputType.h"
+
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+PassOwnPtr<InputType> TextInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new TextInputType(element));
+}
+
+void TextInputType::attach()
+{
+    TextFieldInputType::attach();
+    const AtomicString& type = element()->fastGetAttribute(typeAttr);
+    if (equalIgnoringCase(type, InputTypeNames::datetime()))
+        observeFeatureIfVisible(UseCounter::InputTypeDateTimeFallback);
+    else if (equalIgnoringCase(type, InputTypeNames::week()))
+        observeFeatureIfVisible(UseCounter::InputTypeWeekFallback);
+}
+
+const AtomicString& TextInputType::formControlType() const
+{
+    return InputTypeNames::text();
+}
+
+bool TextInputType::shouldRespectSpeechAttribute()
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/TextInputType.h b/Source/core/html/TextInputType.h
new file mode 100644
index 0000000..5f4ebf7
--- /dev/null
+++ b/Source/core/html/TextInputType.h
@@ -0,0 +1,51 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 TextInputType_h
+#define TextInputType_h
+
+#include "core/html/BaseTextInputType.h"
+
+namespace WebCore {
+
+class TextInputType : public BaseTextInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    TextInputType(HTMLInputElement* element) : BaseTextInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool shouldRespectSpeechAttribute() OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // TextInputType_h
diff --git a/Source/core/html/TextMetrics.h b/Source/core/html/TextMetrics.h
new file mode 100644
index 0000000..b272ef6
--- /dev/null
+++ b/Source/core/html/TextMetrics.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 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. ``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 TextMetrics_h
+#define TextMetrics_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class TextMetrics : public RefCounted<TextMetrics> {
+public:
+    static PassRefPtr<TextMetrics> create() { return adoptRef(new TextMetrics); }
+
+    float width() const { return m_width; }
+    void setWidth(float w) { m_width = w; }
+
+private:
+    TextMetrics()
+        : m_width(0)
+    { }
+
+    float m_width;
+};
+
+} // namespace WebCore
+
+#endif // TextMetrics_h
diff --git a/Source/core/html/TextMetrics.idl b/Source/core/html/TextMetrics.idl
new file mode 100644
index 0000000..7677784
--- /dev/null
+++ b/Source/core/html/TextMetrics.idl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 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. ``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. 
+ */
+[
+    ImplementationLacksVTable,
+] interface TextMetrics {
+    readonly attribute float width;
+};
+
diff --git a/Source/core/html/TimeInputType.cpp b/Source/core/html/TimeInputType.cpp
new file mode 100644
index 0000000..bc0d6ea
--- /dev/null
+++ b/Source/core/html/TimeInputType.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/TimeInputType.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/platform/DateComponents.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/DateMath.h>
+#include <wtf/MathExtras.h>
+#include <wtf/PassOwnPtr.h>
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/DateTimeFieldsState.h"
+#include "core/platform/text/PlatformLocale.h"
+#include <wtf/text/WTFString.h>
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const int timeDefaultStep = 60;
+static const int timeDefaultStepBase = 0;
+static const int timeStepScaleFactor = 1000;
+
+TimeInputType::TimeInputType(HTMLInputElement*  element)
+    : BaseTimeInputType(element)
+{
+}
+
+PassOwnPtr<InputType> TimeInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new TimeInputType(element));
+}
+
+void TimeInputType::attach()
+{
+    observeFeatureIfVisible(UseCounter::InputTypeTime);
+}
+
+const AtomicString& TimeInputType::formControlType() const
+{
+    return InputTypeNames::time();
+}
+
+DateComponents::Type TimeInputType::dateType() const
+{
+    return DateComponents::Time;
+}
+
+Decimal TimeInputType::defaultValueForStepUp() const
+{
+    double current = currentTimeMS();
+    double utcOffset = calculateUTCOffset();
+    double dstOffset = calculateDSTOffset(current, utcOffset);
+    int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+    current += offset * msPerMinute;
+
+    DateComponents date;
+    date.setMillisecondsSinceMidnight(current);
+    double milliseconds = date.millisecondsSinceEpoch();
+    ASSERT(std::isfinite(milliseconds));
+    return Decimal::fromDouble(milliseconds);
+}
+
+StepRange TimeInputType::createStepRange(AnyStepHandling anyStepHandling) const
+{
+    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (timeDefaultStep, timeDefaultStepBase, timeStepScaleFactor, StepRange::ScaledStepValueShouldBeInteger));
+
+    const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0);
+    const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumTime()));
+    const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumTime()));
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+    return StepRange(stepBase, minimum, maximum, step, stepDescription);
+}
+
+bool TimeInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const
+{
+    ASSERT(out);
+    unsigned end;
+    return out->parseTime(characters, length, 0, end) && end == length;
+}
+
+bool TimeInputType::setMillisecondToDateComponents(double value, DateComponents* date) const
+{
+    ASSERT(date);
+    return date->setMillisecondsSinceMidnight(value);
+}
+
+bool TimeInputType::isTimeField() const
+{
+    return true;
+}
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+
+String TimeInputType::localizeValue(const String& proposedValue) const
+{
+    DateComponents date;
+    if (!parseToDateComponents(proposedValue, &date))
+        return proposedValue;
+
+    Locale::FormatType formatType = shouldHaveSecondField(date) ? Locale::FormatTypeMedium : Locale::FormatTypeShort;
+
+    String localized = element()->locale().formatDateTime(date, formatType);
+    return localized.isEmpty() ? proposedValue : localized;
+}
+
+String TimeInputType::formatDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) const
+{
+    if (!dateTimeFieldsState.hasHour() || !dateTimeFieldsState.hasMinute() || !dateTimeFieldsState.hasAMPM())
+        return emptyString();
+    if (dateTimeFieldsState.hasMillisecond() && dateTimeFieldsState.millisecond())
+        return String::format("%02u:%02u:%02u.%03u",
+                dateTimeFieldsState.hour23(),
+                dateTimeFieldsState.minute(),
+                dateTimeFieldsState.hasSecond() ? dateTimeFieldsState.second() : 0,
+                dateTimeFieldsState.millisecond());
+    if (dateTimeFieldsState.hasSecond() && dateTimeFieldsState.second())
+        return String::format("%02u:%02u:%02u",
+                dateTimeFieldsState.hour23(),
+                dateTimeFieldsState.minute(),
+                dateTimeFieldsState.second());
+    return String::format("%02u:%02u", dateTimeFieldsState.hour23(), dateTimeFieldsState.minute());
+}
+
+void TimeInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& date) const
+{
+    if (shouldHaveSecondField(date)) {
+        layoutParameters.dateTimeFormat = layoutParameters.locale.timeFormat();
+        layoutParameters.fallbackDateTimeFormat = "HH:mm:ss";
+    } else {
+        layoutParameters.dateTimeFormat = layoutParameters.locale.shortTimeFormat();
+        layoutParameters.fallbackDateTimeFormat = "HH:mm";
+    }
+    if (!parseToDateComponents(element()->fastGetAttribute(minAttr), &layoutParameters.minimum))
+        layoutParameters.minimum = DateComponents();
+    if (!parseToDateComponents(element()->fastGetAttribute(maxAttr), &layoutParameters.maximum))
+        layoutParameters.maximum = DateComponents();
+}
+
+bool TimeInputType::isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const
+{
+    return hasHour && hasMinute && hasAMPM;
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/core/html/TimeInputType.h b/Source/core/html/TimeInputType.h
new file mode 100644
index 0000000..4a1eca6
--- /dev/null
+++ b/Source/core/html/TimeInputType.h
@@ -0,0 +1,71 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 TimeInputType_h
+#define TimeInputType_h
+
+#include "core/html/BaseChooserOnlyDateAndTimeInputType.h"
+#include "core/html/BaseMultipleFieldsDateAndTimeInputType.h"
+
+namespace WebCore {
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+typedef BaseMultipleFieldsDateAndTimeInputType BaseTimeInputType;
+#else
+typedef BaseChooserOnlyDateAndTimeInputType BaseTimeInputType;
+#endif
+
+class TimeInputType : public BaseTimeInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    TimeInputType(HTMLInputElement*);
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual DateComponents::Type dateType() const OVERRIDE;
+    virtual Decimal defaultValueForStepUp() const OVERRIDE;
+    virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
+    virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
+    virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
+    virtual bool isTimeField() const OVERRIDE;
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+    virtual String localizeValue(const String&) const OVERRIDE;
+
+    // BaseMultipleFieldsDateAndTimeInputType functions
+    virtual String formatDateTimeFieldsState(const DateTimeFieldsState&) const OVERRIDE FINAL;
+    virtual void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const OVERRIDE FINAL;
+    virtual bool isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // TimeInputType_h
diff --git a/Source/core/html/TimeRanges.cpp b/Source/core/html/TimeRanges.cpp
new file mode 100644
index 0000000..28396fe
--- /dev/null
+++ b/Source/core/html/TimeRanges.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2007, 2009, 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/TimeRanges.h"
+
+#include <math.h>
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+
+using namespace WebCore;
+using namespace std;
+
+TimeRanges::TimeRanges(double start, double end)
+{
+    add(start, end);
+}
+
+PassRefPtr<TimeRanges> TimeRanges::copy() const
+{
+    RefPtr<TimeRanges> newSession = TimeRanges::create();
+
+    unsigned size = m_ranges.size();
+    for (unsigned i = 0; i < size; i++)
+        newSession->add(m_ranges[i].m_start, m_ranges[i].m_end);
+
+    return newSession.release();
+}
+
+void TimeRanges::invert()
+{
+    RefPtr<TimeRanges> inverted = TimeRanges::create();
+    double posInf = std::numeric_limits<double>::infinity();
+    double negInf = -std::numeric_limits<double>::infinity();
+
+    if (!m_ranges.size())
+        inverted->add(negInf, posInf);
+    else {
+        if (double start = m_ranges.first().m_start != negInf)
+            inverted->add(negInf, start);
+
+        for (size_t index = 0; index + 1 < m_ranges.size(); ++index)
+            inverted->add(m_ranges[index].m_end, m_ranges[index + 1].m_start);
+
+        if (double end = m_ranges.last().m_end != posInf)
+            inverted->add(end, posInf);
+    }
+
+    m_ranges.swap(inverted->m_ranges);
+}
+
+void TimeRanges::intersectWith(const TimeRanges* other)
+{
+    ASSERT(other);
+    RefPtr<TimeRanges> inverted = copy();
+    RefPtr<TimeRanges> invertedOther = other->copy();
+    inverted->unionWith(invertedOther.get());
+    inverted->invert();
+
+    m_ranges.swap(inverted->m_ranges);
+}
+
+void TimeRanges::unionWith(const TimeRanges* other)
+{
+    ASSERT(other);
+    RefPtr<TimeRanges> unioned = copy();
+    for (size_t index = 0; index < other->m_ranges.size(); ++index) {
+        const Range& range = other->m_ranges[index];
+        unioned->add(range.m_start, range.m_end);
+    }
+
+    m_ranges.swap(unioned->m_ranges);
+}
+
+double TimeRanges::start(unsigned index, ExceptionCode& ec) const
+{
+    if (index >= length()) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }
+    return m_ranges[index].m_start;
+}
+
+double TimeRanges::end(unsigned index, ExceptionCode& ec) const
+{
+    if (index >= length()) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }
+    return m_ranges[index].m_end;
+}
+
+void TimeRanges::add(double start, double end)
+{
+    ASSERT(start <= end);
+    unsigned int overlappingArcIndex;
+    Range addedRange(start, end);
+
+    // For each present range check if we need to:
+    // - merge with the added range, in case we are overlapping or contiguous
+    // - Need to insert in place, we we are completely, not overlapping and not contiguous
+    // in between two ranges.
+    //
+    // TODO: Given that we assume that ranges are correctly ordered, this could be optimized.
+
+    for (overlappingArcIndex = 0; overlappingArcIndex < m_ranges.size(); overlappingArcIndex++) {
+        if (addedRange.isOverlappingRange(m_ranges[overlappingArcIndex])
+         || addedRange.isContiguousWithRange(m_ranges[overlappingArcIndex])) {
+            // We need to merge the addedRange and that range.
+            addedRange = addedRange.unionWithOverlappingOrContiguousRange(m_ranges[overlappingArcIndex]);
+            m_ranges.remove(overlappingArcIndex);
+            overlappingArcIndex--;
+        } else {
+            // Check the case for which there is no more to do
+            if (!overlappingArcIndex) {
+                if (addedRange.isBeforeRange(m_ranges[0])) {
+                    // First index, and we are completely before that range (and not contiguous, nor overlapping).
+                    // We just need to be inserted here.
+                    break;
+                }
+            } else {
+                if (m_ranges[overlappingArcIndex - 1].isBeforeRange(addedRange)
+                 && addedRange.isBeforeRange(m_ranges[overlappingArcIndex])) {
+                    // We are exactly after the current previous range, and before the current range, while
+                    // not overlapping with none of them. Insert here.
+                    break;
+                }
+            }
+        }
+    }
+
+    // Now that we are sure we don't overlap with any range, just add it.
+    m_ranges.insert(overlappingArcIndex, addedRange);
+}
+
+bool TimeRanges::contain(double time) const
+{
+    for (unsigned n = 0; n < length(); n++) {
+        if (time >= start(n, IGNORE_EXCEPTION) && time <= end(n, IGNORE_EXCEPTION))
+            return true;
+    }
+    return false;
+}
+
+double TimeRanges::nearest(double time) const
+{
+    double closest = 0;
+    unsigned count = length();
+    for (unsigned ndx = 0; ndx < count; ndx++) {
+        double startTime = start(ndx, IGNORE_EXCEPTION);
+        double endTime = end(ndx, IGNORE_EXCEPTION);
+        if (time >= startTime && time <= endTime)
+            return time;
+        if (fabs(startTime - time) < closest)
+            closest = fabsf(startTime - time);
+        else if (fabs(endTime - time) < closest)
+            closest = fabsf(endTime - time);
+    }
+    return closest;
+}
diff --git a/Source/core/html/TimeRanges.h b/Source/core/html/TimeRanges.h
new file mode 100644
index 0000000..efdcabf
--- /dev/null
+++ b/Source/core/html/TimeRanges.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007, 2009 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 COMPUTER, 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 COMPUTER, 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 TimeRanges_h
+#define TimeRanges_h
+
+#include <algorithm>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+typedef int ExceptionCode;
+
+class TimeRanges : public RefCounted<TimeRanges> {
+public:
+    static PassRefPtr<TimeRanges> create() 
+    {
+        return adoptRef(new TimeRanges);
+    }
+    static PassRefPtr<TimeRanges> create(double start, double end)
+    {
+        return adoptRef(new TimeRanges(start, end));
+    }
+
+    PassRefPtr<TimeRanges> copy() const;
+    void invert();
+    void intersectWith(const TimeRanges*);
+    void unionWith(const TimeRanges*);
+
+    unsigned length() const { return m_ranges.size(); }
+    double start(unsigned index, ExceptionCode&) const;
+    double end(unsigned index, ExceptionCode&) const;
+    
+    void add(double start, double end);
+    
+    bool contain(double time) const;
+    
+    double nearest(double time) const;
+
+private:
+    TimeRanges() { }
+    TimeRanges(double start, double end);
+    TimeRanges(const TimeRanges&);
+
+    // We consider all the Ranges to be semi-bounded as follow: [start, end[
+    struct Range {
+        Range() { }
+        Range(double start, double end)
+        {
+            m_start = start;
+            m_end = end;
+        }
+        double m_start;
+        double m_end;
+
+        inline bool isPointInRange(double point) const
+        {
+            return m_start <= point && point < m_end;
+        }
+        
+        inline bool isOverlappingRange(const Range& range) const
+        {
+            return isPointInRange(range.m_start) || isPointInRange(range.m_end) || range.isPointInRange(m_start);
+        }
+
+        inline bool isContiguousWithRange(const Range& range) const
+        {
+            return range.m_start == m_end || range.m_end == m_start;
+        }
+        
+        inline Range unionWithOverlappingOrContiguousRange(const Range& range) const
+        {
+            Range ret;
+
+            ret.m_start = std::min(m_start, range.m_start);
+            ret.m_end = std::max(m_end, range.m_end);
+
+            return ret;
+        }
+
+        inline bool isBeforeRange(const Range& range) const
+        {
+            return range.m_start >= m_end;
+        }
+    };
+    
+    Vector<Range> m_ranges;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/TimeRanges.idl b/Source/core/html/TimeRanges.idl
new file mode 100644
index 0000000..3847b7a
--- /dev/null
+++ b/Source/core/html/TimeRanges.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007, 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    ImplementationLacksVTable
+] interface TimeRanges {
+    readonly attribute unsigned long length;
+    [RaisesException] double start(unsigned long index);
+    [RaisesException] double end(unsigned long index);
+};
+
diff --git a/Source/core/html/TypeAhead.cpp b/Source/core/html/TypeAhead.cpp
new file mode 100644
index 0000000..e404255
--- /dev/null
+++ b/Source/core/html/TypeAhead.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/TypeAhead.h"
+
+#include "core/dom/KeyboardEvent.h"
+#include <wtf/unicode/CharacterNames.h>
+#include <wtf/unicode/Unicode.h>
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+TypeAhead::TypeAhead(TypeAheadDataSource* dataSource)
+    : m_dataSource(dataSource)
+    , m_lastTypeTime(0)
+    , m_repeatingChar(0)
+{
+}
+
+static const DOMTimeStamp typeAheadTimeout = 1000;
+
+static String stripLeadingWhiteSpace(const String& string)
+{
+    unsigned length = string.length();
+
+    unsigned i;
+    for (i = 0; i < length; ++i) {
+        if (string[i] != noBreakSpace && (string[i] <= 0x7F ? !isASCIISpace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral)))
+            break;
+    }
+
+    return string.substring(i, length - i);
+}
+
+int TypeAhead::handleEvent(KeyboardEvent* event, MatchModeFlags matchMode)
+{
+    if (event->timeStamp() < m_lastTypeTime)
+        return -1;
+
+    int optionCount = m_dataSource->optionCount();
+    DOMTimeStamp delta = event->timeStamp() - m_lastTypeTime;
+    m_lastTypeTime = event->timeStamp();
+
+    UChar c = event->charCode();
+
+    if (delta > typeAheadTimeout)
+        m_buffer.clear();
+    m_buffer.append(c);
+
+    if (optionCount < 1)
+        return -1;
+
+    int searchStartOffset = 1;
+    String prefix;
+    if (matchMode & CycleFirstChar && c == m_repeatingChar) {
+        // The user is likely trying to cycle through all the items starting
+        // with this character, so just search on the character.
+        prefix = String(&c, 1);
+        m_repeatingChar = c;
+    } else if (matchMode & MatchPrefix) {
+        prefix = m_buffer.toString();
+        if (m_buffer.length() > 1) {
+            m_repeatingChar = 0;
+            searchStartOffset = 0;
+        } else
+            m_repeatingChar = c;
+    }
+
+    if (!prefix.isEmpty()) {
+        int selected = m_dataSource->indexOfSelectedOption();
+        int index = (selected < 0 ? 0 : selected) + searchStartOffset;
+        index %= optionCount;
+
+        // Compute a case-folded copy of the prefix string before beginning the search for
+        // a matching element. This code uses foldCase to work around the fact that
+        // String::startWith does not fold non-ASCII characters. This code can be changed
+        // to use startWith once that is fixed.
+        String prefixWithCaseFolded(prefix.foldCase());
+        for (int i = 0; i < optionCount; ++i, index = (index + 1) % optionCount) {
+            // Fold the option string and check if its prefix is equal to the folded prefix.
+            String text = m_dataSource->optionAtIndex(index);
+            if (stripLeadingWhiteSpace(text).foldCase().startsWith(prefixWithCaseFolded))
+                return index;
+        }
+    }
+
+    if (matchMode & MatchIndex) {
+        bool ok = false;
+        int index = m_buffer.toString().toInt(&ok);
+        if (index > 0 && index <= optionCount)
+            return index - 1;
+    }
+    return -1;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/TypeAhead.h b/Source/core/html/TypeAhead.h
new file mode 100644
index 0000000..dcc50ed
--- /dev/null
+++ b/Source/core/html/TypeAhead.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 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. 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 TypeAhead_h
+#define TypeAhead_h
+
+#include "core/dom/DOMTimeStamp.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class KeyboardEvent;
+
+class TypeAheadDataSource {
+public:
+    virtual ~TypeAheadDataSource() { }
+
+    virtual int indexOfSelectedOption() const = 0;
+    virtual int optionCount() const = 0;
+    virtual String optionAtIndex(int index) const = 0;
+};
+
+class TypeAhead {
+public:
+    TypeAhead(TypeAheadDataSource*);
+
+    enum ModeFlag {
+        MatchPrefix = 1 << 0,
+        CycleFirstChar = 1 << 1,
+        MatchIndex = 1 << 2,
+    };
+    typedef unsigned MatchModeFlags;
+
+    // Returns the index for the matching option.
+    int handleEvent(KeyboardEvent*, MatchModeFlags);
+
+private:
+    TypeAheadDataSource* m_dataSource;
+    DOMTimeStamp m_lastTypeTime;
+    UChar m_repeatingChar;
+    StringBuilder m_buffer;
+};
+
+} // namespace WebCore
+
+#endif // TypeAhead_h
diff --git a/Source/core/html/URLInputType.cpp b/Source/core/html/URLInputType.cpp
new file mode 100644
index 0000000..de4a2a4
--- /dev/null
+++ b/Source/core/html/URLInputType.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/URLInputType.h"
+
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/platform/KURL.h"
+#include "core/platform/LocalizedStrings.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<InputType> URLInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new URLInputType(element));
+}
+
+void URLInputType::attach()
+{
+    TextFieldInputType::attach();
+    observeFeatureIfVisible(UseCounter::InputTypeURL);
+}
+
+const AtomicString& URLInputType::formControlType() const
+{
+    return InputTypeNames::url();
+}
+
+bool URLInputType::typeMismatchFor(const String& value) const
+{
+    return !value.isEmpty() && !KURL(KURL(), value).isValid();
+}
+
+bool URLInputType::typeMismatch() const
+{
+    return typeMismatchFor(element()->value());
+}
+
+String URLInputType::typeMismatchText() const
+{
+    return validationMessageTypeMismatchForURLText();
+}
+
+bool URLInputType::isURLField() const
+{
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/URLInputType.h b/Source/core/html/URLInputType.h
new file mode 100644
index 0000000..1adc39b
--- /dev/null
+++ b/Source/core/html/URLInputType.h
@@ -0,0 +1,54 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 URLInputType_h
+#define URLInputType_h
+
+#include "core/html/BaseTextInputType.h"
+
+namespace WebCore {
+
+class URLInputType : public BaseTextInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    URLInputType(HTMLInputElement* element) : BaseTextInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual bool typeMismatchFor(const String&) const OVERRIDE;
+    virtual bool typeMismatch() const OVERRIDE;
+    virtual String typeMismatchText() const OVERRIDE;
+    virtual bool isURLField() const OVERRIDE;
+};
+
+} // namespace WebCore
+
+#endif // URLInputType_h
diff --git a/Source/core/html/ValidationMessage.cpp b/Source/core/html/ValidationMessage.cpp
new file mode 100644
index 0000000..c155fa2
--- /dev/null
+++ b/Source/core/html/ValidationMessage.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2010, 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/ValidationMessage.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLBRElement.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLFormControlElement.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/page/ValidationMessageClient.h"
+#include "core/rendering/RenderBlock.h"
+#include "core/rendering/RenderObject.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+ALWAYS_INLINE ValidationMessage::ValidationMessage(HTMLFormControlElement* element)
+    : m_element(element)
+{
+    ASSERT(m_element);
+}
+
+ValidationMessage::~ValidationMessage()
+{
+    if (ValidationMessageClient* client = validationMessageClient()) {
+        client->hideValidationMessage(*m_element);
+        return;
+    }
+
+    deleteBubbleTree();
+}
+
+PassOwnPtr<ValidationMessage> ValidationMessage::create(HTMLFormControlElement* element)
+{
+    return adoptPtr(new ValidationMessage(element));
+}
+
+ValidationMessageClient* ValidationMessage::validationMessageClient() const
+{
+    if (Page* page = m_element->document()->page())
+        return page->validationMessageClient();
+    return 0;
+}
+
+void ValidationMessage::updateValidationMessage(const String& message)
+{
+    String updatedMessage = message;
+    if (!validationMessageClient()) {
+        // HTML5 specification doesn't ask UA to show the title attribute value
+        // with the validationMessage. However, this behavior is same as Opera
+        // and the specification describes such behavior as an example.
+        const AtomicString& title = m_element->fastGetAttribute(titleAttr);
+        if (!updatedMessage.isEmpty() && !title.isEmpty()) {
+            updatedMessage.append('\n');
+            updatedMessage.append(title);
+        }
+    }
+
+    if (updatedMessage.isEmpty()) {
+        requestToHideMessage();
+        return;
+    }
+    setMessage(updatedMessage);
+}
+
+void ValidationMessage::setMessage(const String& message)
+{
+    if (ValidationMessageClient* client = validationMessageClient()) {
+        client->showValidationMessage(*m_element, message);
+        return;
+    }
+
+    // Don't modify the DOM tree in this context.
+    // If so, an assertion in Node::isFocusable() fails.
+    ASSERT(!message.isEmpty());
+    m_message = message;
+    if (!m_bubble)
+        m_timer = adoptPtr(new Timer<ValidationMessage>(this, &ValidationMessage::buildBubbleTree));
+    else
+        m_timer = adoptPtr(new Timer<ValidationMessage>(this, &ValidationMessage::setMessageDOMAndStartTimer));
+    m_timer->startOneShot(0);
+}
+
+void ValidationMessage::setMessageDOMAndStartTimer(Timer<ValidationMessage>*)
+{
+    ASSERT(!validationMessageClient());
+    ASSERT(m_messageHeading);
+    ASSERT(m_messageBody);
+    m_messageHeading->removeChildren();
+    m_messageBody->removeChildren();
+    Vector<String> lines;
+    m_message.split('\n', lines);
+    Document* doc = m_messageHeading->document();
+    for (unsigned i = 0; i < lines.size(); ++i) {
+        if (i) {
+            m_messageBody->appendChild(Text::create(doc, lines[i]), ASSERT_NO_EXCEPTION);
+            if (i < lines.size() - 1)
+                m_messageBody->appendChild(HTMLBRElement::create(doc), ASSERT_NO_EXCEPTION);
+        } else
+            m_messageHeading->setInnerText(lines[i], ASSERT_NO_EXCEPTION);
+    }
+
+    int magnification = doc->page() ? doc->page()->settings()->validationMessageTimerMagnification() : -1;
+    if (magnification <= 0)
+        m_timer.clear();
+    else {
+        m_timer = adoptPtr(new Timer<ValidationMessage>(this, &ValidationMessage::deleteBubbleTree));
+        m_timer->startOneShot(max(5.0, static_cast<double>(m_message.length()) * magnification / 1000));
+    }
+}
+
+static void adjustBubblePosition(const LayoutRect& hostRect, HTMLElement* bubble)
+{
+    ASSERT(bubble);
+    if (hostRect.isEmpty())
+        return;
+    double hostX = hostRect.x();
+    double hostY = hostRect.y();
+    if (RenderObject* renderer = bubble->renderer()) {
+        if (RenderBox* container = renderer->containingBlock()) {
+            FloatPoint containerLocation = container->localToAbsolute();
+            hostX -= containerLocation.x() + container->borderLeft();
+            hostY -= containerLocation.y() + container->borderTop();
+        }
+    }
+
+    bubble->setInlineStyleProperty(CSSPropertyTop, hostY + hostRect.height(), CSSPrimitiveValue::CSS_PX);
+    // The 'left' value of ::-webkit-validation-bubble-arrow.
+    const int bubbleArrowTopOffset = 32;
+    double bubbleX = hostX;
+    if (hostRect.width() / 2 < bubbleArrowTopOffset)
+        bubbleX = max(hostX + hostRect.width() / 2 - bubbleArrowTopOffset, 0.0);
+    bubble->setInlineStyleProperty(CSSPropertyLeft, bubbleX, CSSPrimitiveValue::CSS_PX);
+}
+
+void ValidationMessage::buildBubbleTree(Timer<ValidationMessage>*)
+{
+    ASSERT(!validationMessageClient());
+    ShadowRoot* shadowRoot = m_element->ensureUserAgentShadowRoot();
+
+    Document* doc = m_element->document();
+    m_bubble = HTMLDivElement::create(doc);
+    m_bubble->setPseudo(AtomicString("-webkit-validation-bubble", AtomicString::ConstructFromLiteral));
+    // Need to force position:absolute because RenderMenuList doesn't assume it
+    // contains non-absolute or non-fixed renderers as children.
+    m_bubble->setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute);
+    shadowRoot->appendChild(m_bubble.get(), ASSERT_NO_EXCEPTION);
+    m_element->document()->updateLayout();
+    adjustBubblePosition(m_element->boundingBox(), m_bubble.get());
+
+    RefPtr<HTMLDivElement> clipper = HTMLDivElement::create(doc);
+    clipper->setPseudo(AtomicString("-webkit-validation-bubble-arrow-clipper", AtomicString::ConstructFromLiteral));
+    RefPtr<HTMLDivElement> bubbleArrow = HTMLDivElement::create(doc);
+    bubbleArrow->setPseudo(AtomicString("-webkit-validation-bubble-arrow", AtomicString::ConstructFromLiteral));
+    clipper->appendChild(bubbleArrow.release(), ASSERT_NO_EXCEPTION);
+    m_bubble->appendChild(clipper.release(), ASSERT_NO_EXCEPTION);
+
+    RefPtr<HTMLElement> message = HTMLDivElement::create(doc);
+    message->setPseudo(AtomicString("-webkit-validation-bubble-message", AtomicString::ConstructFromLiteral));
+    RefPtr<HTMLElement> icon = HTMLDivElement::create(doc);
+    icon->setPseudo(AtomicString("-webkit-validation-bubble-icon", AtomicString::ConstructFromLiteral));
+    message->appendChild(icon.release(), ASSERT_NO_EXCEPTION);
+    RefPtr<HTMLElement> textBlock = HTMLDivElement::create(doc);
+    textBlock->setPseudo(AtomicString("-webkit-validation-bubble-text-block", AtomicString::ConstructFromLiteral));
+    m_messageHeading = HTMLDivElement::create(doc);
+    m_messageHeading->setPseudo(AtomicString("-webkit-validation-bubble-heading", AtomicString::ConstructFromLiteral));
+    textBlock->appendChild(m_messageHeading, ASSERT_NO_EXCEPTION);
+    m_messageBody = HTMLDivElement::create(doc);
+    m_messageBody->setPseudo(AtomicString("-webkit-validation-bubble-body", AtomicString::ConstructFromLiteral));
+    textBlock->appendChild(m_messageBody, ASSERT_NO_EXCEPTION);
+    message->appendChild(textBlock.release(), ASSERT_NO_EXCEPTION);
+    m_bubble->appendChild(message.release(), ASSERT_NO_EXCEPTION);
+
+    setMessageDOMAndStartTimer();
+
+    // FIXME: Use transition to show the bubble.
+}
+
+void ValidationMessage::requestToHideMessage()
+{
+    if (ValidationMessageClient* client = validationMessageClient()) {
+        client->hideValidationMessage(*m_element);
+        return;
+    }
+
+    // We must not modify the DOM tree in this context by the same reason as setMessage().
+    m_timer = adoptPtr(new Timer<ValidationMessage>(this, &ValidationMessage::deleteBubbleTree));
+    m_timer->startOneShot(0);
+}
+
+bool ValidationMessage::shadowTreeContains(Node* node) const
+{
+    if (validationMessageClient() || !m_bubble)
+        return false;
+    return m_bubble->treeScope() == node->treeScope();
+}
+
+void ValidationMessage::deleteBubbleTree(Timer<ValidationMessage>*)
+{
+    ASSERT(!validationMessageClient());
+    if (m_bubble) {
+        m_messageHeading = 0;
+        m_messageBody = 0;
+        m_element->userAgentShadowRoot()->removeChild(m_bubble.get(), ASSERT_NO_EXCEPTION);
+        m_bubble = 0;
+    }
+    m_message = String();
+}
+
+bool ValidationMessage::isVisible() const
+{
+    if (ValidationMessageClient* client = validationMessageClient())
+        return client->isValidationMessageVisible(*m_element);
+    return !m_message.isEmpty();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/ValidationMessage.h b/Source/core/html/ValidationMessage.h
new file mode 100644
index 0000000..83c7f26
--- /dev/null
+++ b/Source/core/html/ValidationMessage.h
@@ -0,0 +1,77 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 ValidationMessage_h
+#define ValidationMessage_h
+
+#include "core/platform/Timer.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class HTMLElement;
+class HTMLFormControlElement;
+class Node;
+class ValidationMessageClient;
+
+// FIXME: We should remove the code for !validationMessageClient() when all
+// ports supporting interactive validation switch to ValidationMessageClient.
+class ValidationMessage {
+    WTF_MAKE_NONCOPYABLE(ValidationMessage); WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<ValidationMessage> create(HTMLFormControlElement*);
+    ~ValidationMessage();
+    void updateValidationMessage(const String&);
+    void requestToHideMessage();
+    bool isVisible() const;
+    bool shadowTreeContains(Node*) const;
+
+private:
+    ValidationMessage(HTMLFormControlElement*);
+    ValidationMessageClient* validationMessageClient() const;
+    void setMessage(const String&);
+    void setMessageDOMAndStartTimer(Timer<ValidationMessage>* = 0);
+    void buildBubbleTree(Timer<ValidationMessage>*);
+    void deleteBubbleTree(Timer<ValidationMessage>* = 0);
+
+    HTMLFormControlElement* m_element;
+    String m_message;
+    OwnPtr<Timer<ValidationMessage> > m_timer;
+    RefPtr<HTMLElement> m_bubble;
+    RefPtr<HTMLElement> m_messageHeading;
+    RefPtr<HTMLElement> m_messageBody;
+};
+
+} // namespace WebCore
+
+#endif // ValidationMessage_h
diff --git a/Source/core/html/ValidityState.cpp b/Source/core/html/ValidityState.cpp
new file mode 100644
index 0000000..98cbdb7
--- /dev/null
+++ b/Source/core/html/ValidityState.cpp
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2009 Michelangelo De Simone <micdesim@gmail.com>
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "core/html/ValidityState.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLSelectElement.h"
+#include "core/html/HTMLTextAreaElement.h"
+#include "core/html/parser/HTMLTreeBuilder.h"
+#include "core/platform/LocalizedStrings.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+String ValidityState::validationMessage() const
+{
+    return m_control->validationMessage();
+}
+
+bool ValidityState::valueMissing() const
+{
+    return m_control->valueMissing();
+}
+
+bool ValidityState::typeMismatch() const
+{
+    return m_control->typeMismatch();
+}
+
+bool ValidityState::patternMismatch() const
+{
+    return m_control->patternMismatch();
+}
+
+bool ValidityState::tooLong() const
+{
+    return m_control->tooLong();
+}
+
+bool ValidityState::rangeUnderflow() const
+{
+    return m_control->rangeUnderflow();
+}
+
+bool ValidityState::rangeOverflow() const
+{
+    return m_control->rangeOverflow();
+}
+
+bool ValidityState::stepMismatch() const
+{
+    return m_control->stepMismatch();
+}
+
+bool ValidityState::badInput() const
+{
+    return m_control->hasBadInput();
+}
+
+bool ValidityState::customError() const
+{
+    return m_control->customError();
+}
+
+bool ValidityState::valid() const
+{
+    return m_control->valid();
+}
+
+} // namespace
diff --git a/Source/core/html/ValidityState.h b/Source/core/html/ValidityState.h
new file mode 100644
index 0000000..9f24806
--- /dev/null
+++ b/Source/core/html/ValidityState.h
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2009 Michelangelo De Simone <micdesim@gmail.com>
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ValidityState_h
+#define ValidityState_h
+
+#include "bindings/v8/ScriptWrappable.h"
+#include "core/html/FormAssociatedElement.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class ValidityState : public ScriptWrappable {
+    WTF_MAKE_NONCOPYABLE(ValidityState); WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<ValidityState> create(FormAssociatedElement* control)
+    {
+        return adoptPtr(new ValidityState(control));
+    }
+
+    void ref() { m_control->ref(); }
+    void deref() { m_control->deref(); }
+
+    String validationMessage() const;
+
+    void setCustomErrorMessage(const String&);
+
+    bool valueMissing() const;
+    bool typeMismatch() const;
+    bool patternMismatch() const;
+    bool tooLong() const;
+    bool rangeUnderflow() const;
+    bool rangeOverflow() const;
+    bool stepMismatch() const;
+    bool badInput() const;
+    bool customError() const;
+    bool valid() const;
+
+private:
+    ValidityState(FormAssociatedElement* control) : m_control(control)
+    {
+        ScriptWrappable::init(this);
+    }
+
+    FormAssociatedElement* m_control;
+};
+
+} // namespace WebCore
+
+#endif // ValidityState_h
diff --git a/Source/core/html/ValidityState.idl b/Source/core/html/ValidityState.idl
new file mode 100644
index 0000000..963c830
--- /dev/null
+++ b/Source/core/html/ValidityState.idl
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2009 Michelangelo De Simone <micdesim@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+[
+    ImplementationLacksVTable
+] interface ValidityState {
+    readonly attribute boolean         valueMissing;
+    readonly attribute boolean         typeMismatch;
+    readonly attribute boolean         patternMismatch;
+    readonly attribute boolean         tooLong;
+    readonly attribute boolean         rangeUnderflow;
+    readonly attribute boolean         rangeOverflow;
+    readonly attribute boolean         stepMismatch;
+    readonly attribute boolean         badInput;
+    readonly attribute boolean         customError;
+    readonly attribute boolean         valid;
+};
diff --git a/Source/core/html/VoidCallback.h b/Source/core/html/VoidCallback.h
new file mode 100644
index 0000000..3ee383f
--- /dev/null
+++ b/Source/core/html/VoidCallback.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 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 COMPUTER, 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 COMPUTER, 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 VoidCallback_h
+#define VoidCallback_h
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class VoidCallback : public RefCounted<VoidCallback> {
+public:
+    virtual ~VoidCallback() { }
+    virtual bool handleEvent() = 0;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/VoidCallback.idl b/Source/core/html/VoidCallback.idl
new file mode 100644
index 0000000..577fcf5
--- /dev/null
+++ b/Source/core/html/VoidCallback.idl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2007 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+callback interface VoidCallback {
+    boolean handleEvent();
+};
diff --git a/Source/core/html/WeekInputType.cpp b/Source/core/html/WeekInputType.cpp
new file mode 100644
index 0000000..64ad701
--- /dev/null
+++ b/Source/core/html/WeekInputType.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/WeekInputType.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/InputTypeNames.h"
+#include "core/platform/DateComponents.h"
+#include <wtf/PassOwnPtr.h>
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/DateTimeFieldsState.h"
+#include "core/platform/LocalizedStrings.h"
+#include <wtf/text/WTFString.h>
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const int weekDefaultStepBase = -259200000; // The first day of 1970-W01.
+static const int weekDefaultStep = 1;
+static const int weekStepScaleFactor = 604800000;
+
+PassOwnPtr<InputType> WeekInputType::create(HTMLInputElement* element)
+{
+    return adoptPtr(new WeekInputType(element));
+}
+
+void WeekInputType::attach()
+{
+    observeFeatureIfVisible(UseCounter::InputTypeWeek);
+}
+
+const AtomicString& WeekInputType::formControlType() const
+{
+    return InputTypeNames::week();
+}
+
+DateComponents::Type WeekInputType::dateType() const
+{
+    return DateComponents::Week;
+}
+
+StepRange WeekInputType::createStepRange(AnyStepHandling anyStepHandling) const
+{
+    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (weekDefaultStep, weekDefaultStepBase, weekStepScaleFactor, StepRange::ParsedStepValueShouldBeInteger));
+
+    const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), weekDefaultStepBase);
+    const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumWeek()));
+    const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumWeek()));
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+    return StepRange(stepBase, minimum, maximum, step, stepDescription);
+}
+
+bool WeekInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const
+{
+    ASSERT(out);
+    unsigned end;
+    return out->parseWeek(characters, length, 0, end) && end == length;
+}
+
+bool WeekInputType::setMillisecondToDateComponents(double value, DateComponents* date) const
+{
+    ASSERT(date);
+    return date->setMillisecondsSinceEpochForWeek(value);
+}
+
+bool WeekInputType::isWeekField() const
+{
+    return true;
+}
+
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+String WeekInputType::formatDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState) const
+{
+    if (!dateTimeFieldsState.hasYear() || !dateTimeFieldsState.hasWeekOfYear())
+        return emptyString();
+    return String::format("%04u-W%02u", dateTimeFieldsState.year(), dateTimeFieldsState.weekOfYear());
+}
+
+void WeekInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents&) const
+{
+    layoutParameters.dateTimeFormat = weekFormatInLDML();
+    layoutParameters.fallbackDateTimeFormat = "yyyy-'W'ww";
+    if (!parseToDateComponents(element()->fastGetAttribute(minAttr), &layoutParameters.minimum))
+        layoutParameters.minimum = DateComponents();
+    if (!parseToDateComponents(element()->fastGetAttribute(maxAttr), &layoutParameters.maximum))
+        layoutParameters.maximum = DateComponents();
+    layoutParameters.placeholderForYear = "----";
+}
+
+bool WeekInputType::isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const
+{
+    return hasYear && hasWeek;
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/core/html/WeekInputType.h b/Source/core/html/WeekInputType.h
new file mode 100644
index 0000000..9242089
--- /dev/null
+++ b/Source/core/html/WeekInputType.h
@@ -0,0 +1,69 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 WeekInputType_h
+#define WeekInputType_h
+
+#include "core/html/BaseChooserOnlyDateAndTimeInputType.h"
+#include "core/html/BaseMultipleFieldsDateAndTimeInputType.h"
+
+namespace WebCore {
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+typedef BaseMultipleFieldsDateAndTimeInputType BaseWeekInputType;
+#else
+typedef BaseChooserOnlyDateAndTimeInputType BaseWeekInputType;
+#endif
+
+class WeekInputType : public BaseWeekInputType {
+public:
+    static PassOwnPtr<InputType> create(HTMLInputElement*);
+
+private:
+    WeekInputType(HTMLInputElement* element) : BaseWeekInputType(element) { }
+    virtual void attach() OVERRIDE;
+    virtual const AtomicString& formControlType() const OVERRIDE;
+    virtual DateComponents::Type dateType() const OVERRIDE;
+    virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
+    virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
+    virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
+    virtual bool isWeekField() const OVERRIDE;
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+    // BaseMultipleFieldsDateAndTimeInputType functions
+    virtual String formatDateTimeFieldsState(const DateTimeFieldsState&) const OVERRIDE FINAL;
+    virtual void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const OVERRIDE FINAL;
+    virtual bool isValidFormat(bool hasYear, bool hasMonth, bool hasWeek, bool hasDay, bool hasAMPM, bool hasHour, bool hasMinute, bool hasSecond) const;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // WeekInputType_h
diff --git a/Source/core/html/canvas/ArrayBuffer.idl b/Source/core/html/canvas/ArrayBuffer.idl
new file mode 100644
index 0000000..b56950f
--- /dev/null
+++ b/Source/core/html/canvas/ArrayBuffer.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009, 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    CustomConstructor(unsigned long length),
+    ImplementationNamespace=WTF,
+    ImplementationLacksVTable
+] interface ArrayBuffer {
+    readonly attribute unsigned long byteLength;
+    ArrayBuffer slice(long begin, optional long end);
+};
+
diff --git a/Source/core/html/canvas/ArrayBufferView.idl b/Source/core/html/canvas/ArrayBufferView.idl
new file mode 100644
index 0000000..1ed4f9f
--- /dev/null
+++ b/Source/core/html/canvas/ArrayBufferView.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    CustomToV8,
+    ImplementationNamespace=WTF
+] interface ArrayBufferView {
+    readonly attribute ArrayBuffer buffer;
+    readonly attribute unsigned long byteOffset;
+    readonly attribute unsigned long byteLength;
+};
diff --git a/Source/core/html/canvas/Canvas2DContextAttributes.cpp b/Source/core/html/canvas/Canvas2DContextAttributes.cpp
new file mode 100644
index 0000000..1e8c33e
--- /dev/null
+++ b/Source/core/html/canvas/Canvas2DContextAttributes.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "Canvas2DContextAttributes.h"
+
+namespace WebCore {
+
+Canvas2DContextAttributes::Canvas2DContextAttributes()
+    : m_alpha(true)
+{
+}
+
+Canvas2DContextAttributes::~Canvas2DContextAttributes()
+{
+}
+
+PassRefPtr<Canvas2DContextAttributes> Canvas2DContextAttributes::create()
+{
+    return adoptRef(new Canvas2DContextAttributes());
+}
+
+bool Canvas2DContextAttributes::alpha() const
+{
+    return m_alpha;
+}
+
+void Canvas2DContextAttributes::setAlpha(bool alpha)
+{
+    m_alpha = alpha;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/Canvas2DContextAttributes.h b/Source/core/html/canvas/Canvas2DContextAttributes.h
new file mode 100644
index 0000000..dbf1586
--- /dev/null
+++ b/Source/core/html/canvas/Canvas2DContextAttributes.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 Canvas2DContextAttributes_h
+#define Canvas2DContextAttributes_h
+
+#include "CanvasContextAttributes.h"
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class Canvas2DContextAttributes : public CanvasContextAttributes {
+public:
+    virtual ~Canvas2DContextAttributes();
+
+    // Create a new attributes object
+    static PassRefPtr<Canvas2DContextAttributes> create();
+
+    // Whether or not the drawing buffer has an alpha channel; default=true
+    bool alpha() const;
+    void setAlpha(bool);
+
+protected:
+    Canvas2DContextAttributes();
+
+    bool m_alpha;
+};
+
+} // namespace WebCore
+
+#endif // Canvas2DContextAttributes_h
diff --git a/Source/core/html/canvas/Canvas2DContextAttributes.idl b/Source/core/html/canvas/Canvas2DContextAttributes.idl
new file mode 100644
index 0000000..f266a57
--- /dev/null
+++ b/Source/core/html/canvas/Canvas2DContextAttributes.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013, 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+[EnabledAtRuntime=experimentalCanvasFeatures] interface Canvas2DContextAttributes {
+    attribute boolean alpha;
+};
diff --git a/Source/core/html/canvas/CanvasContextAttributes.cpp b/Source/core/html/canvas/CanvasContextAttributes.cpp
new file mode 100644
index 0000000..591bbf0
--- /dev/null
+++ b/Source/core/html/canvas/CanvasContextAttributes.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/CanvasContextAttributes.h"
+
+namespace WebCore {
+
+CanvasContextAttributes::CanvasContextAttributes()
+{
+}
+
+CanvasContextAttributes::~CanvasContextAttributes()
+{
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/CanvasContextAttributes.h b/Source/core/html/canvas/CanvasContextAttributes.h
new file mode 100644
index 0000000..dfdfcf4
--- /dev/null
+++ b/Source/core/html/canvas/CanvasContextAttributes.h
@@ -0,0 +1,47 @@
+/*
+ * 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 CanvasContextAttributes_h
+#define CanvasContextAttributes_h
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+// A base class for any attributes that are needed which would affect
+// the creation of the Canvas's rendering context.
+
+class CanvasContextAttributes : public RefCounted<CanvasContextAttributes> {
+  public:
+    virtual ~CanvasContextAttributes();
+
+  protected:
+    CanvasContextAttributes();
+};
+
+} // namespace WebCore
+
+#endif // CanvasContextAttributes_h
diff --git a/Source/core/html/canvas/CanvasGradient.cpp b/Source/core/html/canvas/CanvasGradient.cpp
new file mode 100644
index 0000000..f2180e3
--- /dev/null
+++ b/Source/core/html/canvas/CanvasGradient.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+#include "core/html/canvas/CanvasGradient.h"
+
+#include "core/css/CSSParser.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/html/canvas/CanvasPattern.h"
+#include "core/html/canvas/CanvasStyle.h"
+
+namespace WebCore {
+
+CanvasGradient::CanvasGradient(const FloatPoint& p0, const FloatPoint& p1)
+    : m_gradient(Gradient::create(p0, p1))
+{
+}
+
+CanvasGradient::CanvasGradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1)
+    : m_gradient(Gradient::create(p0, r0, p1, r1))
+{
+}
+
+void CanvasGradient::addColorStop(float value, const String& color, ExceptionCode& ec)
+{
+    if (!(value >= 0 && value <= 1.0f)) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    RGBA32 rgba = 0;
+    if (!parseColorOrCurrentColor(rgba, color, 0 /*canvas*/)) {
+        ec = SYNTAX_ERR;
+        return;
+    }
+
+    m_gradient->addColorStop(value, Color(rgba));
+}
+
+} // namespace
diff --git a/Source/core/html/canvas/CanvasGradient.h b/Source/core/html/canvas/CanvasGradient.h
new file mode 100644
index 0000000..c423e8d
--- /dev/null
+++ b/Source/core/html/canvas/CanvasGradient.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * 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 COMPUTER, 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 COMPUTER, 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 CanvasGradient_h
+#define CanvasGradient_h
+
+#include "core/platform/graphics/Gradient.h"
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+    typedef int ExceptionCode;
+
+    class CanvasGradient : public RefCounted<CanvasGradient> {
+    public:
+        static PassRefPtr<CanvasGradient> create(const FloatPoint& p0, const FloatPoint& p1)
+        {
+            return adoptRef(new CanvasGradient(p0, p1));
+        }
+        static PassRefPtr<CanvasGradient> create(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1)
+        {
+            return adoptRef(new CanvasGradient(p0, r0, p1, r1));
+        }
+        
+        Gradient* gradient() const { return m_gradient.get(); }
+
+        void addColorStop(float value, const String& color, ExceptionCode&);
+
+        void getColor(float value, float* r, float* g, float* b, float* a) const { m_gradient->getColor(value, r, g, b, a); }
+    private:
+        CanvasGradient(const FloatPoint& p0, const FloatPoint& p1);
+        CanvasGradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1);
+        
+        RefPtr<Gradient> m_gradient;
+    };
+
+} //namespace
+
+#endif
diff --git a/Source/core/html/canvas/CanvasGradient.idl b/Source/core/html/canvas/CanvasGradient.idl
new file mode 100644
index 0000000..6ecd51b
--- /dev/null
+++ b/Source/core/html/canvas/CanvasGradient.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+[
+    ImplementationLacksVTable
+] interface CanvasGradient {
+
+    [RaisesException] void addColorStop([Default=Undefined] optional float offset, 
+                      [Default=Undefined] optional DOMString color);
+
+};
+
diff --git a/Source/core/html/canvas/CanvasPathMethods.cpp b/Source/core/html/canvas/CanvasPathMethods.cpp
new file mode 100644
index 0000000..0226af2
--- /dev/null
+++ b/Source/core/html/canvas/CanvasPathMethods.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2012, 2013 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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 "core/html/canvas/CanvasPathMethods.h"
+
+#include "core/dom/ExceptionCode.h"
+#include "core/platform/graphics/FloatRect.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+void CanvasPathMethods::closePath()
+{
+    if (m_path.isEmpty())
+        return;
+
+    FloatRect boundRect = m_path.boundingRect();
+    if (boundRect.width() || boundRect.height())
+        m_path.closeSubpath();
+}
+
+void CanvasPathMethods::moveTo(float x, float y)
+{
+    if (!std::isfinite(x) || !std::isfinite(y))
+        return;
+    if (!isTransformInvertible())
+        return;
+    m_path.moveTo(FloatPoint(x, y));
+}
+
+void CanvasPathMethods::lineTo(float x, float y)
+{
+    if (!std::isfinite(x) || !std::isfinite(y))
+        return;
+    if (!isTransformInvertible())
+        return;
+
+    FloatPoint p1 = FloatPoint(x, y);
+    if (!m_path.hasCurrentPoint())
+        m_path.moveTo(p1);
+    else if (p1 != m_path.currentPoint())
+        m_path.addLineTo(p1);
+}
+
+void CanvasPathMethods::quadraticCurveTo(float cpx, float cpy, float x, float y)
+{
+    if (!std::isfinite(cpx) || !std::isfinite(cpy) || !std::isfinite(x) || !std::isfinite(y))
+        return;
+    if (!isTransformInvertible())
+        return;
+    if (!m_path.hasCurrentPoint())
+        m_path.moveTo(FloatPoint(cpx, cpy));
+
+    FloatPoint p1 = FloatPoint(x, y);
+    FloatPoint cp = FloatPoint(cpx, cpy);
+    if (p1 != m_path.currentPoint() || p1 != cp)
+        m_path.addQuadCurveTo(cp, p1);
+}
+
+void CanvasPathMethods::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
+{
+    if (!std::isfinite(cp1x) || !std::isfinite(cp1y) || !std::isfinite(cp2x) || !std::isfinite(cp2y) || !std::isfinite(x) || !std::isfinite(y))
+        return;
+    if (!isTransformInvertible())
+        return;
+    if (!m_path.hasCurrentPoint())
+        m_path.moveTo(FloatPoint(cp1x, cp1y));
+
+    FloatPoint p1 = FloatPoint(x, y);
+    FloatPoint cp1 = FloatPoint(cp1x, cp1y);
+    FloatPoint cp2 = FloatPoint(cp2x, cp2y);
+    if (p1 != m_path.currentPoint() || p1 != cp1 ||  p1 != cp2)
+        m_path.addBezierCurveTo(cp1, cp2, p1);
+}
+
+void CanvasPathMethods::arcTo(float x1, float y1, float x2, float y2, float r, ExceptionCode& ec)
+{
+    ec = 0;
+    if (!std::isfinite(x1) || !std::isfinite(y1) || !std::isfinite(x2) || !std::isfinite(y2) || !std::isfinite(r))
+        return;
+
+    if (r < 0) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    if (!isTransformInvertible())
+        return;
+
+    FloatPoint p1 = FloatPoint(x1, y1);
+    FloatPoint p2 = FloatPoint(x2, y2);
+
+    if (!m_path.hasCurrentPoint())
+        m_path.moveTo(p1);
+    else if (p1 == m_path.currentPoint() || p1 == p2 || !r)
+        lineTo(x1, y1);
+    else
+        m_path.addArcTo(p1, p2, r);
+}
+
+void CanvasPathMethods::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec)
+{
+    ec = 0;
+    if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(r) || !std::isfinite(sa) || !std::isfinite(ea))
+        return;
+
+    if (r < 0) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    if (!r || sa == ea) {
+        // The arc is empty but we still need to draw the connecting line.
+        lineTo(x + r * cosf(sa), y + r * sinf(sa));
+        return;
+    }
+
+    if (!isTransformInvertible())
+        return;
+
+    // If 'sa' and 'ea' differ by more than 2Pi, just add a circle starting/ending at 'sa'.
+    if (anticlockwise && sa - ea >= 2 * piFloat) {
+        m_path.addArc(FloatPoint(x, y), r, sa, sa - 2 * piFloat, anticlockwise);
+        return;
+    }
+    if (!anticlockwise && ea - sa >= 2 * piFloat) {
+        m_path.addArc(FloatPoint(x, y), r, sa, sa + 2 * piFloat, anticlockwise);
+        return;
+    }
+
+    m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise);
+}
+
+void CanvasPathMethods::rect(float x, float y, float width, float height)
+{
+    if (!isTransformInvertible())
+        return;
+
+    if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) || !std::isfinite(height))
+        return;
+
+    if (!width && !height) {
+        m_path.moveTo(FloatPoint(x, y));
+        return;
+    }
+
+    m_path.addRect(FloatRect(x, y, width, height));
+}
+}
diff --git a/Source/core/html/canvas/CanvasPathMethods.h b/Source/core/html/canvas/CanvasPathMethods.h
new file mode 100644
index 0000000..19fa93e
--- /dev/null
+++ b/Source/core/html/canvas/CanvasPathMethods.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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 CanvasPathMethods_h
+#define CanvasPathMethods_h
+
+#include "core/platform/graphics/Path.h"
+
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class FloatRect;
+
+typedef int ExceptionCode;
+
+class CanvasPathMethods {
+public:
+    virtual ~CanvasPathMethods() { }
+
+    void closePath();
+    void moveTo(float x, float y);
+    void lineTo(float x, float y);
+    void quadraticCurveTo(float cpx, float cpy, float x, float y);
+    void bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y);
+    void arcTo(float x0, float y0, float x1, float y1, float radius, ExceptionCode&);
+    void arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode&);
+    void rect(float x, float y, float width, float height);
+
+    virtual bool isTransformInvertible() const { return true; }
+
+protected:
+    CanvasPathMethods() { }
+    Path m_path;
+};
+}
+
+#endif
diff --git a/Source/core/html/canvas/CanvasPattern.cpp b/Source/core/html/canvas/CanvasPattern.cpp
new file mode 100644
index 0000000..1b2148d
--- /dev/null
+++ b/Source/core/html/canvas/CanvasPattern.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006, 2008 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+#include "core/html/canvas/CanvasPattern.h"
+
+#include "core/dom/ExceptionCode.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+void CanvasPattern::parseRepetitionType(const String& type, bool& repeatX, bool& repeatY, ExceptionCode& ec)
+{
+    ec = 0;
+    if (type.isEmpty() || type == "repeat") {
+        repeatX = true;
+        repeatY = true;
+        return;
+    }
+    if (type == "no-repeat") {
+        repeatX = false;
+        repeatY = false;
+        return;
+    }
+    if (type == "repeat-x") {
+        repeatX = true;
+        repeatY = false;
+        return;
+    }
+    if (type == "repeat-y") {
+        repeatX = false;
+        repeatY = true;
+        return;
+    }
+    ec = SYNTAX_ERR;
+}
+
+CanvasPattern::CanvasPattern(PassRefPtr<Image> image, bool repeatX, bool repeatY, bool originClean)
+    : m_pattern(Pattern::create(image, repeatX, repeatY))
+    , m_originClean(originClean)
+{
+}
+
+}
diff --git a/Source/core/html/canvas/CanvasPattern.h b/Source/core/html/canvas/CanvasPattern.h
new file mode 100644
index 0000000..f36d0f4
--- /dev/null
+++ b/Source/core/html/canvas/CanvasPattern.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2006, 2008 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 COMPUTER, 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 COMPUTER, 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 CanvasPattern_h
+#define CanvasPattern_h
+
+#include "core/platform/graphics/Pattern.h"
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+    class Image;
+
+    typedef int ExceptionCode;
+
+    class CanvasPattern : public RefCounted<CanvasPattern> {
+    public:
+        static void parseRepetitionType(const String&, bool& repeatX, bool& repeatY, ExceptionCode&);
+
+        static PassRefPtr<CanvasPattern> create(PassRefPtr<Image> image, bool repeatX, bool repeatY, bool originClean)
+        {
+            return adoptRef(new CanvasPattern(image, repeatX, repeatY, originClean));
+        }
+
+        Pattern* pattern() const { return m_pattern.get(); }
+
+        bool originClean() const { return m_originClean; }
+
+    private:
+        CanvasPattern(PassRefPtr<Image>, bool repeatX, bool repeatY, bool originClean);
+
+        RefPtr<Pattern> m_pattern;
+        bool m_originClean;
+    };
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/canvas/CanvasPattern.idl b/Source/core/html/canvas/CanvasPattern.idl
new file mode 100644
index 0000000..4ded936
--- /dev/null
+++ b/Source/core/html/canvas/CanvasPattern.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+[
+    ImplementationLacksVTable
+] interface CanvasPattern {
+};
+
diff --git a/Source/core/html/canvas/CanvasRenderingContext.cpp b/Source/core/html/canvas/CanvasRenderingContext.cpp
new file mode 100644
index 0000000..8aec589
--- /dev/null
+++ b/Source/core/html/canvas/CanvasRenderingContext.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+#include "core/html/canvas/CanvasRenderingContext.h"
+
+#include "core/html/HTMLCanvasElement.h"
+#include "core/html/HTMLImageElement.h"
+#include "core/html/HTMLVideoElement.h"
+#include "core/html/canvas/CanvasPattern.h"
+#include "core/loader/cache/CachedImage.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/platform/KURL.h"
+
+namespace WebCore {
+
+CanvasRenderingContext::CanvasRenderingContext(HTMLCanvasElement* canvas)
+    : m_canvas(canvas)
+{
+    ScriptWrappable::init(this);
+}
+
+bool CanvasRenderingContext::wouldTaintOrigin(const CanvasPattern* pattern)
+{
+    if (canvas()->originClean() && pattern && !pattern->originClean())
+        return true;
+    return false;
+}
+
+bool CanvasRenderingContext::wouldTaintOrigin(const HTMLCanvasElement* sourceCanvas)
+{
+    if (canvas()->originClean() && sourceCanvas && !sourceCanvas->originClean())
+        return true;
+    return false;
+}
+
+bool CanvasRenderingContext::wouldTaintOrigin(const HTMLImageElement* image)
+{
+    if (!image || !canvas()->originClean())
+        return false;
+
+    CachedImage* cachedImage = image->cachedImage();
+    if (!cachedImage->image()->hasSingleSecurityOrigin())
+        return true;
+
+    return wouldTaintOrigin(cachedImage->response().url()) && !cachedImage->passesAccessControlCheck(canvas()->securityOrigin());
+}
+
+bool CanvasRenderingContext::wouldTaintOrigin(const HTMLVideoElement* video)
+{
+    // FIXME: This check is likely wrong when a redirect is involved. We need
+    // to test the finalURL. Please be careful when fixing this issue not to
+    // make currentSrc be the final URL because then the
+    // HTMLMediaElement.currentSrc DOM API would leak redirect destinations!
+    if (!video || !canvas()->originClean())
+        return false;
+
+    if (!video->hasSingleSecurityOrigin())
+        return true;
+
+    if (!(video->player() && video->player()->didPassCORSAccessCheck()) && wouldTaintOrigin(video->currentSrc()))
+        return true;
+
+    return false;
+}
+
+bool CanvasRenderingContext::wouldTaintOrigin(const KURL& url)
+{
+    if (!canvas()->originClean() || m_cleanURLs.contains(url.string()))
+        return false;
+
+    if (canvas()->securityOrigin()->taintsCanvas(url))
+        return true;
+
+    if (url.protocolIsData())
+        return false;
+
+    m_cleanURLs.add(url.string());
+    return false;
+}
+
+void CanvasRenderingContext::checkOrigin(const KURL& url)
+{
+    if (wouldTaintOrigin(url))
+        canvas()->setOriginTainted();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/CanvasRenderingContext.h b/Source/core/html/canvas/CanvasRenderingContext.h
new file mode 100644
index 0000000..f9846f9
--- /dev/null
+++ b/Source/core/html/canvas/CanvasRenderingContext.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 CanvasRenderingContext_h
+#define CanvasRenderingContext_h
+
+#include "bindings/v8/ScriptWrappable.h"
+#include "core/html/HTMLCanvasElement.h"
+#include "core/platform/graphics/GraphicsLayer.h"
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class CanvasPattern;
+class HTMLCanvasElement;
+class HTMLImageElement;
+class HTMLVideoElement;
+class KURL;
+class WebGLObject;
+
+class CanvasRenderingContext : public ScriptWrappable {
+    WTF_MAKE_NONCOPYABLE(CanvasRenderingContext); WTF_MAKE_FAST_ALLOCATED;
+public:
+    virtual ~CanvasRenderingContext() { }
+
+    void ref() { m_canvas->ref(); }
+    void deref() { m_canvas->deref(); }
+    HTMLCanvasElement* canvas() const { return m_canvas; }
+
+    virtual bool is2d() const { return false; }
+    virtual bool is3d() const { return false; }
+    virtual bool isAccelerated() const { return false; }
+    virtual bool hasAlpha() const { return true; }
+
+    virtual void paintRenderingResultsToCanvas() {}
+
+    virtual PlatformLayer* platformLayer() const { return 0; }
+
+protected:
+    CanvasRenderingContext(HTMLCanvasElement*);
+    bool wouldTaintOrigin(const CanvasPattern*);
+    bool wouldTaintOrigin(const HTMLCanvasElement*);
+    bool wouldTaintOrigin(const HTMLImageElement*);
+    bool wouldTaintOrigin(const HTMLVideoElement*);
+    bool wouldTaintOrigin(const KURL&);
+
+    template<class T> void checkOrigin(const T* arg)
+    {
+        if (wouldTaintOrigin(arg))
+            canvas()->setOriginTainted();
+    }
+    void checkOrigin(const KURL&);
+
+private:
+    HTMLCanvasElement* m_canvas;
+    HashSet<String> m_cleanURLs;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/canvas/CanvasRenderingContext.idl b/Source/core/html/canvas/CanvasRenderingContext.idl
new file mode 100644
index 0000000..819ae77
--- /dev/null
+++ b/Source/core/html/canvas/CanvasRenderingContext.idl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    CustomToV8
+] interface CanvasRenderingContext {
+    readonly attribute HTMLCanvasElement canvas;
+};
+
diff --git a/Source/core/html/canvas/CanvasRenderingContext2D.cpp b/Source/core/html/canvas/CanvasRenderingContext2D.cpp
new file mode 100644
index 0000000..3962dff
--- /dev/null
+++ b/Source/core/html/canvas/CanvasRenderingContext2D.cpp
@@ -0,0 +1,2262 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2013 Adobe Systems Incorporated. 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+#include "core/html/canvas/CanvasRenderingContext2D.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "core/css/CSSFontSelector.h"
+#include "core/css/CSSParser.h"
+#include "core/css/StylePropertySet.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/html/HTMLCanvasElement.h"
+#include "core/html/HTMLImageElement.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/html/HTMLVideoElement.h"
+#include "core/html/ImageData.h"
+#include "core/html/TextMetrics.h"
+#include "core/html/canvas/Canvas2DContextAttributes.h"
+#include "core/html/canvas/CanvasGradient.h"
+#include "core/html/canvas/CanvasPattern.h"
+#include "core/html/canvas/CanvasStyle.h"
+#include "core/html/canvas/DOMPath.h"
+#include "core/loader/cache/CachedImage.h"
+#include "core/page/Console.h"
+#include "core/page/Page.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/page/Settings.h"
+#include "core/platform/FloatConversion.h"
+#include "core/platform/KURL.h"
+#include "core/platform/graphics/FloatQuad.h"
+#include "core/platform/graphics/FontCache.h"
+#include "core/platform/graphics/GraphicsContext.h"
+#include "core/platform/graphics/StrokeStyleApplier.h"
+#include "core/platform/graphics/TextRun.h"
+#include "core/platform/graphics/transforms/AffineTransform.h"
+#include "core/rendering/RenderHTMLCanvas.h"
+#include "core/rendering/RenderLayer.h"
+
+#include <wtf/CheckedArithmetic.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/Uint8ClampedArray.h>
+#include <wtf/UnusedParam.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const int defaultFontSize = 10;
+static const char* const defaultFontFamily = "sans-serif";
+static const char* const defaultFont = "10px sans-serif";
+
+static bool isOriginClean(CachedImage* cachedImage, SecurityOrigin* securityOrigin)
+{
+    if (!cachedImage->image()->hasSingleSecurityOrigin())
+        return false;
+    if (cachedImage->passesAccessControlCheck(securityOrigin))
+        return true;
+    return !securityOrigin->taintsCanvas(cachedImage->response().url());
+}
+
+class CanvasStrokeStyleApplier : public StrokeStyleApplier {
+public:
+    CanvasStrokeStyleApplier(CanvasRenderingContext2D* canvasContext)
+        : m_canvasContext(canvasContext)
+    {
+    }
+
+    virtual void strokeStyle(GraphicsContext* c)
+    {
+        c->setStrokeThickness(m_canvasContext->lineWidth());
+        c->setLineCap(m_canvasContext->getLineCap());
+        c->setLineJoin(m_canvasContext->getLineJoin());
+        c->setMiterLimit(m_canvasContext->miterLimit());
+        const Vector<float>& lineDash = m_canvasContext->getLineDash();
+        DashArray convertedLineDash(lineDash.size());
+        for (size_t i = 0; i < lineDash.size(); ++i)
+            convertedLineDash[i] = static_cast<DashArrayElement>(lineDash[i]);
+        c->setLineDash(convertedLineDash, m_canvasContext->lineDashOffset());
+    }
+
+private:
+    CanvasRenderingContext2D* m_canvasContext;
+};
+
+CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, const Canvas2DContextAttributes* attrs, bool usesCSSCompatibilityParseMode)
+    : CanvasRenderingContext(canvas)
+    , m_stateStack(1)
+    , m_unrealizedSaveCount(0)
+    , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
+    , m_hasAlpha(!attrs || attrs->alpha())
+{
+    ScriptWrappable::init(this);
+}
+
+void CanvasRenderingContext2D::unwindStateStack()
+{
+    // Ensure that the state stack in the ImageBuffer's context
+    // is cleared before destruction, to avoid assertions in the
+    // GraphicsContext dtor.
+    if (size_t stackSize = m_stateStack.size()) {
+        if (GraphicsContext* context = canvas()->existingDrawingContext()) {
+            while (--stackSize)
+                context->restore();
+        }
+    }
+}
+
+CanvasRenderingContext2D::~CanvasRenderingContext2D()
+{
+#if !ASSERT_DISABLED
+    unwindStateStack();
+#endif
+}
+
+bool CanvasRenderingContext2D::isAccelerated() const
+{
+    if (!canvas()->hasCreatedImageBuffer())
+        return false;
+    GraphicsContext* context = drawingContext();
+    return context && context->isAccelerated();
+}
+
+void CanvasRenderingContext2D::reset()
+{
+    unwindStateStack();
+    m_stateStack.resize(1);
+    m_stateStack.first() = State();
+    m_path.clear();
+    m_unrealizedSaveCount = 0;
+}
+
+CanvasRenderingContext2D::State::State()
+    : m_strokeStyle(CanvasStyle::createFromRGBA(Color::black))
+    , m_fillStyle(CanvasStyle::createFromRGBA(Color::black))
+    , m_lineWidth(1)
+    , m_lineCap(ButtCap)
+    , m_lineJoin(MiterJoin)
+    , m_miterLimit(10)
+    , m_shadowBlur(0)
+    , m_shadowColor(Color::transparent)
+    , m_globalAlpha(1)
+    , m_globalComposite(CompositeSourceOver)
+    , m_globalBlend(BlendModeNormal)
+    , m_invertibleCTM(true)
+    , m_lineDashOffset(0)
+    , m_imageSmoothingEnabled(true)
+    , m_textAlign(StartTextAlign)
+    , m_textBaseline(AlphabeticTextBaseline)
+    , m_unparsedFont(defaultFont)
+    , m_realizedFont(false)
+{
+}
+
+CanvasRenderingContext2D::State::State(const State& other)
+    : FontSelectorClient()
+    , m_unparsedStrokeColor(other.m_unparsedStrokeColor)
+    , m_unparsedFillColor(other.m_unparsedFillColor)
+    , m_strokeStyle(other.m_strokeStyle)
+    , m_fillStyle(other.m_fillStyle)
+    , m_lineWidth(other.m_lineWidth)
+    , m_lineCap(other.m_lineCap)
+    , m_lineJoin(other.m_lineJoin)
+    , m_miterLimit(other.m_miterLimit)
+    , m_shadowOffset(other.m_shadowOffset)
+    , m_shadowBlur(other.m_shadowBlur)
+    , m_shadowColor(other.m_shadowColor)
+    , m_globalAlpha(other.m_globalAlpha)
+    , m_globalComposite(other.m_globalComposite)
+    , m_globalBlend(other.m_globalBlend)
+    , m_transform(other.m_transform)
+    , m_invertibleCTM(other.m_invertibleCTM)
+    , m_lineDashOffset(other.m_lineDashOffset)
+    , m_imageSmoothingEnabled(other.m_imageSmoothingEnabled)
+    , m_textAlign(other.m_textAlign)
+    , m_textBaseline(other.m_textBaseline)
+    , m_unparsedFont(other.m_unparsedFont)
+    , m_font(other.m_font)
+    , m_realizedFont(other.m_realizedFont)
+{
+    if (m_realizedFont)
+        m_font.fontSelector()->registerForInvalidationCallbacks(this);
+}
+
+CanvasRenderingContext2D::State& CanvasRenderingContext2D::State::operator=(const State& other)
+{
+    if (this == &other)
+        return *this;
+
+    if (m_realizedFont)
+        m_font.fontSelector()->unregisterForInvalidationCallbacks(this);
+
+    m_unparsedStrokeColor = other.m_unparsedStrokeColor;
+    m_unparsedFillColor = other.m_unparsedFillColor;
+    m_strokeStyle = other.m_strokeStyle;
+    m_fillStyle = other.m_fillStyle;
+    m_lineWidth = other.m_lineWidth;
+    m_lineCap = other.m_lineCap;
+    m_lineJoin = other.m_lineJoin;
+    m_miterLimit = other.m_miterLimit;
+    m_shadowOffset = other.m_shadowOffset;
+    m_shadowBlur = other.m_shadowBlur;
+    m_shadowColor = other.m_shadowColor;
+    m_globalAlpha = other.m_globalAlpha;
+    m_globalComposite = other.m_globalComposite;
+    m_globalBlend = other.m_globalBlend;
+    m_transform = other.m_transform;
+    m_invertibleCTM = other.m_invertibleCTM;
+    m_imageSmoothingEnabled = other.m_imageSmoothingEnabled;
+    m_textAlign = other.m_textAlign;
+    m_textBaseline = other.m_textBaseline;
+    m_unparsedFont = other.m_unparsedFont;
+    m_font = other.m_font;
+    m_realizedFont = other.m_realizedFont;
+
+    if (m_realizedFont)
+        m_font.fontSelector()->registerForInvalidationCallbacks(this);
+
+    return *this;
+}
+
+CanvasRenderingContext2D::State::~State()
+{
+    if (m_realizedFont)
+        m_font.fontSelector()->unregisterForInvalidationCallbacks(this);
+}
+
+void CanvasRenderingContext2D::State::fontsNeedUpdate(FontSelector* fontSelector)
+{
+    ASSERT_ARG(fontSelector, fontSelector == m_font.fontSelector());
+    ASSERT(m_realizedFont);
+
+    m_font.update(fontSelector);
+}
+
+void CanvasRenderingContext2D::realizeSavesLoop()
+{
+    ASSERT(m_unrealizedSaveCount);
+    ASSERT(m_stateStack.size() >= 1);
+    GraphicsContext* context = drawingContext();
+    do {
+        m_stateStack.append(state());
+        if (context)
+            context->save();
+    } while (--m_unrealizedSaveCount);
+}
+
+void CanvasRenderingContext2D::restore()
+{
+    if (m_unrealizedSaveCount) {
+        --m_unrealizedSaveCount;
+        return;
+    }
+    ASSERT(m_stateStack.size() >= 1);
+    if (m_stateStack.size() <= 1)
+        return;
+    m_path.transform(state().m_transform);
+    m_stateStack.removeLast();
+    m_path.transform(state().m_transform.inverse());
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->restore();
+}
+
+CanvasStyle* CanvasRenderingContext2D::strokeStyle() const
+{
+    return state().m_strokeStyle.get();
+}
+
+void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> prpStyle)
+{
+    RefPtr<CanvasStyle> style = prpStyle;
+
+    if (!style)
+        return;
+
+    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style))
+        return;
+
+    if (style->isCurrentColor()) {
+        if (style->hasOverrideAlpha())
+            style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha()));
+        else
+            style = CanvasStyle::createFromRGBA(currentColor(canvas()));
+    } else
+        checkOrigin(style->canvasPattern());
+
+    realizeSaves();
+    modifiableState().m_strokeStyle = style.release();
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    state().m_strokeStyle->applyStrokeColor(c);
+    modifiableState().m_unparsedStrokeColor = String();
+}
+
+CanvasStyle* CanvasRenderingContext2D::fillStyle() const
+{
+    return state().m_fillStyle.get();
+}
+
+void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> prpStyle)
+{
+    RefPtr<CanvasStyle> style = prpStyle;
+
+    if (!style)
+        return;
+
+    if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style))
+        return;
+
+    if (style->isCurrentColor()) {
+        if (style->hasOverrideAlpha())
+            style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha()));
+        else
+            style = CanvasStyle::createFromRGBA(currentColor(canvas()));
+    } else
+        checkOrigin(style->canvasPattern());
+
+    realizeSaves();
+    modifiableState().m_fillStyle = style.release();
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    state().m_fillStyle->applyFillColor(c);
+    modifiableState().m_unparsedFillColor = String();
+}
+
+float CanvasRenderingContext2D::lineWidth() const
+{
+    return state().m_lineWidth;
+}
+
+void CanvasRenderingContext2D::setLineWidth(float width)
+{
+    if (!(std::isfinite(width) && width > 0))
+        return;
+    if (state().m_lineWidth == width)
+        return;
+    realizeSaves();
+    modifiableState().m_lineWidth = width;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setStrokeThickness(width);
+}
+
+String CanvasRenderingContext2D::lineCap() const
+{
+    return lineCapName(state().m_lineCap);
+}
+
+void CanvasRenderingContext2D::setLineCap(const String& s)
+{
+    LineCap cap;
+    if (!parseLineCap(s, cap))
+        return;
+    if (state().m_lineCap == cap)
+        return;
+    realizeSaves();
+    modifiableState().m_lineCap = cap;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setLineCap(cap);
+}
+
+String CanvasRenderingContext2D::lineJoin() const
+{
+    return lineJoinName(state().m_lineJoin);
+}
+
+void CanvasRenderingContext2D::setLineJoin(const String& s)
+{
+    LineJoin join;
+    if (!parseLineJoin(s, join))
+        return;
+    if (state().m_lineJoin == join)
+        return;
+    realizeSaves();
+    modifiableState().m_lineJoin = join;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setLineJoin(join);
+}
+
+float CanvasRenderingContext2D::miterLimit() const
+{
+    return state().m_miterLimit;
+}
+
+void CanvasRenderingContext2D::setMiterLimit(float limit)
+{
+    if (!(std::isfinite(limit) && limit > 0))
+        return;
+    if (state().m_miterLimit == limit)
+        return;
+    realizeSaves();
+    modifiableState().m_miterLimit = limit;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setMiterLimit(limit);
+}
+
+float CanvasRenderingContext2D::shadowOffsetX() const
+{
+    return state().m_shadowOffset.width();
+}
+
+void CanvasRenderingContext2D::setShadowOffsetX(float x)
+{
+    if (!std::isfinite(x))
+        return;
+    if (state().m_shadowOffset.width() == x)
+        return;
+    realizeSaves();
+    modifiableState().m_shadowOffset.setWidth(x);
+    applyShadow();
+}
+
+float CanvasRenderingContext2D::shadowOffsetY() const
+{
+    return state().m_shadowOffset.height();
+}
+
+void CanvasRenderingContext2D::setShadowOffsetY(float y)
+{
+    if (!std::isfinite(y))
+        return;
+    if (state().m_shadowOffset.height() == y)
+        return;
+    realizeSaves();
+    modifiableState().m_shadowOffset.setHeight(y);
+    applyShadow();
+}
+
+float CanvasRenderingContext2D::shadowBlur() const
+{
+    return state().m_shadowBlur;
+}
+
+void CanvasRenderingContext2D::setShadowBlur(float blur)
+{
+    if (!(std::isfinite(blur) && blur >= 0))
+        return;
+    if (state().m_shadowBlur == blur)
+        return;
+    realizeSaves();
+    modifiableState().m_shadowBlur = blur;
+    applyShadow();
+}
+
+String CanvasRenderingContext2D::shadowColor() const
+{
+    return Color(state().m_shadowColor).serialized();
+}
+
+void CanvasRenderingContext2D::setShadowColor(const String& color)
+{
+    RGBA32 rgba;
+    if (!parseColorOrCurrentColor(rgba, color, canvas()))
+        return;
+    if (state().m_shadowColor == rgba)
+        return;
+    realizeSaves();
+    modifiableState().m_shadowColor = rgba;
+    applyShadow();
+}
+
+const Vector<float>& CanvasRenderingContext2D::getLineDash() const
+{
+    return state().m_lineDash;
+}
+
+static bool lineDashSequenceIsValid(const Vector<float>& dash)
+{
+    for (size_t i = 0; i < dash.size(); i++) {
+        if (!std::isfinite(dash[i]) || dash[i] < 0)
+            return false;
+    }
+    return true;
+}
+
+void CanvasRenderingContext2D::setLineDash(const Vector<float>& dash)
+{
+    if (!lineDashSequenceIsValid(dash))
+        return;
+
+    realizeSaves();
+    modifiableState().m_lineDash = dash;
+    // Spec requires the concatenation of two copies the dash list when the
+    // number of elements is odd
+    if (dash.size() % 2)
+        modifiableState().m_lineDash.append(dash);
+
+    applyLineDash();
+}
+
+void CanvasRenderingContext2D::setWebkitLineDash(const Vector<float>& dash)
+{
+    if (!lineDashSequenceIsValid(dash))
+        return;
+
+    realizeSaves();
+    modifiableState().m_lineDash = dash;
+
+    applyLineDash();
+}
+
+float CanvasRenderingContext2D::lineDashOffset() const
+{
+    return state().m_lineDashOffset;
+}
+
+void CanvasRenderingContext2D::setLineDashOffset(float offset)
+{
+    if (!std::isfinite(offset) || state().m_lineDashOffset == offset)
+        return;
+
+    realizeSaves();
+    modifiableState().m_lineDashOffset = offset;
+    applyLineDash();
+}
+
+float CanvasRenderingContext2D::webkitLineDashOffset() const
+{
+    return lineDashOffset();
+}
+
+void CanvasRenderingContext2D::setWebkitLineDashOffset(float offset)
+{
+    setLineDashOffset(offset);
+}
+
+void CanvasRenderingContext2D::applyLineDash() const
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    DashArray convertedLineDash(state().m_lineDash.size());
+    for (size_t i = 0; i < state().m_lineDash.size(); ++i)
+        convertedLineDash[i] = static_cast<DashArrayElement>(state().m_lineDash[i]);
+    c->setLineDash(convertedLineDash, state().m_lineDashOffset);
+}
+
+float CanvasRenderingContext2D::globalAlpha() const
+{
+    return state().m_globalAlpha;
+}
+
+void CanvasRenderingContext2D::setGlobalAlpha(float alpha)
+{
+    if (!(alpha >= 0 && alpha <= 1))
+        return;
+    if (state().m_globalAlpha == alpha)
+        return;
+    realizeSaves();
+    modifiableState().m_globalAlpha = alpha;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setAlpha(alpha);
+}
+
+String CanvasRenderingContext2D::globalCompositeOperation() const
+{
+    return compositeOperatorName(state().m_globalComposite, state().m_globalBlend);
+}
+
+void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation)
+{
+    CompositeOperator op = CompositeSourceOver;
+    BlendMode blendMode = BlendModeNormal;
+    if (!parseCompositeAndBlendOperator(operation, op, blendMode))
+        return;
+    if ((state().m_globalComposite == op) && (state().m_globalBlend == blendMode))
+        return;
+    realizeSaves();
+    modifiableState().m_globalComposite = op;
+    modifiableState().m_globalBlend = blendMode;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setCompositeOperation(op, blendMode);
+}
+
+void CanvasRenderingContext2D::scale(float sx, float sy)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    if (!std::isfinite(sx) | !std::isfinite(sy))
+        return;
+
+    AffineTransform newTransform = state().m_transform;
+    newTransform.scaleNonUniform(sx, sy);
+    if (state().m_transform == newTransform)
+        return;
+
+    realizeSaves();
+
+    if (!newTransform.isInvertible()) {
+        modifiableState().m_invertibleCTM = false;
+        return;
+    }
+
+    modifiableState().m_transform = newTransform;
+    c->scale(FloatSize(sx, sy));
+    m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
+}
+
+void CanvasRenderingContext2D::rotate(float angleInRadians)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    if (!std::isfinite(angleInRadians))
+        return;
+
+    AffineTransform newTransform = state().m_transform;
+    newTransform.rotate(angleInRadians / piDouble * 180.0);
+    if (state().m_transform == newTransform)
+        return;
+
+    realizeSaves();
+
+    if (!newTransform.isInvertible()) {
+        modifiableState().m_invertibleCTM = false;
+        return;
+    }
+
+    modifiableState().m_transform = newTransform;
+    c->rotate(angleInRadians);
+    m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0));
+}
+
+void CanvasRenderingContext2D::translate(float tx, float ty)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    if (!std::isfinite(tx) | !std::isfinite(ty))
+        return;
+
+    AffineTransform newTransform = state().m_transform;
+    newTransform.translate(tx, ty);
+    if (state().m_transform == newTransform)
+        return;
+
+    realizeSaves();
+
+    if (!newTransform.isInvertible()) {
+        modifiableState().m_invertibleCTM = false;
+        return;
+    }
+
+    modifiableState().m_transform = newTransform;
+    c->translate(tx, ty);
+    m_path.transform(AffineTransform().translate(-tx, -ty));
+}
+
+void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    if (!std::isfinite(m11) | !std::isfinite(m21) | !std::isfinite(dx) | !std::isfinite(m12) | !std::isfinite(m22) | !std::isfinite(dy))
+        return;
+
+    AffineTransform transform(m11, m12, m21, m22, dx, dy);
+    AffineTransform newTransform = state().m_transform * transform;
+    if (state().m_transform == newTransform)
+        return;
+
+    realizeSaves();
+
+    if (!newTransform.isInvertible()) {
+        modifiableState().m_invertibleCTM = false;
+        return;
+    }
+
+    modifiableState().m_transform = newTransform;
+    c->concatCTM(transform);
+    m_path.transform(transform.inverse());
+}
+
+void CanvasRenderingContext2D::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+
+    if (!std::isfinite(m11) | !std::isfinite(m21) | !std::isfinite(dx) | !std::isfinite(m12) | !std::isfinite(m22) | !std::isfinite(dy))
+        return;
+
+    AffineTransform ctm = state().m_transform;
+    if (!ctm.isInvertible())
+        return;
+
+    realizeSaves();
+    
+    c->setCTM(canvas()->baseTransform());
+    modifiableState().m_transform = AffineTransform();
+    m_path.transform(ctm);
+
+    modifiableState().m_invertibleCTM = true;
+    transform(m11, m12, m21, m22, dx, dy);
+}
+
+void CanvasRenderingContext2D::setStrokeColor(const String& color)
+{
+    if (color == state().m_unparsedStrokeColor)
+        return;
+    realizeSaves();
+    setStrokeStyle(CanvasStyle::createFromString(color, canvas()->document()));
+    modifiableState().m_unparsedStrokeColor = color;
+}
+
+void CanvasRenderingContext2D::setStrokeColor(float grayLevel)
+{
+    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
+        return;
+    setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
+}
+
+void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
+{
+    setStrokeStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
+}
+
+void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
+{
+    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
+        return;
+    setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
+}
+
+void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a)
+{
+    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(r, g, b, a))
+        return;
+    setStrokeStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
+}
+
+void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a)
+{
+    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentCMYKA(c, m, y, k, a))
+        return;
+    setStrokeStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
+}
+
+void CanvasRenderingContext2D::setFillColor(const String& color)
+{
+    if (color == state().m_unparsedFillColor)
+        return;
+    realizeSaves();
+    setFillStyle(CanvasStyle::createFromString(color, canvas()->document()));
+    modifiableState().m_unparsedFillColor = color;
+}
+
+void CanvasRenderingContext2D::setFillColor(float grayLevel)
+{
+    if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
+        return;
+    setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
+}
+
+void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
+{
+    setFillStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
+}
+
+void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
+{
+    if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
+        return;
+    setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
+}
+
+void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
+{
+    if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(r, g, b, a))
+        return;
+    setFillStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
+}
+
+void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
+{
+    if (state().m_fillStyle && state().m_fillStyle->isEquivalentCMYKA(c, m, y, k, a))
+        return;
+    setFillStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
+}
+
+void CanvasRenderingContext2D::beginPath()
+{
+    m_path.clear();
+}
+
+PassRefPtr<DOMPath> CanvasRenderingContext2D::currentPath()
+{
+    return DOMPath::create(m_path);
+}
+
+void CanvasRenderingContext2D::setCurrentPath(DOMPath* path)
+{
+    if (!path)
+        return;
+    m_path = path->path();
+}
+
+static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
+{
+    if (!std::isfinite(x) | !std::isfinite(y) | !std::isfinite(width) | !std::isfinite(height))
+        return false;
+
+    if (!width && !height)
+        return false;
+
+    if (width < 0) {
+        width = -width;
+        x -= width;
+    }
+
+    if (height < 0) {
+        height = -height;
+        y -= height;
+    }
+
+    return true;
+}
+
+static bool isFullCanvasCompositeMode(CompositeOperator op)
+{
+    // See 4.8.11.1.3 Compositing
+    // CompositeSourceAtop and CompositeDestinationOut are not listed here as the platforms already
+    // implement the specification's behavior.
+    return op == CompositeSourceIn || op == CompositeSourceOut || op == CompositeDestinationIn || op == CompositeDestinationAtop;
+}
+
+static bool parseWinding(const String& windingRuleString, WindRule& windRule)
+{
+    if (windingRuleString == "nonzero")
+        windRule = RULE_NONZERO;
+    else if (windingRuleString == "evenodd")
+        windRule = RULE_EVENODD;
+    else
+        return false;
+    
+    return true;
+}
+
+void CanvasRenderingContext2D::fill(const String& windingRuleString)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    // If gradient size is zero, then paint nothing.
+    Gradient* gradient = c->fillGradient();
+    if (gradient && gradient->isZeroSize())
+        return;
+
+    if (!m_path.isEmpty()) {
+        WindRule windRule = c->fillRule();
+        WindRule newWindRule = RULE_NONZERO;
+        if (!parseWinding(windingRuleString, newWindRule))
+            return;
+        c->setFillRule(newWindRule);
+
+        if (isFullCanvasCompositeMode(state().m_globalComposite)) {
+            fullCanvasCompositedFill(m_path);
+            didDrawEntireCanvas();
+        } else if (state().m_globalComposite == CompositeCopy) {
+            clearCanvas();
+            c->fillPath(m_path);
+            didDrawEntireCanvas();
+        } else {
+            c->fillPath(m_path);
+            didDraw(m_path.boundingRect());
+        }
+        
+        c->setFillRule(windRule);
+    }
+}
+
+void CanvasRenderingContext2D::stroke()
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    // If gradient size is zero, then paint nothing.
+    Gradient* gradient = c->strokeGradient();
+    if (gradient && gradient->isZeroSize())
+        return;
+
+    if (!m_path.isEmpty()) {
+        FloatRect dirtyRect = m_path.boundingRect();
+        inflateStrokeRect(dirtyRect);
+
+        c->strokePath(m_path);
+        didDraw(dirtyRect);
+    }
+}
+
+void CanvasRenderingContext2D::clip(const String& windingRuleString)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    WindRule newWindRule = RULE_NONZERO;
+    if (!parseWinding(windingRuleString, newWindRule))
+        return;
+
+    realizeSaves();
+    c->canvasClip(m_path, newWindRule);
+}
+
+bool CanvasRenderingContext2D::isPointInPath(const float x, const float y, const String& windingRuleString)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return false;
+    if (!state().m_invertibleCTM)
+        return false;
+
+    FloatPoint point(x, y);
+    AffineTransform ctm = state().m_transform;
+    FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
+    if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
+        return false;
+
+    WindRule windRule = RULE_NONZERO;
+    if (!parseWinding(windingRuleString, windRule))
+        return false;
+    
+    return m_path.contains(transformedPoint, windRule);
+}
+
+
+bool CanvasRenderingContext2D::isPointInStroke(const float x, const float y)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return false;
+    if (!state().m_invertibleCTM)
+        return false;
+
+    FloatPoint point(x, y);
+    AffineTransform ctm = state().m_transform;
+    FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
+    if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
+        return false;
+
+    CanvasStrokeStyleApplier applier(this);
+    return m_path.strokeContains(&applier, transformedPoint);
+}
+
+void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
+{
+    if (!validateRectForCanvas(x, y, width, height))
+        return;
+    GraphicsContext* context = drawingContext();
+    if (!context)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+    FloatRect rect(x, y, width, height);
+
+    bool saved = false;
+    if (shouldDrawShadows()) {
+        context->save();
+        saved = true;
+        context->setLegacyShadow(FloatSize(), 0, Color::transparent, ColorSpaceDeviceRGB);
+    }
+    if (state().m_globalAlpha != 1) {
+        if (!saved) {
+            context->save();
+            saved = true;
+        }
+        context->setAlpha(1);
+    }
+    if (state().m_globalComposite != CompositeSourceOver) {
+        if (!saved) {
+            context->save();
+            saved = true;
+        }
+        context->setCompositeOperation(CompositeSourceOver);
+    }
+    context->clearRect(rect);
+    if (saved)
+        context->restore();
+    didDraw(rect);
+}
+
+void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
+{
+    if (!validateRectForCanvas(x, y, width, height))
+        return;
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    // from the HTML5 Canvas spec:
+    // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
+    // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
+    Gradient* gradient = c->fillGradient();
+    if (gradient && gradient->isZeroSize())
+        return;
+
+    FloatRect rect(x, y, width, height);
+
+    if (rectContainsCanvas(rect)) {
+        c->fillRect(rect);
+        didDrawEntireCanvas();
+    } else if (isFullCanvasCompositeMode(state().m_globalComposite)) {
+        fullCanvasCompositedFill(rect);
+        didDrawEntireCanvas();
+    } else if (state().m_globalComposite == CompositeCopy) {
+        clearCanvas();
+        c->fillRect(rect);
+        didDrawEntireCanvas();
+    } else {
+        c->fillRect(rect);
+        didDraw(rect);
+    }
+}
+
+void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height)
+{
+    if (!validateRectForCanvas(x, y, width, height))
+        return;
+    strokeRect(x, y, width, height, state().m_lineWidth);
+}
+
+void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth)
+{
+    if (!validateRectForCanvas(x, y, width, height))
+        return;
+
+    if (!(lineWidth >= 0))
+        return;
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    // If gradient size is zero, then paint nothing.
+    Gradient* gradient = c->strokeGradient();
+    if (gradient && gradient->isZeroSize())
+        return;
+
+    FloatRect rect(x, y, width, height);
+
+    FloatRect boundingRect = rect;
+    boundingRect.inflate(lineWidth / 2);
+
+    c->strokeRect(rect, lineWidth);
+    didDraw(boundingRect);
+}
+
+void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
+{
+    setShadow(FloatSize(width, height), blur, Color::transparent);
+}
+
+void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color)
+{
+    RGBA32 rgba;
+    if (!parseColorOrCurrentColor(rgba, color, canvas()))
+        return;
+    setShadow(FloatSize(width, height), blur, rgba);
+}
+
+void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
+{
+    setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1));
+}
+
+void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha)
+{
+    RGBA32 rgba;
+    if (!parseColorOrCurrentColor(rgba, color, canvas()))
+        return;
+    setShadow(FloatSize(width, height), blur, colorWithOverrideAlpha(rgba, alpha));
+}
+
+void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
+{
+    setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha));
+}
+
+void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
+{
+    setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(r, g, b, a));
+}
+
+void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
+{
+    setShadow(FloatSize(width, height), blur, makeRGBAFromCMYKA(c, m, y, k, a));
+}
+
+void CanvasRenderingContext2D::clearShadow()
+{
+    setShadow(FloatSize(), 0, Color::transparent);
+}
+
+void CanvasRenderingContext2D::setShadow(const FloatSize& offset, float blur, RGBA32 color)
+{
+    if (state().m_shadowOffset == offset && state().m_shadowBlur == blur && state().m_shadowColor == color)
+        return;
+    bool wasDrawingShadows = shouldDrawShadows();
+    realizeSaves();
+    modifiableState().m_shadowOffset = offset;
+    modifiableState().m_shadowBlur = blur;
+    modifiableState().m_shadowColor = color;
+    if (!wasDrawingShadows && !shouldDrawShadows())
+        return;
+    applyShadow();
+}
+
+void CanvasRenderingContext2D::applyShadow()
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+
+    if (shouldDrawShadows()) {
+        float width = state().m_shadowOffset.width();
+        float height = state().m_shadowOffset.height();
+        c->setLegacyShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB);
+    } else
+        c->setLegacyShadow(FloatSize(), 0, Color::transparent, ColorSpaceDeviceRGB);
+}
+
+bool CanvasRenderingContext2D::shouldDrawShadows() const
+{
+    return alphaChannel(state().m_shadowColor) && (state().m_shadowBlur || !state().m_shadowOffset.isZero());
+}
+
+static LayoutSize size(HTMLImageElement* image)
+{
+    if (CachedImage* cachedImage = image->cachedImage())
+        return cachedImage->imageSizeForRenderer(image->renderer(), 1.0f); // FIXME: Not sure about this.
+    return IntSize();
+}
+
+static IntSize size(HTMLVideoElement* video)
+{
+    if (MediaPlayer* player = video->player())
+        return player->naturalSize();
+    return IntSize();
+}
+
+static inline FloatRect normalizeRect(const FloatRect& rect)
+{
+    return FloatRect(min(rect.x(), rect.maxX()),
+        min(rect.y(), rect.maxY()),
+        max(rect.width(), -rect.width()),
+        max(rect.height(), -rect.height()));
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y, ExceptionCode& ec)
+{
+    if (!image) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+    LayoutSize s = size(image);
+    drawImage(image, x, y, s.width(), s.height(), ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
+    float x, float y, float width, float height, ExceptionCode& ec)
+{
+    if (!image) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+    LayoutSize s = size(image);
+    drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
+    float sx, float sy, float sw, float sh,
+    float dx, float dy, float dw, float dh, ExceptionCode& ec)
+{
+    drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec)
+{
+    drawImage(image, srcRect, dstRect, state().m_globalComposite, state().m_globalBlend, ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator& op, const BlendMode& blendMode, ExceptionCode& ec)
+{
+    if (!image) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+
+    ec = 0;
+
+    if (!std::isfinite(dstRect.x()) || !std::isfinite(dstRect.y()) || !std::isfinite(dstRect.width()) || !std::isfinite(dstRect.height())
+        || !std::isfinite(srcRect.x()) || !std::isfinite(srcRect.y()) || !std::isfinite(srcRect.width()) || !std::isfinite(srcRect.height()))
+        return;
+
+    if (!dstRect.width() || !dstRect.height())
+        return;
+
+    if (!image->complete())
+        return;
+
+    FloatRect normalizedSrcRect = normalizeRect(srcRect);
+    FloatRect normalizedDstRect = normalizeRect(dstRect);
+
+    FloatRect imageRect = FloatRect(FloatPoint(), size(image));
+    if (!srcRect.width() || !srcRect.height()) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+    if (!imageRect.contains(normalizedSrcRect))
+        return;
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    CachedImage* cachedImage = image->cachedImage();
+    if (!cachedImage)
+        return;
+
+    checkOrigin(image);
+
+    Image* imageForRendering = cachedImage->imageForRenderer(image->renderer());
+
+    // For images that depend on an unavailable container size, we need to fall back to the intrinsic
+    // object size. http://www.w3.org/TR/2dcontext2/#dom-context-2d-drawimage
+    // FIXME: Without a specified image size this should resolve against the canvas element's size, see: crbug.com/230163.
+    if (!image->renderer() && imageForRendering->usesContainerSize())
+        imageForRendering->setContainerSize(imageForRendering->size());
+
+    if (rectContainsCanvas(normalizedDstRect)) {
+        c->drawImage(imageForRendering, ColorSpaceDeviceRGB, normalizedDstRect, normalizedSrcRect, op, blendMode);
+        didDrawEntireCanvas();
+    } else if (isFullCanvasCompositeMode(op)) {
+        fullCanvasCompositedDrawImage(imageForRendering, ColorSpaceDeviceRGB, normalizedDstRect, normalizedSrcRect, op);
+        didDrawEntireCanvas();
+    } else if (op == CompositeCopy) {
+        clearCanvas();
+        c->drawImage(imageForRendering, ColorSpaceDeviceRGB, normalizedDstRect, normalizedSrcRect, op, blendMode);
+        didDrawEntireCanvas();
+    } else {
+        c->drawImage(imageForRendering, ColorSpaceDeviceRGB, normalizedDstRect, normalizedSrcRect, op, blendMode);
+        didDraw(normalizedDstRect);
+    }
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, float x, float y, ExceptionCode& ec)
+{
+    drawImage(sourceCanvas, 0, 0, sourceCanvas->width(), sourceCanvas->height(), x, y, sourceCanvas->width(), sourceCanvas->height(), ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas,
+    float x, float y, float width, float height, ExceptionCode& ec)
+{
+    drawImage(sourceCanvas, FloatRect(0, 0, sourceCanvas->width(), sourceCanvas->height()), FloatRect(x, y, width, height), ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas,
+    float sx, float sy, float sw, float sh,
+    float dx, float dy, float dw, float dh, ExceptionCode& ec)
+{
+    drawImage(sourceCanvas, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const FloatRect& srcRect,
+    const FloatRect& dstRect, ExceptionCode& ec)
+{
+    if (!sourceCanvas) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+
+    FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas->size());
+
+    if (!srcCanvasRect.width() || !srcCanvasRect.height()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    if (!srcRect.width() || !srcRect.height()) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    ec = 0;
+
+    if (!srcCanvasRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
+        return;
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    // FIXME: Do this through platform-independent GraphicsContext API.
+    ImageBuffer* buffer = sourceCanvas->buffer();
+    if (!buffer)
+        return;
+
+    checkOrigin(sourceCanvas);
+
+    // If we're drawing from one accelerated canvas 2d to another, avoid calling sourceCanvas->makeRenderingResultsAvailable()
+    // as that will do a readback to software.
+    CanvasRenderingContext* sourceContext = sourceCanvas->renderingContext();
+    // FIXME: Implement an accelerated path for drawing from a WebGL canvas to a 2d canvas when possible.
+    if (!isAccelerated() || !sourceContext || !sourceContext->isAccelerated() || !sourceContext->is2d())
+        sourceCanvas->makeRenderingResultsAvailable();
+
+    if (rectContainsCanvas(dstRect)) {
+        c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, srcRect, state().m_globalComposite, state().m_globalBlend);
+        didDrawEntireCanvas();
+    } else if (isFullCanvasCompositeMode(state().m_globalComposite)) {
+        fullCanvasCompositedDrawImage(buffer, ColorSpaceDeviceRGB, dstRect, srcRect, state().m_globalComposite);
+        didDrawEntireCanvas();
+    } else if (state().m_globalComposite == CompositeCopy) {
+        clearCanvas();
+        c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, srcRect, state().m_globalComposite, state().m_globalBlend);
+        didDrawEntireCanvas();
+    } else {
+        c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, srcRect, state().m_globalComposite, state().m_globalBlend);
+        didDraw(dstRect);
+    }
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y, ExceptionCode& ec)
+{
+    if (!video) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+    IntSize s = size(video);
+    drawImage(video, x, y, s.width(), s.height(), ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
+                                         float x, float y, float width, float height, ExceptionCode& ec)
+{
+    if (!video) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+    IntSize s = size(video);
+    drawImage(video, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
+    float sx, float sy, float sw, float sh,
+    float dx, float dy, float dw, float dh, ExceptionCode& ec)
+{
+    drawImage(video, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
+}
+
+void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRect& srcRect, const FloatRect& dstRect,
+                                         ExceptionCode& ec)
+{
+    if (!video) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+
+    ec = 0;
+
+    if (video->readyState() == HTMLMediaElement::HAVE_NOTHING || video->readyState() == HTMLMediaElement::HAVE_METADATA)
+        return;
+
+    FloatRect videoRect = FloatRect(FloatPoint(), size(video));
+    if (!srcRect.width() || !srcRect.height()) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    if (!videoRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
+        return;
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    checkOrigin(video);
+
+    GraphicsContextStateSaver stateSaver(*c);
+    c->clip(dstRect);
+    c->translate(dstRect.x(), dstRect.y());
+    c->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height()));
+    c->translate(-srcRect.x(), -srcRect.y());
+    video->paintCurrentFrameInContext(c, IntRect(IntPoint(), size(video)));
+    stateSaver.restore();
+    didDraw(dstRect);
+}
+
+void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
+    float sx, float sy, float sw, float sh,
+    float dx, float dy, float dw, float dh,
+    const String& compositeOperation)
+{
+    CompositeOperator op;
+    BlendMode blendOp = BlendModeNormal;
+    if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blendOp != BlendModeNormal)
+        op = CompositeSourceOver;
+
+    drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), op, BlendModeNormal, IGNORE_EXCEPTION);
+}
+
+void CanvasRenderingContext2D::setAlpha(float alpha)
+{
+    setGlobalAlpha(alpha);
+}
+
+void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
+{
+    setGlobalCompositeOperation(operation);
+}
+
+void CanvasRenderingContext2D::clearCanvas()
+{
+    FloatRect canvasRect(0, 0, canvas()->width(), canvas()->height());
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+
+    c->save();
+    c->setCTM(canvas()->baseTransform());
+    c->clearRect(canvasRect);
+    c->restore();
+}
+
+Path CanvasRenderingContext2D::transformAreaToDevice(const Path& path) const
+{
+    Path transformed(path);
+    transformed.transform(state().m_transform);
+    transformed.transform(canvas()->baseTransform());
+    return transformed;
+}
+
+Path CanvasRenderingContext2D::transformAreaToDevice(const FloatRect& rect) const
+{
+    Path path;
+    path.addRect(rect);
+    return transformAreaToDevice(path);
+}
+
+bool CanvasRenderingContext2D::rectContainsCanvas(const FloatRect& rect) const
+{
+    FloatQuad quad(rect);
+    FloatQuad canvasQuad(FloatRect(0, 0, canvas()->width(), canvas()->height()));
+    return state().m_transform.mapQuad(quad).containsQuad(canvasQuad);
+}
+
+template<class T> IntRect CanvasRenderingContext2D::calculateCompositingBufferRect(const T& area, IntSize* croppedOffset)
+{
+    IntRect canvasRect(0, 0, canvas()->width(), canvas()->height());
+    canvasRect = canvas()->baseTransform().mapRect(canvasRect);
+    Path path = transformAreaToDevice(area);
+    IntRect bufferRect = enclosingIntRect(path.boundingRect());
+    IntPoint originalLocation = bufferRect.location();
+    bufferRect.intersect(canvasRect);
+    if (croppedOffset)
+        *croppedOffset = originalLocation - bufferRect.location();
+    return bufferRect;
+}
+
+PassOwnPtr<ImageBuffer> CanvasRenderingContext2D::createCompositingBuffer(const IntRect& bufferRect)
+{
+    RenderingMode renderMode = isAccelerated() ? Accelerated : Unaccelerated;
+    return ImageBuffer::create(bufferRect.size(), 1, ColorSpaceDeviceRGB, renderMode);
+}
+
+void CanvasRenderingContext2D::compositeBuffer(ImageBuffer* buffer, const IntRect& bufferRect, CompositeOperator op)
+{
+    IntRect canvasRect(0, 0, canvas()->width(), canvas()->height());
+    canvasRect = canvas()->baseTransform().mapRect(canvasRect);
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+
+    c->save();
+    c->setCTM(AffineTransform());
+    c->setCompositeOperation(op);
+
+    c->save();
+    c->clipOut(bufferRect);
+    c->clearRect(canvasRect);
+    c->restore();
+
+    c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, bufferRect.location(), state().m_globalComposite);
+    c->restore();
+}
+
+static void drawImageToContext(Image* image, GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
+{
+    context->drawImage(image, styleColorSpace, dest, src, op);
+}
+
+static void drawImageToContext(ImageBuffer* imageBuffer, GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
+{
+    context->drawImageBuffer(imageBuffer, styleColorSpace, dest, src, op);
+}
+
+template<class T> void  CanvasRenderingContext2D::fullCanvasCompositedDrawImage(T* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
+{
+    ASSERT(isFullCanvasCompositeMode(op));
+
+    IntSize croppedOffset;
+    IntRect bufferRect = calculateCompositingBufferRect(dest, &croppedOffset);
+    if (bufferRect.isEmpty()) {
+        clearCanvas();
+        return;
+    }
+
+    OwnPtr<ImageBuffer> buffer = createCompositingBuffer(bufferRect);
+    if (!buffer)
+        return;
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+
+    FloatRect adjustedDest = dest;
+    adjustedDest.setLocation(FloatPoint(0, 0));
+    AffineTransform effectiveTransform = c->getCTM();
+    IntRect transformedAdjustedRect = enclosingIntRect(effectiveTransform.mapRect(adjustedDest));
+    buffer->context()->translate(-transformedAdjustedRect.location().x(), -transformedAdjustedRect.location().y());
+    buffer->context()->translate(croppedOffset.width(), croppedOffset.height());
+    buffer->context()->concatCTM(effectiveTransform);
+    drawImageToContext(image, buffer->context(), styleColorSpace, adjustedDest, src, CompositeSourceOver);
+
+    compositeBuffer(buffer.get(), bufferRect, op);
+}
+
+template<class T> void CanvasRenderingContext2D::fullCanvasCompositedFill(const T& area)
+{
+    ASSERT(isFullCanvasCompositeMode(state().m_globalComposite));
+
+    IntRect bufferRect = calculateCompositingBufferRect(area, 0);
+    if (bufferRect.isEmpty()) {
+        clearCanvas();
+        return;
+    }
+
+    OwnPtr<ImageBuffer> buffer = createCompositingBuffer(bufferRect);
+    if (!buffer)
+        return;
+
+    Path path = transformAreaToDevice(area);
+    path.translate(FloatSize(-bufferRect.x(), -bufferRect.y()));
+
+    buffer->context()->setCompositeOperation(CompositeSourceOver);
+    state().m_fillStyle->applyFillColor(buffer->context());
+    buffer->context()->fillPath(path);
+
+    compositeBuffer(buffer.get(), bufferRect, state().m_globalComposite);
+}
+
+PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1, ExceptionCode& ec)
+{
+    if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(x1) || !std::isfinite(y1)) {
+        ec = NOT_SUPPORTED_ERR;
+        return 0;
+    }
+
+    RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
+    return gradient.release();
+}
+
+PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode& ec)
+{
+    if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(r0) || !std::isfinite(x1) || !std::isfinite(y1) || !std::isfinite(r1)) {
+        ec = NOT_SUPPORTED_ERR;
+        return 0;
+    }
+
+    if (r0 < 0 || r1 < 0) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }
+
+    RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
+    return gradient.release();
+}
+
+PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image,
+    const String& repetitionType, ExceptionCode& ec)
+{
+    if (!image) {
+        ec = TYPE_MISMATCH_ERR;
+        return 0;
+    }
+    bool repeatX, repeatY;
+    ec = 0;
+    CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
+    if (ec)
+        return 0;
+
+    if (!image->complete())
+        return 0;
+
+    CachedImage* cachedImage = image->cachedImage();
+    Image* imageForRendering = cachedImage ? cachedImage->imageForRenderer(image->renderer()) : 0;
+    if (!imageForRendering)
+        return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true);
+
+    // We need to synthesize a container size if a renderer is not available to provide one.
+    if (!image->renderer() && imageForRendering->usesContainerSize())
+        imageForRendering->setContainerSize(imageForRendering->size());
+
+    bool originClean = isOriginClean(cachedImage, canvas()->securityOrigin());
+    return CanvasPattern::create(imageForRendering, repeatX, repeatY, originClean);
+}
+
+PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas,
+    const String& repetitionType, ExceptionCode& ec)
+{
+    if (!canvas) {
+        ec = TYPE_MISMATCH_ERR;
+        return 0;
+    }
+    if (!canvas->width() || !canvas->height()) {
+        ec = INVALID_STATE_ERR;
+        return 0;
+    }
+
+    bool repeatX, repeatY;
+    ec = 0;
+    CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
+    if (ec)
+        return 0;
+    return CanvasPattern::create(canvas->copiedImage(), repeatX, repeatY, canvas->originClean());
+}
+
+void CanvasRenderingContext2D::didDrawEntireCanvas()
+{
+    didDraw(FloatRect(FloatPoint::zero(), canvas()->size()), CanvasDidDrawApplyClip);
+}
+
+void CanvasRenderingContext2D::didDraw(const FloatRect& r, unsigned options)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+
+    // If we are drawing to hardware and we have a composited layer, just call contentChanged().
+    if (isAccelerated()) {
+        RenderBox* renderBox = canvas()->renderBox();
+        if (renderBox && renderBox->hasAcceleratedCompositing()) {
+            renderBox->contentChanged(CanvasPixelsChanged);
+            canvas()->clearCopiedImage();
+            canvas()->notifyObserversCanvasChanged(r);
+            return;
+        }
+    }
+
+    FloatRect dirtyRect = r;
+    if (options & CanvasDidDrawApplyTransform) {
+        AffineTransform ctm = state().m_transform;
+        dirtyRect = ctm.mapRect(r);
+    }
+
+    if (options & CanvasDidDrawApplyShadow && alphaChannel(state().m_shadowColor)) {
+        // The shadow gets applied after transformation
+        FloatRect shadowRect(dirtyRect);
+        shadowRect.move(state().m_shadowOffset);
+        shadowRect.inflate(state().m_shadowBlur);
+        dirtyRect.unite(shadowRect);
+    }
+
+    if (options & CanvasDidDrawApplyClip) {
+        // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
+        // back out of the GraphicsContext, so to take clip into account for incremental painting,
+        // we'd have to keep the clip path around.
+    }
+
+    canvas()->didDraw(dirtyRect);
+}
+
+GraphicsContext* CanvasRenderingContext2D::drawingContext() const
+{
+    return canvas()->drawingContext();
+}
+
+static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size)
+{
+    Checked<int, RecordOverflow> dataSize = 4;
+    dataSize *= size.width();
+    dataSize *= size.height();
+    if (dataSize.hasOverflowed())
+        return 0;
+
+    RefPtr<ImageData> data = ImageData::create(size);
+    data->data()->zeroFill();
+    return data.release();
+}
+
+PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(PassRefPtr<ImageData> imageData, ExceptionCode& ec) const
+{
+    if (!imageData) {
+        ec = NOT_SUPPORTED_ERR;
+        return 0;
+    }
+
+    return createEmptyImageData(imageData->size());
+}
+
+PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh, ExceptionCode& ec) const
+{
+    ec = 0;
+    if (!sw || !sh) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }
+    if (!std::isfinite(sw) || !std::isfinite(sh)) {
+        ec = NOT_SUPPORTED_ERR;
+        return 0;
+    }
+
+    FloatSize logicalSize(fabs(sw), fabs(sh));
+    if (!logicalSize.isExpressibleAsIntSize())
+        return 0;
+
+    IntSize size = expandedIntSize(logicalSize);
+    if (size.width() < 1)
+        size.setWidth(1);
+    if (size.height() < 1)
+        size.setHeight(1);
+
+    return createEmptyImageData(size);
+}
+
+PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const
+{
+    return getImageData(ImageBuffer::LogicalCoordinateSystem, sx, sy, sw, sh, ec);
+}
+
+PassRefPtr<ImageData> CanvasRenderingContext2D::webkitGetImageDataHD(float sx, float sy, float sw, float sh, ExceptionCode& ec) const
+{
+    return getImageData(ImageBuffer::BackingStoreCoordinateSystem, sx, sy, sw, sh, ec);
+}
+
+PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(ImageBuffer::CoordinateSystem coordinateSystem, float sx, float sy, float sw, float sh, ExceptionCode& ec) const
+{
+    if (!canvas()->originClean()) {
+        DEFINE_STATIC_LOCAL(String, consoleMessage, (ASCIILiteral("Unable to get image data from canvas because the canvas has been tainted by cross-origin data.")));
+        canvas()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, consoleMessage);
+        ec = SECURITY_ERR;
+        return 0;
+    }
+
+    if (!sw || !sh) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }
+    if (!std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sw) || !std::isfinite(sh)) {
+        ec = NOT_SUPPORTED_ERR;
+        return 0;
+    }
+
+    if (sw < 0) {
+        sx += sw;
+        sw = -sw;
+    }    
+    if (sh < 0) {
+        sy += sh;
+        sh = -sh;
+    }
+
+    FloatRect logicalRect(sx, sy, sw, sh);
+    if (logicalRect.width() < 1)
+        logicalRect.setWidth(1);
+    if (logicalRect.height() < 1)
+        logicalRect.setHeight(1);
+    if (!logicalRect.isExpressibleAsIntRect())
+        return 0;
+
+    IntRect imageDataRect = enclosingIntRect(logicalRect);
+    ImageBuffer* buffer = canvas()->buffer();
+    if (!buffer)
+        return createEmptyImageData(imageDataRect.size());
+
+    RefPtr<Uint8ClampedArray> byteArray = buffer->getUnmultipliedImageData(imageDataRect, coordinateSystem);
+    if (!byteArray)
+        return 0;
+
+    return ImageData::create(imageDataRect.size(), byteArray.release());
+}
+
+void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec)
+{
+    if (!data) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+    putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec);
+}
+
+void CanvasRenderingContext2D::webkitPutImageDataHD(ImageData* data, float dx, float dy, ExceptionCode& ec)
+{
+    if (!data) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+    webkitPutImageDataHD(data, dx, dy, 0, 0, data->width(), data->height(), ec);
+}
+
+void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY,
+                                            float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
+{
+    putImageData(data, ImageBuffer::LogicalCoordinateSystem, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight, ec);
+}
+
+void CanvasRenderingContext2D::webkitPutImageDataHD(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
+{
+    putImageData(data, ImageBuffer::BackingStoreCoordinateSystem, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight, ec);
+}
+
+void CanvasRenderingContext2D::putImageData(ImageData* data, ImageBuffer::CoordinateSystem coordinateSystem, float dx, float dy, float dirtyX, float dirtyY,
+                                            float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
+{
+    if (!data) {
+        ec = TYPE_MISMATCH_ERR;
+        return;
+    }
+    if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dirtyX) || !std::isfinite(dirtyY) || !std::isfinite(dirtyWidth) || !std::isfinite(dirtyHeight)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+
+    ImageBuffer* buffer = canvas()->buffer();
+    if (!buffer)
+        return;
+
+    if (dirtyWidth < 0) {
+        dirtyX += dirtyWidth;
+        dirtyWidth = -dirtyWidth;
+    }
+
+    if (dirtyHeight < 0) {
+        dirtyY += dirtyHeight;
+        dirtyHeight = -dirtyHeight;
+    }
+
+    FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+    clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
+    IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
+    IntRect destRect = enclosingIntRect(clipRect);
+    destRect.move(destOffset);
+    destRect.intersect(IntRect(IntPoint(), coordinateSystem == ImageBuffer::LogicalCoordinateSystem ? buffer->logicalSize() : buffer->internalSize()));
+    if (destRect.isEmpty())
+        return;
+    IntRect sourceRect(destRect);
+    sourceRect.move(-destOffset);
+
+    buffer->putByteArray(Unmultiplied, data->data(), IntSize(data->width(), data->height()), sourceRect, IntPoint(destOffset), coordinateSystem);
+
+    if (coordinateSystem == ImageBuffer::BackingStoreCoordinateSystem) {
+        FloatRect dirtyRect = destRect;
+        dirtyRect.scale(1 / canvas()->deviceScaleFactor());
+        destRect = enclosingIntRect(dirtyRect);
+    }
+    didDraw(destRect, CanvasDidDrawApplyNone); // ignore transform, shadow and clip
+}
+
+String CanvasRenderingContext2D::font() const
+{
+    if (!state().m_realizedFont)
+        return defaultFont;
+
+    StringBuilder serializedFont;
+    const FontDescription& fontDescription = state().m_font.fontDescription();
+
+    if (fontDescription.italic())
+        serializedFont.appendLiteral("italic ");
+    if (fontDescription.smallCaps() == FontSmallCapsOn)
+        serializedFont.appendLiteral("small-caps ");
+
+    serializedFont.appendNumber(fontDescription.computedPixelSize());
+    serializedFont.appendLiteral("px");
+
+    const FontFamily& firstFontFamily = fontDescription.family();
+    for (const FontFamily* fontFamily = &firstFontFamily; fontFamily; fontFamily = fontFamily->next()) {
+        if (fontFamily != &firstFontFamily)
+            serializedFont.append(',');
+
+        // FIXME: We should append family directly to serializedFont rather than building a temporary string.
+        String family = fontFamily->family();
+        if (family.startsWith("-webkit-"))
+            family = family.substring(8);
+        if (family.contains(' '))
+            family = makeString('"', family, '"');
+
+        serializedFont.append(' ');
+        serializedFont.append(family);
+    }
+
+    return serializedFont.toString();
+}
+
+void CanvasRenderingContext2D::setFont(const String& newFont)
+{
+    if (newFont == state().m_unparsedFont && state().m_realizedFont)
+        return;
+
+    RefPtr<StylePropertySet> parsedStyle = StylePropertySet::create();
+    CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, newFont, true, strictToCSSParserMode(!m_usesCSSCompatibilityParseMode), 0);
+    if (parsedStyle->isEmpty())
+        return;
+
+    String fontValue = parsedStyle->getPropertyValue(CSSPropertyFont);
+
+    // According to http://lists.w3.org/Archives/Public/public-html/2009Jul/0947.html,
+    // the "inherit" and "initial" values must be ignored.
+    if (fontValue == "inherit" || fontValue == "initial")
+        return;
+
+    // The parse succeeded.
+    String newFontSafeCopy(newFont); // Create a string copy since newFont can be deleted inside realizeSaves.
+    realizeSaves();
+    modifiableState().m_unparsedFont = newFontSafeCopy;
+
+    // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
+    // relative to the canvas.
+    RefPtr<RenderStyle> newStyle = RenderStyle::create();
+    if (RenderStyle* computedStyle = canvas()->computedStyle())
+        newStyle->setFontDescription(computedStyle->fontDescription());
+    else {
+        FontFamily fontFamily;
+        fontFamily.setFamily(defaultFontFamily);
+
+        FontDescription defaultFontDescription;
+        defaultFontDescription.setFamily(fontFamily);
+        defaultFontDescription.setSpecifiedSize(defaultFontSize);
+        defaultFontDescription.setComputedSize(defaultFontSize);
+
+        newStyle->setFontDescription(defaultFontDescription);
+    }
+
+    newStyle->font().update(newStyle->font().fontSelector());
+
+    // Now map the font property longhands into the style.
+    StyleResolver* styleResolver = canvas()->styleResolver();
+    styleResolver->applyPropertyToStyle(CSSPropertyFontFamily, parsedStyle->getPropertyCSSValue(CSSPropertyFontFamily).get(), newStyle.get());
+    styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontStyle, parsedStyle->getPropertyCSSValue(CSSPropertyFontStyle).get());
+    styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontVariant, parsedStyle->getPropertyCSSValue(CSSPropertyFontVariant).get());
+    styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontWeight, parsedStyle->getPropertyCSSValue(CSSPropertyFontWeight).get());
+
+    // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call,
+    // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122).
+    // The updateFont() calls below update the fontMetrics and ensure the proper setting of font-size and line-height.
+    styleResolver->updateFont();
+    styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontSize, parsedStyle->getPropertyCSSValue(CSSPropertyFontSize).get());
+    styleResolver->updateFont();
+    styleResolver->applyPropertyToCurrentStyle(CSSPropertyLineHeight, parsedStyle->getPropertyCSSValue(CSSPropertyLineHeight).get());
+
+    modifiableState().m_font = newStyle->font();
+    modifiableState().m_font.update(styleResolver->fontSelector());
+    modifiableState().m_realizedFont = true;
+    styleResolver->fontSelector()->registerForInvalidationCallbacks(&modifiableState());
+}
+
+String CanvasRenderingContext2D::textAlign() const
+{
+    return textAlignName(state().m_textAlign);
+}
+
+void CanvasRenderingContext2D::setTextAlign(const String& s)
+{
+    TextAlign align;
+    if (!parseTextAlign(s, align))
+        return;
+    if (state().m_textAlign == align)
+        return;
+    realizeSaves();
+    modifiableState().m_textAlign = align;
+}
+
+String CanvasRenderingContext2D::textBaseline() const
+{
+    return textBaselineName(state().m_textBaseline);
+}
+
+void CanvasRenderingContext2D::setTextBaseline(const String& s)
+{
+    TextBaseline baseline;
+    if (!parseTextBaseline(s, baseline))
+        return;
+    if (state().m_textBaseline == baseline)
+        return;
+    realizeSaves();
+    modifiableState().m_textBaseline = baseline;
+}
+
+void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
+{
+    drawTextInternal(text, x, y, true);
+}
+
+void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth)
+{
+    drawTextInternal(text, x, y, true, maxWidth, true);
+}
+
+void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
+{
+    drawTextInternal(text, x, y, false);
+}
+
+void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
+{
+    drawTextInternal(text, x, y, false, maxWidth, true);
+}
+
+PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
+{
+    FontCachePurgePreventer fontCachePurgePreventer;
+    RefPtr<TextMetrics> metrics = TextMetrics::create();
+    metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length())));
+    return metrics.release();
+}
+
+static void replaceCharacterInString(String& text, WTF::CharacterMatchFunctionPtr matchFunction, const String& replacement)
+{
+    const size_t replacementLength = replacement.length();
+    size_t index = 0;
+    while ((index = text.find(matchFunction, index)) != notFound) {
+        text.replace(index, 1, replacement);
+        index += replacementLength;
+    }
+}
+
+void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float maxWidth, bool useMaxWidth)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().m_invertibleCTM)
+        return;
+    if (!std::isfinite(x) | !std::isfinite(y))
+        return;
+    if (useMaxWidth && (!std::isfinite(maxWidth) || maxWidth <= 0))
+        return;
+
+    // If gradient size is zero, then paint nothing.
+    Gradient* gradient = c->strokeGradient();
+    if (!fill && gradient && gradient->isZeroSize())
+        return;
+
+    gradient = c->fillGradient();
+    if (fill && gradient && gradient->isZeroSize())
+        return;
+
+    FontCachePurgePreventer fontCachePurgePreventer;
+
+    const Font& font = accessFont();
+    const FontMetrics& fontMetrics = font.fontMetrics();
+    // According to spec, all the space characters must be replaced with U+0020 SPACE characters.
+    String normalizedText = text;
+    replaceCharacterInString(normalizedText, isSpaceOrNewline, " ");
+
+    // FIXME: Need to turn off font smoothing.
+
+    RenderStyle* computedStyle = canvas()->computedStyle();
+    TextDirection direction = computedStyle ? computedStyle->direction() : LTR;
+    bool isRTL = direction == RTL;
+    bool override = computedStyle ? isOverride(computedStyle->unicodeBidi()) : false;
+
+    TextRun textRun(normalizedText, 0, 0, TextRun::AllowTrailingExpansion, direction, override, true, TextRun::NoRounding);
+    // Draw the item text at the correct point.
+    FloatPoint location(x, y);
+    switch (state().m_textBaseline) {
+    case TopTextBaseline:
+    case HangingTextBaseline:
+        location.setY(y + fontMetrics.ascent());
+        break;
+    case BottomTextBaseline:
+    case IdeographicTextBaseline:
+        location.setY(y - fontMetrics.descent());
+        break;
+    case MiddleTextBaseline:
+        location.setY(y - fontMetrics.descent() + fontMetrics.height() / 2);
+        break;
+    case AlphabeticTextBaseline:
+    default:
+         // Do nothing.
+        break;
+    }
+
+    float fontWidth = font.width(TextRun(normalizedText, 0, 0, TextRun::AllowTrailingExpansion, direction, override));
+
+    useMaxWidth = (useMaxWidth && maxWidth < fontWidth);
+    float width = useMaxWidth ? maxWidth : fontWidth;
+
+    TextAlign align = state().m_textAlign;
+    if (align == StartTextAlign)
+        align = isRTL ? RightTextAlign : LeftTextAlign;
+    else if (align == EndTextAlign)
+        align = isRTL ? LeftTextAlign : RightTextAlign;
+
+    switch (align) {
+    case CenterTextAlign:
+        location.setX(location.x() - width / 2);
+        break;
+    case RightTextAlign:
+        location.setX(location.x() - width);
+        break;
+    default:
+        break;
+    }
+
+    // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
+    FloatRect textRect = FloatRect(location.x() - fontMetrics.height() / 2, location.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
+                                   width + fontMetrics.height(), fontMetrics.lineSpacing());
+    if (!fill)
+        inflateStrokeRect(textRect);
+
+    c->setTextDrawingMode(fill ? TextModeFill : TextModeStroke);
+    if (useMaxWidth) {
+        GraphicsContextStateSaver stateSaver(*c);
+        c->translate(location.x(), location.y());
+        // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
+        c->scale(FloatSize((fontWidth > 0 ? (width / fontWidth) : 0), 1));
+        c->drawBidiText(font, textRun, FloatPoint(0, 0), Font::UseFallbackIfFontNotReady);
+    } else
+        c->drawBidiText(font, textRun, location, Font::UseFallbackIfFontNotReady);
+
+    didDraw(textRect);
+}
+
+void CanvasRenderingContext2D::inflateStrokeRect(FloatRect& rect) const
+{
+    // Fast approximation of the stroke's bounding rect.
+    // This yields a slightly oversized rect but is very fast
+    // compared to Path::strokeBoundingRect().
+    static const float root2 = sqrtf(2);
+    float delta = state().m_lineWidth / 2;
+    if (state().m_lineJoin == MiterJoin)
+        delta *= state().m_miterLimit;
+    else if (state().m_lineCap == SquareCap)
+        delta *= root2;
+
+    rect.inflate(delta);
+}
+
+const Font& CanvasRenderingContext2D::accessFont()
+{
+    canvas()->document()->updateStyleIfNeeded();
+
+    if (!state().m_realizedFont)
+        setFont(state().m_unparsedFont);
+    return state().m_font;
+}
+
+PlatformLayer* CanvasRenderingContext2D::platformLayer() const
+{
+    return canvas()->buffer() ? canvas()->buffer()->platformLayer() : 0;
+}
+
+bool CanvasRenderingContext2D::webkitImageSmoothingEnabled() const
+{
+    return state().m_imageSmoothingEnabled;
+}
+
+void CanvasRenderingContext2D::setWebkitImageSmoothingEnabled(bool enabled)
+{
+    if (enabled == state().m_imageSmoothingEnabled)
+        return;
+
+    realizeSaves();
+    modifiableState().m_imageSmoothingEnabled = enabled;
+    GraphicsContext* c = drawingContext();
+    if (c)
+        c->setImageInterpolationQuality(enabled ? DefaultInterpolationQuality : InterpolationNone);
+}
+
+PassRefPtr<Canvas2DContextAttributes> CanvasRenderingContext2D::getContextAttributes() const
+{
+    RefPtr<Canvas2DContextAttributes> attributes = Canvas2DContextAttributes::create();
+    attributes->setAlpha(m_hasAlpha);
+    return attributes.release();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/CanvasRenderingContext2D.h b/Source/core/html/canvas/CanvasRenderingContext2D.h
new file mode 100644
index 0000000..cafba65
--- /dev/null
+++ b/Source/core/html/canvas/CanvasRenderingContext2D.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012 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 COMPUTER, 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 COMPUTER, 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 CanvasRenderingContext2D_h
+#define CanvasRenderingContext2D_h
+
+#include "core/html/canvas/Canvas2DContextAttributes.h"
+#include "core/html/canvas/CanvasPathMethods.h"
+#include "core/html/canvas/CanvasRenderingContext.h"
+#include "core/platform/graphics/Color.h"
+#include "core/platform/graphics/ColorSpace.h"
+#include "core/platform/graphics/DashArray.h"
+#include "core/platform/graphics/FloatSize.h"
+#include "core/platform/graphics/Font.h"
+#include "core/platform/graphics/GraphicsTypes.h"
+#include "core/platform/graphics/ImageBuffer.h"
+#include "core/platform/graphics/Path.h"
+#include "core/platform/graphics/PlatformLayer.h"
+#include "core/platform/graphics/transforms/AffineTransform.h"
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+
+namespace WebCore {
+
+class CanvasGradient;
+class CanvasPattern;
+class CanvasStyle;
+class DOMPath;
+class FloatRect;
+class GraphicsContext;
+class HTMLCanvasElement;
+class HTMLImageElement;
+class HTMLVideoElement;
+class ImageData;
+class TextMetrics;
+
+typedef int ExceptionCode;
+
+class CanvasRenderingContext2D : public CanvasRenderingContext, public CanvasPathMethods {
+public:
+    static PassOwnPtr<CanvasRenderingContext2D> create(HTMLCanvasElement* canvas, const Canvas2DContextAttributes* attrs, bool usesCSSCompatibilityParseMode)
+    {
+        return adoptPtr(new CanvasRenderingContext2D(canvas, attrs, usesCSSCompatibilityParseMode));
+    }
+    virtual ~CanvasRenderingContext2D();
+
+    CanvasStyle* strokeStyle() const;
+    void setStrokeStyle(PassRefPtr<CanvasStyle>);
+
+    CanvasStyle* fillStyle() const;
+    void setFillStyle(PassRefPtr<CanvasStyle>);
+
+    float lineWidth() const;
+    void setLineWidth(float);
+
+    String lineCap() const;
+    void setLineCap(const String&);
+
+    String lineJoin() const;
+    void setLineJoin(const String&);
+
+    float miterLimit() const;
+    void setMiterLimit(float);
+
+    const Vector<float>& getLineDash() const;
+    void setLineDash(const Vector<float>&);
+    void setWebkitLineDash(const Vector<float>&);
+
+    float lineDashOffset() const;
+    void setLineDashOffset(float);
+    float webkitLineDashOffset() const;
+    void setWebkitLineDashOffset(float);
+
+    float shadowOffsetX() const;
+    void setShadowOffsetX(float);
+
+    float shadowOffsetY() const;
+    void setShadowOffsetY(float);
+
+    float shadowBlur() const;
+    void setShadowBlur(float);
+
+    String shadowColor() const;
+    void setShadowColor(const String&);
+
+    float globalAlpha() const;
+    void setGlobalAlpha(float);
+
+    String globalCompositeOperation() const;
+    void setGlobalCompositeOperation(const String&);
+
+    void save() { ++m_unrealizedSaveCount; }
+    void restore();
+
+    void scale(float sx, float sy);
+    void rotate(float angleInRadians);
+    void translate(float tx, float ty);
+    void transform(float m11, float m12, float m21, float m22, float dx, float dy);
+    void setTransform(float m11, float m12, float m21, float m22, float dx, float dy);
+
+    void setStrokeColor(const String& color);
+    void setStrokeColor(float grayLevel);
+    void setStrokeColor(const String& color, float alpha);
+    void setStrokeColor(float grayLevel, float alpha);
+    void setStrokeColor(float r, float g, float b, float a);
+    void setStrokeColor(float c, float m, float y, float k, float a);
+
+    void setFillColor(const String& color);
+    void setFillColor(float grayLevel);
+    void setFillColor(const String& color, float alpha);
+    void setFillColor(float grayLevel, float alpha);
+    void setFillColor(float r, float g, float b, float a);
+    void setFillColor(float c, float m, float y, float k, float a);
+
+    void beginPath();
+
+    PassRefPtr<DOMPath> currentPath();
+    void setCurrentPath(DOMPath*);
+    void fill(const String& winding = "nonzero");
+    void stroke();
+    void clip(const String& winding = "nonzero");
+
+    bool isPointInPath(const float x, const float y, const String& winding = "nonzero");
+    bool isPointInStroke(const float x, const float y);
+
+    void clearRect(float x, float y, float width, float height);
+    void fillRect(float x, float y, float width, float height);
+    void strokeRect(float x, float y, float width, float height);
+    void strokeRect(float x, float y, float width, float height, float lineWidth);
+
+    void setShadow(float width, float height, float blur);
+    void setShadow(float width, float height, float blur, const String& color);
+    void setShadow(float width, float height, float blur, float grayLevel);
+    void setShadow(float width, float height, float blur, const String& color, float alpha);
+    void setShadow(float width, float height, float blur, float grayLevel, float alpha);
+    void setShadow(float width, float height, float blur, float r, float g, float b, float a);
+    void setShadow(float width, float height, float blur, float c, float m, float y, float k, float a);
+
+    void clearShadow();
+
+    void drawImage(HTMLImageElement*, float x, float y, ExceptionCode&);
+    void drawImage(HTMLImageElement*, float x, float y, float width, float height, ExceptionCode&);
+    void drawImage(HTMLImageElement*, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, ExceptionCode&);
+    void drawImage(HTMLImageElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&);
+    void drawImage(HTMLCanvasElement*, float x, float y, ExceptionCode&);
+    void drawImage(HTMLCanvasElement*, float x, float y, float width, float height, ExceptionCode&);
+    void drawImage(HTMLCanvasElement*, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, ExceptionCode&);
+    void drawImage(HTMLCanvasElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&);
+    void drawImage(HTMLImageElement*, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator&, const BlendMode&, ExceptionCode&);
+    void drawImage(HTMLVideoElement*, float x, float y, ExceptionCode&);
+    void drawImage(HTMLVideoElement*, float x, float y, float width, float height, ExceptionCode&);
+    void drawImage(HTMLVideoElement*, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, ExceptionCode&);
+    void drawImage(HTMLVideoElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&);
+
+    void drawImageFromRect(HTMLImageElement*, float sx = 0, float sy = 0, float sw = 0, float sh = 0,
+                           float dx = 0, float dy = 0, float dw = 0, float dh = 0, const String& compositeOperation = emptyString());
+
+    void setAlpha(float);
+
+    void setCompositeOperation(const String&);
+
+    PassRefPtr<CanvasGradient> createLinearGradient(float x0, float y0, float x1, float y1, ExceptionCode&);
+    PassRefPtr<CanvasGradient> createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode&);
+    PassRefPtr<CanvasPattern> createPattern(HTMLImageElement*, const String& repetitionType, ExceptionCode&);
+    PassRefPtr<CanvasPattern> createPattern(HTMLCanvasElement*, const String& repetitionType, ExceptionCode&);
+
+    PassRefPtr<ImageData> createImageData(PassRefPtr<ImageData>, ExceptionCode&) const;
+    PassRefPtr<ImageData> createImageData(float width, float height, ExceptionCode&) const;
+    PassRefPtr<ImageData> getImageData(float sx, float sy, float sw, float sh, ExceptionCode&) const;
+    PassRefPtr<ImageData> webkitGetImageDataHD(float sx, float sy, float sw, float sh, ExceptionCode&) const;
+    void putImageData(ImageData*, float dx, float dy, ExceptionCode&);
+    void putImageData(ImageData*, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight, ExceptionCode&);
+    void webkitPutImageDataHD(ImageData*, float dx, float dy, ExceptionCode&);
+    void webkitPutImageDataHD(ImageData*, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight, ExceptionCode&);
+
+    float webkitBackingStorePixelRatio() const { return canvas()->deviceScaleFactor(); }
+
+    void reset();
+
+    String font() const;
+    void setFont(const String&);
+
+    String textAlign() const;
+    void setTextAlign(const String&);
+
+    String textBaseline() const;
+    void setTextBaseline(const String&);
+
+    void fillText(const String& text, float x, float y);
+    void fillText(const String& text, float x, float y, float maxWidth);
+    void strokeText(const String& text, float x, float y);
+    void strokeText(const String& text, float x, float y, float maxWidth);
+    PassRefPtr<TextMetrics> measureText(const String& text);
+
+    LineCap getLineCap() const { return state().m_lineCap; }
+    LineJoin getLineJoin() const { return state().m_lineJoin; }
+
+    bool webkitImageSmoothingEnabled() const;
+    void setWebkitImageSmoothingEnabled(bool);
+
+    PassRefPtr<Canvas2DContextAttributes> getContextAttributes() const;
+
+private:
+    struct State : FontSelectorClient {
+        State();
+        virtual ~State();
+
+        State(const State&);
+        State& operator=(const State&);
+
+        virtual void fontsNeedUpdate(FontSelector*) OVERRIDE;
+
+        String m_unparsedStrokeColor;
+        String m_unparsedFillColor;
+        RefPtr<CanvasStyle> m_strokeStyle;
+        RefPtr<CanvasStyle> m_fillStyle;
+        float m_lineWidth;
+        LineCap m_lineCap;
+        LineJoin m_lineJoin;
+        float m_miterLimit;
+        FloatSize m_shadowOffset;
+        float m_shadowBlur;
+        RGBA32 m_shadowColor;
+        float m_globalAlpha;
+        CompositeOperator m_globalComposite;
+        BlendMode m_globalBlend;
+        AffineTransform m_transform;
+        bool m_invertibleCTM;
+        Vector<float> m_lineDash;
+        float m_lineDashOffset;
+        bool m_imageSmoothingEnabled;
+
+        // Text state.
+        TextAlign m_textAlign;
+        TextBaseline m_textBaseline;
+
+        String m_unparsedFont;
+        Font m_font;
+        bool m_realizedFont;
+    };
+
+    enum CanvasDidDrawOption {
+        CanvasDidDrawApplyNone = 0,
+        CanvasDidDrawApplyTransform = 1,
+        CanvasDidDrawApplyShadow = 1 << 1,
+        CanvasDidDrawApplyClip = 1 << 2,
+        CanvasDidDrawApplyAll = 0xffffffff
+    };
+
+    CanvasRenderingContext2D(HTMLCanvasElement*, const Canvas2DContextAttributes* attrs, bool usesCSSCompatibilityParseMode);
+
+    State& modifiableState() { ASSERT(!m_unrealizedSaveCount); return m_stateStack.last(); }
+    const State& state() const { return m_stateStack.last(); }
+
+    void applyLineDash() const;
+    void setShadow(const FloatSize& offset, float blur, RGBA32 color);
+    void applyShadow();
+    bool shouldDrawShadows() const;
+
+    void didDraw(const FloatRect&, unsigned options = CanvasDidDrawApplyAll);
+    void didDrawEntireCanvas();
+
+    GraphicsContext* drawingContext() const;
+
+    void unwindStateStack();
+    void realizeSaves()
+    {
+        if (m_unrealizedSaveCount)
+            realizeSavesLoop();
+    }
+    void realizeSavesLoop();
+
+    void applyStrokePattern();
+    void applyFillPattern();
+
+    void drawTextInternal(const String& text, float x, float y, bool fill, float maxWidth = 0, bool useMaxWidth = false);
+
+    const Font& accessFont();
+
+    void clearCanvas();
+    Path transformAreaToDevice(const Path&) const;
+    Path transformAreaToDevice(const FloatRect&) const;
+    bool rectContainsCanvas(const FloatRect&) const;
+
+    template<class T> IntRect calculateCompositingBufferRect(const T&, IntSize*);
+    PassOwnPtr<ImageBuffer> createCompositingBuffer(const IntRect&);
+    void compositeBuffer(ImageBuffer*, const IntRect&, CompositeOperator);
+
+    void inflateStrokeRect(FloatRect&) const;
+
+    template<class T> void fullCanvasCompositedFill(const T&);
+    template<class T> void fullCanvasCompositedDrawImage(T*, ColorSpace, const FloatRect&, const FloatRect&, CompositeOperator);
+
+    PassRefPtr<ImageData> getImageData(ImageBuffer::CoordinateSystem, float sx, float sy, float sw, float sh, ExceptionCode&) const;
+    void putImageData(ImageData*, ImageBuffer::CoordinateSystem, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight, ExceptionCode&);
+
+    virtual bool is2d() const OVERRIDE { return true; }
+    virtual bool isAccelerated() const OVERRIDE;
+    virtual bool hasAlpha() const OVERRIDE { return m_hasAlpha; }
+
+    virtual bool isTransformInvertible() const { return state().m_invertibleCTM; }
+
+    virtual PlatformLayer* platformLayer() const OVERRIDE;
+
+    Vector<State, 1> m_stateStack;
+    unsigned m_unrealizedSaveCount;
+    bool m_usesCSSCompatibilityParseMode;
+    bool m_hasAlpha;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/canvas/CanvasRenderingContext2D.idl b/Source/core/html/canvas/CanvasRenderingContext2D.idl
new file mode 100644
index 0000000..98df7fa
--- /dev/null
+++ b/Source/core/html/canvas/CanvasRenderingContext2D.idl
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+enum CanvasWindingRule { "nonzero", "evenodd" };
+
+interface CanvasRenderingContext2D : CanvasRenderingContext {
+
+    void save();
+    void restore();
+
+    void scale([Default=Undefined] optional float sx,
+               [Default=Undefined] optional float sy);
+    void rotate([Default=Undefined] optional float angle);
+    void translate([Default=Undefined] optional float tx,
+                   [Default=Undefined] optional float ty);
+    void transform([Default=Undefined] optional float m11,
+                   [Default=Undefined] optional float m12,
+                   [Default=Undefined] optional float m21,
+                   [Default=Undefined] optional float m22,
+                   [Default=Undefined] optional float dx,
+                   [Default=Undefined] optional float dy);
+    void setTransform([Default=Undefined] optional float m11,
+                      [Default=Undefined] optional float m12,
+                      [Default=Undefined] optional float m21,
+                      [Default=Undefined] optional float m22,
+                      [Default=Undefined] optional float dx,
+                      [Default=Undefined] optional float dy);
+
+    attribute float globalAlpha;
+    [TreatNullAs=NullString] attribute DOMString globalCompositeOperation;
+
+    [RaisesException] CanvasGradient createLinearGradient([Default=Undefined] optional float x0,
+                                        [Default=Undefined] optional float y0,
+                                        [Default=Undefined] optional float x1,
+                                        [Default=Undefined] optional float y1);
+    [RaisesException] CanvasGradient createRadialGradient([Default=Undefined] optional float x0,
+                                        [Default=Undefined] optional float y0,
+                                        [Default=Undefined] optional float r0,
+                                        [Default=Undefined] optional float x1,
+                                        [Default=Undefined] optional float y1,
+                                        [Default=Undefined] optional float r1);
+
+    attribute float lineWidth;
+    [TreatNullAs=NullString] attribute DOMString lineCap;
+    [TreatNullAs=NullString] attribute DOMString lineJoin;
+    attribute float miterLimit;
+
+    attribute float shadowOffsetX;
+    attribute float shadowOffsetY;
+    attribute float shadowBlur;
+    [TreatNullAs=NullString] attribute DOMString shadowColor;
+
+    void setLineDash(sequence<float> dash);
+    sequence<float> getLineDash();
+    attribute float lineDashOffset;
+
+    // FIXME: These attributes should be implemented.
+    // [Custom] attribute Array webkitLineDash;
+    // attribute float webkitLineDashOffset;
+
+    void clearRect([Default=Undefined] optional float x,
+                   [Default=Undefined] optional float y,
+                   [Default=Undefined] optional float width,
+                   [Default=Undefined] optional float height);
+    void fillRect([Default=Undefined] optional float x,
+                  [Default=Undefined] optional float y,
+                  [Default=Undefined] optional float width,
+                  [Default=Undefined] optional float height);
+
+    void beginPath();
+
+    attribute DOMPath currentPath;
+
+    // FIXME: These methods should be shared with CanvasRenderingContext2D in the CanvasPathMethods interface.
+    void closePath();
+    void moveTo([Default=Undefined] optional float x,
+                [Default=Undefined] optional float y);
+    void lineTo([Default=Undefined] optional float x,
+                [Default=Undefined] optional float y);
+    void quadraticCurveTo([Default=Undefined] optional float cpx,
+                          [Default=Undefined] optional float cpy,
+                          [Default=Undefined] optional float x,
+                          [Default=Undefined] optional float y);
+    void bezierCurveTo([Default=Undefined] optional float cp1x,
+                       [Default=Undefined] optional float cp1y,
+                       [Default=Undefined] optional float cp2x,
+                       [Default=Undefined] optional float cp2y,
+                       [Default=Undefined] optional float x,
+                       [Default=Undefined] optional float y);
+    [RaisesException] void arcTo([Default=Undefined] optional float x1,
+               [Default=Undefined] optional float y1,
+               [Default=Undefined] optional float x2,
+               [Default=Undefined] optional float y2,
+               [Default=Undefined] optional float radius);
+    void rect([Default=Undefined] optional float x,
+              [Default=Undefined] optional float y,
+              [Default=Undefined] optional float width,
+              [Default=Undefined] optional float height);
+    [RaisesException] void arc([Default=Undefined] optional float x,
+             [Default=Undefined] optional float y,
+             [Default=Undefined] optional float radius,
+             [Default=Undefined] optional float startAngle,
+             [Default=Undefined] optional float endAngle,
+             [Default=Undefined] optional boolean anticlockwise);
+
+    void fill(optional CanvasWindingRule winding);
+    void stroke();
+    void clip(optional CanvasWindingRule winding);
+    boolean isPointInPath([Default=Undefined] optional float x,
+                          [Default=Undefined] optional float y,
+                          optional CanvasWindingRule winding);
+    boolean isPointInStroke([Default=Undefined] optional float x,
+                            [Default=Undefined] optional float y);
+
+    // text
+    attribute DOMString font;
+    attribute DOMString textAlign;
+    attribute DOMString textBaseline;
+
+    TextMetrics measureText([Default=Undefined] optional DOMString text);
+
+    // other
+
+    void setAlpha([Default=Undefined] optional float alpha);
+    void setCompositeOperation([Default=Undefined] optional DOMString compositeOperation);
+
+    void setLineWidth([Default=Undefined] optional float width);
+    void setLineCap([Default=Undefined] optional DOMString cap);
+    void setLineJoin([Default=Undefined] optional DOMString join);
+    void setMiterLimit([Default=Undefined] optional float limit);
+
+    void clearShadow();
+
+    void fillText(DOMString text, float x, float y, optional float maxWidth);
+    void strokeText(DOMString text, float x, float y, optional float maxWidth);
+
+    void setStrokeColor([StrictTypeChecking] DOMString color, optional float alpha);
+    void setStrokeColor(float grayLevel, optional float alpha);
+    void setStrokeColor(float r, float g, float b, float a);
+    void setStrokeColor(float c, float m, float y, float k, float a);
+
+    void setFillColor([StrictTypeChecking] DOMString color, optional float alpha);
+    void setFillColor(float grayLevel, optional float alpha);
+    void setFillColor(float r, float g, float b, float a);
+    void setFillColor(float c, float m, float y, float k, float a);
+
+    void strokeRect([Default=Undefined] optional float x,
+                    [Default=Undefined] optional float y,
+                    [Default=Undefined] optional float width,
+                    [Default=Undefined] optional float height,
+                    optional float lineWidth);
+
+    [RaisesException] void drawImage(HTMLImageElement? image, float x, float y);
+    [RaisesException] void drawImage(HTMLImageElement? image, float x, float y, float width, float height);
+    [RaisesException] void drawImage(HTMLImageElement? image, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh);
+    [RaisesException] void drawImage(HTMLCanvasElement? canvas, float x, float y);
+    [RaisesException] void drawImage(HTMLCanvasElement? canvas, float x, float y, float width, float height);
+    [RaisesException] void drawImage(HTMLCanvasElement? canvas, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh);
+    [RaisesException] void drawImage(HTMLVideoElement? video, float x, float y);
+    [RaisesException] void drawImage(HTMLVideoElement? video, float x, float y, float width, float height);
+    [RaisesException] void drawImage(HTMLVideoElement? video, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh);
+
+    void drawImageFromRect(HTMLImageElement image,
+                           optional float sx, optional float sy, optional float sw, optional float sh,
+                           optional float dx, optional float dy, optional float dw, optional float dh,
+                           optional DOMString compositeOperation);
+
+    void setShadow(float width, float height, float blur, [StrictTypeChecking] optional DOMString color, optional float alpha);
+    void setShadow(float width, float height, float blur, float grayLevel, optional float alpha);
+    void setShadow(float width, float height, float blur, float r, float g, float b, float a);
+    void setShadow(float width, float height, float blur, float c, float m, float y, float k, float a);
+
+    [RaisesException] void putImageData(ImageData? imagedata, float dx, float dy);
+    [RaisesException] void putImageData(ImageData? imagedata, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight);
+
+    [RaisesException] void webkitPutImageDataHD(ImageData? imagedata, float dx, float dy);
+    [RaisesException] void webkitPutImageDataHD(ImageData? imagedata, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight);
+
+    [RaisesException] CanvasPattern createPattern(HTMLCanvasElement? canvas, [TreatNullAs=NullString] DOMString repetitionType);
+    [RaisesException] CanvasPattern createPattern(HTMLImageElement? image, [TreatNullAs=NullString] DOMString repetitionType);
+    [RaisesException] ImageData createImageData(ImageData? imagedata);
+    [RaisesException] ImageData createImageData(float sw, float sh);
+
+    [Custom] attribute custom strokeStyle;
+    [Custom] attribute custom fillStyle;
+
+    // pixel manipulation
+    [RaisesException] ImageData getImageData([Default=Undefined] optional float sx, [Default=Undefined] optional float sy,
+                           [Default=Undefined] optional float sw, [Default=Undefined] optional float sh);
+
+    [RaisesException] ImageData webkitGetImageDataHD([Default=Undefined] optional float sx, [Default=Undefined] optional float sy,
+                                   [Default=Undefined] optional float sw, [Default=Undefined] optional float sh);
+
+    readonly attribute float webkitBackingStorePixelRatio;
+
+    attribute boolean webkitImageSmoothingEnabled;
+
+    [EnabledAtRuntime=experimentalCanvasFeatures] Canvas2DContextAttributes getContextAttributes();
+};
+
diff --git a/Source/core/html/canvas/CanvasStyle.cpp b/Source/core/html/canvas/CanvasStyle.cpp
new file mode 100644
index 0000000..b4c1c95
--- /dev/null
+++ b/Source/core/html/canvas/CanvasStyle.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+#include "core/html/canvas/CanvasStyle.h"
+
+#include "CSSPropertyNames.h"
+#include "core/css/CSSParser.h"
+#include "core/css/StylePropertySet.h"
+#include "core/html/HTMLCanvasElement.h"
+#include "core/html/canvas/CanvasGradient.h"
+#include "core/html/canvas/CanvasPattern.h"
+#include "core/platform/graphics/GraphicsContext.h"
+#include <wtf/Assertions.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+enum ColorParseResult { ParsedRGBA, ParsedCurrentColor, ParsedSystemColor, ParseFailed };
+
+static ColorParseResult parseColor(RGBA32& parsedColor, const String& colorString, Document* document = 0)
+{
+    if (equalIgnoringCase(colorString, "currentcolor"))
+        return ParsedCurrentColor;
+    if (CSSParser::parseColor(parsedColor, colorString))
+        return ParsedRGBA;
+    if (CSSParser::parseSystemColor(parsedColor, colorString, document))
+        return ParsedSystemColor;
+    return ParseFailed;
+}
+
+RGBA32 currentColor(HTMLCanvasElement* canvas)
+{
+    if (!canvas || !canvas->inDocument() || !canvas->inlineStyle())
+        return Color::black;
+    RGBA32 rgba = Color::black;
+    CSSParser::parseColor(rgba, canvas->inlineStyle()->getPropertyValue(CSSPropertyColor));
+    return rgba;
+}
+
+bool parseColorOrCurrentColor(RGBA32& parsedColor, const String& colorString, HTMLCanvasElement* canvas)
+{
+    ColorParseResult parseResult = parseColor(parsedColor, colorString, canvas ? canvas->document() : 0);
+    switch (parseResult) {
+    case ParsedRGBA:
+    case ParsedSystemColor:
+        return true;
+    case ParsedCurrentColor:
+        parsedColor = currentColor(canvas);
+        return true;
+    case ParseFailed:
+        return false;
+    default:
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+}
+
+CanvasStyle::CanvasStyle(Type type, float overrideAlpha)
+    : m_type(type)
+    , m_overrideAlpha(overrideAlpha)
+{
+}
+
+CanvasStyle::CanvasStyle(RGBA32 rgba)
+    : m_type(RGBA)
+    , m_rgba(rgba)
+{
+}
+
+CanvasStyle::CanvasStyle(float grayLevel, float alpha)
+    : m_type(RGBA)
+    , m_rgba(makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha))
+{
+}
+
+CanvasStyle::CanvasStyle(float r, float g, float b, float a)
+    : m_type(RGBA)
+    , m_rgba(makeRGBA32FromFloats(r, g, b, a))
+{
+}
+
+CanvasStyle::CanvasStyle(float c, float m, float y, float k, float a)
+    : m_type(CMYKA)
+    , m_rgba(makeRGBAFromCMYKA(c, m, y, k, a))
+    , m_cmyka(c, m, y, k, a)
+{
+}
+
+CanvasStyle::CanvasStyle(PassRefPtr<CanvasGradient> gradient)
+    : m_type(Gradient)
+    , m_gradient(gradient)
+{
+}
+
+CanvasStyle::CanvasStyle(PassRefPtr<CanvasPattern> pattern)
+    : m_type(ImagePattern)
+    , m_pattern(pattern)
+{
+}
+
+PassRefPtr<CanvasStyle> CanvasStyle::createFromString(const String& color, Document* document)
+{
+    RGBA32 rgba;
+    ColorParseResult parseResult = parseColor(rgba, color, document);
+    switch (parseResult) {
+    case ParsedRGBA:
+    case ParsedSystemColor:
+        return adoptRef(new CanvasStyle(rgba));
+    case ParsedCurrentColor:
+        return adoptRef(new CanvasStyle(CurrentColor));
+    case ParseFailed:
+        return 0;
+    default:
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
+PassRefPtr<CanvasStyle> CanvasStyle::createFromStringWithOverrideAlpha(const String& color, float alpha)
+{
+    RGBA32 rgba;
+    ColorParseResult parseResult = parseColor(rgba, color);
+    switch (parseResult) {
+    case ParsedRGBA:
+        return adoptRef(new CanvasStyle(colorWithOverrideAlpha(rgba, alpha)));
+    case ParsedCurrentColor:
+        return adoptRef(new CanvasStyle(CurrentColorWithOverrideAlpha, alpha));
+    case ParseFailed:
+        return 0;
+    default:
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
+PassRefPtr<CanvasStyle> CanvasStyle::createFromGradient(PassRefPtr<CanvasGradient> gradient)
+{
+    if (!gradient)
+        return 0;
+    return adoptRef(new CanvasStyle(gradient));
+}
+PassRefPtr<CanvasStyle> CanvasStyle::createFromPattern(PassRefPtr<CanvasPattern> pattern)
+{
+    if (!pattern)
+        return 0;
+    return adoptRef(new CanvasStyle(pattern));
+}
+
+bool CanvasStyle::isEquivalentColor(const CanvasStyle& other) const
+{
+    if (m_type != other.m_type)
+        return false;
+
+    switch (m_type) {
+    case RGBA:
+        return m_rgba == other.m_rgba;
+    case CMYKA:
+        return m_cmyka.c == other.m_cmyka.c
+            && m_cmyka.m == other.m_cmyka.m
+            && m_cmyka.y == other.m_cmyka.y
+            && m_cmyka.k == other.m_cmyka.k
+            && m_cmyka.a == other.m_cmyka.a;
+    case Gradient:
+    case ImagePattern:
+    case CurrentColor:
+    case CurrentColorWithOverrideAlpha:
+        return false;
+    }
+
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+bool CanvasStyle::isEquivalentRGBA(float r, float g, float b, float a) const
+{
+    if (m_type != RGBA)
+        return false;
+
+    return m_rgba == makeRGBA32FromFloats(r, g, b, a);
+}
+
+bool CanvasStyle::isEquivalentCMYKA(float c, float m, float y, float k, float a) const
+{
+    if (m_type != CMYKA)
+        return false;
+
+    return c == m_cmyka.c
+        && m == m_cmyka.m
+        && y == m_cmyka.y
+        && k == m_cmyka.k
+        && a == m_cmyka.a;
+}
+
+void CanvasStyle::applyStrokeColor(GraphicsContext* context)
+{
+    if (!context)
+        return;
+    switch (m_type) {
+    case RGBA:
+        context->setStrokeColor(m_rgba, ColorSpaceDeviceRGB);
+        break;
+    case CMYKA: {
+        // FIXME: Do this through platform-independent GraphicsContext API.
+        // We'll need a fancier Color abstraction to support CMYKA correctly
+        context->setStrokeColor(m_rgba, ColorSpaceDeviceRGB);
+        break;
+    }
+    case Gradient:
+        context->setStrokeGradient(canvasGradient()->gradient());
+        break;
+    case ImagePattern:
+        context->setStrokePattern(canvasPattern()->pattern());
+        break;
+    case CurrentColor:
+    case CurrentColorWithOverrideAlpha:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+void CanvasStyle::applyFillColor(GraphicsContext* context)
+{
+    if (!context)
+        return;
+    switch (m_type) {
+    case RGBA:
+        context->setFillColor(m_rgba, ColorSpaceDeviceRGB);
+        break;
+    case CMYKA: {
+        // FIXME: Do this through platform-independent GraphicsContext API.
+        // We'll need a fancier Color abstraction to support CMYKA correctly
+        context->setFillColor(m_rgba, ColorSpaceDeviceRGB);
+        break;
+    }
+    case Gradient:
+        context->setFillGradient(canvasGradient()->gradient());
+        break;
+    case ImagePattern:
+        context->setFillPattern(canvasPattern()->pattern());
+        break;
+    case CurrentColor:
+    case CurrentColorWithOverrideAlpha:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+}
diff --git a/Source/core/html/canvas/CanvasStyle.h b/Source/core/html/canvas/CanvasStyle.h
new file mode 100644
index 0000000..fad215b
--- /dev/null
+++ b/Source/core/html/canvas/CanvasStyle.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 COMPUTER, 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 COMPUTER, 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 CanvasStyle_h
+#define CanvasStyle_h
+
+#include "core/platform/graphics/Color.h"
+#include <wtf/Assertions.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+    class CanvasGradient;
+    class CanvasPattern;
+    class Document;
+    class GraphicsContext;
+    class HTMLCanvasElement;
+
+    class CanvasStyle : public RefCounted<CanvasStyle> {
+    public:
+        static PassRefPtr<CanvasStyle> createFromRGBA(RGBA32 rgba) { return adoptRef(new CanvasStyle(rgba)); }
+        static PassRefPtr<CanvasStyle> createFromString(const String& color, Document* = 0);
+        static PassRefPtr<CanvasStyle> createFromStringWithOverrideAlpha(const String& color, float alpha);
+        static PassRefPtr<CanvasStyle> createFromGrayLevelWithAlpha(float grayLevel, float alpha) { return adoptRef(new CanvasStyle(grayLevel, alpha)); }
+        static PassRefPtr<CanvasStyle> createFromRGBAChannels(float r, float g, float b, float a) { return adoptRef(new CanvasStyle(r, g, b, a)); }
+        static PassRefPtr<CanvasStyle> createFromCMYKAChannels(float c, float m, float y, float k, float a) { return adoptRef(new CanvasStyle(c, m, y, k, a)); }
+        static PassRefPtr<CanvasStyle> createFromGradient(PassRefPtr<CanvasGradient>);
+        static PassRefPtr<CanvasStyle> createFromPattern(PassRefPtr<CanvasPattern>);
+
+        bool isCurrentColor() const { return m_type == CurrentColor || m_type == CurrentColorWithOverrideAlpha; }
+        bool hasOverrideAlpha() const { return m_type == CurrentColorWithOverrideAlpha; }
+        float overrideAlpha() const { ASSERT(m_type == CurrentColorWithOverrideAlpha); return m_overrideAlpha; }
+
+        String color() const { ASSERT(m_type == RGBA || m_type == CMYKA); return Color(m_rgba).serialized(); }
+        CanvasGradient* canvasGradient() const { return m_gradient.get(); }
+        CanvasPattern* canvasPattern() const { return m_pattern.get(); }
+
+        void applyFillColor(GraphicsContext*);
+        void applyStrokeColor(GraphicsContext*);
+
+        bool isEquivalentColor(const CanvasStyle&) const;
+        bool isEquivalentRGBA(float r, float g, float b, float a) const;
+        bool isEquivalentCMYKA(float c, float m, float y, float k, float a) const;
+
+    private:
+        enum Type { RGBA, CMYKA, Gradient, ImagePattern, CurrentColor, CurrentColorWithOverrideAlpha };
+
+        CanvasStyle(Type, float overrideAlpha = 0);
+        CanvasStyle(RGBA32 rgba);
+        CanvasStyle(float grayLevel, float alpha);
+        CanvasStyle(float r, float g, float b, float a);
+        CanvasStyle(float c, float m, float y, float k, float a);
+        CanvasStyle(PassRefPtr<CanvasGradient>);
+        CanvasStyle(PassRefPtr<CanvasPattern>);
+
+        Type m_type;
+
+        union {
+            RGBA32 m_rgba;
+            float m_overrideAlpha;
+        };
+
+        RefPtr<CanvasGradient> m_gradient;
+        RefPtr<CanvasPattern> m_pattern;
+
+        struct CMYKAValues {
+            CMYKAValues() : c(0), m(0), y(0), k(0), a(0) { }
+            CMYKAValues(float cyan, float magenta, float yellow, float black, float alpha) : c(cyan), m(magenta), y(yellow), k(black), a(alpha) { }
+            float c;
+            float m;
+            float y;
+            float k;
+            float a;
+        } m_cmyka;
+    };
+
+    RGBA32 currentColor(HTMLCanvasElement*);
+    bool parseColorOrCurrentColor(RGBA32& parsedColor, const String& colorString, HTMLCanvasElement*);
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/canvas/CheckedInt.h b/Source/core/html/canvas/CheckedInt.h
new file mode 100644
index 0000000..542d9a8
--- /dev/null
+++ b/Source/core/html/canvas/CheckedInt.h
@@ -0,0 +1,819 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Provides checked integers, detecting integer overflow and divide-by-0. */
+
+// Necessary modifications are made to the original CheckedInt.h file when
+// incorporating it into WebKit:
+// 1) Comment out #define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
+// 2) Comment out #include "mozilla/StandardInteger.h"
+// 3) Define MOZ_DELETE
+// 4) Change namespace mozilla to namespace WebCore
+
+#ifndef mozilla_CheckedInt_h_
+#define mozilla_CheckedInt_h_
+
+/*
+ * Build options. Comment out these #defines to disable the corresponding
+ * optional feature. Disabling features may be useful for code using
+ * CheckedInt outside of Mozilla (e.g. WebKit)
+ */
+
+// Enable usage of MOZ_STATIC_ASSERT to check for unsupported types.
+// If disabled, static asserts are replaced by regular assert().
+// #define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
+
+/*
+ * End of build options
+ */
+
+#ifdef MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
+#  include "mozilla/Assertions.h"
+#else
+#  ifndef MOZ_STATIC_ASSERT
+#    include <cassert>
+#    define MOZ_STATIC_ASSERT(cond, reason) assert((cond) && reason)
+#    define MOZ_ASSERT(cond, reason) assert((cond) && reason)
+#  endif
+#endif
+
+// #include "mozilla/StandardInteger.h"
+
+#ifndef MOZ_DELETE
+#define MOZ_DELETE
+#endif
+
+#include <climits>
+#include <cstddef>
+
+namespace WebCore {
+
+namespace detail {
+
+/*
+ * Step 1: manually record supported types
+ *
+ * What's nontrivial here is that there are different families of integer
+ * types: basic integer types and stdint types. It is merrily undefined which
+ * types from one family may be just typedefs for a type from another family.
+ *
+ * For example, on GCC 4.6, aside from the basic integer types, the only other
+ * type that isn't just a typedef for some of them, is int8_t.
+ */
+
+struct UnsupportedType {};
+
+template<typename IntegerType>
+struct IsSupportedPass2
+{
+    static const bool value = false;
+};
+
+template<typename IntegerType>
+struct IsSupported
+{
+    static const bool value = IsSupportedPass2<IntegerType>::value;
+};
+
+template<>
+struct IsSupported<int8_t>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<uint8_t>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<int16_t>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<uint16_t>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<int32_t>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<uint32_t>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<int64_t>
+{ static const bool value = true; };
+
+template<>
+struct IsSupported<uint64_t>
+{ static const bool value = true; };
+
+
+template<>
+struct IsSupportedPass2<char>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<unsigned char>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<short>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<unsigned short>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<int>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<unsigned int>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<long>
+{ static const bool value = true; };
+
+template<>
+struct IsSupportedPass2<unsigned long>
+{ static const bool value = true; };
+
+
+/*
+ * Step 2: some integer-traits kind of stuff.
+ */
+
+template<size_t Size, bool Signedness>
+struct StdintTypeForSizeAndSignedness
+{};
+
+template<>
+struct StdintTypeForSizeAndSignedness<1, true>
+{ typedef int8_t   Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<1, false>
+{ typedef uint8_t  Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<2, true>
+{ typedef int16_t  Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<2, false>
+{ typedef uint16_t Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<4, true>
+{ typedef int32_t  Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<4, false>
+{ typedef uint32_t Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<8, true>
+{ typedef int64_t  Type; };
+
+template<>
+struct StdintTypeForSizeAndSignedness<8, false>
+{ typedef uint64_t Type; };
+
+template<typename IntegerType>
+struct UnsignedType
+{
+    typedef typename StdintTypeForSizeAndSignedness<sizeof(IntegerType),
+                                                    false>::Type Type;
+};
+
+template<typename IntegerType>
+struct IsSigned
+{
+    static const bool value = IntegerType(-1) <= IntegerType(0);
+};
+
+template<typename IntegerType, size_t Size = sizeof(IntegerType)>
+struct TwiceBiggerType
+{
+    typedef typename StdintTypeForSizeAndSignedness<
+                       sizeof(IntegerType) * 2,
+                       IsSigned<IntegerType>::value
+                     >::Type Type;
+};
+
+template<typename IntegerType>
+struct TwiceBiggerType<IntegerType, 8>
+{
+    typedef UnsupportedType Type;
+};
+
+template<typename IntegerType>
+struct PositionOfSignBit
+{
+    static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1;
+};
+
+template<typename IntegerType>
+struct MinValue
+{
+  private:
+    typedef typename UnsignedType<IntegerType>::Type UnsignedIntegerType;
+    static const size_t PosOfSignBit = PositionOfSignBit<IntegerType>::value;
+
+  public:
+    // Bitwise ops may return a larger type, that's why we cast explicitly.
+    // In C++, left bit shifts on signed values is undefined by the standard
+    // unless the shifted value is representable.
+    // Notice that signed-to-unsigned conversions are always well-defined in
+    // the standard as the value congruent to 2**n, as expected. By contrast,
+    // unsigned-to-signed is only well-defined if the value is representable.
+    static const IntegerType value =
+        IsSigned<IntegerType>::value
+        ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit)
+        : IntegerType(0);
+};
+
+template<typename IntegerType>
+struct MaxValue
+{
+    // Tricksy, but covered by the unit test.
+    // Relies heavily on the type of MinValue<IntegerType>::value
+    // being IntegerType.
+    static const IntegerType value = ~MinValue<IntegerType>::value;
+};
+
+/*
+ * Step 3: Implement the actual validity checks.
+ *
+ * Ideas taken from IntegerLib, code different.
+ */
+
+template<typename T>
+inline bool
+HasSignBit(T x)
+{
+  // In C++, right bit shifts on negative values is undefined by the standard.
+  // Notice that signed-to-unsigned conversions are always well-defined in the
+  // standard, as the value congruent modulo 2**n as expected. By contrast,
+  // unsigned-to-signed is only well-defined if the value is representable.
+  return bool(typename UnsignedType<T>::Type(x)
+                >> PositionOfSignBit<T>::value);
+}
+
+// Bitwise ops may return a larger type, so it's good to use this inline
+// helper guaranteeing that the result is really of type T.
+template<typename T>
+inline T
+BinaryComplement(T x)
+{
+  return ~x;
+}
+
+template<typename T,
+         typename U,
+         bool IsTSigned = IsSigned<T>::value,
+         bool IsUSigned = IsSigned<U>::value>
+struct DoesRangeContainRange
+{
+};
+
+template<typename T, typename U, bool Signedness>
+struct DoesRangeContainRange<T, U, Signedness, Signedness>
+{
+    static const bool value = sizeof(T) >= sizeof(U);
+};
+
+template<typename T, typename U>
+struct DoesRangeContainRange<T, U, true, false>
+{
+    static const bool value = sizeof(T) > sizeof(U);
+};
+
+template<typename T, typename U>
+struct DoesRangeContainRange<T, U, false, true>
+{
+    static const bool value = false;
+};
+
+template<typename T,
+         typename U,
+         bool IsTSigned = IsSigned<T>::value,
+         bool IsUSigned = IsSigned<U>::value,
+         bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
+struct IsInRangeImpl {};
+
+template<typename T, typename U, bool IsTSigned, bool IsUSigned>
+struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
+{
+    static bool run(U)
+    {
+       return true;
+    }
+};
+
+template<typename T, typename U>
+struct IsInRangeImpl<T, U, true, true, false>
+{
+    static bool run(U x)
+    {
+      return x <= MaxValue<T>::value && x >= MinValue<T>::value;
+    }
+};
+
+template<typename T, typename U>
+struct IsInRangeImpl<T, U, false, false, false>
+{
+    static bool run(U x)
+    {
+      return x <= MaxValue<T>::value;
+    }
+};
+
+template<typename T, typename U>
+struct IsInRangeImpl<T, U, true, false, false>
+{
+    static bool run(U x)
+    {
+      return sizeof(T) > sizeof(U) || x <= U(MaxValue<T>::value);
+    }
+};
+
+template<typename T, typename U>
+struct IsInRangeImpl<T, U, false, true, false>
+{
+    static bool run(U x)
+    {
+      return sizeof(T) >= sizeof(U)
+             ? x >= 0
+             : x >= 0 && x <= U(MaxValue<T>::value);
+    }
+};
+
+template<typename T, typename U>
+inline bool
+IsInRange(U x)
+{
+  return IsInRangeImpl<T, U>::run(x);
+}
+
+template<typename T>
+inline bool
+IsAddValid(T x, T y)
+{
+  // Addition is valid if the sign of x+y is equal to either that of x or that
+  // of y. Since the value of x+y is undefined if we have a signed type, we
+  // compute it using the unsigned type of the same size.
+  // Beware! These bitwise operations can return a larger integer type,
+  // if T was a small type like int8_t, so we explicitly cast to T.
+
+  typename UnsignedType<T>::Type ux = x;
+  typename UnsignedType<T>::Type uy = y;
+  typename UnsignedType<T>::Type result = ux + uy;
+  return IsSigned<T>::value
+         ? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y))))
+         : BinaryComplement(x) >= y;
+}
+
+template<typename T>
+inline bool
+IsSubValid(T x, T y)
+{
+  // Subtraction is valid if either x and y have same sign, or x-y and x have
+  // same sign. Since the value of x-y is undefined if we have a signed type,
+  // we compute it using the unsigned type of the same size.
+  typename UnsignedType<T>::Type ux = x;
+  typename UnsignedType<T>::Type uy = y;
+  typename UnsignedType<T>::Type result = ux - uy;
+
+  return IsSigned<T>::value
+         ? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y))))
+         : x >= y;
+}
+
+template<typename T,
+         bool IsSigned = IsSigned<T>::value,
+         bool TwiceBiggerTypeIsSupported =
+           IsSupported<typename TwiceBiggerType<T>::Type>::value>
+struct IsMulValidImpl {};
+
+template<typename T, bool IsSigned>
+struct IsMulValidImpl<T, IsSigned, true>
+{
+    static bool run(T x, T y)
+    {
+      typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
+      TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y);
+      return IsInRange<T>(product);
+    }
+};
+
+template<typename T>
+struct IsMulValidImpl<T, true, false>
+{
+    static bool run(T x, T y)
+    {
+      const T max = MaxValue<T>::value;
+      const T min = MinValue<T>::value;
+
+      if (x == 0 || y == 0)
+        return true;
+
+      if (x > 0) {
+        return y > 0
+               ? x <= max / y
+               : y >= min / x;
+      }
+
+      // If we reach this point, we know that x < 0.
+      return y > 0
+             ? x >= min / y
+             : y >= max / x;
+    }
+};
+
+template<typename T>
+struct IsMulValidImpl<T, false, false>
+{
+    static bool run(T x, T y)
+    {
+      return y == 0 ||  x <= MaxValue<T>::value / y;
+    }
+};
+
+template<typename T>
+inline bool
+IsMulValid(T x, T y)
+{
+  return IsMulValidImpl<T>::run(x, y);
+}
+
+template<typename T>
+inline bool
+IsDivValid(T x, T y)
+{
+  // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max.
+  return y != 0 &&
+         !(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1));
+}
+
+// This is just to shut up msvc warnings about negating unsigned ints.
+template<typename T, bool IsSigned = IsSigned<T>::value>
+struct OppositeIfSignedImpl
+{
+    static T run(T x) { return -x; }
+};
+template<typename T>
+struct OppositeIfSignedImpl<T, false>
+{
+    static T run(T x) { return x; }
+};
+template<typename T>
+inline T
+OppositeIfSigned(T x)
+{
+  return OppositeIfSignedImpl<T>::run(x);
+}
+
+} // namespace detail
+
+
+/*
+ * Step 4: Now define the CheckedInt class.
+ */
+
+/**
+ * @class CheckedInt
+ * @brief Integer wrapper class checking for integer overflow and other errors
+ * @param T the integer type to wrap. Can be any type among the following:
+ *            - any basic integer type such as |int|
+ *            - any stdint type such as |int8_t|
+ *
+ * This class implements guarded integer arithmetic. Do a computation, check
+ * that isValid() returns true, you then have a guarantee that no problem, such
+ * as integer overflow, happened during this computation, and you can call
+ * value() to get the plain integer value.
+ *
+ * The arithmetic operators in this class are guaranteed not to raise a signal
+ * (e.g. in case of a division by zero).
+ *
+ * For example, suppose that you want to implement a function that computes
+ * (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by
+ * zero or integer overflow). You could code it as follows:
+   @code
+   bool computeXPlusYOverZ(int x, int y, int z, int *result)
+   {
+       CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z;
+       if (checkedResult.isValid()) {
+           *result = checkedResult.value();
+           return true;
+       } else {
+           return false;
+       }
+   }
+   @endcode
+ *
+ * Implicit conversion from plain integers to checked integers is allowed. The
+ * plain integer is checked to be in range before being casted to the
+ * destination type. This means that the following lines all compile, and the
+ * resulting CheckedInts are correctly detected as valid or invalid:
+ * @code
+   // 1 is of type int, is found to be in range for uint8_t, x is valid
+   CheckedInt<uint8_t> x(1);
+   // -1 is of type int, is found not to be in range for uint8_t, x is invalid
+   CheckedInt<uint8_t> x(-1);
+   // -1 is of type int, is found to be in range for int8_t, x is valid
+   CheckedInt<int8_t> x(-1);
+   // 1000 is of type int16_t, is found not to be in range for int8_t,
+   // x is invalid
+   CheckedInt<int8_t> x(int16_t(1000)); 
+   // 3123456789 is of type uint32_t, is found not to be in range for int32_t,
+   // x is invalid
+   CheckedInt<int32_t> x(uint32_t(3123456789));
+ * @endcode
+ * Implicit conversion from
+ * checked integers to plain integers is not allowed. As shown in the
+ * above example, to get the value of a checked integer as a normal integer,
+ * call value().
+ *
+ * Arithmetic operations between checked and plain integers is allowed; the
+ * result type is the type of the checked integer.
+ *
+ * Checked integers of different types cannot be used in the same arithmetic
+ * expression.
+ *
+ * There are convenience typedefs for all stdint types, of the following form
+ * (these are just 2 examples):
+   @code
+   typedef CheckedInt<int32_t> CheckedInt32;
+   typedef CheckedInt<uint16_t> CheckedUint16;
+   @endcode
+ */
+template<typename T>
+class CheckedInt
+{
+  protected:
+    T mValue;
+    bool mIsValid;
+
+    template<typename U>
+    CheckedInt(U value, bool isValid) : mValue(value), mIsValid(isValid)
+    {
+      MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
+                        "This type is not supported by CheckedInt");
+    }
+
+  public:
+    /**
+     * Constructs a checked integer with given @a value. The checked integer is
+     * initialized as valid or invalid depending on whether the @a value
+     * is in range.
+     *
+     * This constructor is not explicit. Instead, the type of its argument is a
+     * separate template parameter, ensuring that no conversion is performed
+     * before this constructor is actually called. As explained in the above
+     * documentation for class CheckedInt, this constructor checks that its
+     * argument is valid.
+     */
+    template<typename U>
+    CheckedInt(U value)
+      : mValue(T(value)),
+        mIsValid(detail::IsInRange<T>(value))
+    {
+      MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
+                        "This type is not supported by CheckedInt");
+    }
+
+    /** Constructs a valid checked integer with initial value 0 */
+    CheckedInt() : mValue(0), mIsValid(true)
+    {
+      MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
+                        "This type is not supported by CheckedInt");
+    }
+
+    /** @returns the actual value */
+    T value() const
+    {
+      MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
+      return mValue;
+    }
+
+    /**
+     * @returns true if the checked integer is valid, i.e. is not the result
+     * of an invalid operation or of an operation involving an invalid checked
+     * integer
+     */
+    bool isValid() const
+    {
+      return mIsValid;
+    }
+
+    template<typename U>
+    friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
+                                    const CheckedInt<U>& rhs);
+    template<typename U>
+    CheckedInt& operator +=(U rhs);
+    template<typename U>
+    friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
+                                    const CheckedInt<U> &rhs);
+    template<typename U>
+    CheckedInt& operator -=(U rhs);
+    template<typename U>
+    friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
+                                    const CheckedInt<U> &rhs);
+    template<typename U>
+    CheckedInt& operator *=(U rhs);
+    template<typename U>
+    friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
+                                    const CheckedInt<U> &rhs);
+    template<typename U>
+    CheckedInt& operator /=(U rhs);
+
+    CheckedInt operator -() const
+    {
+      // Circumvent msvc warning about - applied to unsigned int.
+      // if we're unsigned, the only valid case anyway is 0
+      // in which case - is a no-op.
+      T result = detail::OppositeIfSigned(mValue);
+      /* Help the compiler perform RVO (return value optimization). */
+      return CheckedInt(result,
+                        mIsValid && detail::IsSubValid(T(0),
+                                                       mValue));
+    }
+
+    /**
+     * @returns true if the left and right hand sides are valid
+     * and have the same value.
+     *
+     * Note that these semantics are the reason why we don't offer
+     * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
+     * but that would mean that whenever a or b is invalid, a!=b
+     * is always true, which would be very confusing.
+     *
+     * For similar reasons, operators <, >, <=, >= would be very tricky to
+     * specify, so we just avoid offering them.
+     *
+     * Notice that these == semantics are made more reasonable by these facts:
+     *  1. a==b implies equality at the raw data level
+     *     (the converse is false, as a==b is never true among invalids)
+     *  2. This is similar to the behavior of IEEE floats, where a==b
+     *     means that a and b have the same value *and* neither is NaN.
+     */
+    bool operator ==(const CheckedInt& other) const
+    {
+      return mIsValid && other.mIsValid && mValue == other.mValue;
+    }
+
+    /** prefix ++ */
+    CheckedInt& operator++()
+    {
+      *this += 1;
+      return *this;
+    }
+
+    /** postfix ++ */
+    CheckedInt operator++(int)
+    {
+      CheckedInt tmp = *this;
+      *this += 1;
+      return tmp;
+    }
+
+    /** prefix -- */
+    CheckedInt& operator--()
+    {
+      *this -= 1;
+      return *this;
+    }
+
+    /** postfix -- */
+    CheckedInt operator--(int)
+    {
+      CheckedInt tmp = *this;
+      *this -= 1;
+      return tmp;
+    }
+
+  private:
+    /**
+     * The !=, <, <=, >, >= operators are disabled:
+     * see the comment on operator==.
+     */
+    template<typename U>
+    bool operator !=(U other) const MOZ_DELETE;
+    template<typename U>
+    bool operator <(U other) const MOZ_DELETE;
+    template<typename U>
+    bool operator <=(U other) const MOZ_DELETE;
+    template<typename U>
+    bool operator >(U other) const MOZ_DELETE;
+    template<typename U>
+    bool operator >=(U other) const MOZ_DELETE;
+};
+
+#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP)                \
+template<typename T>                                                  \
+inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs,            \
+                                 const CheckedInt<T> &rhs)            \
+{                                                                     \
+  if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue))               \
+    return CheckedInt<T>(0, false);                                   \
+                                                                      \
+  return CheckedInt<T>(lhs.mValue OP rhs.mValue,                      \
+                       lhs.mIsValid && rhs.mIsValid);                 \
+}
+
+MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
+MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
+MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
+MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /)
+
+#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
+
+// Implement castToCheckedInt<T>(x), making sure that
+//  - it allows x to be either a CheckedInt<T> or any integer type
+//    that can be casted to T
+//  - if x is already a CheckedInt<T>, we just return a reference to it,
+//    instead of copying it (optimization)
+
+namespace detail {
+
+template<typename T, typename U>
+struct CastToCheckedIntImpl
+{
+    typedef CheckedInt<T> ReturnType;
+    static CheckedInt<T> run(U u) { return u; }
+};
+
+template<typename T>
+struct CastToCheckedIntImpl<T, CheckedInt<T> >
+{
+    typedef const CheckedInt<T>& ReturnType;
+    static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
+};
+
+} // namespace detail
+
+template<typename T, typename U>
+inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
+castToCheckedInt(U u)
+{
+  return detail::CastToCheckedIntImpl<T, U>::run(u);
+}
+
+#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP)  \
+template<typename T>                                              \
+template<typename U>                                              \
+CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs)         \
+{                                                                 \
+  *this = *this OP castToCheckedInt<T>(rhs);                      \
+  return *this;                                                   \
+}                                                                 \
+template<typename T, typename U>                                  \
+inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
+{                                                                 \
+  return lhs OP castToCheckedInt<T>(rhs);                         \
+}                                                                 \
+template<typename T, typename U>                                  \
+inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
+{                                                                 \
+  return castToCheckedInt<T>(lhs) OP rhs;                         \
+}
+
+MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
+MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
+MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
+MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
+
+#undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
+
+template<typename T, typename U>
+inline bool
+operator ==(const CheckedInt<T> &lhs, U rhs)
+{
+  return lhs == castToCheckedInt<T>(rhs);
+}
+
+template<typename T, typename U>
+inline bool
+operator ==(U  lhs, const CheckedInt<T> &rhs)
+{
+  return castToCheckedInt<T>(lhs) == rhs;
+}
+
+// Convenience typedefs.
+typedef CheckedInt<int8_t>   CheckedInt8;
+typedef CheckedInt<uint8_t>  CheckedUint8;
+typedef CheckedInt<int16_t>  CheckedInt16;
+typedef CheckedInt<uint16_t> CheckedUint16;
+typedef CheckedInt<int32_t>  CheckedInt32;
+typedef CheckedInt<uint32_t> CheckedUint32;
+typedef CheckedInt<int64_t>  CheckedInt64;
+typedef CheckedInt<uint64_t> CheckedUint64;
+
+} // namespace WebCore
+
+#endif /* mozilla_CheckedInt_h_ */
diff --git a/Source/core/html/canvas/DOMPath.h b/Source/core/html/canvas/DOMPath.h
new file mode 100644
index 0000000..386e8b2
--- /dev/null
+++ b/Source/core/html/canvas/DOMPath.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012, 2013 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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 DOMPath_h
+#define DOMPath_h
+
+#include "core/html/canvas/CanvasPathMethods.h"
+#if ENABLE(SVG)
+#include "core/svg/SVGPathUtilities.h"
+#endif
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class DOMPath : public RefCounted<DOMPath>, public CanvasPathMethods {
+    WTF_MAKE_NONCOPYABLE(DOMPath); WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassRefPtr<DOMPath> create() { return adoptRef(new DOMPath); }
+    static PassRefPtr<DOMPath> create(const String& pathData) { return adoptRef(new DOMPath(pathData)); }
+    static PassRefPtr<DOMPath> create(DOMPath* path) { return adoptRef(new DOMPath(path)); }
+
+    static PassRefPtr<DOMPath> create(const Path& path) { return adoptRef(new DOMPath(path)); }
+
+    const Path& path() const { return m_path; }
+
+    virtual ~DOMPath() { }
+private:
+    DOMPath() : CanvasPathMethods() { }
+    DOMPath(const Path& path)
+        : CanvasPathMethods()
+    {
+        m_path = path;
+    }
+    DOMPath(DOMPath* path)
+        : CanvasPathMethods()
+    {
+        m_path = path->path();
+    }
+    DOMPath(const String& pathData)
+        : CanvasPathMethods()
+    {
+#if ENABLE(SVG)
+        buildPathFromString(pathData, m_path);
+#else
+        UNUSED_PARAM(pathData);
+#endif
+    }
+};
+}
+#endif
diff --git a/Source/core/html/canvas/DOMPath.idl b/Source/core/html/canvas/DOMPath.idl
new file mode 100644
index 0000000..9a68c72
--- /dev/null
+++ b/Source/core/html/canvas/DOMPath.idl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2012, 2013 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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.
+ */
+
+[
+    EnabledAtRuntime=canvasPath,
+    Constructor,
+    Constructor(DOMPath path),
+#if defined(ENABLE_SVG) && ENABLE_SVG
+    Constructor(DOMString text),
+#endif
+    InterfaceName=Path
+] interface DOMPath {
+
+    // FIXME: These methods should be shared with CanvasRenderingContext2D in the CanvasPathMethods interface.
+    void closePath();
+    void moveTo([Default=Undefined] optional float x,
+                [Default=Undefined] optional float y);
+    void lineTo([Default=Undefined] optional float x,
+                [Default=Undefined] optional float y);
+    void quadraticCurveTo([Default=Undefined] optional float cpx,
+                          [Default=Undefined] optional float cpy,
+                          [Default=Undefined] optional float x,
+                          [Default=Undefined] optional float y);
+    void bezierCurveTo([Default=Undefined] optional float cp1x,
+                       [Default=Undefined] optional float cp1y,
+                       [Default=Undefined] optional float cp2x,
+                       [Default=Undefined] optional float cp2y,
+                       [Default=Undefined] optional float x,
+                       [Default=Undefined] optional float y);
+    [RaisesException] void arcTo([Default=Undefined] optional float x1,
+               [Default=Undefined] optional float y1,
+               [Default=Undefined] optional float x2,
+               [Default=Undefined] optional float y2,
+               [Default=Undefined] optional float radius);
+    void rect([Default=Undefined] optional float x,
+              [Default=Undefined] optional float y,
+              [Default=Undefined] optional float width,
+              [Default=Undefined] optional float height);
+    [RaisesException] void arc([Default=Undefined] optional float x,
+             [Default=Undefined] optional float y,
+             [Default=Undefined] optional float radius,
+             [Default=Undefined] optional float startAngle,
+             [Default=Undefined] optional float endAngle,
+             [Default=Undefined] optional boolean anticlockwise);
+};
diff --git a/Source/core/html/canvas/DataView.cpp b/Source/core/html/canvas/DataView.cpp
new file mode 100644
index 0000000..1c3c1b1
--- /dev/null
+++ b/Source/core/html/canvas/DataView.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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 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 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 "core/html/canvas/DataView.h"
+
+#include "core/dom/ExceptionCode.h"
+#include "core/html/canvas/CheckedInt.h"
+
+namespace {
+
+template<typename T>
+union Value {
+    T data;
+    char bytes[sizeof(T)];
+};
+
+}
+
+namespace WebCore {
+
+PassRefPtr<DataView> DataView::create(unsigned length)
+{
+    RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, sizeof(uint8_t));
+    if (!buffer.get())
+        return 0;
+    return create(buffer, 0, length);
+}
+
+PassRefPtr<DataView> DataView::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength)
+{
+    if (byteOffset > buffer->byteLength())
+        return 0;
+    CheckedInt<uint32_t> checkedOffset(byteOffset);
+    CheckedInt<uint32_t> checkedLength(byteLength);
+    CheckedInt<uint32_t> checkedMax = checkedOffset + checkedLength;
+    if (!checkedMax.isValid() || checkedMax.value() > buffer->byteLength())
+        return 0;
+    return adoptRef(new DataView(buffer, byteOffset, byteLength));
+}
+
+DataView::DataView(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength)
+    : ArrayBufferView(buffer, byteOffset)
+    , m_byteLength(byteLength)
+{
+}
+
+static bool needToFlipBytes(bool littleEndian)
+{
+#if CPU(BIG_ENDIAN)
+    return littleEndian;
+#else
+    return !littleEndian;
+#endif
+}
+
+inline void swapBytes(char* p, char* q)
+{
+    char temp = *p;
+    *p = *q;
+    *q = temp;
+}
+
+static void flipBytesFor16Bits(char* p)
+{
+    swapBytes(p, p + 1);
+}
+
+static void flipBytesFor32Bits(char* p)
+{
+    swapBytes(p, p + 3);
+    swapBytes(p + 1, p + 2);
+}
+
+static void flipBytesFor64Bits(char* p)
+{
+    swapBytes(p, p + 7);
+    swapBytes(p + 1, p + 6);
+    swapBytes(p + 2, p + 5);
+    swapBytes(p + 3, p + 4);
+}
+
+static void flipBytesIfNeeded(char* value, size_t size, bool littleEndian)
+{
+    if (!needToFlipBytes(littleEndian))
+        return;
+
+    switch (size) {
+    case 1:
+        // Nothing to do.
+        break;
+    case 2:
+        flipBytesFor16Bits(value);
+        break;
+    case 4:
+        flipBytesFor32Bits(value);
+        break;
+    case 8:
+        flipBytesFor64Bits(value);
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+template<typename T>
+T DataView::getData(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) const
+{
+    if (beyondRange<T>(byteOffset)) {
+        ec = INDEX_SIZE_ERR;
+        return 0;
+    }
+
+    // We do not want to load the data directly since it would cause a bus error on architectures that don't support unaligned loads.
+    Value<T> value;
+    memcpy(value.bytes, static_cast<const char*>(m_baseAddress) + byteOffset, sizeof(T));
+    flipBytesIfNeeded(value.bytes, sizeof(T), littleEndian);
+    return value.data;
+}
+
+template<typename T>
+void DataView::setData(unsigned byteOffset, T value, bool littleEndian, ExceptionCode& ec)
+{
+    if (beyondRange<T>(byteOffset)) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    // We do not want to store the data directly since it would cause a bus error on architectures that don't support unaligned stores.
+    Value<T> tempValue;
+    tempValue.data = value;
+    flipBytesIfNeeded(tempValue.bytes, sizeof(T), littleEndian);
+    memcpy(static_cast<char*>(m_baseAddress) + byteOffset, tempValue.bytes, sizeof(T));
+}
+
+int8_t DataView::getInt8(unsigned byteOffset, ExceptionCode& ec)
+{
+    return getData<int8_t>(byteOffset, false, ec);
+}
+
+uint8_t DataView::getUint8(unsigned byteOffset, ExceptionCode& ec)
+{
+    return getData<uint8_t>(byteOffset, false, ec);
+}
+
+int16_t DataView::getInt16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
+{
+    return getData<int16_t>(byteOffset, littleEndian, ec);
+}
+
+uint16_t DataView::getUint16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
+{
+    return getData<uint16_t>(byteOffset, littleEndian, ec);
+}
+
+int32_t DataView::getInt32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
+{
+    return getData<int32_t>(byteOffset, littleEndian, ec);
+}
+
+uint32_t DataView::getUint32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
+{
+    return getData<uint32_t>(byteOffset, littleEndian, ec);
+}
+
+float DataView::getFloat32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
+{
+    return getData<float>(byteOffset, littleEndian, ec);
+}
+
+double DataView::getFloat64(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
+{
+    return getData<double>(byteOffset, littleEndian, ec);
+}
+
+void DataView::setInt8(unsigned byteOffset, int8_t value, ExceptionCode& ec)
+{
+    setData<int8_t>(byteOffset, value, false, ec);
+}
+
+void DataView::setUint8(unsigned byteOffset, uint8_t value, ExceptionCode& ec)
+{
+    setData<uint8_t>(byteOffset, value, false, ec);
+}
+
+void DataView::setInt16(unsigned byteOffset, short value, bool littleEndian, ExceptionCode& ec)
+{
+    setData<int16_t>(byteOffset, value, littleEndian, ec);
+}
+
+void DataView::setUint16(unsigned byteOffset, uint16_t value, bool littleEndian, ExceptionCode& ec)
+{
+    setData<uint16_t>(byteOffset, value, littleEndian, ec);
+}
+
+void DataView::setInt32(unsigned byteOffset, int32_t value, bool littleEndian, ExceptionCode& ec)
+{
+    setData<int32_t>(byteOffset, value, littleEndian, ec);
+}
+
+void DataView::setUint32(unsigned byteOffset, uint32_t value, bool littleEndian, ExceptionCode& ec)
+{
+    setData<uint32_t>(byteOffset, value, littleEndian, ec);
+}
+
+void DataView::setFloat32(unsigned byteOffset, float value, bool littleEndian, ExceptionCode& ec)
+{
+    setData<float>(byteOffset, value, littleEndian, ec);
+}
+
+void DataView::setFloat64(unsigned byteOffset, double value, bool littleEndian, ExceptionCode& ec)
+{
+    setData<double>(byteOffset, value, littleEndian, ec);
+}
+
+void DataView::neuter()
+{
+    ArrayBufferView::neuter();
+    m_byteLength = 0;
+}
+
+}
diff --git a/Source/core/html/canvas/DataView.h b/Source/core/html/canvas/DataView.h
new file mode 100644
index 0000000..00d56d8
--- /dev/null
+++ b/Source/core/html/canvas/DataView.h
@@ -0,0 +1,101 @@
+/*
+ * 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 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 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 DataView_h
+#define DataView_h
+
+#include <wtf/ArrayBufferView.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+typedef int ExceptionCode;
+
+class DataView : public ArrayBufferView {
+public:
+    static PassRefPtr<DataView> create(unsigned length);
+    static PassRefPtr<DataView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned byteLength);
+
+    virtual unsigned length() const { return m_byteLength; }
+    virtual unsigned byteLength() const { return m_byteLength; }
+    virtual PassRefPtr<ArrayBufferView> slice(int, int) const { return 0; }
+
+    int8_t getInt8(unsigned byteOffset, ExceptionCode&);
+    uint8_t getUint8(unsigned byteOffset, ExceptionCode&);
+    int16_t getInt16(unsigned byteOffset, ExceptionCode& ec) { return getInt16(byteOffset, false, ec); }
+    int16_t getInt16(unsigned byteOffset, bool littleEndian, ExceptionCode&);
+    uint16_t getUint16(unsigned byteOffset, ExceptionCode& ec) { return getUint16(byteOffset, false, ec); }
+    uint16_t getUint16(unsigned byteOffset, bool littleEndian, ExceptionCode&);
+    int32_t getInt32(unsigned byteOffset, ExceptionCode& ec) { return getInt32(byteOffset, false, ec); }
+    int32_t getInt32(unsigned byteOffset, bool littleEndian, ExceptionCode&);
+    uint32_t getUint32(unsigned byteOffset, ExceptionCode& ec) { return getUint32(byteOffset, false, ec); }
+    uint32_t getUint32(unsigned byteOffset, bool littleEndian, ExceptionCode&);
+    float getFloat32(unsigned byteOffset, ExceptionCode& ec) { return getFloat32(byteOffset, false, ec); }
+    float getFloat32(unsigned byteOffset, bool littleEndian, ExceptionCode&);
+    double getFloat64(unsigned byteOffset, ExceptionCode& ec) { return getFloat64(byteOffset, false, ec); }
+    double getFloat64(unsigned byteOffset, bool littleEndian, ExceptionCode&);
+
+    void setInt8(unsigned byteOffset, int8_t value, ExceptionCode&);
+    void setUint8(unsigned byteOffset, uint8_t value, ExceptionCode&);
+    void setInt16(unsigned byteOffset, int16_t value, ExceptionCode& ec) { setInt16(byteOffset, value, false, ec); }
+    void setInt16(unsigned byteOffset, int16_t value, bool littleEndian, ExceptionCode&);
+    void setUint16(unsigned byteOffset, uint16_t value, ExceptionCode& ec) { setUint16(byteOffset, value, false, ec); }
+    void setUint16(unsigned byteOffset, uint16_t value, bool littleEndian, ExceptionCode&);
+    void setInt32(unsigned byteOffset, int32_t value, ExceptionCode& ec) { setInt32(byteOffset, value, false, ec); } 
+    void setInt32(unsigned byteOffset, int32_t value, bool littleEndian, ExceptionCode&);
+    void setUint32(unsigned byteOffset, uint32_t value, ExceptionCode& ec) { setUint32(byteOffset, value, false, ec); }
+    void setUint32(unsigned byteOffset, uint32_t value, bool littleEndian, ExceptionCode&);
+    void setFloat32(unsigned byteOffset, float value, ExceptionCode& ec) { setFloat32(byteOffset, value, false, ec); }
+    void setFloat32(unsigned byteOffset, float value, bool littleEndian, ExceptionCode&);
+    void setFloat64(unsigned byteOffset, double value, ExceptionCode& ec) { setFloat64(byteOffset, value, false, ec); }
+    void setFloat64(unsigned byteOffset, double value, bool littleEndian, ExceptionCode&);
+
+    virtual ViewType getType() const
+    {
+        return TypeDataView;
+    }
+
+protected:
+    virtual void neuter();
+
+private:
+    DataView(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned byteLength);
+
+    template<typename T>
+    inline bool beyondRange(unsigned byteOffset) const { return byteOffset >= m_byteLength || byteOffset + sizeof(T) > m_byteLength; }
+
+    template<typename T>
+    T getData(unsigned byteOffset, bool littleEndian, ExceptionCode&) const;
+
+    template<typename T>
+    void setData(unsigned byteOffset, T value, bool littleEndian, ExceptionCode&);
+
+    unsigned m_byteLength;
+};
+
+
+} // namespace WebCore
+
+#endif // DataView_h
diff --git a/Source/core/html/canvas/DataView.idl b/Source/core/html/canvas/DataView.idl
new file mode 100644
index 0000000..1636c4c
--- /dev/null
+++ b/Source/core/html/canvas/DataView.idl
@@ -0,0 +1,60 @@
+/*
+ * 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 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 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.
+ */
+
+[
+    CustomConstructor(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long byteLength),
+    CustomToV8
+] interface DataView : ArrayBufferView {
+    // All these methods raise an exception if they would read or write beyond the end of the view.
+
+    // We have to use custom code because our code generator does not support int8_t type.
+    // int8_t getInt8(unsigned long byteOffset);
+    // uint8_t getUint8(unsigned long byteOffset);
+    [Custom, RaisesException] any getInt8();
+    [Custom, RaisesException] any getUint8();
+
+    [StrictTypeChecking, RaisesException] short getInt16(unsigned long byteOffset, optional boolean littleEndian);
+    [StrictTypeChecking, RaisesException] unsigned short getUint16(unsigned long byteOffset, optional boolean littleEndian);
+    [StrictTypeChecking, RaisesException] long getInt32(unsigned long byteOffset, optional boolean littleEndian);
+    [StrictTypeChecking, RaisesException] unsigned long getUint32(unsigned long byteOffset, optional boolean littleEndian);
+
+    // Use custom code to handle NaN case for JSC.
+    [StrictTypeChecking, RaisesException] float getFloat32(unsigned long byteOffset, optional boolean littleEndian);
+    [StrictTypeChecking, RaisesException] double getFloat64(unsigned long byteOffset, optional boolean littleEndian);
+
+    // We have to use custom code because our code generator does not support uint8_t type.
+    // void setInt8(unsigned long byteOffset, int8_t value);
+    // void setUint8(unsigned long byteOffset, uint8_t value);
+    [Custom, RaisesException] void setInt8();
+    [Custom, RaisesException] void setUint8();
+
+    [StrictTypeChecking, RaisesException] void setInt16(unsigned long byteOffset, short value, optional boolean littleEndian);
+    [StrictTypeChecking, RaisesException] void setUint16(unsigned long byteOffset, unsigned short value, optional boolean littleEndian);
+    [StrictTypeChecking, RaisesException] void setInt32(unsigned long byteOffset, long value, optional boolean littleEndian);
+    [StrictTypeChecking, RaisesException] void setUint32(unsigned long byteOffset, unsigned long value, optional boolean littleEndian);
+    [StrictTypeChecking, RaisesException] void setFloat32(unsigned long byteOffset, float value, optional boolean littleEndian);
+    [StrictTypeChecking, RaisesException] void setFloat64(unsigned long byteOffset, double value, optional boolean littleEndian);
+};
+
diff --git a/Source/core/html/canvas/EXTDrawBuffers.cpp b/Source/core/html/canvas/EXTDrawBuffers.cpp
new file mode 100644
index 0000000..714b81b
--- /dev/null
+++ b/Source/core/html/canvas/EXTDrawBuffers.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2013 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 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 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 "core/html/canvas/EXTDrawBuffers.h"
+
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+EXTDrawBuffers::EXTDrawBuffers(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_EXT_draw_buffers");
+}
+
+EXTDrawBuffers::~EXTDrawBuffers()
+{
+}
+
+WebGLExtension::ExtensionName EXTDrawBuffers::getName() const
+{
+    return WebGLExtension::EXTDrawBuffersName;
+}
+
+PassOwnPtr<EXTDrawBuffers> EXTDrawBuffers::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new EXTDrawBuffers(context));
+}
+
+// static
+bool EXTDrawBuffers::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return (extensions->supports("GL_EXT_draw_buffers")
+        && satisfiesWebGLRequirements(context));
+}
+
+const char* EXTDrawBuffers::getExtensionName()
+{
+    return "EXT_draw_buffers";
+}
+
+void EXTDrawBuffers::drawBuffersEXT(const Vector<GC3Denum>& buffers)
+{
+    if (m_context->isContextLost())
+        return;
+    GC3Dsizei n = buffers.size();
+    const GC3Denum* bufs = buffers.data();
+    if (!m_context->m_framebufferBinding) {
+        if (n != 1) {
+            m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawBuffersEXT", "more than one buffer");
+            return;
+        }
+        if (bufs[0] != GraphicsContext3D::BACK && bufs[0] != GraphicsContext3D::NONE) {
+            m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawBuffersEXT", "BACK or NONE");
+            return;
+        }
+        // Because the backbuffer is simulated on all current WebKit ports, we need to change BACK to COLOR_ATTACHMENT0.
+        GC3Denum value = (bufs[0] == GraphicsContext3D::BACK) ? GraphicsContext3D::COLOR_ATTACHMENT0 : GraphicsContext3D::NONE;
+        m_context->graphicsContext3D()->getExtensions()->drawBuffersEXT(1, &value);
+        m_context->setBackDrawBuffer(bufs[0]);
+    } else {
+        if (n > m_context->getMaxDrawBuffers()) {
+            m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawBuffersEXT", "more than max draw buffers");
+            return;
+        }
+        for (GC3Dsizei i = 0; i < n; ++i) {
+            if (bufs[i] != GraphicsContext3D::NONE && bufs[i] != static_cast<GC3Denum>(Extensions3D::COLOR_ATTACHMENT0_EXT + i)) {
+                m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawBuffersEXT", "COLOR_ATTACHMENTi_EXT or NONE");
+                return;
+            }
+        }
+        m_context->m_framebufferBinding->drawBuffers(buffers);
+    }
+}
+
+// static
+bool EXTDrawBuffers::satisfiesWebGLRequirements(WebGLRenderingContext* webglContext)
+{
+    GraphicsContext3D* context = webglContext->graphicsContext3D();
+
+    // This is called after we make sure GL_EXT_draw_buffers is supported.
+    GC3Dint maxDrawBuffers = 0;
+    GC3Dint maxColorAttachments = 0;
+    context->getIntegerv(Extensions3D::MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
+    context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments);
+    if (maxDrawBuffers < 4 || maxColorAttachments < 4)
+        return false;
+
+    Platform3DObject fbo = context->createFramebuffer();
+    context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, fbo);
+
+    const unsigned char* buffer = 0; // Chromium doesn't allow init data for depth/stencil tetxures.
+    bool supportsDepth = (context->getExtensions()->supports("GL_CHROMIUM_depth_texture")
+        || context->getExtensions()->supports("GL_OES_depth_texture")
+        || context->getExtensions()->supports("GL_ARB_depth_texture"));
+    bool supportsDepthStencil = (context->getExtensions()->supports("GL_EXT_packed_depth_stencil")
+        || context->getExtensions()->supports("GL_OES_packed_depth_stencil"));
+    Platform3DObject depthStencil = 0;
+    if (supportsDepthStencil) {
+        depthStencil = context->createTexture();
+        context->bindTexture(GraphicsContext3D::TEXTURE_2D, depthStencil);
+        context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::DEPTH_STENCIL, 1, 1, 0, GraphicsContext3D::DEPTH_STENCIL, GraphicsContext3D::UNSIGNED_INT_24_8, buffer);
+    }
+    Platform3DObject depth = 0;
+    if (supportsDepth) {
+        depth = context->createTexture();
+        context->bindTexture(GraphicsContext3D::TEXTURE_2D, depth);
+        context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::DEPTH_COMPONENT, 1, 1, 0, GraphicsContext3D::DEPTH_COMPONENT, GraphicsContext3D::UNSIGNED_INT, buffer);
+    }
+
+    Vector<Platform3DObject> colors;
+    bool ok = true;
+    GC3Dint maxAllowedBuffers = std::min(maxDrawBuffers, maxColorAttachments);
+    for (GC3Dint i = 0; i < maxAllowedBuffers; ++i) {
+        Platform3DObject color = context->createTexture();
+        colors.append(color);
+        context->bindTexture(GraphicsContext3D::TEXTURE_2D, color);
+        context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, buffer);
+        context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0 + i, GraphicsContext3D::TEXTURE_2D, color, 0);
+        if (context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+            ok = false;
+            break;
+        }
+        if (supportsDepth) {
+            context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, depth, 0);
+            if (context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+                ok = false;
+                break;
+            }
+            context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, 0, 0);
+        }
+        if (supportsDepthStencil) {
+            context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, depthStencil, 0);
+            context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, depthStencil, 0);
+            if (context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+                ok = false;
+                break;
+            }
+            context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, 0, 0);
+            context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, 0, 0);
+        }
+    }
+
+    webglContext->restoreCurrentFramebuffer();
+    context->deleteFramebuffer(fbo);
+    webglContext->restoreCurrentTexture2D();
+    if (supportsDepth)
+        context->deleteTexture(depth);
+    if (supportsDepthStencil)
+        context->deleteTexture(depthStencil);
+    for (size_t i = 0; i < colors.size(); ++i)
+        context->deleteTexture(colors[i]);
+    return ok;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/EXTDrawBuffers.h b/Source/core/html/canvas/EXTDrawBuffers.h
new file mode 100644
index 0000000..ac61aec
--- /dev/null
+++ b/Source/core/html/canvas/EXTDrawBuffers.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 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 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 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 EXTDrawBuffers_h
+#define EXTDrawBuffers_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class EXTDrawBuffers : public WebGLExtension {
+public:
+    static PassOwnPtr<EXTDrawBuffers> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~EXTDrawBuffers();
+    virtual ExtensionName getName() const;
+
+    void drawBuffersEXT(const Vector<GC3Denum>& buffers);
+
+private:
+    EXTDrawBuffers(WebGLRenderingContext*);
+
+    static bool satisfiesWebGLRequirements(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // EXTDrawBuffers_h
diff --git a/Source/core/html/canvas/EXTDrawBuffers.idl b/Source/core/html/canvas/EXTDrawBuffers.idl
new file mode 100644
index 0000000..f348e15
--- /dev/null
+++ b/Source/core/html/canvas/EXTDrawBuffers.idl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 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 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 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.
+ */
+
+typedef unsigned long GLenum;
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface EXTDrawBuffers {
+    const GLenum COLOR_ATTACHMENT0_EXT = 0x8CE0;
+    const GLenum COLOR_ATTACHMENT1_EXT = 0x8CE1;
+    const GLenum COLOR_ATTACHMENT2_EXT = 0x8CE2;
+    const GLenum COLOR_ATTACHMENT3_EXT = 0x8CE3;
+    const GLenum COLOR_ATTACHMENT4_EXT = 0x8CE4;
+    const GLenum COLOR_ATTACHMENT5_EXT = 0x8CE5;
+    const GLenum COLOR_ATTACHMENT6_EXT = 0x8CE6;
+    const GLenum COLOR_ATTACHMENT7_EXT = 0x8CE7;
+    const GLenum COLOR_ATTACHMENT8_EXT = 0x8CE8;
+    const GLenum COLOR_ATTACHMENT9_EXT = 0x8CE9;
+    const GLenum COLOR_ATTACHMENT10_EXT = 0x8CEA;
+    const GLenum COLOR_ATTACHMENT11_EXT = 0x8CEB;
+    const GLenum COLOR_ATTACHMENT12_EXT = 0x8CEC;
+    const GLenum COLOR_ATTACHMENT13_EXT = 0x8CED;
+    const GLenum COLOR_ATTACHMENT14_EXT = 0x8CEE;
+    const GLenum COLOR_ATTACHMENT15_EXT = 0x8CEF;
+
+    const GLenum DRAW_BUFFER0_EXT = 0x8825;
+    const GLenum DRAW_BUFFER1_EXT = 0x8826;
+    const GLenum DRAW_BUFFER2_EXT = 0x8827;
+    const GLenum DRAW_BUFFER3_EXT = 0x8828;
+    const GLenum DRAW_BUFFER4_EXT = 0x8829;
+    const GLenum DRAW_BUFFER5_EXT = 0x882A;
+    const GLenum DRAW_BUFFER6_EXT = 0x882B;
+    const GLenum DRAW_BUFFER7_EXT = 0x882C;
+    const GLenum DRAW_BUFFER8_EXT = 0x882D;
+    const GLenum DRAW_BUFFER9_EXT = 0x882E;
+    const GLenum DRAW_BUFFER10_EXT = 0x882F;
+    const GLenum DRAW_BUFFER11_EXT = 0x8830;
+    const GLenum DRAW_BUFFER12_EXT = 0x8831;
+    const GLenum DRAW_BUFFER13_EXT = 0x8832;
+    const GLenum DRAW_BUFFER14_EXT = 0x8833;
+    const GLenum DRAW_BUFFER15_EXT = 0x8834;
+
+    const GLenum MAX_COLOR_ATTACHMENTS_EXT = 0x8CDF;
+    const GLenum MAX_DRAW_BUFFERS_EXT = 0x8824;
+
+    void drawBuffersEXT(sequence<GLenum> buffers);
+};
diff --git a/Source/core/html/canvas/EXTTextureFilterAnisotropic.cpp b/Source/core/html/canvas/EXTTextureFilterAnisotropic.cpp
new file mode 100644
index 0000000..3241eea
--- /dev/null
+++ b/Source/core/html/canvas/EXTTextureFilterAnisotropic.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 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 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 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 "core/html/canvas/EXTTextureFilterAnisotropic.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+EXTTextureFilterAnisotropic::EXTTextureFilterAnisotropic(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_EXT_texture_filter_anisotropic");
+}
+
+EXTTextureFilterAnisotropic::~EXTTextureFilterAnisotropic()
+{
+}
+
+WebGLExtension::ExtensionName EXTTextureFilterAnisotropic::getName() const
+{
+    return EXTTextureFilterAnisotropicName;
+}
+
+PassOwnPtr<EXTTextureFilterAnisotropic> EXTTextureFilterAnisotropic::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new EXTTextureFilterAnisotropic(context));
+}
+
+bool EXTTextureFilterAnisotropic::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_EXT_texture_filter_anisotropic");
+}
+
+const char* EXTTextureFilterAnisotropic::getExtensionName()
+{
+    return "EXT_texture_filter_anisotropic";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/EXTTextureFilterAnisotropic.h b/Source/core/html/canvas/EXTTextureFilterAnisotropic.h
new file mode 100644
index 0000000..54cb69c
--- /dev/null
+++ b/Source/core/html/canvas/EXTTextureFilterAnisotropic.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 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 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 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 EXTTextureFilterAnisotropic_h
+#define EXTTextureFilterAnisotropic_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class EXTTextureFilterAnisotropic : public WebGLExtension {
+public:
+    static PassOwnPtr<EXTTextureFilterAnisotropic> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~EXTTextureFilterAnisotropic();
+    virtual ExtensionName getName() const;
+
+private:
+    EXTTextureFilterAnisotropic(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // EXTTextureFilterAnisotropic_h
diff --git a/Source/core/html/canvas/EXTTextureFilterAnisotropic.idl b/Source/core/html/canvas/EXTTextureFilterAnisotropic.idl
new file mode 100644
index 0000000..d454a9b
--- /dev/null
+++ b/Source/core/html/canvas/EXTTextureFilterAnisotropic.idl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface EXTTextureFilterAnisotropic {
+    const unsigned long TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+    const unsigned long MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
+};
diff --git a/Source/core/html/canvas/Float32Array.idl b/Source/core/html/canvas/Float32Array.idl
new file mode 100644
index 0000000..306b7e3
--- /dev/null
+++ b/Source/core/html/canvas/Float32Array.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+[
+    ConstructorTemplate=TypedArray,
+    CustomToV8,
+    DoNotCheckConstants,
+    TypedArray=float,
+    ImplementationNamespace=WTF
+] interface Float32Array : ArrayBufferView {
+    const unsigned long BYTES_PER_ELEMENT = 4;
+
+    readonly attribute unsigned long length;
+    Float32Array subarray([Default=Undefined] optional long start, 
+                          optional long end);
+
+    // void set(Float32Array array, optional in unsigned long offset);
+    // void set(sequence<long> array, optional in unsigned long offset);
+    void set();
+};
diff --git a/Source/core/html/canvas/Float64Array.idl b/Source/core/html/canvas/Float64Array.idl
new file mode 100644
index 0000000..51870fa
--- /dev/null
+++ b/Source/core/html/canvas/Float64Array.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+[
+    ConstructorTemplate=TypedArray,
+    CustomToV8,
+    DoNotCheckConstants,
+    TypedArray=double,
+    ImplementationNamespace=WTF
+] interface Float64Array : ArrayBufferView {
+    const unsigned long BYTES_PER_ELEMENT = 8;
+
+    readonly attribute unsigned long length;
+    Float64Array subarray([Default=Undefined] optional long start, 
+                          optional long end);
+
+    // void set(Float64Array array, optional in unsigned long offset);
+    // void set(sequence<long> array, optional in unsigned long offset);
+    void set();
+};
diff --git a/Source/core/html/canvas/Int16Array.idl b/Source/core/html/canvas/Int16Array.idl
new file mode 100644
index 0000000..ffa5682
--- /dev/null
+++ b/Source/core/html/canvas/Int16Array.idl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006, 2010 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+[
+    ConstructorTemplate=TypedArray,
+    CustomToV8,
+    DoNotCheckConstants,
+    TypedArray=short,
+    ImplementationNamespace=WTF
+] interface Int16Array : ArrayBufferView {
+    const unsigned long BYTES_PER_ELEMENT = 2;
+
+    readonly attribute unsigned long length;
+    Int16Array subarray([Default=Undefined] optional long start, 
+                        optional long end);
+
+    // void set(Int16Array array, optional in unsigned long offset);
+    // void set(sequence<long> array, optional in unsigned long offset);
+    void set();
+};
diff --git a/Source/core/html/canvas/Int32Array.idl b/Source/core/html/canvas/Int32Array.idl
new file mode 100644
index 0000000..c46242b
--- /dev/null
+++ b/Source/core/html/canvas/Int32Array.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    ConstructorTemplate=TypedArray,
+    CustomToV8,
+    DoNotCheckConstants,
+    TypedArray=int,
+    ImplementationNamespace=WTF
+] interface Int32Array : ArrayBufferView {
+    const unsigned long BYTES_PER_ELEMENT = 4;
+
+    readonly attribute unsigned long length;
+    Int32Array subarray([Default=Undefined] optional long start, 
+                        optional long end);
+
+    // void set(Int32Array array, optional in unsigned long offset);
+    // void set(sequence<long> array, optional in unsigned long offset);
+    void set();
+};
diff --git a/Source/core/html/canvas/Int8Array.idl b/Source/core/html/canvas/Int8Array.idl
new file mode 100644
index 0000000..5cb46ab
--- /dev/null
+++ b/Source/core/html/canvas/Int8Array.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    ConstructorTemplate=TypedArray,
+    CustomToV8,
+    DoNotCheckConstants,
+    TypedArray=signed char,
+    ImplementationNamespace=WTF
+] interface Int8Array : ArrayBufferView {
+    const unsigned long BYTES_PER_ELEMENT = 1;
+
+    readonly attribute unsigned long length;
+    Int8Array subarray([Default=Undefined] optional long start, 
+                       optional long end);
+
+    // void set(Int8Array array, optional in unsigned long offset);
+    // void set(sequence<long> array, optional in unsigned long offset);
+    void set();
+};
diff --git a/Source/core/html/canvas/OESElementIndexUint.cpp b/Source/core/html/canvas/OESElementIndexUint.cpp
new file mode 100644
index 0000000..ce7f267
--- /dev/null
+++ b/Source/core/html/canvas/OESElementIndexUint.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 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 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 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 "core/html/canvas/OESElementIndexUint.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+OESElementIndexUint::OESElementIndexUint(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_OES_element_index_uint");
+}
+
+OESElementIndexUint::~OESElementIndexUint()
+{
+}
+
+WebGLExtension::ExtensionName OESElementIndexUint::getName() const
+{
+    return OESElementIndexUintName;
+}
+
+PassOwnPtr<OESElementIndexUint> OESElementIndexUint::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new OESElementIndexUint(context));
+}
+
+bool OESElementIndexUint::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_OES_element_index_uint");
+}
+
+const char* OESElementIndexUint::getExtensionName()
+{
+    return "OES_element_index_uint";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/OESElementIndexUint.h b/Source/core/html/canvas/OESElementIndexUint.h
new file mode 100644
index 0000000..8acfaba
--- /dev/null
+++ b/Source/core/html/canvas/OESElementIndexUint.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 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 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 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 OESElementIndexUint_h
+#define OESElementIndexUint_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class OESElementIndexUint : public WebGLExtension {
+public:
+    static PassOwnPtr<OESElementIndexUint> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~OESElementIndexUint();
+    virtual ExtensionName getName() const;
+
+private:
+    OESElementIndexUint(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // OESElementIndexUint_h
diff --git a/Source/core/html/canvas/OESElementIndexUint.idl b/Source/core/html/canvas/OESElementIndexUint.idl
new file mode 100644
index 0000000..6e76baa
--- /dev/null
+++ b/Source/core/html/canvas/OESElementIndexUint.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+] interface OESElementIndexUint {
+};
diff --git a/Source/core/html/canvas/OESStandardDerivatives.cpp b/Source/core/html/canvas/OESStandardDerivatives.cpp
new file mode 100644
index 0000000..1228e9d
--- /dev/null
+++ b/Source/core/html/canvas/OESStandardDerivatives.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 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 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 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 "core/html/canvas/OESStandardDerivatives.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+OESStandardDerivatives::OESStandardDerivatives(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
+}
+
+OESStandardDerivatives::~OESStandardDerivatives()
+{
+}
+
+WebGLExtension::ExtensionName OESStandardDerivatives::getName() const
+{
+    return OESStandardDerivativesName;
+}
+
+PassOwnPtr<OESStandardDerivatives> OESStandardDerivatives::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new OESStandardDerivatives(context));
+}
+
+bool OESStandardDerivatives::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_OES_standard_derivatives");
+}
+
+const char* OESStandardDerivatives::getExtensionName()
+{
+    return "OES_standard_derivatives";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/OESStandardDerivatives.h b/Source/core/html/canvas/OESStandardDerivatives.h
new file mode 100644
index 0000000..1dbacb6
--- /dev/null
+++ b/Source/core/html/canvas/OESStandardDerivatives.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 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 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 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 OESStandardDerivatives_h
+#define OESStandardDerivatives_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class OESStandardDerivatives : public WebGLExtension {
+public:
+    static PassOwnPtr<OESStandardDerivatives> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~OESStandardDerivatives();
+    virtual ExtensionName getName() const;
+
+private:
+    OESStandardDerivatives(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // OESStandardDerivatives_h
diff --git a/Source/core/html/canvas/OESStandardDerivatives.idl b/Source/core/html/canvas/OESStandardDerivatives.idl
new file mode 100644
index 0000000..6dbfd5d
--- /dev/null
+++ b/Source/core/html/canvas/OESStandardDerivatives.idl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface OESStandardDerivatives {
+    const unsigned long FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B;
+};
diff --git a/Source/core/html/canvas/OESTextureFloat.cpp b/Source/core/html/canvas/OESTextureFloat.cpp
new file mode 100644
index 0000000..0a98358
--- /dev/null
+++ b/Source/core/html/canvas/OESTextureFloat.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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 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 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 "core/html/canvas/OESTextureFloat.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+OESTextureFloat::OESTextureFloat(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_OES_texture_float");
+}
+
+OESTextureFloat::~OESTextureFloat()
+{
+}
+
+WebGLExtension::ExtensionName OESTextureFloat::getName() const
+{
+    return OESTextureFloatName;
+}
+
+PassOwnPtr<OESTextureFloat> OESTextureFloat::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new OESTextureFloat(context));
+}
+
+bool OESTextureFloat::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_OES_texture_float");
+}
+
+const char* OESTextureFloat::getExtensionName()
+{
+    return "OES_texture_float";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/OESTextureFloat.h b/Source/core/html/canvas/OESTextureFloat.h
new file mode 100644
index 0000000..34e1fee
--- /dev/null
+++ b/Source/core/html/canvas/OESTextureFloat.h
@@ -0,0 +1,49 @@
+/*
+ * 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 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 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 OESTextureFloat_h
+#define OESTextureFloat_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class OESTextureFloat : public WebGLExtension {
+public:
+    static PassOwnPtr<OESTextureFloat> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~OESTextureFloat();
+    virtual ExtensionName getName() const;
+
+private:
+    OESTextureFloat(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // OESTextureFloat_h
diff --git a/Source/core/html/canvas/OESTextureFloat.idl b/Source/core/html/canvas/OESTextureFloat.idl
new file mode 100644
index 0000000..e58a7a3
--- /dev/null
+++ b/Source/core/html/canvas/OESTextureFloat.idl
@@ -0,0 +1,29 @@
+/*
+ * 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+] interface OESTextureFloat {
+};
diff --git a/Source/core/html/canvas/OESTextureHalfFloat.cpp b/Source/core/html/canvas/OESTextureHalfFloat.cpp
new file mode 100644
index 0000000..cfa9f77
--- /dev/null
+++ b/Source/core/html/canvas/OESTextureHalfFloat.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 Motorola Mobility LLC. 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 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 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 "core/html/canvas/OESTextureHalfFloat.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+OESTextureHalfFloat::OESTextureHalfFloat(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_OES_texture_half_float");
+}
+
+OESTextureHalfFloat::~OESTextureHalfFloat()
+{
+}
+
+WebGLExtension::ExtensionName OESTextureHalfFloat::getName() const
+{
+    return OESTextureHalfFloatName;
+}
+
+PassOwnPtr<OESTextureHalfFloat> OESTextureHalfFloat::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new OESTextureHalfFloat(context));
+}
+
+bool OESTextureHalfFloat::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_OES_texture_half_float");
+}
+
+const char* OESTextureHalfFloat::getExtensionName()
+{
+    return "OES_texture_half_float";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/OESTextureHalfFloat.h b/Source/core/html/canvas/OESTextureHalfFloat.h
new file mode 100644
index 0000000..b6e8c54
--- /dev/null
+++ b/Source/core/html/canvas/OESTextureHalfFloat.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Motorola Mobility LLC. 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 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 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 OESTextureHalfFloat_h
+#define OESTextureHalfFloat_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class OESTextureHalfFloat : public WebGLExtension {
+public:
+    static PassOwnPtr<OESTextureHalfFloat> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~OESTextureHalfFloat();
+    virtual ExtensionName getName() const;
+
+private:
+    OESTextureHalfFloat(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // OESTextureHalfFloat_h
diff --git a/Source/core/html/canvas/OESTextureHalfFloat.idl b/Source/core/html/canvas/OESTextureHalfFloat.idl
new file mode 100644
index 0000000..d95898c
--- /dev/null
+++ b/Source/core/html/canvas/OESTextureHalfFloat.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 Motorola Mobility LLC. 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 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 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.
+ */
+
+typedef unsigned long GLenum;
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface OESTextureHalfFloat {
+    const GLenum HALF_FLOAT_OES                 = 0x8D61;
+};
diff --git a/Source/core/html/canvas/OESVertexArrayObject.cpp b/Source/core/html/canvas/OESVertexArrayObject.cpp
new file mode 100644
index 0000000..4ebd1b8
--- /dev/null
+++ b/Source/core/html/canvas/OESVertexArrayObject.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/OESVertexArrayObject.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include "core/html/canvas/WebGLVertexArrayObjectOES.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+OESVertexArrayObject::OESVertexArrayObject(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
+}
+
+OESVertexArrayObject::~OESVertexArrayObject()
+{
+}
+
+WebGLExtension::ExtensionName OESVertexArrayObject::getName() const
+{
+    return OESVertexArrayObjectName;
+}
+
+PassOwnPtr<OESVertexArrayObject> OESVertexArrayObject::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new OESVertexArrayObject(context));
+}
+
+PassRefPtr<WebGLVertexArrayObjectOES> OESVertexArrayObject::createVertexArrayOES()
+{
+    if (m_context->isContextLost())
+        return 0;
+    
+    RefPtr<WebGLVertexArrayObjectOES> o = WebGLVertexArrayObjectOES::create(m_context, WebGLVertexArrayObjectOES::VaoTypeUser);
+    m_context->addContextObject(o.get());
+    return o.release();
+}
+
+void OESVertexArrayObject::deleteVertexArrayOES(WebGLVertexArrayObjectOES* arrayObject)
+{
+    if (!arrayObject || m_context->isContextLost())
+        return;
+    
+    if (!arrayObject->isDefaultObject() && arrayObject == m_context->m_boundVertexArrayObject)
+        m_context->setBoundVertexArrayObject(0);
+
+    arrayObject->deleteObject(m_context->graphicsContext3D());
+}
+
+GC3Dboolean OESVertexArrayObject::isVertexArrayOES(WebGLVertexArrayObjectOES* arrayObject)
+{
+    if (!arrayObject || m_context->isContextLost())
+        return 0;
+    
+    if (!arrayObject->hasEverBeenBound())
+        return 0;
+    
+    Extensions3D* extensions = m_context->graphicsContext3D()->getExtensions();
+    return extensions->isVertexArrayOES(arrayObject->object());
+}
+
+void OESVertexArrayObject::bindVertexArrayOES(WebGLVertexArrayObjectOES* arrayObject, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (m_context->isContextLost())
+        return;
+    
+    if (arrayObject && (arrayObject->isDeleted() || !arrayObject->validate(0, context()))) {
+        m_context->graphicsContext3D()->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+        return;
+    }
+    
+    Extensions3D* extensions = m_context->graphicsContext3D()->getExtensions();
+    if (arrayObject && !arrayObject->isDefaultObject() && arrayObject->object()) {
+        extensions->bindVertexArrayOES(arrayObject->object());
+        
+        arrayObject->setHasEverBeenBound();
+        m_context->setBoundVertexArrayObject(arrayObject);
+    } else {
+        extensions->bindVertexArrayOES(0);
+        m_context->setBoundVertexArrayObject(0);
+    }
+}
+
+bool OESVertexArrayObject::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_OES_vertex_array_object");
+}
+
+const char* OESVertexArrayObject::getExtensionName()
+{
+    return "OES_vertex_array_object";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/OESVertexArrayObject.h b/Source/core/html/canvas/OESVertexArrayObject.h
new file mode 100644
index 0000000..728dd6a
--- /dev/null
+++ b/Source/core/html/canvas/OESVertexArrayObject.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 OESVertexArrayObject_h
+#define OESVertexArrayObject_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include "core/html/canvas/WebGLVertexArrayObjectOES.h"
+#include "core/platform/graphics/GraphicsTypes3D.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+class WebGLRenderingContext;
+class WebGLVertexArrayObjectOES;
+
+typedef int ExceptionCode;
+
+class OESVertexArrayObject : public WebGLExtension {
+public:
+    static PassOwnPtr<OESVertexArrayObject> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~OESVertexArrayObject();
+    virtual ExtensionName getName() const;
+    
+    PassRefPtr<WebGLVertexArrayObjectOES> createVertexArrayOES();
+    void deleteVertexArrayOES(WebGLVertexArrayObjectOES*);
+    GC3Dboolean isVertexArrayOES(WebGLVertexArrayObjectOES*);
+    void bindVertexArrayOES(WebGLVertexArrayObjectOES*, ExceptionCode&);
+
+private:
+    OESVertexArrayObject(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // OESVertexArrayObject_h
diff --git a/Source/core/html/canvas/OESVertexArrayObject.idl b/Source/core/html/canvas/OESVertexArrayObject.idl
new file mode 100644
index 0000000..5de854f
--- /dev/null
+++ b/Source/core/html/canvas/OESVertexArrayObject.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBGL, 
+    DoNotCheckConstants
+] interface OESVertexArrayObject {
+    const unsigned long VERTEX_ARRAY_BINDING_OES = 0x85B5;
+    
+    [StrictTypeChecking] WebGLVertexArrayObjectOES createVertexArrayOES();
+    [StrictTypeChecking] void         deleteVertexArrayOES([Default=Undefined] optional WebGLVertexArrayObjectOES arrayObject);
+    [StrictTypeChecking] boolean      isVertexArrayOES([Default=Undefined] optional WebGLVertexArrayObjectOES arrayObject);
+    [StrictTypeChecking, RaisesException] void         bindVertexArrayOES([Default=Undefined] optional WebGLVertexArrayObjectOES arrayObject);
+};
diff --git a/Source/core/html/canvas/Uint16Array.idl b/Source/core/html/canvas/Uint16Array.idl
new file mode 100644
index 0000000..4268ef6
--- /dev/null
+++ b/Source/core/html/canvas/Uint16Array.idl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    ConstructorTemplate=TypedArray,
+    CustomToV8,
+    DoNotCheckConstants,
+    TypedArray=unsigned short,
+    ImplementationNamespace=WTF
+] interface Uint16Array : ArrayBufferView {
+    const unsigned long BYTES_PER_ELEMENT = 2;
+
+    readonly attribute unsigned long length;
+    Uint16Array subarray([Default=Undefined] optional long start, optional long end);
+
+    // void set(Uint16Array array, optional in unsigned long offset);
+    // void set(sequence<long> array, optional in unsigned long offset);
+    void set();
+};
diff --git a/Source/core/html/canvas/Uint32Array.idl b/Source/core/html/canvas/Uint32Array.idl
new file mode 100644
index 0000000..76936df
--- /dev/null
+++ b/Source/core/html/canvas/Uint32Array.idl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    ConstructorTemplate=TypedArray,
+    CustomToV8,
+    DoNotCheckConstants,
+    TypedArray=unsigned int,
+    ImplementationNamespace=WTF
+] interface Uint32Array : ArrayBufferView {
+    const unsigned long BYTES_PER_ELEMENT = 4;
+
+    readonly attribute unsigned long length;
+    Uint32Array subarray([Default=Undefined] optional long start, optional long end);
+
+    // void set(Uint32Array array, optional in unsigned long offset);
+    // void set(sequence<long> array, optional in unsigned long offset);
+    void set();
+};
diff --git a/Source/core/html/canvas/Uint8Array.idl b/Source/core/html/canvas/Uint8Array.idl
new file mode 100644
index 0000000..b6e3917
--- /dev/null
+++ b/Source/core/html/canvas/Uint8Array.idl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    ConstructorTemplate=TypedArray,
+    CustomToV8,
+    DoNotCheckConstants,
+    TypedArray=unsigned char,
+    ImplementationNamespace=WTF
+] interface Uint8Array : ArrayBufferView {
+    const unsigned long BYTES_PER_ELEMENT = 1;
+
+    readonly attribute unsigned long length;
+    Uint8Array subarray([Default=Undefined] optional long start, optional long end);
+
+    // void set(Uint8Array array, optional in unsigned long offset);
+    // void set(sequence<long> array, optional in unsigned long offset);
+    void set();
+};
diff --git a/Source/core/html/canvas/Uint8ClampedArray.idl b/Source/core/html/canvas/Uint8ClampedArray.idl
new file mode 100644
index 0000000..cd15b26
--- /dev/null
+++ b/Source/core/html/canvas/Uint8ClampedArray.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+[
+    ConstructorTemplate=TypedArray,
+    CustomToV8,
+    DoNotCheckConstants,
+    TypedArray=unsigned char,
+    ImplementationNamespace=WTF
+] interface Uint8ClampedArray : Uint8Array {
+    const unsigned long BYTES_PER_ELEMENT = 1;
+
+    readonly attribute unsigned long length;
+    Uint8ClampedArray subarray([Default=Undefined] optional long start, optional long end);
+
+    // FIXME: Missing other setters!
+    // void set(Uint8ClampedArray array, optional in unsigned long offset);
+    // void set(sequence<long> array, optional in unsigned long offset);
+    void set();
+};
diff --git a/Source/core/html/canvas/WebGLActiveInfo.h b/Source/core/html/canvas/WebGLActiveInfo.h
new file mode 100644
index 0000000..3f34ffc
--- /dev/null
+++ b/Source/core/html/canvas/WebGLActiveInfo.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 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. ``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 WebGLActiveInfo_h
+#define WebGLActiveInfo_h
+
+#include "core/platform/graphics/GraphicsContext3D.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class WebGLActiveInfo : public RefCounted<WebGLActiveInfo> {
+public:
+    static PassRefPtr<WebGLActiveInfo> create(const String& name, GC3Denum type, GC3Dint size)
+    {
+        return adoptRef(new WebGLActiveInfo(name, type, size));
+    }
+    String name() const { return m_name; }
+    GC3Denum type() const { return m_type; }
+    GC3Dint size() const { return m_size; }
+
+private:
+    WebGLActiveInfo(const String& name, GC3Denum type, GC3Dint size)
+        : m_name(name)
+        , m_type(type)
+        , m_size(size)
+    {
+        ASSERT(name.length());
+        ASSERT(type);
+        ASSERT(size);
+    }
+    String m_name;
+    GC3Denum m_type;
+    GC3Dint m_size;
+};
+
+}
+
+#endif // WebGLActiveInfo_h
diff --git a/Source/core/html/canvas/WebGLActiveInfo.idl b/Source/core/html/canvas/WebGLActiveInfo.idl
new file mode 100644
index 0000000..32ff970
--- /dev/null
+++ b/Source/core/html/canvas/WebGLActiveInfo.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 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. ``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. 
+ */
+
+[
+    Conditional=WEBGL,
+    ImplementationLacksVTable
+] interface WebGLActiveInfo {
+    readonly attribute long size;
+    readonly attribute unsigned long type;
+    readonly attribute DOMString name;
+};
+
diff --git a/Source/core/html/canvas/WebGLBuffer.cpp b/Source/core/html/canvas/WebGLBuffer.cpp
new file mode 100644
index 0000000..9e4bc14
--- /dev/null
+++ b/Source/core/html/canvas/WebGLBuffer.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLBuffer.h"
+
+#include "core/html/canvas/CheckedInt.h"
+#include "core/html/canvas/WebGLContextGroup.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include <wtf/ArrayBufferView.h>
+
+namespace WebCore {
+
+PassRefPtr<WebGLBuffer> WebGLBuffer::create(WebGLRenderingContext* ctx)
+{
+    return adoptRef(new WebGLBuffer(ctx));
+}
+
+WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx)
+    : WebGLSharedObject(ctx)
+    , m_target(0)
+{
+    setObject(ctx->graphicsContext3D()->createBuffer());
+}
+
+WebGLBuffer::~WebGLBuffer()
+{
+    deleteObject(0);
+}
+
+void WebGLBuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
+{
+      context3d->deleteBuffer(object);
+}
+
+void WebGLBuffer::setTarget(GC3Denum target)
+{
+    // In WebGL, a buffer is bound to one target in its lifetime
+    if (m_target)
+        return;
+    if (target == GraphicsContext3D::ARRAY_BUFFER || target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
+        m_target = target;
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLBuffer.h b/Source/core/html/canvas/WebGLBuffer.h
new file mode 100644
index 0000000..a21298f
--- /dev/null
+++ b/Source/core/html/canvas/WebGLBuffer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 WebGLBuffer_h
+#define WebGLBuffer_h
+
+#include "core/html/canvas/WebGLSharedObject.h"
+
+#include <wtf/ArrayBuffer.h>
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WebGLBuffer : public WebGLSharedObject {
+public:
+    virtual ~WebGLBuffer();
+
+    static PassRefPtr<WebGLBuffer> create(WebGLRenderingContext*);
+
+    GC3Denum getTarget() const { return m_target; }
+    void setTarget(GC3Denum);
+
+    bool hasEverBeenBound() const { return object() && m_target; }
+
+protected:
+    WebGLBuffer(WebGLRenderingContext*);
+
+    virtual void deleteObjectImpl(GraphicsContext3D*, Platform3DObject);
+
+private:
+    virtual bool isBuffer() const { return true; }
+
+    GC3Denum m_target;
+};
+
+} // namespace WebCore
+
+#endif // WebGLBuffer_h
diff --git a/Source/core/html/canvas/WebGLBuffer.idl b/Source/core/html/canvas/WebGLBuffer.idl
new file mode 100644
index 0000000..f43cd63
--- /dev/null
+++ b/Source/core/html/canvas/WebGLBuffer.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBGL,
+] interface WebGLBuffer {
+};
diff --git a/Source/core/html/canvas/WebGLCompressedTextureATC.cpp b/Source/core/html/canvas/WebGLCompressedTextureATC.cpp
new file mode 100644
index 0000000..d88f578
--- /dev/null
+++ b/Source/core/html/canvas/WebGLCompressedTextureATC.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2013 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 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 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 "core/html/canvas/WebGLCompressedTextureATC.h"
+
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+WebGLCompressedTextureATC::WebGLCompressedTextureATC(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_ATC_RGB_AMD);
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD);
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD);
+}
+
+WebGLCompressedTextureATC::~WebGLCompressedTextureATC()
+{
+}
+
+WebGLExtension::ExtensionName WebGLCompressedTextureATC::getName() const
+{
+    return WebGLCompressedTextureATCName;
+}
+
+PassOwnPtr<WebGLCompressedTextureATC> WebGLCompressedTextureATC::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new WebGLCompressedTextureATC(context));
+}
+
+bool WebGLCompressedTextureATC::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_AMD_compressed_ATC_texture");
+}
+
+const char* WebGLCompressedTextureATC::getExtensionName()
+{
+    return "WEBGL_compressed_texture_atc";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLCompressedTextureATC.h b/Source/core/html/canvas/WebGLCompressedTextureATC.h
new file mode 100644
index 0000000..0391449
--- /dev/null
+++ b/Source/core/html/canvas/WebGLCompressedTextureATC.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 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 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 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 WebGLCompressedTextureATC_h
+#define WebGLCompressedTextureATC_h
+
+#include "core/dom/ExceptionCode.h"
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebGLTexture;
+
+class WebGLCompressedTextureATC : public WebGLExtension {
+public:
+    static PassOwnPtr<WebGLCompressedTextureATC> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~WebGLCompressedTextureATC();
+    virtual ExtensionName getName() const;
+
+private:
+    WebGLCompressedTextureATC(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // WebGLCompressedTextureATC_h
diff --git a/Source/core/html/canvas/WebGLCompressedTextureATC.idl b/Source/core/html/canvas/WebGLCompressedTextureATC.idl
new file mode 100644
index 0000000..10db90e
--- /dev/null
+++ b/Source/core/html/canvas/WebGLCompressedTextureATC.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface WebGLCompressedTextureATC {
+    /* Compressed Texture Formats */
+    const unsigned long COMPRESSED_RGB_ATC_WEBGL                     = 0x8C92;
+    const unsigned long COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL     = 0x8C93;
+    const unsigned long COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
+};
diff --git a/Source/core/html/canvas/WebGLCompressedTexturePVRTC.cpp b/Source/core/html/canvas/WebGLCompressedTexturePVRTC.cpp
new file mode 100644
index 0000000..8774d58
--- /dev/null
+++ b/Source/core/html/canvas/WebGLCompressedTexturePVRTC.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 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 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 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 "core/html/canvas/WebGLCompressedTexturePVRTC.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+WebGLCompressedTexturePVRTC::WebGLCompressedTexturePVRTC(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_RGB_PVRTC_4BPPV1_IMG);
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_RGB_PVRTC_2BPPV1_IMG);
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_RGBA_PVRTC_4BPPV1_IMG);
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_RGBA_PVRTC_2BPPV1_IMG);
+}
+
+WebGLCompressedTexturePVRTC::~WebGLCompressedTexturePVRTC()
+{
+}
+
+WebGLExtension::ExtensionName WebGLCompressedTexturePVRTC::getName() const
+{
+    return WebGLCompressedTexturePVRTCName;
+}
+
+PassOwnPtr<WebGLCompressedTexturePVRTC> WebGLCompressedTexturePVRTC::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new WebGLCompressedTexturePVRTC(context));
+}
+
+bool WebGLCompressedTexturePVRTC::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_IMG_texture_compression_pvrtc");
+}
+
+const char* WebGLCompressedTexturePVRTC::getExtensionName()
+{
+    return "WEBGL_compressed_texture_pvrtc";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLCompressedTexturePVRTC.h b/Source/core/html/canvas/WebGLCompressedTexturePVRTC.h
new file mode 100644
index 0000000..7109939
--- /dev/null
+++ b/Source/core/html/canvas/WebGLCompressedTexturePVRTC.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 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 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 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 WebGLCompressedTexturePVRTC_h
+#define WebGLCompressedTexturePVRTC_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebGLCompressedTexturePVRTC : public WebGLExtension {
+public:
+    static PassOwnPtr<WebGLCompressedTexturePVRTC> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~WebGLCompressedTexturePVRTC();
+    virtual ExtensionName getName() const;
+
+private:
+    WebGLCompressedTexturePVRTC(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // WebGLCompressedTexturePVRTC_h
diff --git a/Source/core/html/canvas/WebGLCompressedTexturePVRTC.idl b/Source/core/html/canvas/WebGLCompressedTexturePVRTC.idl
new file mode 100644
index 0000000..36e73dc
--- /dev/null
+++ b/Source/core/html/canvas/WebGLCompressedTexturePVRTC.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface WebGLCompressedTexturePVRTC {
+    /* Compressed Texture Formats */
+    const unsigned long COMPRESSED_RGB_PVRTC_4BPPV1_IMG  = 0x8C00;
+    const unsigned long COMPRESSED_RGB_PVRTC_2BPPV1_IMG  = 0x8C01;
+    const unsigned long COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
+    const unsigned long COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;
+};
diff --git a/Source/core/html/canvas/WebGLCompressedTextureS3TC.cpp b/Source/core/html/canvas/WebGLCompressedTextureS3TC.cpp
new file mode 100644
index 0000000..adcb26b
--- /dev/null
+++ b/Source/core/html/canvas/WebGLCompressedTextureS3TC.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 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 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 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 "core/html/canvas/WebGLCompressedTextureS3TC.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+#include <wtf/Int32Array.h>
+#include <wtf/OwnArrayPtr.h>
+
+namespace WebCore {
+
+WebGLCompressedTextureS3TC::WebGLCompressedTextureS3TC(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT);
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT);
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT);
+    context->addCompressedTextureFormat(Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT);
+}
+
+WebGLCompressedTextureS3TC::~WebGLCompressedTextureS3TC()
+{
+}
+
+WebGLExtension::ExtensionName WebGLCompressedTextureS3TC::getName() const
+{
+    return WebGLCompressedTextureS3TCName;
+}
+
+PassOwnPtr<WebGLCompressedTextureS3TC> WebGLCompressedTextureS3TC::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new WebGLCompressedTextureS3TC(context));
+}
+
+bool WebGLCompressedTextureS3TC::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_EXT_texture_compression_s3tc")
+        || (extensions->supports("GL_EXT_texture_compression_dxt1")
+            && extensions->supports("GL_CHROMIUM_texture_compression_dxt3")
+            && extensions->supports("GL_CHROMIUM_texture_compression_dxt5"));
+}
+
+const char* WebGLCompressedTextureS3TC::getExtensionName()
+{
+    return "WEBGL_compressed_texture_s3tc";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLCompressedTextureS3TC.h b/Source/core/html/canvas/WebGLCompressedTextureS3TC.h
new file mode 100644
index 0000000..b2acc95
--- /dev/null
+++ b/Source/core/html/canvas/WebGLCompressedTextureS3TC.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012 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 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 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 WebGLCompressedTextureS3TC_h
+#define WebGLCompressedTextureS3TC_h
+
+#include "core/dom/ExceptionCode.h"
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebGLTexture;
+
+class WebGLCompressedTextureS3TC : public WebGLExtension {
+public:
+    static PassOwnPtr<WebGLCompressedTextureS3TC> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~WebGLCompressedTextureS3TC();
+    virtual ExtensionName getName() const;
+
+private:
+    WebGLCompressedTextureS3TC(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // WebGLCompressedTextureS3TC_h
diff --git a/Source/core/html/canvas/WebGLCompressedTextureS3TC.idl b/Source/core/html/canvas/WebGLCompressedTextureS3TC.idl
new file mode 100644
index 0000000..4e96637
--- /dev/null
+++ b/Source/core/html/canvas/WebGLCompressedTextureS3TC.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface WebGLCompressedTextureS3TC {
+    /* Compressed Texture Formats */
+    const unsigned int COMPRESSED_RGB_S3TC_DXT1_EXT        = 0x83F0;
+    const unsigned int COMPRESSED_RGBA_S3TC_DXT1_EXT       = 0x83F1;
+    const unsigned int COMPRESSED_RGBA_S3TC_DXT3_EXT       = 0x83F2;
+    const unsigned int COMPRESSED_RGBA_S3TC_DXT5_EXT       = 0x83F3;
+};
diff --git a/Source/core/html/canvas/WebGLContextAttributes.cpp b/Source/core/html/canvas/WebGLContextAttributes.cpp
new file mode 100644
index 0000000..374828e
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextAttributes.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLContextAttributes.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLContextAttributes> WebGLContextAttributes::create()
+{
+    return adoptRef(new WebGLContextAttributes());
+}
+
+PassRefPtr<WebGLContextAttributes> WebGLContextAttributes::create(GraphicsContext3D::Attributes attributes)
+{
+    return adoptRef(new WebGLContextAttributes(attributes));
+}
+
+WebGLContextAttributes::WebGLContextAttributes()
+    : CanvasContextAttributes()
+{
+}
+
+WebGLContextAttributes::WebGLContextAttributes(GraphicsContext3D::Attributes attributes)
+    : CanvasContextAttributes()
+    , m_attrs(attributes)
+{
+}
+
+WebGLContextAttributes::~WebGLContextAttributes()
+{
+}
+
+bool WebGLContextAttributes::alpha() const
+{
+    return m_attrs.alpha;
+}
+
+void WebGLContextAttributes::setAlpha(bool alpha)
+{
+    m_attrs.alpha = alpha;
+}
+
+bool WebGLContextAttributes::depth() const
+{
+    return m_attrs.depth;
+}
+
+void WebGLContextAttributes::setDepth(bool depth)
+{
+    m_attrs.depth = depth;
+}
+
+bool WebGLContextAttributes::stencil() const
+{
+    return m_attrs.stencil;
+}
+
+void WebGLContextAttributes::setStencil(bool stencil)
+{
+    m_attrs.stencil = stencil;
+}
+
+bool WebGLContextAttributes::antialias() const
+{
+    return m_attrs.antialias;
+}
+
+void WebGLContextAttributes::setAntialias(bool antialias)
+{
+    m_attrs.antialias = antialias;
+}
+
+bool WebGLContextAttributes::premultipliedAlpha() const
+{
+    return m_attrs.premultipliedAlpha;
+}
+
+void WebGLContextAttributes::setPremultipliedAlpha(bool premultipliedAlpha)
+{
+    m_attrs.premultipliedAlpha = premultipliedAlpha;
+}
+
+bool WebGLContextAttributes::preserveDrawingBuffer() const
+{
+    return m_attrs.preserveDrawingBuffer;
+}
+
+void WebGLContextAttributes::setPreserveDrawingBuffer(bool preserveDrawingBuffer)
+{
+    m_attrs.preserveDrawingBuffer = preserveDrawingBuffer;
+}
+
+GraphicsContext3D::Attributes WebGLContextAttributes::attributes() const
+{
+    return m_attrs;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLContextAttributes.h b/Source/core/html/canvas/WebGLContextAttributes.h
new file mode 100644
index 0000000..414ec00
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextAttributes.h
@@ -0,0 +1,87 @@
+/*
+ * 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 WebGLContextAttributes_h
+#define WebGLContextAttributes_h
+
+#include "core/html/canvas/CanvasContextAttributes.h"
+#include "core/platform/graphics/GraphicsContext3D.h"
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class WebGLContextAttributes : public CanvasContextAttributes {
+  public:
+    virtual ~WebGLContextAttributes();
+
+    // Create a new attributes object
+    static PassRefPtr<WebGLContextAttributes> create();
+
+    // Create a new attributes object initialized with preexisting attributes
+    static PassRefPtr<WebGLContextAttributes> create(GraphicsContext3D::Attributes attributes);
+
+    // Whether or not the drawing buffer has an alpha channel; default=true
+    bool alpha() const;
+    void setAlpha(bool alpha);
+
+    // Whether or not the drawing buffer has a depth buffer; default=true
+    bool depth() const;
+    void setDepth(bool depth);
+
+    // Whether or not the drawing buffer has a stencil buffer; default=true
+    bool stencil() const;
+    void setStencil(bool stencil);
+
+    // Whether or not the drawing buffer is antialiased; default=true
+    bool antialias() const;
+    void setAntialias(bool antialias);
+
+    // Whether or not to treat the values in the drawing buffer as
+    // though their alpha channel has already been multiplied into the
+    // color channels; default=true
+    bool premultipliedAlpha() const;
+    void setPremultipliedAlpha(bool premultipliedAlpha);
+
+    // Whether or not to preserve the drawing buffer after presentation to the
+    // screen; default=false
+    bool preserveDrawingBuffer() const;
+    void setPreserveDrawingBuffer(bool);
+
+    // Fetches a copy of the attributes stored in this object in a
+    // form that can be used to initialize a GraphicsContext3D.
+    GraphicsContext3D::Attributes attributes() const;
+
+  protected:
+    WebGLContextAttributes();
+    WebGLContextAttributes(GraphicsContext3D::Attributes attributes);
+
+  private:
+    GraphicsContext3D::Attributes m_attrs;
+};
+
+} // namespace WebCore
+
+#endif // WebGLContextAttributes_h
diff --git a/Source/core/html/canvas/WebGLContextAttributes.idl b/Source/core/html/canvas/WebGLContextAttributes.idl
new file mode 100644
index 0000000..df45175
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextAttributes.idl
@@ -0,0 +1,36 @@
+/*
+ * 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+[
+    Conditional=WEBGL,
+] interface WebGLContextAttributes {
+    attribute boolean alpha;
+    attribute boolean depth;
+    attribute boolean stencil;
+    attribute boolean antialias;
+    attribute boolean premultipliedAlpha;
+    attribute boolean preserveDrawingBuffer;
+};
diff --git a/Source/core/html/canvas/WebGLContextEvent.cpp b/Source/core/html/canvas/WebGLContextEvent.cpp
new file mode 100644
index 0000000..9d03537
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextEvent.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 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 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 "core/html/canvas/WebGLContextEvent.h"
+
+#include "core/dom/EventNames.h"
+
+namespace WebCore {
+
+WebGLContextEventInit::WebGLContextEventInit()
+{
+}
+
+WebGLContextEvent::WebGLContextEvent()
+{
+    ScriptWrappable::init(this);
+}
+
+WebGLContextEvent::WebGLContextEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& statusMessage)
+    : Event(type, canBubble, cancelable)
+    , m_statusMessage(statusMessage)
+{
+    ScriptWrappable::init(this);
+}
+
+WebGLContextEvent::WebGLContextEvent(const AtomicString& type, const WebGLContextEventInit& initializer)
+    : Event(type, initializer)
+    , m_statusMessage(initializer.statusMessage)
+{
+    ScriptWrappable::init(this);
+}
+
+WebGLContextEvent::~WebGLContextEvent()
+{
+}
+
+const AtomicString& WebGLContextEvent::interfaceName() const
+{
+    return eventNames().interfaceForWebGLContextEvent;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLContextEvent.h b/Source/core/html/canvas/WebGLContextEvent.h
new file mode 100644
index 0000000..c5b0078
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextEvent.h
@@ -0,0 +1,69 @@
+/*
+ * 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 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 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 WebGLContextEvent_h
+#define WebGLContextEvent_h
+
+#include "core/dom/Event.h"
+
+namespace WebCore {
+
+struct WebGLContextEventInit : public EventInit {
+    WebGLContextEventInit();
+
+    String statusMessage;
+};
+
+class WebGLContextEvent : public Event {
+public:
+    static PassRefPtr<WebGLContextEvent> create()
+    {
+        return adoptRef(new WebGLContextEvent);
+    }
+    static PassRefPtr<WebGLContextEvent> create(const AtomicString& type, bool canBubble, bool cancelable, const String& statusMessage)
+    {
+        return adoptRef(new WebGLContextEvent(type, canBubble, cancelable, statusMessage));
+    }
+    static PassRefPtr<WebGLContextEvent> create(const AtomicString& type, const WebGLContextEventInit& initializer)
+    {
+        return adoptRef(new WebGLContextEvent(type, initializer));
+    }
+    virtual ~WebGLContextEvent();
+
+    const String& statusMessage() const { return m_statusMessage; }
+
+    virtual const AtomicString& interfaceName() const;
+
+private:
+    WebGLContextEvent();
+    WebGLContextEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& statusMessage);
+    WebGLContextEvent(const AtomicString&, const WebGLContextEventInit&);
+
+    String m_statusMessage;
+};
+
+} // namespace WebCore
+
+#endif // WebGLContextEvent_h
diff --git a/Source/core/html/canvas/WebGLContextEvent.idl b/Source/core/html/canvas/WebGLContextEvent.idl
new file mode 100644
index 0000000..c3eba10
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextEvent.idl
@@ -0,0 +1,32 @@
+/*
+ * 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+    ConstructorTemplate=Event
+] interface WebGLContextEvent : Event {
+    [InitializedByEventConstructor] readonly attribute DOMString statusMessage;
+};
+
diff --git a/Source/core/html/canvas/WebGLContextGroup.cpp b/Source/core/html/canvas/WebGLContextGroup.cpp
new file mode 100644
index 0000000..b51db1b
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextGroup.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLContextGroup.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include "core/html/canvas/WebGLSharedObject.h"
+#include "core/platform/graphics/GraphicsContext3D.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLContextGroup> WebGLContextGroup::create()
+{
+    RefPtr<WebGLContextGroup> contextGroup = adoptRef(new WebGLContextGroup());
+    return contextGroup.release();
+}
+
+WebGLContextGroup::WebGLContextGroup()
+{
+}
+
+WebGLContextGroup::~WebGLContextGroup()
+{
+    detachAndRemoveAllObjects();
+}
+
+GraphicsContext3D* WebGLContextGroup::getAGraphicsContext3D()
+{
+    ASSERT(!m_contexts.isEmpty());
+    HashSet<WebGLRenderingContext*>::iterator it = m_contexts.begin();
+    return (*it)->graphicsContext3D();
+}
+
+void WebGLContextGroup::addContext(WebGLRenderingContext* context)
+{
+    m_contexts.add(context);
+}
+
+void WebGLContextGroup::removeContext(WebGLRenderingContext* context)
+{
+    // We must call detachAndRemoveAllObjects before removing the last context.
+    if (m_contexts.size() == 1 && m_contexts.contains(context))
+        detachAndRemoveAllObjects();
+
+    m_contexts.remove(context);
+}
+
+void WebGLContextGroup::removeObject(WebGLSharedObject* object)
+{
+    m_groupObjects.remove(object);
+}
+
+void WebGLContextGroup::addObject(WebGLSharedObject* object)
+{
+    m_groupObjects.add(object);
+}
+
+void WebGLContextGroup::detachAndRemoveAllObjects()
+{
+    while (!m_groupObjects.isEmpty()) {
+        HashSet<WebGLSharedObject*>::iterator it = m_groupObjects.begin();
+        (*it)->detachContextGroup();
+    }
+}
+
+void WebGLContextGroup::loseContextGroup(WebGLRenderingContext::LostContextMode mode)
+{
+    for (HashSet<WebGLRenderingContext*>::iterator it = m_contexts.begin(); it != m_contexts.end(); ++it)
+        (*it)->loseContextImpl(mode);
+
+    detachAndRemoveAllObjects();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLContextGroup.h b/Source/core/html/canvas/WebGLContextGroup.h
new file mode 100644
index 0000000..e888083
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextGroup.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 WebGLContextGroup_h
+#define WebGLContextGroup_h
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class GraphicsContext3D;
+class WebGLExtension;
+class WebGLSharedObject;
+class WebGLRenderingContext;
+
+typedef int ExceptionCode;
+
+class WebGLContextGroup : public RefCounted<WebGLContextGroup> {
+public:
+    static PassRefPtr<WebGLContextGroup> create();
+    virtual ~WebGLContextGroup();
+
+    void addContext(WebGLRenderingContext*);
+    void removeContext(WebGLRenderingContext*);
+
+    void addObject(WebGLSharedObject*);
+    void removeObject(WebGLSharedObject*);
+
+    GraphicsContext3D* getAGraphicsContext3D();
+
+    void loseContextGroup(WebGLRenderingContext::LostContextMode);
+
+  private:
+    friend class WebGLObject;
+
+    WebGLContextGroup();
+
+    void detachAndRemoveAllObjects();
+
+    HashSet<WebGLRenderingContext*> m_contexts;
+    HashSet<WebGLSharedObject*> m_groupObjects;
+};
+
+} // namespace WebCore
+
+#endif // WebGLContextGroup_h
diff --git a/Source/core/html/canvas/WebGLContextObject.cpp b/Source/core/html/canvas/WebGLContextObject.cpp
new file mode 100644
index 0000000..ea718c5
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextObject.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLContextObject.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+WebGLContextObject::WebGLContextObject(WebGLRenderingContext* context)
+    : WebGLObject(context)
+    , m_context(context)
+{
+}
+
+WebGLContextObject::~WebGLContextObject()
+{
+    if (m_context)
+        m_context->removeContextObject(this);
+}
+
+void WebGLContextObject::detachContext()
+{
+    detach();
+    if (m_context) {
+        deleteObject(m_context->graphicsContext3D());
+        m_context->removeContextObject(this);
+        m_context = 0;
+    }
+}
+
+GraphicsContext3D* WebGLContextObject::getAGraphicsContext3D() const
+{
+    return m_context ? m_context->graphicsContext3D() : 0;
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLContextObject.h b/Source/core/html/canvas/WebGLContextObject.h
new file mode 100644
index 0000000..b894008
--- /dev/null
+++ b/Source/core/html/canvas/WebGLContextObject.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 WebGLContextObject_h
+#define WebGLContextObject_h
+
+#include "core/html/canvas/WebGLObject.h"
+#include "core/platform/graphics/GraphicsContext3D.h"
+
+namespace WebCore {
+
+class GraphicsContext3D;
+class WebGLRenderingContext;
+
+// WebGLContextObject the base class for objects that are owned by a specific
+// WebGLRenderingContext.
+class WebGLContextObject : public WebGLObject {
+public:
+    virtual ~WebGLContextObject();
+
+    WebGLRenderingContext* context() const { return m_context; }
+
+    virtual bool validate(const WebGLContextGroup*, const WebGLRenderingContext* context) const
+    {
+        return context == m_context;
+    }
+
+    void detachContext();
+
+protected:
+    WebGLContextObject(WebGLRenderingContext*);
+
+    virtual bool hasGroupOrContext() const
+    {
+        return m_context;
+    }
+
+    virtual GraphicsContext3D* getAGraphicsContext3D() const;
+
+private:
+    WebGLRenderingContext* m_context;
+};
+
+} // namespace WebCore
+
+#endif // WebGLContextObject_h
diff --git a/Source/core/html/canvas/WebGLDebugRendererInfo.cpp b/Source/core/html/canvas/WebGLDebugRendererInfo.cpp
new file mode 100644
index 0000000..44672d6
--- /dev/null
+++ b/Source/core/html/canvas/WebGLDebugRendererInfo.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 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 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 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 "core/html/canvas/WebGLDebugRendererInfo.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+WebGLDebugRendererInfo::WebGLDebugRendererInfo(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+}
+
+WebGLDebugRendererInfo::~WebGLDebugRendererInfo()
+{
+}
+
+WebGLExtension::ExtensionName WebGLDebugRendererInfo::getName() const
+{
+    return WebGLDebugRendererInfoName;
+}
+
+PassOwnPtr<WebGLDebugRendererInfo> WebGLDebugRendererInfo::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new WebGLDebugRendererInfo(context));
+}
+
+bool WebGLDebugRendererInfo::supported(WebGLRenderingContext*)
+{
+    return true;
+}
+
+const char* WebGLDebugRendererInfo::getExtensionName()
+{
+    return "WEBGL_debug_renderer_info";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLDebugRendererInfo.h b/Source/core/html/canvas/WebGLDebugRendererInfo.h
new file mode 100644
index 0000000..f9590c1
--- /dev/null
+++ b/Source/core/html/canvas/WebGLDebugRendererInfo.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 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 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 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 WebGLDebugRendererInfo_h
+#define WebGLDebugRendererInfo_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebGLDebugRendererInfo : public WebGLExtension {
+public:
+    enum EnumType {
+        UNMASKED_VENDOR_WEBGL = 0x9245,
+        UNMASKED_RENDERER_WEBGL = 0x9246
+    };
+
+    static PassOwnPtr<WebGLDebugRendererInfo> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~WebGLDebugRendererInfo();
+    virtual ExtensionName getName() const;
+
+private:
+    WebGLDebugRendererInfo(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // WebGLDebugRendererInfo_h
diff --git a/Source/core/html/canvas/WebGLDebugRendererInfo.idl b/Source/core/html/canvas/WebGLDebugRendererInfo.idl
new file mode 100644
index 0000000..bd37ddb
--- /dev/null
+++ b/Source/core/html/canvas/WebGLDebugRendererInfo.idl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface WebGLDebugRendererInfo {
+    const unsigned long UNMASKED_VENDOR_WEBGL = 0x9245;
+    const unsigned long UNMASKED_RENDERER_WEBGL = 0x9246;
+};
diff --git a/Source/core/html/canvas/WebGLDebugShaders.cpp b/Source/core/html/canvas/WebGLDebugShaders.cpp
new file mode 100644
index 0000000..60cc55a
--- /dev/null
+++ b/Source/core/html/canvas/WebGLDebugShaders.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 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 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 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 "core/html/canvas/WebGLDebugShaders.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include "core/html/canvas/WebGLShader.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+#include <wtf/OwnArrayPtr.h>
+
+namespace WebCore {
+
+WebGLDebugShaders::WebGLDebugShaders(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+}
+
+WebGLDebugShaders::~WebGLDebugShaders()
+{
+}
+
+WebGLExtension::ExtensionName WebGLDebugShaders::getName() const
+{
+    return WebGLDebugShadersName;
+}
+
+PassOwnPtr<WebGLDebugShaders> WebGLDebugShaders::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new WebGLDebugShaders(context));
+}
+
+String WebGLDebugShaders::getTranslatedShaderSource(WebGLShader* shader, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (m_context->isContextLost())
+        return String();
+    if (!m_context->validateWebGLObject("getTranslatedShaderSource", shader))
+        return "";
+    return m_context->graphicsContext3D()->getExtensions()->getTranslatedShaderSourceANGLE(shader->object());
+}
+
+bool WebGLDebugShaders::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_ANGLE_translated_shader_source");
+}
+
+const char* WebGLDebugShaders::getExtensionName()
+{
+    return "WEBGL_debug_shaders";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLDebugShaders.h b/Source/core/html/canvas/WebGLDebugShaders.h
new file mode 100644
index 0000000..1583b93
--- /dev/null
+++ b/Source/core/html/canvas/WebGLDebugShaders.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 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 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 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 WebGLDebugShaders_h
+#define WebGLDebugShaders_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebGLShader;
+
+typedef int ExceptionCode;
+
+class WebGLDebugShaders : public WebGLExtension {
+public:
+    static PassOwnPtr<WebGLDebugShaders> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~WebGLDebugShaders();
+    virtual ExtensionName getName() const;
+
+    String getTranslatedShaderSource(WebGLShader*, ExceptionCode&);
+
+private:
+    WebGLDebugShaders(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // WebGLDebugShaders_h
diff --git a/Source/core/html/canvas/WebGLDebugShaders.idl b/Source/core/html/canvas/WebGLDebugShaders.idl
new file mode 100644
index 0000000..59e0cdd
--- /dev/null
+++ b/Source/core/html/canvas/WebGLDebugShaders.idl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+] interface WebGLDebugShaders {
+    [StrictTypeChecking, TreatReturnedNullStringAs=Null, RaisesException] DOMString getTranslatedShaderSource(WebGLShader shader);
+};
diff --git a/Source/core/html/canvas/WebGLDepthTexture.cpp b/Source/core/html/canvas/WebGLDepthTexture.cpp
new file mode 100644
index 0000000..a15e91a
--- /dev/null
+++ b/Source/core/html/canvas/WebGLDepthTexture.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 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 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 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 "core/html/canvas/WebGLDepthTexture.h"
+
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+WebGLDepthTexture::WebGLDepthTexture(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_CHROMIUM_depth_texture");
+}
+
+WebGLDepthTexture::~WebGLDepthTexture()
+{
+}
+
+WebGLExtension::ExtensionName WebGLDepthTexture::getName() const
+{
+    return WebGLDepthTextureName;
+}
+
+PassOwnPtr<WebGLDepthTexture> WebGLDepthTexture::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new WebGLDepthTexture(context));
+}
+
+bool WebGLDepthTexture::supported(WebGLRenderingContext* context)
+{
+    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
+    return extensions->supports("GL_CHROMIUM_depth_texture")
+        || extensions->supports("GL_OES_depth_texture")
+        || extensions->supports("GL_ARB_depth_texture");
+}
+
+const char* WebGLDepthTexture::getExtensionName()
+{
+    return "WEBGL_depth_texture";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLDepthTexture.h b/Source/core/html/canvas/WebGLDepthTexture.h
new file mode 100644
index 0000000..7573b1a
--- /dev/null
+++ b/Source/core/html/canvas/WebGLDepthTexture.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 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 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 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 WebGLDepthTexture_h
+#define WebGLDepthTexture_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebGLDepthTexture : public WebGLExtension {
+public:
+    static PassOwnPtr<WebGLDepthTexture> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~WebGLDepthTexture();
+    virtual ExtensionName getName() const;
+
+private:
+    WebGLDepthTexture(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // WebGLDepthTexture_h
diff --git a/Source/core/html/canvas/WebGLDepthTexture.idl b/Source/core/html/canvas/WebGLDepthTexture.idl
new file mode 100644
index 0000000..84f3acd
--- /dev/null
+++ b/Source/core/html/canvas/WebGLDepthTexture.idl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface WebGLDepthTexture {
+    const unsigned long UNSIGNED_INT_24_8_WEBGL = 0x84FA;
+};
diff --git a/Source/core/html/canvas/WebGLExtension.cpp b/Source/core/html/canvas/WebGLExtension.cpp
new file mode 100644
index 0000000..9d3c941
--- /dev/null
+++ b/Source/core/html/canvas/WebGLExtension.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 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 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 "core/html/canvas/WebGLExtension.h"
+
+namespace WebCore {
+
+WebGLExtension::WebGLExtension(WebGLRenderingContext* context)
+    : m_context(context)
+{
+}
+
+WebGLExtension::~WebGLExtension()
+{
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLExtension.h b/Source/core/html/canvas/WebGLExtension.h
new file mode 100644
index 0000000..2a481e0
--- /dev/null
+++ b/Source/core/html/canvas/WebGLExtension.h
@@ -0,0 +1,68 @@
+/*
+ * 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 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 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 WebGLExtension_h
+#define WebGLExtension_h
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+class WebGLExtension {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    // Extension names are needed to properly wrap instances in JavaScript objects.
+    enum ExtensionName {
+        WebGLLoseContextName,
+        EXTDrawBuffersName,
+        EXTTextureFilterAnisotropicName,
+        OESTextureFloatName,
+        OESTextureHalfFloatName,
+        OESStandardDerivativesName,
+        OESVertexArrayObjectName,
+        WebGLDebugRendererInfoName,
+        WebGLDebugShadersName,
+        WebGLCompressedTextureS3TCName,
+        WebGLDepthTextureName,
+        OESElementIndexUintName,
+        WebGLCompressedTextureATCName,
+        WebGLCompressedTexturePVRTCName,
+    };
+
+    void ref() { m_context->ref(); }
+    void deref() { m_context->deref(); }
+    WebGLRenderingContext* context() { return m_context; }
+
+    virtual ~WebGLExtension();
+    virtual ExtensionName getName() const = 0;
+
+protected:
+    WebGLExtension(WebGLRenderingContext*);
+    WebGLRenderingContext* m_context;
+};
+
+} // namespace WebCore
+
+#endif // WebGLExtension_h
diff --git a/Source/core/html/canvas/WebGLFramebuffer.cpp b/Source/core/html/canvas/WebGLFramebuffer.cpp
new file mode 100644
index 0000000..ddcaa6e
--- /dev/null
+++ b/Source/core/html/canvas/WebGLFramebuffer.cpp
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLFramebuffer.h"
+
+#include "core/html/canvas/EXTDrawBuffers.h"
+#include "core/html/canvas/WebGLContextGroup.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+namespace {
+
+    Platform3DObject objectOrZero(WebGLObject* object)
+    {
+        return object ? object->object() : 0;
+    }
+
+    class WebGLRenderbufferAttachment : public WebGLFramebuffer::WebGLAttachment {
+    public:
+        static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*);
+
+    private:
+        WebGLRenderbufferAttachment(WebGLRenderbuffer*);
+        virtual GC3Dsizei getWidth() const;
+        virtual GC3Dsizei getHeight() const;
+        virtual GC3Denum getFormat() const;
+        virtual WebGLSharedObject* getObject() const;
+        virtual bool isSharedObject(WebGLSharedObject*) const;
+        virtual bool isValid() const;
+        virtual bool isInitialized() const;
+        virtual void setInitialized();
+        virtual void onDetached(GraphicsContext3D*);
+        virtual void attach(GraphicsContext3D*, GC3Denum attachment);
+        virtual void unattach(GraphicsContext3D*, GC3Denum attachment);
+
+        WebGLRenderbufferAttachment() { };
+
+        RefPtr<WebGLRenderbuffer> m_renderbuffer;
+    };
+
+    PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer)
+    {
+        return adoptRef(new WebGLRenderbufferAttachment(renderbuffer));
+    }
+
+    WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer)
+        : m_renderbuffer(renderbuffer)
+    {
+    }
+
+    GC3Dsizei WebGLRenderbufferAttachment::getWidth() const
+    {
+        return m_renderbuffer->getWidth();
+    }
+
+    GC3Dsizei WebGLRenderbufferAttachment::getHeight() const
+    {
+        return m_renderbuffer->getHeight();
+    }
+
+    GC3Denum WebGLRenderbufferAttachment::getFormat() const
+    {
+        return m_renderbuffer->getInternalFormat();
+    }
+
+    WebGLSharedObject* WebGLRenderbufferAttachment::getObject() const
+    {
+        return m_renderbuffer->object() ? m_renderbuffer.get() : 0;
+    }
+
+    bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const
+    {
+        return object == m_renderbuffer;
+    }
+
+    bool WebGLRenderbufferAttachment::isValid() const
+    {
+        return m_renderbuffer->object();
+    }
+
+    bool WebGLRenderbufferAttachment::isInitialized() const
+    {
+        return m_renderbuffer->object() && m_renderbuffer->isInitialized();
+    }
+
+    void WebGLRenderbufferAttachment::setInitialized()
+    {
+        if (m_renderbuffer->object())
+            m_renderbuffer->setInitialized();
+    }
+
+    void WebGLRenderbufferAttachment::onDetached(GraphicsContext3D* context)
+    {
+        m_renderbuffer->onDetached(context);
+    }
+
+    void WebGLRenderbufferAttachment::attach(GraphicsContext3D* context, GC3Denum attachment)
+    {
+        Platform3DObject object = objectOrZero(m_renderbuffer.get());
+        context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, object);
+    }
+
+    void WebGLRenderbufferAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment)
+    {
+        if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) {
+            context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
+            context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
+        } else
+            context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, 0);
+    }
+
+    class WebGLTextureAttachment : public WebGLFramebuffer::WebGLAttachment {
+    public:
+        static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GC3Denum target, GC3Dint level);
+
+    private:
+        WebGLTextureAttachment(WebGLTexture*, GC3Denum target, GC3Dint level);
+        virtual GC3Dsizei getWidth() const;
+        virtual GC3Dsizei getHeight() const;
+        virtual GC3Denum getFormat() const;
+        virtual WebGLSharedObject* getObject() const;
+        virtual bool isSharedObject(WebGLSharedObject*) const;
+        virtual bool isValid() const;
+        virtual bool isInitialized() const;
+        virtual void setInitialized();
+        virtual void onDetached(GraphicsContext3D*);
+        virtual void attach(GraphicsContext3D*, GC3Denum attachment);
+        virtual void unattach(GraphicsContext3D*, GC3Denum attachment);
+
+        WebGLTextureAttachment() { };
+
+        RefPtr<WebGLTexture> m_texture;
+        GC3Denum m_target;
+        GC3Dint m_level;
+    };
+
+    PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GC3Denum target, GC3Dint level)
+    {
+        return adoptRef(new WebGLTextureAttachment(texture, target, level));
+    }
+
+    WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GC3Denum target, GC3Dint level)
+        : m_texture(texture)
+        , m_target(target)
+        , m_level(level)
+    {
+    }
+
+    GC3Dsizei WebGLTextureAttachment::getWidth() const
+    {
+        return m_texture->getWidth(m_target, m_level);
+    }
+
+    GC3Dsizei WebGLTextureAttachment::getHeight() const
+    {
+        return m_texture->getHeight(m_target, m_level);
+    }
+
+    GC3Denum WebGLTextureAttachment::getFormat() const
+    {
+        return m_texture->getInternalFormat(m_target, m_level);
+    }
+
+    WebGLSharedObject* WebGLTextureAttachment::getObject() const
+    {
+        return m_texture->object() ? m_texture.get() : 0;
+    }
+
+    bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const
+    {
+        return object == m_texture;
+    }
+
+    bool WebGLTextureAttachment::isValid() const
+    {
+        return m_texture->object();
+    }
+
+    bool WebGLTextureAttachment::isInitialized() const
+    {
+        // Textures are assumed to be initialized.
+        return true;
+    }
+
+    void WebGLTextureAttachment::setInitialized()
+    {
+        // Textures are assumed to be initialized.
+    }
+
+    void WebGLTextureAttachment::onDetached(GraphicsContext3D* context)
+    {
+        m_texture->onDetached(context);
+    }
+
+    void WebGLTextureAttachment::attach(GraphicsContext3D* context, GC3Denum attachment)
+    {
+        Platform3DObject object = objectOrZero(m_texture.get());
+        context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, object, m_level);
+    }
+
+    void WebGLTextureAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment)
+    {
+        if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) {
+            context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, m_target, 0, m_level);
+            context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, m_target, 0, m_level);
+        } else
+            context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, 0, m_level);
+    }
+
+    bool isAttachmentComplete(WebGLFramebuffer::WebGLAttachment* attachedObject, GC3Denum attachment, const char** reason)
+    {
+        ASSERT(attachedObject && attachedObject->isValid());
+        ASSERT(reason);
+        GC3Denum format = attachedObject->getFormat();
+        unsigned need = GraphicsContext3D::getClearBitsByAttachmentType(attachment);
+        unsigned have = GraphicsContext3D::getClearBitsByFormat(format);
+
+        if ((need & have) != need) {
+            *reason = "attachment type is not correct for attachment";
+            return false;
+        }
+        if (!attachedObject->getWidth() || !attachedObject->getHeight()) {
+            *reason = "attachment has a 0 dimension";
+            return false;
+        }
+        if ((attachment == GraphicsContext3D::DEPTH_ATTACHMENT || attachment == GraphicsContext3D::STENCIL_ATTACHMENT)
+            && format == GraphicsContext3D::DEPTH_STENCIL) {
+          *reason = "attachment DEPTH_STENCIL not allowed on DEPTH or STENCIL attachment";
+          return false;
+        }
+        return true;
+    }
+
+} // anonymous namespace
+
+WebGLFramebuffer::WebGLAttachment::WebGLAttachment()
+{
+}
+
+WebGLFramebuffer::WebGLAttachment::~WebGLAttachment()
+{
+}
+
+PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx)
+{
+    return adoptRef(new WebGLFramebuffer(ctx));
+}
+
+WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx)
+    : WebGLContextObject(ctx)
+    , m_hasEverBeenBound(false)
+{
+    setObject(ctx->graphicsContext3D()->createFramebuffer());
+}
+
+WebGLFramebuffer::~WebGLFramebuffer()
+{
+    deleteObject(0);
+}
+
+void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, GC3Denum texTarget, WebGLTexture* texture, GC3Dint level)
+{
+    ASSERT(isBound());
+    removeAttachmentFromBoundFramebuffer(attachment);
+    if (!object())
+        return;
+    if (texture && texture->object()) {
+        m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level));
+        drawBuffersIfNecessary(false);
+        texture->onAttached();
+    }
+}
+
+void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, WebGLRenderbuffer* renderbuffer)
+{
+    ASSERT(isBound());
+    removeAttachmentFromBoundFramebuffer(attachment);
+    if (!object())
+        return;
+    if (renderbuffer && renderbuffer->object()) {
+        m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer));
+        drawBuffersIfNecessary(false);
+        renderbuffer->onAttached();
+    }
+}
+
+void WebGLFramebuffer::attach(GC3Denum attachment, GC3Denum attachmentPoint)
+{
+    ASSERT(isBound());
+    WebGLAttachment* attachmentObject = getAttachment(attachment);
+    if (attachmentObject)
+        attachmentObject->attach(context()->graphicsContext3D(), attachmentPoint);
+}
+
+WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GC3Denum attachment) const
+{
+    if (!object())
+        return 0;
+    WebGLAttachment* attachmentObject = getAttachment(attachment);
+    return attachmentObject ? attachmentObject->getObject() : 0;
+}
+
+WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GC3Denum attachment) const
+{
+    const AttachmentMap::const_iterator it = m_attachments.find(attachment);
+    return (it != m_attachments.end()) ? it->value.get() : 0;
+}
+
+void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GC3Denum attachment)
+{
+    ASSERT(isBound());
+    if (!object())
+        return;
+
+    WebGLAttachment* attachmentObject = getAttachment(attachment);
+    if (attachmentObject) {
+        attachmentObject->onDetached(context()->graphicsContext3D());
+        m_attachments.remove(attachment);
+        drawBuffersIfNecessary(false);
+        switch (attachment) {
+        case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+            attach(GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT);
+            attach(GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT);
+            break;
+        case GraphicsContext3D::DEPTH_ATTACHMENT:
+            attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT);
+            break;
+        case GraphicsContext3D::STENCIL_ATTACHMENT:
+            attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT);
+            break;
+        }
+    }
+}
+
+void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment)
+{
+    ASSERT(isBound());
+    if (!object())
+        return;
+    if (!attachment)
+        return;
+
+    bool checkMore = true;
+    while (checkMore) {
+        checkMore = false;
+        for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
+            WebGLAttachment* attachmentObject = it->value.get();
+            if (attachmentObject->isSharedObject(attachment)) {
+                GC3Denum attachmentType = it->key;
+                attachmentObject->unattach(context()->graphicsContext3D(), attachmentType);
+                removeAttachmentFromBoundFramebuffer(attachmentType);
+                checkMore = true;
+                break;
+            }
+        }
+    }
+}
+
+GC3Dsizei WebGLFramebuffer::getColorBufferWidth() const
+{
+    if (!object())
+        return 0;
+    WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
+    if (!attachment)
+        return 0;
+
+    return attachment->getWidth();
+}
+
+GC3Dsizei WebGLFramebuffer::getColorBufferHeight() const
+{
+    if (!object())
+        return 0;
+    WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
+    if (!attachment)
+        return 0;
+
+    return attachment->getHeight();
+}
+
+GC3Denum WebGLFramebuffer::getColorBufferFormat() const
+{
+    if (!object())
+        return 0;
+    WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
+    if (!attachment)
+        return 0;
+    return attachment->getFormat();
+}
+
+GC3Denum WebGLFramebuffer::checkStatus(const char** reason) const
+{
+    unsigned int count = 0;
+    GC3Dsizei width = 0, height = 0;
+    bool haveDepth = false;
+    bool haveStencil = false;
+    bool haveDepthStencil = false;
+    for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
+        WebGLAttachment* attachment = it->value.get();
+        if (!isAttachmentComplete(attachment, it->key, reason))
+            return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+        if (!attachment->isValid()) {
+            *reason = "attachment is not valid";
+            return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
+        }
+        if (!attachment->getFormat()) {
+            *reason = "attachment is an unsupported format";
+            return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+        }
+        switch (it->key) {
+        case GraphicsContext3D::DEPTH_ATTACHMENT:
+            haveDepth = true;
+            break;
+        case GraphicsContext3D::STENCIL_ATTACHMENT:
+            haveStencil = true;
+            break;
+        case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+            haveDepthStencil = true;
+            break;
+        }
+        if (!count) {
+            width = attachment->getWidth();
+            height = attachment->getHeight();
+        } else {
+            if (width != attachment->getWidth() || height != attachment->getHeight()) {
+                *reason = "attachments do not have the same dimensions";
+                return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+            }
+        }
+        ++count;
+    }
+    if (!count) {
+        *reason = "no attachments";
+        return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+    }
+    if (!width || !height) {
+        *reason = "framebuffer has a 0 dimension";
+        return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+    }
+    // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
+    if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
+        *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
+        return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
+    }
+    return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
+}
+
+bool WebGLFramebuffer::onAccess(GraphicsContext3D* context3d, const char** reason)
+{
+    if (checkStatus(reason) != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
+        return false;
+    return true;
+}
+
+bool WebGLFramebuffer::hasStencilBuffer() const
+{
+    WebGLAttachment* attachment = getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT);
+    if (!attachment)
+        attachment = getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT);
+    return attachment && attachment->isValid();
+}
+
+void WebGLFramebuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
+{
+    for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it)
+        it->value->onDetached(context3d);
+
+    context3d->deleteFramebuffer(object);
+}
+
+bool WebGLFramebuffer::isBound() const
+{
+    return (context()->m_framebufferBinding.get() == this);
+}
+
+void WebGLFramebuffer::drawBuffers(const Vector<GC3Denum>& bufs)
+{
+    m_drawBuffers = bufs;
+    m_filteredDrawBuffers.resize(m_drawBuffers.size());
+    for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i)
+        m_filteredDrawBuffers[i] = GraphicsContext3D::NONE;
+    drawBuffersIfNecessary(true);
+}
+
+void WebGLFramebuffer::drawBuffersIfNecessary(bool force)
+{
+    if (!context()->m_extDrawBuffers)
+        return;
+    bool reset = force;
+    // This filtering works around graphics driver bugs on Mac OS X.
+    for (size_t i = 0; i < m_drawBuffers.size(); ++i) {
+        if (m_drawBuffers[i] != GraphicsContext3D::NONE && getAttachment(m_drawBuffers[i])) {
+            if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) {
+                m_filteredDrawBuffers[i] = m_drawBuffers[i];
+                reset = true;
+            }
+        } else {
+            if (m_filteredDrawBuffers[i] != GraphicsContext3D::NONE) {
+                m_filteredDrawBuffers[i] = GraphicsContext3D::NONE;
+                reset = true;
+            }
+        }
+    }
+    if (reset) {
+        context()->graphicsContext3D()->getExtensions()->drawBuffersEXT(
+            m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data());
+    }
+}
+
+GC3Denum WebGLFramebuffer::getDrawBuffer(GC3Denum drawBuffer)
+{
+    int index = static_cast<int>(drawBuffer - Extensions3D::DRAW_BUFFER0_EXT);
+    ASSERT(index >= 0);
+    if (index < static_cast<int>(m_drawBuffers.size()))
+        return m_drawBuffers[index];
+    if (drawBuffer == Extensions3D::DRAW_BUFFER0_EXT)
+        return GraphicsContext3D::COLOR_ATTACHMENT0;
+    return GraphicsContext3D::NONE;
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLFramebuffer.h b/Source/core/html/canvas/WebGLFramebuffer.h
new file mode 100644
index 0000000..987b680
--- /dev/null
+++ b/Source/core/html/canvas/WebGLFramebuffer.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 WebGLFramebuffer_h
+#define WebGLFramebuffer_h
+
+#include "core/html/canvas/WebGLContextObject.h"
+#include "core/html/canvas/WebGLSharedObject.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WebGLRenderbuffer;
+class WebGLTexture;
+
+class WebGLFramebuffer : public WebGLContextObject {
+public:
+    class WebGLAttachment : public RefCounted<WebGLAttachment> {
+    public:
+        virtual ~WebGLAttachment();
+
+        virtual GC3Dsizei getWidth() const = 0;
+        virtual GC3Dsizei getHeight() const = 0;
+        virtual GC3Denum getFormat() const = 0;
+        virtual WebGLSharedObject* getObject() const = 0;
+        virtual bool isSharedObject(WebGLSharedObject*) const = 0;
+        virtual bool isValid() const = 0;
+        virtual bool isInitialized() const = 0;
+        virtual void setInitialized() = 0;
+        virtual void onDetached(GraphicsContext3D*) = 0;
+        virtual void attach(GraphicsContext3D*, GC3Denum attachment) = 0;
+        virtual void unattach(GraphicsContext3D*, GC3Denum attachment) = 0;
+
+    protected:
+        WebGLAttachment();
+    };
+
+    virtual ~WebGLFramebuffer();
+
+    static PassRefPtr<WebGLFramebuffer> create(WebGLRenderingContext*);
+
+    void setAttachmentForBoundFramebuffer(GC3Denum attachment, GC3Denum texTarget, WebGLTexture*, GC3Dint level);
+    void setAttachmentForBoundFramebuffer(GC3Denum attachment, WebGLRenderbuffer*);
+    // If an object is attached to the currently bound framebuffer, remove it.
+    void removeAttachmentFromBoundFramebuffer(WebGLSharedObject*);
+    // If a given attachment point for the currently bound framebuffer is not null, remove the attached object.
+    void removeAttachmentFromBoundFramebuffer(GC3Denum);
+    WebGLSharedObject* getAttachmentObject(GC3Denum) const;
+
+    GC3Denum getColorBufferFormat() const;
+    GC3Dsizei getColorBufferWidth() const;
+    GC3Dsizei getColorBufferHeight() const;
+
+    // This should always be called before drawArray, drawElements, clear,
+    // readPixels, copyTexImage2D, copyTexSubImage2D if this framebuffer is
+    // currently bound.
+    // Return false if the framebuffer is incomplete; otherwise initialize
+    // the buffers if they haven't been initialized and
+    // needToInitializeAttachments is true.
+    bool onAccess(GraphicsContext3D*, const char** reason);
+
+    // Software version of glCheckFramebufferStatus(), except that when
+    // FRAMEBUFFER_COMPLETE is returned, it is still possible for
+    // glCheckFramebufferStatus() to return FRAMEBUFFER_UNSUPPORTED,
+    // depending on hardware implementation.
+    GC3Denum checkStatus(const char** reason) const;
+
+    bool hasEverBeenBound() const { return object() && m_hasEverBeenBound; }
+
+    void setHasEverBeenBound() { m_hasEverBeenBound = true; }
+
+    bool hasStencilBuffer() const;
+
+    // Wrapper for drawBuffersEXT/drawBuffersARB to work around a driver bug.
+    void drawBuffers(const Vector<GC3Denum>& bufs);
+
+    GC3Denum getDrawBuffer(GC3Denum);
+
+protected:
+    WebGLFramebuffer(WebGLRenderingContext*);
+
+    virtual void deleteObjectImpl(GraphicsContext3D*, Platform3DObject);
+
+private:
+    virtual bool isFramebuffer() const { return true; }
+
+    WebGLAttachment* getAttachment(GC3Denum) const;
+
+    // Check if the framebuffer is currently bound.
+    bool isBound() const;
+
+    // attach 'attachment' at 'attachmentPoint'.
+    void attach(GC3Denum attachment, GC3Denum attachmentPoint);
+
+    // Check if a new drawBuffers call should be issued. This is called when we add or remove an attachment.
+    void drawBuffersIfNecessary(bool force);
+
+    typedef WTF::HashMap<GC3Denum, RefPtr<WebGLAttachment> > AttachmentMap;
+
+    AttachmentMap m_attachments;
+
+    bool m_hasEverBeenBound;
+
+    Vector<GC3Denum> m_drawBuffers;
+    Vector<GC3Denum> m_filteredDrawBuffers;
+};
+
+} // namespace WebCore
+
+#endif // WebGLFramebuffer_h
diff --git a/Source/core/html/canvas/WebGLFramebuffer.idl b/Source/core/html/canvas/WebGLFramebuffer.idl
new file mode 100644
index 0000000..e609513
--- /dev/null
+++ b/Source/core/html/canvas/WebGLFramebuffer.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBGL
+] interface WebGLFramebuffer {
+};
diff --git a/Source/core/html/canvas/WebGLGetInfo.cpp b/Source/core/html/canvas/WebGLGetInfo.cpp
new file mode 100644
index 0000000..bb2b986
--- /dev/null
+++ b/Source/core/html/canvas/WebGLGetInfo.cpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 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.
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLGetInfo.h"
+
+#include "core/html/canvas/WebGLBuffer.h"
+#include "core/html/canvas/WebGLFramebuffer.h"
+#include "core/html/canvas/WebGLProgram.h"
+#include "core/html/canvas/WebGLRenderbuffer.h"
+#include "core/html/canvas/WebGLTexture.h"
+#include "core/html/canvas/WebGLVertexArrayObjectOES.h"
+#include <wtf/Float32Array.h>
+#include <wtf/Int32Array.h>
+#include <wtf/Uint32Array.h>
+#include <wtf/Uint8Array.h>
+
+namespace WebCore {
+
+WebGLGetInfo::WebGLGetInfo(bool value)
+    : m_type(kTypeBool)
+    , m_bool(value)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(const bool* value, int size)
+    : m_type(kTypeBoolArray)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+{
+    if (!value || size <=0)
+        return;
+    m_boolArray.resize(size);
+    for (int ii = 0; ii < size; ++ii)
+        m_boolArray[ii] = value[ii];
+}
+
+WebGLGetInfo::WebGLGetInfo(float value)
+    : m_type(kTypeFloat)
+    , m_bool(false)
+    , m_float(value)
+    , m_int(0)
+    , m_unsignedInt(0)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(int value)
+    : m_type(kTypeInt)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(value)
+    , m_unsignedInt(0)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo()
+    : m_type(kTypeNull)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(const String& value)
+    : m_type(kTypeString)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_string(value)
+    , m_unsignedInt(0)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(unsigned int value)
+    : m_type(kTypeUnsignedInt)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<WebGLBuffer> value)
+    : m_type(kTypeWebGLBuffer)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglBuffer(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<Float32Array> value)
+    : m_type(kTypeWebGLFloatArray)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglFloatArray(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<WebGLFramebuffer> value)
+    : m_type(kTypeWebGLFramebuffer)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglFramebuffer(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<Int32Array> value)
+    : m_type(kTypeWebGLIntArray)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglIntArray(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<WebGLProgram> value)
+    : m_type(kTypeWebGLProgram)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglProgram(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<WebGLRenderbuffer> value)
+    : m_type(kTypeWebGLRenderbuffer)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglRenderbuffer(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<WebGLTexture> value)
+    : m_type(kTypeWebGLTexture)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglTexture(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<Uint8Array> value)
+    : m_type(kTypeWebGLUnsignedByteArray)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglUnsignedByteArray(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<Uint32Array> value)
+    : m_type(kTypeWebGLUnsignedIntArray)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglUnsignedIntArray(value)
+{
+}
+
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES> value)
+    : m_type(kTypeWebGLVertexArrayObjectOES)
+    , m_bool(false)
+    , m_float(0)
+    , m_int(0)
+    , m_unsignedInt(0)
+    , m_webglVertexArrayObject(value)
+{
+}
+
+WebGLGetInfo::~WebGLGetInfo()
+{
+}
+
+WebGLGetInfo::Type WebGLGetInfo::getType() const
+{
+    return m_type;
+}
+
+bool WebGLGetInfo::getBool() const
+{
+    ASSERT(getType() == kTypeBool);
+    return m_bool;
+}
+
+const Vector<bool>& WebGLGetInfo::getBoolArray() const
+{
+    ASSERT(getType() == kTypeBoolArray);
+    return m_boolArray;
+}
+
+float WebGLGetInfo::getFloat() const
+{
+    ASSERT(getType() == kTypeFloat);
+    return m_float;
+}
+
+int WebGLGetInfo::getInt() const
+{
+    ASSERT(getType() == kTypeInt);
+    return m_int;
+}
+
+const String& WebGLGetInfo::getString() const
+{
+    ASSERT(getType() == kTypeString);
+    return m_string;
+}
+
+unsigned int WebGLGetInfo::getUnsignedInt() const
+{
+    ASSERT(getType() == kTypeUnsignedInt);
+    return m_unsignedInt;
+}
+
+PassRefPtr<WebGLBuffer> WebGLGetInfo::getWebGLBuffer() const
+{
+    ASSERT(getType() == kTypeWebGLBuffer);
+    return m_webglBuffer;
+}
+
+PassRefPtr<Float32Array> WebGLGetInfo::getWebGLFloatArray() const
+{
+    ASSERT(getType() == kTypeWebGLFloatArray);
+    return m_webglFloatArray;
+}
+
+PassRefPtr<WebGLFramebuffer> WebGLGetInfo::getWebGLFramebuffer() const
+{
+    ASSERT(getType() == kTypeWebGLFramebuffer);
+    return m_webglFramebuffer;
+}
+
+PassRefPtr<Int32Array> WebGLGetInfo::getWebGLIntArray() const
+{
+    ASSERT(getType() == kTypeWebGLIntArray);
+    return m_webglIntArray;
+}
+
+PassRefPtr<WebGLProgram> WebGLGetInfo::getWebGLProgram() const
+{
+    ASSERT(getType() == kTypeWebGLProgram);
+    return m_webglProgram;
+}
+
+PassRefPtr<WebGLRenderbuffer> WebGLGetInfo::getWebGLRenderbuffer() const
+{
+    ASSERT(getType() == kTypeWebGLRenderbuffer);
+    return m_webglRenderbuffer;
+}
+
+PassRefPtr<WebGLTexture> WebGLGetInfo::getWebGLTexture() const
+{
+    ASSERT(getType() == kTypeWebGLTexture);
+    return m_webglTexture;
+}
+
+PassRefPtr<Uint8Array> WebGLGetInfo::getWebGLUnsignedByteArray() const
+{
+    ASSERT(getType() == kTypeWebGLUnsignedByteArray);
+    return m_webglUnsignedByteArray;
+}
+
+PassRefPtr<Uint32Array> WebGLGetInfo::getWebGLUnsignedIntArray() const
+{
+    ASSERT(getType() == kTypeWebGLUnsignedIntArray);
+    return m_webglUnsignedIntArray;
+}
+
+PassRefPtr<WebGLVertexArrayObjectOES> WebGLGetInfo::getWebGLVertexArrayObjectOES() const
+{
+    ASSERT(getType() == kTypeWebGLVertexArrayObjectOES);
+    return m_webglVertexArrayObject;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLGetInfo.h b/Source/core/html/canvas/WebGLGetInfo.h
new file mode 100644
index 0000000..d92c128
--- /dev/null
+++ b/Source/core/html/canvas/WebGLGetInfo.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 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 WebGLGetInfo_h
+#define WebGLGetInfo_h
+
+#include "core/html/canvas/WebGLBuffer.h"
+#include "core/html/canvas/WebGLFramebuffer.h"
+#include "core/html/canvas/WebGLProgram.h"
+#include "core/html/canvas/WebGLRenderbuffer.h"
+#include "core/html/canvas/WebGLTexture.h"
+#include "core/html/canvas/WebGLVertexArrayObjectOES.h"
+#include <wtf/Float32Array.h>
+#include <wtf/Int32Array.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Uint32Array.h>
+#include <wtf/Uint8Array.h>
+
+namespace WebCore {
+
+// A tagged union representing the result of get queries like
+// getParameter (encompassing getBooleanv, getIntegerv, getFloatv) and
+// similar variants. For reference counted types, increments and
+// decrements the reference count of the target object.
+
+class WebGLGetInfo {
+public:
+    enum Type {
+        kTypeBool,
+        kTypeBoolArray,
+        kTypeFloat,
+        kTypeInt,
+        kTypeNull,
+        kTypeString,
+        kTypeUnsignedInt,
+        kTypeWebGLBuffer,
+        kTypeWebGLFloatArray,
+        kTypeWebGLFramebuffer,
+        kTypeWebGLIntArray,
+        kTypeWebGLObjectArray,
+        kTypeWebGLProgram,
+        kTypeWebGLRenderbuffer,
+        kTypeWebGLTexture,
+        kTypeWebGLUnsignedByteArray,
+        kTypeWebGLUnsignedIntArray,
+        kTypeWebGLVertexArrayObjectOES,
+    };
+
+    explicit WebGLGetInfo(bool value);
+    WebGLGetInfo(const bool* value, int size);
+    explicit WebGLGetInfo(float value);
+    explicit WebGLGetInfo(int value);
+    // Represents the null value and type.
+    WebGLGetInfo();
+    explicit WebGLGetInfo(const String& value);
+    explicit WebGLGetInfo(unsigned int value);
+    explicit WebGLGetInfo(PassRefPtr<WebGLBuffer> value);
+    explicit WebGLGetInfo(PassRefPtr<Float32Array> value);
+    explicit WebGLGetInfo(PassRefPtr<WebGLFramebuffer> value);
+    explicit WebGLGetInfo(PassRefPtr<Int32Array> value);
+    // FIXME: implement WebGLObjectArray
+    // WebGLGetInfo(PassRefPtr<WebGLObjectArray> value);
+    explicit WebGLGetInfo(PassRefPtr<WebGLProgram> value);
+    explicit WebGLGetInfo(PassRefPtr<WebGLRenderbuffer> value);
+    explicit WebGLGetInfo(PassRefPtr<WebGLTexture> value);
+    explicit WebGLGetInfo(PassRefPtr<Uint8Array> value);
+    explicit WebGLGetInfo(PassRefPtr<Uint32Array> value);
+    explicit WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES> value);
+
+    virtual ~WebGLGetInfo();
+
+    Type getType() const;
+
+    bool getBool() const;
+    const Vector<bool>& getBoolArray() const;
+    float getFloat() const;
+    int getInt() const;
+    const String& getString() const;
+    unsigned int getUnsignedInt() const;
+    PassRefPtr<WebGLBuffer> getWebGLBuffer() const;
+    PassRefPtr<Float32Array> getWebGLFloatArray() const;
+    PassRefPtr<WebGLFramebuffer> getWebGLFramebuffer() const;
+    PassRefPtr<Int32Array> getWebGLIntArray() const;
+    // FIXME: implement WebGLObjectArray
+    // PassRefPtr<WebGLObjectArray> getWebGLObjectArray() const;
+    PassRefPtr<WebGLProgram> getWebGLProgram() const;
+    PassRefPtr<WebGLRenderbuffer> getWebGLRenderbuffer() const;
+    PassRefPtr<WebGLTexture> getWebGLTexture() const;
+    PassRefPtr<Uint8Array> getWebGLUnsignedByteArray() const;
+    PassRefPtr<Uint32Array> getWebGLUnsignedIntArray() const;
+    PassRefPtr<WebGLVertexArrayObjectOES> getWebGLVertexArrayObjectOES() const;
+
+private:
+    Type m_type;
+    bool m_bool;
+    Vector<bool> m_boolArray;
+    float m_float;
+    int m_int;
+    String m_string;
+    unsigned int m_unsignedInt;
+    RefPtr<WebGLBuffer> m_webglBuffer;
+    RefPtr<Float32Array> m_webglFloatArray;
+    RefPtr<WebGLFramebuffer> m_webglFramebuffer;
+    RefPtr<Int32Array> m_webglIntArray;
+    // FIXME: implement WebGLObjectArray
+    // RefPtr<WebGLObjectArray> m_webglObjectArray;
+    RefPtr<WebGLProgram> m_webglProgram;
+    RefPtr<WebGLRenderbuffer> m_webglRenderbuffer;
+    RefPtr<WebGLTexture> m_webglTexture;
+    RefPtr<Uint8Array> m_webglUnsignedByteArray;
+    RefPtr<Uint32Array> m_webglUnsignedIntArray;
+    RefPtr<WebGLVertexArrayObjectOES> m_webglVertexArrayObject;
+};
+
+} // namespace WebCore
+
+#endif // WebGLGetInfo_h
diff --git a/Source/core/html/canvas/WebGLLoseContext.cpp b/Source/core/html/canvas/WebGLLoseContext.cpp
new file mode 100644
index 0000000..e2a4b7f
--- /dev/null
+++ b/Source/core/html/canvas/WebGLLoseContext.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 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 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 "core/html/canvas/WebGLLoseContext.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+WebGLLoseContext::WebGLLoseContext(WebGLRenderingContext* context)
+    : WebGLExtension(context)
+{
+}
+
+WebGLLoseContext::~WebGLLoseContext()
+{
+}
+
+WebGLExtension::ExtensionName WebGLLoseContext::getName() const
+{
+    return WebGLLoseContextName;
+}
+
+PassOwnPtr<WebGLLoseContext> WebGLLoseContext::create(WebGLRenderingContext* context)
+{
+    return adoptPtr(new WebGLLoseContext(context));
+}
+
+void WebGLLoseContext::loseContext()
+{
+    m_context->forceLostContext(WebGLRenderingContext::SyntheticLostContext);
+}
+
+void WebGLLoseContext::restoreContext()
+{
+    m_context->forceRestoreContext();
+}
+
+bool WebGLLoseContext::supported(WebGLRenderingContext*)
+{
+    return true;
+}
+
+const char* WebGLLoseContext::getExtensionName()
+{
+    return "WEBGL_lose_context";
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLLoseContext.h b/Source/core/html/canvas/WebGLLoseContext.h
new file mode 100644
index 0000000..2f86d5f
--- /dev/null
+++ b/Source/core/html/canvas/WebGLLoseContext.h
@@ -0,0 +1,54 @@
+/*
+ * 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 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 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 WebGLLoseContext_h
+#define WebGLLoseContext_h
+
+#include "core/html/canvas/WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebGLRenderingContext;
+
+class WebGLLoseContext : public WebGLExtension {
+public:
+    static PassOwnPtr<WebGLLoseContext> create(WebGLRenderingContext*);
+    static bool supported(WebGLRenderingContext*);
+    static const char* getExtensionName();
+
+    virtual ~WebGLLoseContext();
+    virtual ExtensionName getName() const;
+
+    void loseContext();
+    void restoreContext();
+
+private:
+    WebGLLoseContext(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // WebGLLoseContext_h
diff --git a/Source/core/html/canvas/WebGLLoseContext.idl b/Source/core/html/canvas/WebGLLoseContext.idl
new file mode 100644
index 0000000..ee07a4f
--- /dev/null
+++ b/Source/core/html/canvas/WebGLLoseContext.idl
@@ -0,0 +1,31 @@
+/*
+ * 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 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 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.
+ */
+
+[
+    Conditional=WEBGL,
+] interface WebGLLoseContext {
+    [StrictTypeChecking] void loseContext();
+    [StrictTypeChecking] void restoreContext();
+};
diff --git a/Source/core/html/canvas/WebGLObject.cpp b/Source/core/html/canvas/WebGLObject.cpp
new file mode 100644
index 0000000..d3d922a
--- /dev/null
+++ b/Source/core/html/canvas/WebGLObject.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLObject.h"
+
+#include "core/html/canvas/EXTTextureFilterAnisotropic.h"
+#include "core/html/canvas/OESStandardDerivatives.h"
+#include "core/html/canvas/OESTextureFloat.h"
+#include "core/html/canvas/OESVertexArrayObject.h"
+#include "core/html/canvas/WebGLCompressedTextureS3TC.h"
+#include "core/html/canvas/WebGLContextGroup.h"
+#include "core/html/canvas/WebGLDebugRendererInfo.h"
+#include "core/html/canvas/WebGLDebugShaders.h"
+#include "core/html/canvas/WebGLLoseContext.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+WebGLObject::WebGLObject(WebGLRenderingContext*)
+    : m_object(0)
+    , m_attachmentCount(0)
+    , m_deleted(false)
+{
+}
+
+WebGLObject::~WebGLObject()
+{
+}
+
+void WebGLObject::setObject(Platform3DObject object)
+{
+    // object==0 && m_deleted==false indicating an uninitialized state;
+    ASSERT(!m_object && !m_deleted);
+    m_object = object;
+}
+
+void WebGLObject::deleteObject(GraphicsContext3D* context3d)
+{
+    m_deleted = true;
+    if (!m_object)
+        return;
+
+    if (!hasGroupOrContext())
+        return;
+
+    if (!m_attachmentCount) {
+        if (!context3d)
+            context3d = getAGraphicsContext3D();
+
+        if (context3d)
+            deleteObjectImpl(context3d, m_object);
+
+        m_object = 0;
+    }
+}
+
+void WebGLObject::detach()
+{
+    m_attachmentCount = 0; // Make sure OpenGL resource is deleted.
+    }
+
+
+void WebGLObject::onDetached(GraphicsContext3D* context3d)
+{
+    if (m_attachmentCount)
+        --m_attachmentCount;
+    if (m_deleted)
+        deleteObject(context3d);
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLObject.h b/Source/core/html/canvas/WebGLObject.h
new file mode 100644
index 0000000..a3a9f86
--- /dev/null
+++ b/Source/core/html/canvas/WebGLObject.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 WebGLObject_h
+#define WebGLObject_h
+
+#include "core/platform/graphics/GraphicsContext3D.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class GraphicsContext3D;
+class WebGLContextGroup;
+class WebGLRenderingContext;
+
+class WebGLObject : public RefCounted<WebGLObject> {
+public:
+    virtual ~WebGLObject();
+
+    Platform3DObject object() const { return m_object; }
+
+    // deleteObject may not always delete the OpenGL resource.  For programs and
+    // shaders, deletion is delayed until they are no longer attached.
+    // FIXME: revisit this when resource sharing between contexts are implemented.
+    void deleteObject(GraphicsContext3D*);
+
+    void onAttached() { ++m_attachmentCount; }
+    void onDetached(GraphicsContext3D*);
+
+    // This indicates whether the client side issue a delete call already, not
+    // whether the OpenGL resource is deleted.
+    // object()==0 indicates the OpenGL resource is deleted.
+    bool isDeleted() { return m_deleted; }
+
+    // True if this object belongs to the group or context.
+    virtual bool validate(const WebGLContextGroup*, const WebGLRenderingContext*) const = 0;
+
+protected:
+    WebGLObject(WebGLRenderingContext*);
+
+    // setObject should be only called once right after creating a WebGLObject.
+    void setObject(Platform3DObject);
+
+    // deleteObjectImpl should be only called once to delete the OpenGL resource.
+    virtual void deleteObjectImpl(GraphicsContext3D*, Platform3DObject) = 0;
+
+    virtual bool hasGroupOrContext() const = 0;
+
+    virtual void detach();
+
+    virtual GraphicsContext3D* getAGraphicsContext3D() const = 0;
+
+private:
+    Platform3DObject m_object;
+    unsigned m_attachmentCount;
+    bool m_deleted;
+};
+
+} // namespace WebCore
+
+#endif // WebGLObject_h
diff --git a/Source/core/html/canvas/WebGLProgram.cpp b/Source/core/html/canvas/WebGLProgram.cpp
new file mode 100644
index 0000000..18d1e1f
--- /dev/null
+++ b/Source/core/html/canvas/WebGLProgram.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLProgram.h"
+
+#include "core/html/canvas/WebGLContextGroup.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLProgram> WebGLProgram::create(WebGLRenderingContext* ctx)
+{
+    return adoptRef(new WebGLProgram(ctx));
+}
+
+WebGLProgram::WebGLProgram(WebGLRenderingContext* ctx)
+    : WebGLSharedObject(ctx)
+    , m_linkStatus(false)
+    , m_linkCount(0)
+    , m_infoValid(true)
+{
+    setObject(ctx->graphicsContext3D()->createProgram());
+}
+
+WebGLProgram::~WebGLProgram()
+{
+    deleteObject(0);
+}
+
+void WebGLProgram::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject obj)
+{
+    context3d->deleteProgram(obj);
+    if (m_vertexShader) {
+        m_vertexShader->onDetached(context3d);
+        m_vertexShader = 0;
+    }
+    if (m_fragmentShader) {
+        m_fragmentShader->onDetached(context3d);
+        m_fragmentShader = 0;
+    }
+}
+
+unsigned WebGLProgram::numActiveAttribLocations()
+{
+    cacheInfoIfNeeded();
+    return m_activeAttribLocations.size();
+}
+
+GC3Dint WebGLProgram::getActiveAttribLocation(GC3Duint index)
+{
+    cacheInfoIfNeeded();
+    if (index >= numActiveAttribLocations())
+        return -1;
+    return m_activeAttribLocations[index];
+}
+
+bool WebGLProgram::isUsingVertexAttrib0()
+{
+    cacheInfoIfNeeded();
+    for (unsigned ii = 0; ii < numActiveAttribLocations(); ++ii) {
+        if (!getActiveAttribLocation(ii))
+            return true;
+    }
+    return false;
+}
+
+bool WebGLProgram::getLinkStatus()
+{
+    cacheInfoIfNeeded();
+    return m_linkStatus;
+}
+
+void WebGLProgram::setLinkStatus(bool status)
+{
+    cacheInfoIfNeeded();
+    m_linkStatus = status;
+}
+
+void WebGLProgram::increaseLinkCount()
+{
+    ++m_linkCount;
+    m_infoValid = false;
+}
+
+WebGLShader* WebGLProgram::getAttachedShader(GC3Denum type)
+{
+    switch (type) {
+    case GraphicsContext3D::VERTEX_SHADER:
+        return m_vertexShader.get();
+    case GraphicsContext3D::FRAGMENT_SHADER:
+        return m_fragmentShader.get();
+    default:
+        return 0;
+    }
+}
+
+bool WebGLProgram::attachShader(WebGLShader* shader)
+{
+    if (!shader || !shader->object())
+        return false;
+    switch (shader->getType()) {
+    case GraphicsContext3D::VERTEX_SHADER:
+        if (m_vertexShader)
+            return false;
+        m_vertexShader = shader;
+        return true;
+    case GraphicsContext3D::FRAGMENT_SHADER:
+        if (m_fragmentShader)
+            return false;
+        m_fragmentShader = shader;
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool WebGLProgram::detachShader(WebGLShader* shader)
+{
+    if (!shader || !shader->object())
+        return false;
+    switch (shader->getType()) {
+    case GraphicsContext3D::VERTEX_SHADER:
+        if (m_vertexShader != shader)
+            return false;
+        m_vertexShader = 0;
+        return true;
+    case GraphicsContext3D::FRAGMENT_SHADER:
+        if (m_fragmentShader != shader)
+            return false;
+        m_fragmentShader = 0;
+        return true;
+    default:
+        return false;
+    }
+}
+
+void WebGLProgram::cacheActiveAttribLocations(GraphicsContext3D* context3d)
+{
+    m_activeAttribLocations.clear();
+
+    GC3Dint numAttribs = 0;
+    context3d->getProgramiv(object(), GraphicsContext3D::ACTIVE_ATTRIBUTES, &numAttribs);
+    m_activeAttribLocations.resize(static_cast<size_t>(numAttribs));
+    for (int i = 0; i < numAttribs; ++i) {
+        ActiveInfo info;
+        context3d->getActiveAttrib(object(), i, info);
+        m_activeAttribLocations[i] = context3d->getAttribLocation(object(), info.name.charactersWithNullTermination());
+    }
+}
+
+void WebGLProgram::cacheInfoIfNeeded()
+{
+    if (m_infoValid)
+        return;
+
+    if (!object())
+        return;
+
+    GraphicsContext3D* context = getAGraphicsContext3D();
+    if (!context)
+        return;
+    GC3Dint linkStatus = 0;
+    context->getProgramiv(object(), GraphicsContext3D::LINK_STATUS, &linkStatus);
+    m_linkStatus = linkStatus;
+    if (m_linkStatus)
+        cacheActiveAttribLocations(context);
+    m_infoValid = true;
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLProgram.h b/Source/core/html/canvas/WebGLProgram.h
new file mode 100644
index 0000000..203109c
--- /dev/null
+++ b/Source/core/html/canvas/WebGLProgram.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 WebGLProgram_h
+#define WebGLProgram_h
+
+#include "core/html/canvas/WebGLSharedObject.h"
+
+#include "core/html/canvas/WebGLShader.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class WebGLProgram : public WebGLSharedObject {
+public:
+    virtual ~WebGLProgram();
+
+    static PassRefPtr<WebGLProgram> create(WebGLRenderingContext*);
+
+    unsigned numActiveAttribLocations();
+    GC3Dint getActiveAttribLocation(GC3Duint index);
+
+    bool isUsingVertexAttrib0();
+
+    bool getLinkStatus();
+    void setLinkStatus(bool);
+
+    unsigned getLinkCount() const { return m_linkCount; }
+
+    // This is to be called everytime after the program is successfully linked.
+    // We don't deal with integer overflow here, assuming in reality a program
+    // will never be linked so many times.
+    // Also, we invalidate the cached program info.
+    void increaseLinkCount();
+
+    WebGLShader* getAttachedShader(GC3Denum);
+    bool attachShader(WebGLShader*);
+    bool detachShader(WebGLShader*);
+
+protected:
+    WebGLProgram(WebGLRenderingContext*);
+
+    virtual void deleteObjectImpl(GraphicsContext3D*, Platform3DObject);
+
+private:
+    virtual bool isProgram() const { return true; }
+
+    void cacheActiveAttribLocations(GraphicsContext3D*);
+    void cacheInfoIfNeeded();
+
+    Vector<GC3Dint> m_activeAttribLocations;
+
+    GC3Dint m_linkStatus;
+
+    // This is used to track whether a WebGLUniformLocation belongs to this
+    // program or not.
+    unsigned m_linkCount;
+
+    RefPtr<WebGLShader> m_vertexShader;
+    RefPtr<WebGLShader> m_fragmentShader;
+
+    bool m_infoValid;
+};
+
+} // namespace WebCore
+
+#endif // WebGLProgram_h
diff --git a/Source/core/html/canvas/WebGLProgram.idl b/Source/core/html/canvas/WebGLProgram.idl
new file mode 100644
index 0000000..d404ebd
--- /dev/null
+++ b/Source/core/html/canvas/WebGLProgram.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBGL
+] interface WebGLProgram {
+};
diff --git a/Source/core/html/canvas/WebGLRenderbuffer.cpp b/Source/core/html/canvas/WebGLRenderbuffer.cpp
new file mode 100644
index 0000000..739690d
--- /dev/null
+++ b/Source/core/html/canvas/WebGLRenderbuffer.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLRenderbuffer.h"
+
+#include "core/html/canvas/WebGLContextGroup.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLRenderbuffer> WebGLRenderbuffer::create(WebGLRenderingContext* ctx)
+{
+    return adoptRef(new WebGLRenderbuffer(ctx));
+}
+
+WebGLRenderbuffer::~WebGLRenderbuffer()
+{
+    deleteObject(0);
+}
+
+WebGLRenderbuffer::WebGLRenderbuffer(WebGLRenderingContext* ctx)
+    : WebGLSharedObject(ctx)
+    , m_internalFormat(GraphicsContext3D::RGBA4)
+    , m_initialized(false)
+    , m_width(0)
+    , m_height(0)
+    , m_isValid(true)
+    , m_hasEverBeenBound(false)
+{
+    setObject(ctx->graphicsContext3D()->createRenderbuffer());
+}
+
+void WebGLRenderbuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
+{
+    context3d->deleteRenderbuffer(object);
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLRenderbuffer.h b/Source/core/html/canvas/WebGLRenderbuffer.h
new file mode 100644
index 0000000..08062ea
--- /dev/null
+++ b/Source/core/html/canvas/WebGLRenderbuffer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 WebGLRenderbuffer_h
+#define WebGLRenderbuffer_h
+
+#include "core/html/canvas/WebGLSharedObject.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WebGLRenderbuffer : public WebGLSharedObject {
+public:
+    virtual ~WebGLRenderbuffer();
+
+    static PassRefPtr<WebGLRenderbuffer> create(WebGLRenderingContext*);
+
+    void setInternalFormat(GC3Denum internalformat)
+    {
+        m_internalFormat = internalformat;
+        m_initialized = false;
+    }
+    GC3Denum getInternalFormat() const { return m_internalFormat; }
+
+    void setSize(GC3Dsizei width, GC3Dsizei height)
+    {
+        m_width = width;
+        m_height = height;
+    }
+    GC3Dsizei getWidth() const { return m_width; }
+    GC3Dsizei getHeight() const { return m_height; }
+
+    void setIsValid(bool isValid) { m_isValid = isValid; }
+    bool isValid() const { return m_isValid; }
+
+    bool isInitialized() const { return m_initialized; }
+    void setInitialized() { m_initialized = true; }
+
+    bool hasEverBeenBound() const { return object() && m_hasEverBeenBound; }
+
+    void setHasEverBeenBound() { m_hasEverBeenBound = true; }
+
+protected:
+    WebGLRenderbuffer(WebGLRenderingContext*);
+
+    virtual void deleteObjectImpl(GraphicsContext3D*, Platform3DObject);
+
+private:
+    virtual bool isRenderbuffer() const { return true; }
+
+    GC3Denum m_internalFormat;
+    bool m_initialized;
+    GC3Dsizei m_width, m_height;
+    bool m_isValid; // This is only false if internalFormat is DEPTH_STENCIL and packed_depth_stencil is not supported.
+
+    bool m_hasEverBeenBound;
+};
+
+} // namespace WebCore
+
+#endif // WebGLRenderbuffer_h
diff --git a/Source/core/html/canvas/WebGLRenderbuffer.idl b/Source/core/html/canvas/WebGLRenderbuffer.idl
new file mode 100644
index 0000000..618f9c4
--- /dev/null
+++ b/Source/core/html/canvas/WebGLRenderbuffer.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBGL
+] interface WebGLRenderbuffer {
+};
diff --git a/Source/core/html/canvas/WebGLRenderingContext.cpp b/Source/core/html/canvas/WebGLRenderingContext.cpp
new file mode 100644
index 0000000..34cf179
--- /dev/null
+++ b/Source/core/html/canvas/WebGLRenderingContext.cpp
@@ -0,0 +1,5474 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+#include "core/dom/ExceptionCode.h"
+#include "core/html/HTMLCanvasElement.h"
+#include "core/html/HTMLImageElement.h"
+#include "core/html/HTMLVideoElement.h"
+#include "core/html/ImageData.h"
+#include "core/html/canvas/CheckedInt.h"
+#include "core/html/canvas/EXTDrawBuffers.h"
+#include "core/html/canvas/EXTTextureFilterAnisotropic.h"
+#include "core/html/canvas/OESElementIndexUint.h"
+#include "core/html/canvas/OESStandardDerivatives.h"
+#include "core/html/canvas/OESTextureFloat.h"
+#include "core/html/canvas/OESTextureHalfFloat.h"
+#include "core/html/canvas/OESVertexArrayObject.h"
+#include "core/html/canvas/WebGLActiveInfo.h"
+#include "core/html/canvas/WebGLBuffer.h"
+#include "core/html/canvas/WebGLCompressedTextureATC.h"
+#include "core/html/canvas/WebGLCompressedTexturePVRTC.h"
+#include "core/html/canvas/WebGLCompressedTextureS3TC.h"
+#include "core/html/canvas/WebGLContextAttributes.h"
+#include "core/html/canvas/WebGLContextEvent.h"
+#include "core/html/canvas/WebGLContextGroup.h"
+#include "core/html/canvas/WebGLDebugRendererInfo.h"
+#include "core/html/canvas/WebGLDebugShaders.h"
+#include "core/html/canvas/WebGLDepthTexture.h"
+#include "core/html/canvas/WebGLFramebuffer.h"
+#include "core/html/canvas/WebGLLoseContext.h"
+#include "core/html/canvas/WebGLProgram.h"
+#include "core/html/canvas/WebGLRenderbuffer.h"
+#include "core/html/canvas/WebGLShader.h"
+#include "core/html/canvas/WebGLShaderPrecisionFormat.h"
+#include "core/html/canvas/WebGLTexture.h"
+#include "core/html/canvas/WebGLUniformLocation.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/loader/cache/CachedImage.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/platform/NotImplemented.h"
+#include "core/platform/graphics/Extensions3D.h"
+#include "core/platform/graphics/ImageBuffer.h"
+#include "core/platform/graphics/IntSize.h"
+#include "core/platform/graphics/gpu/DrawingBuffer.h"
+#include "core/rendering/RenderBox.h"
+
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/PassOwnArrayPtr.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/Uint16Array.h>
+#include <wtf/Uint32Array.h>
+
+namespace WebCore {
+
+const double secondsBetweenRestoreAttempts = 1.0;
+const int maxGLErrorsAllowedToConsole = 256;
+const int maxGLActiveContexts = 16;
+
+Vector<WebGLRenderingContext*>& WebGLRenderingContext::activeContexts()
+{
+    DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContext*>, activeContexts, ());
+    return activeContexts;
+}
+
+Vector<WebGLRenderingContext*>& WebGLRenderingContext::forciblyEvictedContexts()
+{
+    DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContext*>, forciblyEvictedContexts, ());
+    return forciblyEvictedContexts;
+}
+
+void WebGLRenderingContext::forciblyLoseOldestContext(const String& reason)
+{
+    if (activeContexts().size()) {
+        WebGLRenderingContext* oldestActiveContext = activeContexts().first();
+        activeContexts().remove(0);
+
+        oldestActiveContext->printWarningToConsole(reason);
+
+        // This will call deactivateContext once the context has actually been lost.
+        oldestActiveContext->forceLostContext(WebGLRenderingContext::SyntheticLostContext);
+    }
+}
+
+IntSize WebGLRenderingContext::oldestContextSize()
+{
+    IntSize size;
+
+    if (activeContexts().size()) {
+        WebGLRenderingContext* oldestActiveContext = activeContexts().first();
+        size.setWidth(oldestActiveContext->drawingBufferWidth());
+        size.setHeight(oldestActiveContext->drawingBufferHeight());
+    }
+
+    return size;
+}
+
+void WebGLRenderingContext::activateContext(WebGLRenderingContext* context)
+{
+    if (!activeContexts().contains(context))
+        activeContexts().append(context);
+
+    if (activeContexts().size() > maxGLActiveContexts)
+        forciblyLoseOldestContext("WARNING: Too many active WebGL contexts. Oldest context will be lost.");
+}
+
+void WebGLRenderingContext::deactivateContext(WebGLRenderingContext* context, bool addToEvictedList)
+{
+    size_t position = activeContexts().find(context);
+    if (position != WTF::notFound)
+        activeContexts().remove(position);
+
+    if (addToEvictedList && !forciblyEvictedContexts().contains(context))
+        forciblyEvictedContexts().append(context);
+}
+
+void WebGLRenderingContext::willDestroyContext(WebGLRenderingContext* context)
+{
+    size_t position = forciblyEvictedContexts().find(context);
+    if (position != WTF::notFound)
+        forciblyEvictedContexts().remove(position);
+
+    deactivateContext(context, false);
+
+    // Try to re-enable the oldest inactive contexts.
+    while(activeContexts().size() < maxGLActiveContexts && forciblyEvictedContexts().size()) {
+        WebGLRenderingContext* evictedContext = forciblyEvictedContexts().first();
+        if (!evictedContext->m_restoreAllowed) {
+            forciblyEvictedContexts().remove(0);
+            continue;
+        }
+
+        IntSize desiredSize = evictedContext->m_drawingBuffer->adjustSize(evictedContext->clampedCanvasSize());
+
+        // If there's room in the pixel budget for this context, restore it.
+        if (!desiredSize.isEmpty()) {
+            forciblyEvictedContexts().remove(0);
+            evictedContext->forceRestoreContext();
+            activeContexts().append(evictedContext);
+        }
+        break;
+    }
+}
+
+class WebGLRenderingContextEvictionManager : public ContextEvictionManager {
+public:
+    void forciblyLoseOldestContext(const String& reason) {
+        WebGLRenderingContext::forciblyLoseOldestContext(reason);
+    };
+    IntSize oldestContextSize() {
+        return WebGLRenderingContext::oldestContextSize();
+    };
+};
+
+namespace {
+
+    class ScopedDrawingBufferBinder {
+    public:
+        ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer* framebufferBinding)
+            : m_drawingBuffer(drawingBuffer)
+            , m_framebufferBinding(framebufferBinding)
+        {
+            // Commit DrawingBuffer if needed (e.g., for multisampling)
+            if (!m_framebufferBinding && m_drawingBuffer)
+                m_drawingBuffer->commit();
+        }
+
+        ~ScopedDrawingBufferBinder()
+        {
+            // Restore DrawingBuffer if needed
+            if (!m_framebufferBinding && m_drawingBuffer)
+                m_drawingBuffer->bind();
+        }
+
+    private:
+        DrawingBuffer* m_drawingBuffer;
+        WebGLFramebuffer* m_framebufferBinding;
+    };
+
+    Platform3DObject objectOrZero(WebGLObject* object)
+    {
+        return object ? object->object() : 0;
+    }
+
+    void clip1D(GC3Dint start, GC3Dsizei range, GC3Dsizei sourceRange, GC3Dint* clippedStart, GC3Dsizei* clippedRange)
+    {
+        ASSERT(clippedStart && clippedRange);
+        if (start < 0) {
+            range += start;
+            start = 0;
+        }
+        GC3Dint end = start + range;
+        if (end > sourceRange)
+            range -= end - sourceRange;
+        *clippedStart = start;
+        *clippedRange = range;
+    }
+
+    // Returns false if no clipping is necessary, i.e., x, y, width, height stay the same.
+    bool clip2D(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height,
+                GC3Dsizei sourceWidth, GC3Dsizei sourceHeight,
+                GC3Dint* clippedX, GC3Dint* clippedY, GC3Dsizei* clippedWidth, GC3Dsizei*clippedHeight)
+    {
+        ASSERT(clippedX && clippedY && clippedWidth && clippedHeight);
+        clip1D(x, width, sourceWidth, clippedX, clippedWidth);
+        clip1D(y, height, sourceHeight, clippedY, clippedHeight);
+        return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height);
+    }
+
+    GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
+    {
+        if (value < min)
+            value = min;
+        if (value > max)
+            value = max;
+        return value;
+    }
+
+    // Return true if a character belongs to the ASCII subset as defined in
+    // GLSL ES 1.0 spec section 3.1.
+    bool validateCharacter(unsigned char c)
+    {
+        // Printing characters are valid except " $ ` @ \ ' DEL.
+        if (c >= 32 && c <= 126
+            && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
+            return true;
+        // Horizontal tab, line feed, vertical tab, form feed, carriage return
+        // are also valid.
+        if (c >= 9 && c <= 13)
+            return true;
+        return false;
+    }
+
+    bool isPrefixReserved(const String& name)
+    {
+        if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_"))
+            return true;
+        return false;
+    }
+
+    // Strips comments from shader text. This allows non-ASCII characters
+    // to be used in comments without potentially breaking OpenGL
+    // implementations not expecting characters outside the GLSL ES set.
+    class StripComments {
+    public:
+        StripComments(const String& str)
+            : m_parseState(BeginningOfLine)
+            , m_sourceString(str)
+            , m_length(str.length())
+            , m_position(0)
+        {
+            parse();
+        }
+
+        String result()
+        {
+            return m_builder.toString();
+        }
+
+    private:
+        bool hasMoreCharacters()
+        {
+            return (m_position < m_length);
+        }
+
+        void parse()
+        {
+            while (hasMoreCharacters()) {
+                process(current());
+                // process() might advance the position.
+                if (hasMoreCharacters())
+                    advance();
+            }
+        }
+
+        void process(UChar);
+
+        bool peek(UChar& character)
+        {
+            if (m_position + 1 >= m_length)
+                return false;
+            character = m_sourceString[m_position + 1];
+            return true;
+        }
+
+        UChar current()
+        {
+            ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length);
+            return m_sourceString[m_position];
+        }
+
+        void advance()
+        {
+            ++m_position;
+        }
+
+        bool isNewline(UChar character)
+        {
+            // Don't attempt to canonicalize newline related characters.
+            return (character == '\n' || character == '\r');
+        }
+
+        void emit(UChar character)
+        {
+            m_builder.append(character);
+        }
+
+        enum ParseState {
+            // Have not seen an ASCII non-whitespace character yet on
+            // this line. Possible that we might see a preprocessor
+            // directive.
+            BeginningOfLine,
+
+            // Have seen at least one ASCII non-whitespace character
+            // on this line.
+            MiddleOfLine,
+
+            // Handling a preprocessor directive. Passes through all
+            // characters up to the end of the line. Disables comment
+            // processing.
+            InPreprocessorDirective,
+
+            // Handling a single-line comment. The comment text is
+            // replaced with a single space.
+            InSingleLineComment,
+
+            // Handling a multi-line comment. Newlines are passed
+            // through to preserve line numbers.
+            InMultiLineComment
+        };
+
+        ParseState m_parseState;
+        String m_sourceString;
+        unsigned m_length;
+        unsigned m_position;
+        StringBuilder m_builder;
+    };
+
+    void StripComments::process(UChar c)
+    {
+        if (isNewline(c)) {
+            // No matter what state we are in, pass through newlines
+            // so we preserve line numbers.
+            emit(c);
+
+            if (m_parseState != InMultiLineComment)
+                m_parseState = BeginningOfLine;
+
+            return;
+        }
+
+        UChar temp = 0;
+        switch (m_parseState) {
+        case BeginningOfLine:
+            if (WTF::isASCIISpace(c)) {
+                emit(c);
+                break;
+            }
+
+            if (c == '#') {
+                m_parseState = InPreprocessorDirective;
+                emit(c);
+                break;
+            }
+
+            // Transition to normal state and re-handle character.
+            m_parseState = MiddleOfLine;
+            process(c);
+            break;
+
+        case MiddleOfLine:
+            if (c == '/' && peek(temp)) {
+                if (temp == '/') {
+                    m_parseState = InSingleLineComment;
+                    emit(' ');
+                    advance();
+                    break;
+                }
+
+                if (temp == '*') {
+                    m_parseState = InMultiLineComment;
+                    // Emit the comment start in case the user has
+                    // an unclosed comment and we want to later
+                    // signal an error.
+                    emit('/');
+                    emit('*');
+                    advance();
+                    break;
+                }
+            }
+
+            emit(c);
+            break;
+
+        case InPreprocessorDirective:
+            // No matter what the character is, just pass it
+            // through. Do not parse comments in this state. This
+            // might not be the right thing to do long term, but it
+            // should handle the #error preprocessor directive.
+            emit(c);
+            break;
+
+        case InSingleLineComment:
+            // The newline code at the top of this function takes care
+            // of resetting our state when we get out of the
+            // single-line comment. Swallow all other characters.
+            break;
+
+        case InMultiLineComment:
+            if (c == '*' && peek(temp) && temp == '/') {
+                emit('*');
+                emit('/');
+                m_parseState = MiddleOfLine;
+                advance();
+                break;
+            }
+
+            // Swallow all other characters. Unclear whether we may
+            // want or need to just emit a space per character to try
+            // to preserve column numbers for debugging purposes.
+            break;
+        }
+    }
+} // namespace anonymous
+
+class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_context(cb) { }
+    virtual void onContextLost() { m_context->forceLostContext(WebGLRenderingContext::RealLostContext); }
+    virtual ~WebGLRenderingContextLostCallback() {}
+private:
+    WebGLRenderingContext* m_context;
+};
+
+class WebGLRenderingContextErrorMessageCallback : public GraphicsContext3D::ErrorMessageCallback {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContext* cb) : m_context(cb) { }
+    virtual void onErrorMessage(const String& message, GC3Dint)
+    {
+        if (m_context->m_synthesizedErrorsToConsole)
+            m_context->printGLErrorToConsole(message);
+    }
+    virtual ~WebGLRenderingContextErrorMessageCallback() { }
+private:
+    WebGLRenderingContext* m_context;
+};
+
+PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs)
+{
+    Document* document = canvas->document();
+    Frame* frame = document->frame();
+    if (!frame)
+        return nullptr;
+    Settings* settings = frame->settings();
+
+    // The FrameLoaderClient might block creation of a new WebGL context despite the page settings; in
+    // particular, if WebGL contexts were lost one or more times via the GL_ARB_robustness extension.
+    if (!frame->loader()->client()->allowWebGL(settings && settings->webGLEnabled())) {
+        canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Web page was not allowed to create a WebGL context."));
+        return nullptr;
+    }
+
+    HostWindow* hostWindow = document->view()->root()->hostWindow();
+    GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
+
+    if (attributes.antialias) {
+        if (settings && !settings->openGLMultisamplingEnabled())
+            attributes.antialias = false;
+    }
+
+    attributes.noExtensions = true;
+    attributes.shareResources = true;
+    attributes.preferDiscreteGPU = true;
+    attributes.topDocumentURL = document->topDocument()->url();
+
+    RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
+
+    if (!context || !context->makeContextCurrent()) {
+        canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
+        return nullptr;
+    }
+
+    Extensions3D* extensions = context->getExtensions();
+    if (extensions->supports("GL_EXT_debug_marker"))
+        extensions->pushGroupMarkerEXT("WebGLRenderingContext");
+
+    OwnPtr<WebGLRenderingContext> renderingContext = adoptPtr(new WebGLRenderingContext(canvas, context, attributes));
+    renderingContext->suspendIfNeeded();
+
+    if (renderingContext->m_drawingBuffer->isZeroSized()) {
+        canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
+        return nullptr;
+    }
+
+    return renderingContext.release();
+}
+
+WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
+                                             GraphicsContext3D::Attributes attributes)
+    : CanvasRenderingContext(passedCanvas)
+    , ActiveDOMObject(passedCanvas->document())
+    , m_context(context)
+    , m_drawingBuffer(0)
+    , m_dispatchContextLostEventTimer(this, &WebGLRenderingContext::dispatchContextLostEvent)
+    , m_restoreAllowed(false)
+    , m_restoreTimer(this, &WebGLRenderingContext::maybeRestoreContext)
+    , m_videoCache(4)
+    , m_contextLost(false)
+    , m_contextLostMode(SyntheticLostContext)
+    , m_attributes(attributes)
+    , m_synthesizedErrorsToConsole(true)
+    , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
+{
+    ASSERT(m_context);
+    ScriptWrappable::init(this);
+
+    m_contextGroup = WebGLContextGroup::create();
+    m_contextGroup->addContext(this);
+
+    m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
+    m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
+
+    RefPtr<WebGLRenderingContextEvictionManager> contextEvictionManager = adoptRef(new WebGLRenderingContextEvictionManager());
+
+    // Create the DrawingBuffer and initialize the platform layer.
+    DrawingBuffer::PreserveDrawingBuffer preserve = m_attributes.preserveDrawingBuffer ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
+    m_drawingBuffer = DrawingBuffer::create(m_context.get(), clampedCanvasSize(), preserve, contextEvictionManager.release());
+
+    if (!m_drawingBuffer->isZeroSized()) {
+        m_drawingBuffer->bind();
+        setupFlags();
+        initializeNewContext();
+    }
+}
+
+void WebGLRenderingContext::initializeNewContext()
+{
+    ASSERT(!isContextLost());
+    m_needsUpdate = true;
+    m_markedCanvasDirty = false;
+    m_activeTextureUnit = 0;
+    m_packAlignment = 4;
+    m_unpackAlignment = 4;
+    m_unpackFlipY = false;
+    m_unpackPremultiplyAlpha = false;
+    m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
+    m_boundArrayBuffer = 0;
+    m_currentProgram = 0;
+    m_framebufferBinding = 0;
+    m_renderbufferBinding = 0;
+    m_depthMask = true;
+    m_stencilEnabled = false;
+    m_stencilMask = 0xFFFFFFFF;
+    m_stencilMaskBack = 0xFFFFFFFF;
+    m_stencilFuncRef = 0;
+    m_stencilFuncRefBack = 0;
+    m_stencilFuncMask = 0xFFFFFFFF;
+    m_stencilFuncMaskBack = 0xFFFFFFFF;
+    m_layerCleared = false;
+    m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
+    
+    m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
+    m_scissorEnabled = false;
+    m_clearDepth = 1;
+    m_clearStencil = 0;
+    m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
+
+    GC3Dint numCombinedTextureImageUnits = 0;
+    m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
+    m_textureUnits.clear();
+    m_textureUnits.resize(numCombinedTextureImageUnits);
+
+    GC3Dint numVertexAttribs = 0;
+    m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
+    m_maxVertexAttribs = numVertexAttribs;
+    
+    m_maxTextureSize = 0;
+    m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
+    m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
+    m_maxCubeMapTextureSize = 0;
+    m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
+    m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
+    m_maxRenderbufferSize = 0;
+    m_context->getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
+
+    // These two values from EXT_draw_buffers are lazily queried.
+    m_maxDrawBuffers = 0;
+    m_maxColorAttachments = 0;
+
+    m_backDrawBuffer = GraphicsContext3D::BACK;
+
+    m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
+    addContextObject(m_defaultVertexArrayObject.get());
+    m_boundVertexArrayObject = m_defaultVertexArrayObject;
+    
+    m_vertexAttribValue.resize(m_maxVertexAttribs);
+
+    if (!isGLES2NPOTStrict())
+        createFallbackBlackTextures1x1();
+
+    IntSize canvasSize = clampedCanvasSize();
+    m_drawingBuffer->reset(canvasSize);
+
+    m_context->viewport(0, 0, canvasSize.width(), canvasSize.height());
+    m_context->scissor(0, 0, canvasSize.width(), canvasSize.height());
+
+    m_context->setContextLostCallback(adoptPtr(new WebGLRenderingContextLostCallback(this)));
+    m_context->setErrorMessageCallback(adoptPtr(new WebGLRenderingContextErrorMessageCallback(this)));
+
+    activateContext(this);
+}
+
+void WebGLRenderingContext::setupFlags()
+{
+    ASSERT(m_context);
+
+    Page* p = canvas()->document()->page();
+    if (p)
+        m_synthesizedErrorsToConsole = p->settings()->webGLErrorsToConsoleEnabled();
+
+    m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
+    m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
+    m_isRobustnessEXTSupported = m_context->getExtensions()->isEnabled("GL_EXT_robustness");
+}
+
+bool WebGLRenderingContext::allowPrivilegedExtensions() const
+{
+    Page* p = canvas()->document()->page();
+    if (p && p->settings())
+        return p->settings()->privilegedWebGLExtensionsEnabled();
+    return false;
+}
+
+void WebGLRenderingContext::addCompressedTextureFormat(GC3Denum format)
+{
+    if (!m_compressedTextureFormats.contains(format))
+        m_compressedTextureFormats.append(format);
+}
+
+WebGLRenderingContext::~WebGLRenderingContext()
+{
+    // Remove all references to WebGLObjects so if they are the last reference
+    // they will be freed before the last context is removed from the context group.
+    m_boundArrayBuffer = 0;
+    m_defaultVertexArrayObject = 0;
+    m_boundVertexArrayObject = 0;
+    m_vertexAttrib0Buffer = 0;
+    m_currentProgram = 0;
+    m_framebufferBinding = 0;
+    m_renderbufferBinding = 0;
+
+    for (size_t i = 0; i < m_textureUnits.size(); ++i) {
+      m_textureUnits[i].m_texture2DBinding = 0;
+      m_textureUnits[i].m_textureCubeMapBinding = 0;
+    }
+
+    m_blackTexture2D = 0;
+    m_blackTextureCubeMap = 0;
+
+    detachAndRemoveAllObjects();
+    destroyGraphicsContext3D();
+    m_contextGroup->removeContext(this);
+
+    willDestroyContext(this);
+}
+
+void WebGLRenderingContext::destroyGraphicsContext3D()
+{
+    m_contextLost = true;
+
+    // The drawing buffer holds a context reference. It must also be destroyed
+    // in order for the context to be released.
+    m_drawingBuffer->releaseResources();
+
+    if (m_context) {
+        m_context->setContextLostCallback(nullptr);
+        m_context->setErrorMessageCallback(nullptr);
+        m_context.clear();
+    }
+}
+
+void WebGLRenderingContext::markContextChanged()
+{
+    if (m_framebufferBinding || isContextLost())
+        return;
+
+    m_context->markContextChanged();
+    m_drawingBuffer->markContentsChanged();
+
+    m_layerCleared = false;
+    RenderBox* renderBox = canvas()->renderBox();
+    if (renderBox && renderBox->hasAcceleratedCompositing()) {
+        m_markedCanvasDirty = true;
+        canvas()->clearCopiedImage();
+        renderBox->contentChanged(CanvasChanged);
+    } else {
+        if (!m_markedCanvasDirty) {
+            m_markedCanvasDirty = true;
+            canvas()->didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize()));
+        }
+    }
+}
+
+bool WebGLRenderingContext::clearIfComposited(GC3Dbitfield mask)
+{
+    if (isContextLost())
+        return false;
+
+    if (!m_context->layerComposited() || m_layerCleared
+        || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
+        return false;
+
+    RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
+
+    // Determine if it's possible to combine the clear the user asked for and this clear.
+    bool combinedClear = mask && !m_scissorEnabled;
+
+    m_context->disable(GraphicsContext3D::SCISSOR_TEST);
+    if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
+        m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
+                              m_colorMask[1] ? m_clearColor[1] : 0,
+                              m_colorMask[2] ? m_clearColor[2] : 0,
+                              m_colorMask[3] ? m_clearColor[3] : 0);
+    else
+        m_context->clearColor(0, 0, 0, 0);
+    m_context->colorMask(true, true, true, true);
+    GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
+    if (contextAttributes->depth()) {
+        if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
+            m_context->clearDepth(1.0f);
+        clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
+        m_context->depthMask(true);
+    }
+    if (contextAttributes->stencil()) {
+        if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
+            m_context->clearStencil(m_clearStencil & m_stencilMask);
+        else
+            m_context->clearStencil(0);
+        clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
+        m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
+    }
+
+    m_drawingBuffer->clearFramebuffers(clearMask);
+
+    restoreStateAfterClear();
+    if (m_framebufferBinding)
+        m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
+    m_layerCleared = true;
+
+    return combinedClear;
+}
+
+void WebGLRenderingContext::restoreStateAfterClear()
+{
+    if (isContextLost())
+        return;
+
+    // Restore the state that the context set.
+    if (m_scissorEnabled)
+        m_context->enable(GraphicsContext3D::SCISSOR_TEST);
+    m_context->clearColor(m_clearColor[0], m_clearColor[1],
+                          m_clearColor[2], m_clearColor[3]);
+    m_context->colorMask(m_colorMask[0], m_colorMask[1],
+                         m_colorMask[2], m_colorMask[3]);
+    m_context->clearDepth(m_clearDepth);
+    m_context->clearStencil(m_clearStencil);
+    m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
+    m_context->depthMask(m_depthMask);
+}
+
+void WebGLRenderingContext::markLayerComposited()
+{
+    if (!isContextLost())
+        m_context->markLayerComposited();
+}
+
+void WebGLRenderingContext::paintRenderingResultsToCanvas()
+{
+    if (isContextLost()) {
+        canvas()->clearPresentationCopy();
+        return;
+    }
+
+    if (canvas()->document()->printing())
+        canvas()->clearPresentationCopy();
+
+    // Until the canvas is written to by the application, the clear that
+    // happened after it was composited should be ignored by the compositor.
+    if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
+        m_context->paintCompositedResultsToCanvas(canvas()->buffer());
+
+        m_drawingBuffer->paintCompositedResultsToCanvas(canvas()->buffer());
+
+        canvas()->makePresentationCopy();
+    } else
+        canvas()->clearPresentationCopy();
+    clearIfComposited();
+
+    if (!m_markedCanvasDirty && !m_layerCleared)
+        return;
+
+    canvas()->clearCopiedImage();
+    m_markedCanvasDirty = false;
+
+    m_drawingBuffer->commit();
+    m_context->paintRenderingResultsToCanvas(canvas()->buffer(), m_drawingBuffer.get());
+
+    if (m_framebufferBinding)
+        m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
+    else
+        m_drawingBuffer->bind();
+}
+
+PassRefPtr<ImageData> WebGLRenderingContext::paintRenderingResultsToImageData()
+{
+    if (isContextLost())
+        return 0;
+
+    clearIfComposited();
+    m_drawingBuffer->commit();
+    RefPtr<ImageData> imageData = m_context->paintRenderingResultsToImageData(m_drawingBuffer.get());
+
+    if (m_framebufferBinding)
+        m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
+    else
+        m_drawingBuffer->bind();
+
+    return imageData;
+}
+
+void WebGLRenderingContext::reshape(int width, int height)
+{
+    if (isContextLost())
+        return;
+
+    // This is an approximation because at WebGLRenderingContext level we don't
+    // know if the underlying FBO uses textures or renderbuffers.
+    GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
+    // Limit drawing buffer size to 4k to avoid memory exhaustion.
+    const int sizeUpperLimit = 4096;
+    maxSize = std::min(maxSize, sizeUpperLimit);
+    GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
+    GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
+    width = clamp(width, 1, maxWidth);
+    height = clamp(height, 1, maxHeight);
+
+    if (m_needsUpdate) {
+        RenderBox* renderBox = canvas()->renderBox();
+        if (renderBox && renderBox->hasAcceleratedCompositing())
+            renderBox->contentChanged(CanvasChanged);
+        m_needsUpdate = false;
+    }
+
+    // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
+    // clear (and this matches what reshape will do).
+    m_drawingBuffer->reset(IntSize(width, height));
+    restoreStateAfterClear();
+
+    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()));
+    m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
+    if (m_framebufferBinding)
+      m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
+}
+
+int WebGLRenderingContext::drawingBufferWidth() const
+{
+    return m_drawingBuffer->size().width();
+}
+
+int WebGLRenderingContext::drawingBufferHeight() const
+{
+    return m_drawingBuffer->size().height();
+}
+
+unsigned int WebGLRenderingContext::sizeInBytes(GC3Denum type)
+{
+    switch (type) {
+    case GraphicsContext3D::BYTE:
+        return sizeof(GC3Dbyte);
+    case GraphicsContext3D::UNSIGNED_BYTE:
+        return sizeof(GC3Dubyte);
+    case GraphicsContext3D::SHORT:
+        return sizeof(GC3Dshort);
+    case GraphicsContext3D::UNSIGNED_SHORT:
+        return sizeof(GC3Dushort);
+    case GraphicsContext3D::INT:
+        return sizeof(GC3Dint);
+    case GraphicsContext3D::UNSIGNED_INT:
+        return sizeof(GC3Duint);
+    case GraphicsContext3D::FLOAT:
+        return sizeof(GC3Dfloat);
+    }
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+void WebGLRenderingContext::activeTexture(GC3Denum texture, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return;
+    if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "activeTexture", "texture unit out of range");
+        return;
+    }
+    m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
+    m_context->activeTexture(texture);
+
+    m_drawingBuffer->setActiveTextureUnit(texture);
+
+}
+
+void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader))
+        return;
+    if (!program->attachShader(shader)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "attachShader", "shader attachment already has shader");
+        return;
+    }
+    m_context->attachShader(objectOrZero(program), objectOrZero(shader));
+    shader->onAttached();
+}
+
+void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("bindAttribLocation", program))
+        return;
+    if (!validateLocationLength("bindAttribLocation", name))
+        return;
+    if (!validateString("bindAttribLocation", name))
+        return;
+    if (isPrefixReserved(name)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindAttribLocation", "reserved prefix");
+        return;
+    }
+    if (index >= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bindAttribLocation", "index out of range");
+        return;
+    }
+    m_context->bindAttribLocation(objectOrZero(program), index, name);
+}
+
+bool WebGLRenderingContext::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted)
+{
+    deleted = false;
+    if (isContextLost())
+        return false;
+    if (object) {
+        if (!object->validate(contextGroup(), this)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object not from this context");
+            return false;
+        }
+        deleted = !object->object();
+    }
+    return true;
+}
+
+void WebGLRenderingContext::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound("bindBuffer", buffer, deleted))
+        return;
+    if (deleted)
+        buffer = 0;
+    if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets");
+        return;
+    }
+    if (target == GraphicsContext3D::ARRAY_BUFFER)
+        m_boundArrayBuffer = buffer;
+    else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
+        m_boundVertexArrayObject->setElementArrayBuffer(buffer);
+    else {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindBuffer", "invalid target");
+        return;
+    }
+
+    m_context->bindBuffer(target, objectOrZero(buffer));
+    if (buffer)
+        buffer->setTarget(target);
+}
+
+void WebGLRenderingContext::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted))
+        return;
+    if (deleted)
+        buffer = 0;
+    if (target != GraphicsContext3D::FRAMEBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindFramebuffer", "invalid target");
+        return;
+    }
+    m_framebufferBinding = buffer;
+    m_drawingBuffer->setFramebufferBinding(objectOrZero(m_framebufferBinding.get()));
+    if (!m_framebufferBinding) {
+        // Instead of binding fb 0, bind the drawing buffer.
+        m_drawingBuffer->bind();
+    } else
+        m_context->bindFramebuffer(target, objectOrZero(buffer));
+    if (buffer)
+        buffer->setHasEverBeenBound();
+    applyStencilTest();
+}
+
+void WebGLRenderingContext::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
+        return;
+    if (deleted)
+        renderBuffer = 0;
+    if (target != GraphicsContext3D::RENDERBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindRenderbuffer", "invalid target");
+        return;
+    }
+    m_renderbufferBinding = renderBuffer;
+    m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
+    if (renderBuffer)
+        renderBuffer->setHasEverBeenBound();
+}
+
+void WebGLRenderingContext::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound("bindTexture", texture, deleted))
+        return;
+    if (deleted)
+        texture = 0;
+    if (texture && texture->getTarget() && texture->getTarget() != target) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
+        return;
+    }
+    GC3Dint maxLevel = 0;
+    if (target == GraphicsContext3D::TEXTURE_2D) {
+        m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
+        maxLevel = m_maxTextureLevel;
+
+        if (!m_activeTextureUnit)
+            m_drawingBuffer->setTexture2DBinding(objectOrZero(texture));
+
+    } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
+        m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
+        maxLevel = m_maxCubeMapTextureLevel;
+    } else {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindTexture", "invalid target");
+        return;
+    }
+    m_context->bindTexture(target, objectOrZero(texture));
+    if (texture)
+        texture->setTarget(target, maxLevel);
+
+    // Note: previously we used to automatically set the TEXTURE_WRAP_R
+    // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
+    // ES 2.0 doesn't expose this flag (a bug in the specification) and
+    // otherwise the application has no control over the seams in this
+    // dimension. However, it appears that supporting this properly on all
+    // platforms is fairly involved (will require a HashMap from texture ID
+    // in all ports), and we have not had any complaints, so the logic has
+    // been removed.
+
+}
+
+void WebGLRenderingContext::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
+{
+    if (isContextLost())
+        return;
+    m_context->blendColor(red, green, blue, alpha);
+}
+
+void WebGLRenderingContext::blendEquation(GC3Denum mode)
+{
+    if (isContextLost() || !validateBlendEquation("blendEquation", mode))
+        return;
+    m_context->blendEquation(mode);
+}
+
+void WebGLRenderingContext::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
+{
+    if (isContextLost() || !validateBlendEquation("blendEquation", modeRGB) || !validateBlendEquation("blendEquation", modeAlpha))
+        return;
+    m_context->blendEquationSeparate(modeRGB, modeAlpha);
+}
+
+
+void WebGLRenderingContext::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
+{
+    if (isContextLost() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
+        return;
+    m_context->blendFunc(sfactor, dfactor);
+}
+
+void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
+{
+    // Note: Alpha does not have the same restrictions as RGB.
+    if (isContextLost() || !validateBlendFuncFactors("blendFunc", srcRGB, dstRGB))
+        return;
+    m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+void WebGLRenderingContext::bufferData(GC3Denum target, long long size, GC3Denum usage, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
+    if (!buffer)
+        return;
+    if (size < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size < 0");
+        return;
+    }
+    if (!size) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size == 0");
+        return;
+    }
+
+    m_context->bufferData(target, static_cast<GC3Dsizeiptr>(size), usage);
+}
+
+void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
+    if (!buffer)
+        return;
+    if (!data) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
+        return;
+    }
+    m_context->bufferData(target, data->byteLength(), data->data(), usage);
+}
+
+void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
+    if (!buffer)
+        return;
+    if (!data) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
+        return;
+    }
+
+    m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
+}
+
+void WebGLRenderingContext::bufferSubData(GC3Denum target, long long offset, ArrayBuffer* data, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
+    if (!buffer)
+        return;
+    if (offset < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
+        return;
+    }
+    if (!data)
+        return;
+
+    m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->data());
+}
+
+void WebGLRenderingContext::bufferSubData(GC3Denum target, long long offset, ArrayBufferView* data, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
+    if (!buffer)
+        return;
+    if (offset < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
+        return;
+    }
+    if (!data)
+        return;
+
+    m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->baseAddress());
+}
+
+GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target)
+{
+    if (isContextLost())
+        return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
+    if (target != GraphicsContext3D::FRAMEBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "checkFramebufferStatus", "invalid target");
+        return 0;
+    }
+    if (!m_framebufferBinding || !m_framebufferBinding->object())
+        return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
+    const char* reason = "framebuffer incomplete";
+    GC3Denum result = m_framebufferBinding->checkStatus(&reason);
+    if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+        printGLWarningToConsole("checkFramebufferStatus", reason);
+        return result;
+    }
+    result = m_context->checkFramebufferStatus(target);
+    return result;
+}
+
+void WebGLRenderingContext::clear(GC3Dbitfield mask)
+{
+    if (isContextLost())
+        return;
+    if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "clear", "invalid mask");
+        return;
+    }
+    const char* reason = "framebuffer incomplete";
+    if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "clear", reason);
+        return;
+    }
+    if (!clearIfComposited(mask))
+        m_context->clear(mask);
+    markContextChanged();
+}
+
+void WebGLRenderingContext::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
+{
+    if (isContextLost())
+        return;
+    if (std::isnan(r))
+        r = 0;
+    if (std::isnan(g))
+        g = 0;
+    if (std::isnan(b))
+        b = 0;
+    if (std::isnan(a))
+        a = 1;
+    m_clearColor[0] = r;
+    m_clearColor[1] = g;
+    m_clearColor[2] = b;
+    m_clearColor[3] = a;
+    m_context->clearColor(r, g, b, a);
+}
+
+void WebGLRenderingContext::clearDepth(GC3Dfloat depth)
+{
+    if (isContextLost())
+        return;
+    m_clearDepth = depth;
+    m_context->clearDepth(depth);
+}
+
+void WebGLRenderingContext::clearStencil(GC3Dint s)
+{
+    if (isContextLost())
+        return;
+    m_clearStencil = s;
+    m_context->clearStencil(s);
+}
+
+void WebGLRenderingContext::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
+{
+    if (isContextLost())
+        return;
+    m_colorMask[0] = red;
+    m_colorMask[1] = green;
+    m_colorMask[2] = blue;
+    m_colorMask[3] = alpha;
+    m_context->colorMask(red, green, blue, alpha);
+}
+
+void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("compileShader", shader))
+        return;
+    m_context->compileShader(objectOrZero(shader));
+}
+
+void WebGLRenderingContext::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width,
+                                                 GC3Dsizei height, GC3Dint border, ArrayBufferView* data)
+{
+    if (isContextLost())
+        return;
+    if (!validateTexFuncLevel("compressedTexImage2D", target, level))
+        return;
+
+    if (!validateCompressedTexFormat(internalformat)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
+        return;
+    }
+    if (border) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "border not 0");
+        return;
+    }
+    if (!validateCompressedTexDimensions("compressedTexImage2D", level, width, height, internalformat))
+        return;
+    if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
+        return;
+
+    WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
+    if (!tex)
+        return;
+    if (!isGLES2NPOTStrict()) {
+        if (level && WebGLTexture::isNPOT(width, height)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2");
+            return;
+        }
+    }
+    graphicsContext3D()->compressedTexImage2D(target, level, internalformat, width, height,
+                                              border, data->byteLength(), data->baseAddress());
+    tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
+}
+
+void WebGLRenderingContext::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                                    GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView* data)
+{
+    if (isContextLost())
+        return;
+    if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
+        return;
+    if (!validateCompressedTexFormat(format)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
+        return;
+    }
+    if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
+        return;
+
+    WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
+    if (!tex)
+        return;
+
+    if (format != tex->getInternalFormat(target, level)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
+        return;
+    }
+
+    if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
+        return;
+
+    graphicsContext3D()->compressedTexSubImage2D(target, level, xoffset, yoffset,
+                                                 width, height, format, data->byteLength(), data->baseAddress());
+}
+
+bool WebGLRenderingContext::validateSettableTexFormat(const char* functionName, GC3Denum format)
+{
+    if (GraphicsContext3D::getClearBitsByFormat(format) & (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format can not be set, only rendered to");
+        return false;
+    }
+    return true;
+}
+
+void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
+{
+    if (isContextLost())
+        return;
+    if (!validateTexFuncParameters("copyTexImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
+        return;
+    if (!validateSettableTexFormat("copyTexImage2D", internalformat))
+        return;
+    WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true);
+    if (!tex)
+        return;
+    if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexImage2D", "framebuffer is incompatible format");
+        return;
+    }
+    if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexImage2D", "level > 0 not power of 2");
+        return;
+    }
+    const char* reason = "framebuffer incomplete";
+    if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D", reason);
+        return;
+    }
+    clearIfComposited();
+    ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
+    m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
+    // FIXME: if the framebuffer is not complete, none of the below should be executed.
+    tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
+}
+
+void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+    if (isContextLost())
+        return;
+    if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
+        return;
+    WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
+    if (!tex)
+        return;
+    if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
+        return;
+    // Before checking if it is in the range, check if overflow happens first.
+    if (xoffset + width < 0 || yoffset + height < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "bad dimensions");
+        return;
+    }
+    if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
+        return;
+    }
+    GC3Denum internalformat = tex->getInternalFormat(target, level);
+    if (!validateSettableTexFormat("copyTexSubImage2D", internalformat))
+        return;
+    if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
+        return;
+    }
+    const char* reason = "framebuffer incomplete";
+    if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", reason);
+        return;
+    }
+    clearIfComposited();
+    ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
+    m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+}
+
+PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer()
+{
+    if (isContextLost())
+        return 0;
+    RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
+    addSharedObject(o.get());
+    return o;
+}
+
+PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer()
+{
+    if (isContextLost())
+        return 0;
+    RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
+    addContextObject(o.get());
+    return o;
+}
+
+PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture()
+{
+    if (isContextLost())
+        return 0;
+    RefPtr<WebGLTexture> o = WebGLTexture::create(this);
+    addSharedObject(o.get());
+    return o;
+}
+
+PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram()
+{
+    if (isContextLost())
+        return 0;
+    RefPtr<WebGLProgram> o = WebGLProgram::create(this);
+    addSharedObject(o.get());
+    return o;
+}
+
+PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer()
+{
+    if (isContextLost())
+        return 0;
+    RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
+    addSharedObject(o.get());
+    return o;
+}
+
+PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(GC3Denum type, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return 0;
+    if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "createShader", "invalid shader type");
+        return 0;
+    }
+
+    RefPtr<WebGLShader> o = WebGLShader::create(this, type);
+    addSharedObject(o.get());
+    return o;
+}
+
+void WebGLRenderingContext::cullFace(GC3Denum mode)
+{
+    if (isContextLost())
+        return;
+    m_context->cullFace(mode);
+}
+
+bool WebGLRenderingContext::deleteObject(WebGLObject* object)
+{
+    if (isContextLost() || !object)
+        return false;
+    if (!object->validate(contextGroup(), this)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "delete", "object does not belong to this context");
+        return false;
+    }
+    if (object->object())
+        // We need to pass in context here because we want
+        // things in this context unbound.
+        object->deleteObject(graphicsContext3D());
+    return true;
+}
+
+void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
+{
+    if (!deleteObject(buffer))
+        return;
+    if (m_boundArrayBuffer == buffer)
+        m_boundArrayBuffer = 0;
+
+    m_boundVertexArrayObject->unbindBuffer(buffer);
+}
+
+void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
+{
+    if (!deleteObject(framebuffer))
+        return;
+    if (framebuffer == m_framebufferBinding) {
+        m_framebufferBinding = 0;
+        m_drawingBuffer->setFramebufferBinding(0);
+        // Have to call bindFramebuffer here to bind back to internal fbo.
+        m_drawingBuffer->bind();
+    }
+}
+
+void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
+{
+    deleteObject(program);
+    // We don't reset m_currentProgram to 0 here because the deletion of the
+    // current program is delayed.
+}
+
+void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
+{
+    if (!deleteObject(renderbuffer))
+        return;
+    if (renderbuffer == m_renderbufferBinding)
+        m_renderbufferBinding = 0;
+    if (m_framebufferBinding)
+        m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
+}
+
+void WebGLRenderingContext::deleteShader(WebGLShader* shader)
+{
+    deleteObject(shader);
+}
+
+void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
+{
+    if (!deleteObject(texture))
+        return;
+    for (size_t i = 0; i < m_textureUnits.size(); ++i) {
+        if (texture == m_textureUnits[i].m_texture2DBinding)
+            m_textureUnits[i].m_texture2DBinding = 0;
+        if (texture == m_textureUnits[i].m_textureCubeMapBinding)
+            m_textureUnits[i].m_textureCubeMapBinding = 0;
+    }
+    if (m_framebufferBinding)
+        m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
+}
+
+void WebGLRenderingContext::depthFunc(GC3Denum func)
+{
+    if (isContextLost())
+        return;
+    m_context->depthFunc(func);
+}
+
+void WebGLRenderingContext::depthMask(GC3Dboolean flag)
+{
+    if (isContextLost())
+        return;
+    m_depthMask = flag;
+    m_context->depthMask(flag);
+}
+
+void WebGLRenderingContext::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
+{
+    if (isContextLost())
+        return;
+    if (zNear > zFar) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "depthRange", "zNear > zFar");
+        return;
+    }
+    m_context->depthRange(zNear, zFar);
+}
+
+void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
+        return;
+    if (!program->detachShader(shader)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "detachShader", "shader not attached");
+        return;
+    }
+    m_context->detachShader(objectOrZero(program), objectOrZero(shader));
+    shader->onDetached(graphicsContext3D());
+}
+
+void WebGLRenderingContext::disable(GC3Denum cap)
+{
+    if (isContextLost() || !validateCapability("disable", cap))
+        return;
+    if (cap == GraphicsContext3D::STENCIL_TEST) {
+        m_stencilEnabled = false;
+        applyStencilTest();
+        return;
+    }
+    if (cap == GraphicsContext3D::SCISSOR_TEST) {
+        m_scissorEnabled = false;
+        m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
+    }
+    m_context->disable(cap);
+}
+
+void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return;
+    if (index >= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "disableVertexAttribArray", "index out of range");
+        return;
+    }
+
+    WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
+    state.enabled = false;
+    m_context->disableVertexAttribArray(index);
+}
+
+bool WebGLRenderingContext::validateRenderingState()
+{
+    if (!m_currentProgram)
+        return false;
+
+    // Look in each enabled vertex attrib and check if they've been bound to a buffer.
+    for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
+        const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
+        if (state.enabled
+            && (!state.bufferBinding || !state.bufferBinding->object()))
+            return false;
+    }
+
+    return true;
+}
+
+bool WebGLRenderingContext::validateWebGLObject(const char* functionName, WebGLObject* object)
+{
+    if (!object || !object->object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no object or object deleted");
+        return false;
+    }
+    if (!object->validate(contextGroup(), this)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object does not belong to this context");
+        return false;
+    }
+    return true;
+}
+
+void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+
+    if (isContextLost() || !validateDrawMode("drawArrays", mode))
+        return;
+
+    if (!validateStencilSettings("drawArrays"))
+        return;
+
+    if (first < 0 || count < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawArrays", "first or count < 0");
+        return;
+    }
+
+    if (!count) {
+        markContextChanged();
+        return;
+    }
+
+    if (!validateRenderingState()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attribs not setup correctly");
+        return;
+    }
+
+    const char* reason = "framebuffer incomplete";
+    if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawArrays", reason);
+        return;
+    }
+
+    clearIfComposited();
+
+    bool vertexAttrib0Simulated = false;
+    if (!isGLES2NPOTStrict())
+        handleNPOTTextures("drawArrays", true);
+    m_context->drawArrays(mode, first, count);
+    if (!isGLES2NPOTStrict())
+        handleNPOTTextures("drawArrays", false);
+    markContextChanged();
+}
+
+void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+
+    if (isContextLost() || !validateDrawMode("drawElements", mode))
+        return;
+
+    if (!validateStencilSettings("drawElements"))
+        return;
+
+    switch (type) {
+    case GraphicsContext3D::UNSIGNED_BYTE:
+    case GraphicsContext3D::UNSIGNED_SHORT:
+        break;
+    case GraphicsContext3D::UNSIGNED_INT:
+        if (m_oesElementIndexUint)
+            break;
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "drawElements", "invalid type");
+        return;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "drawElements", "invalid type");
+        return;
+    }
+
+    if (count < 0 || offset < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawElements", "count or offset < 0");
+        return;
+    }
+
+    if (!count) {
+        markContextChanged();
+        return;
+    }
+
+    if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "no ELEMENT_ARRAY_BUFFER bound");
+        return;
+    }
+
+    unsigned numElements = 0;
+    if (!validateRenderingState()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attribs not setup correctly");
+        return;
+    }
+
+    const char* reason = "framebuffer incomplete";
+    if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawElements", reason);
+        return;
+    }
+    clearIfComposited();
+
+    if (!isGLES2NPOTStrict())
+        handleNPOTTextures("drawElements", true);
+    m_context->drawElements(mode, count, type, static_cast<GC3Dintptr>(offset));
+    if (!isGLES2NPOTStrict())
+        handleNPOTTextures("drawElements", false);
+    markContextChanged();
+}
+
+void WebGLRenderingContext::enable(GC3Denum cap)
+{
+    if (isContextLost() || !validateCapability("enable", cap))
+        return;
+    if (cap == GraphicsContext3D::STENCIL_TEST) {
+        m_stencilEnabled = true;
+        applyStencilTest();
+        return;
+    }
+    if (cap == GraphicsContext3D::SCISSOR_TEST) {
+        m_scissorEnabled = true;
+        m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
+    }
+    m_context->enable(cap);
+}
+
+void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return;
+    if (index >= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "enableVertexAttribArray", "index out of range");
+        return;
+    }
+
+    WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
+    state.enabled = true;
+
+    m_context->enableVertexAttribArray(index);
+}
+
+void WebGLRenderingContext::finish()
+{
+    if (isContextLost())
+        return;
+    m_context->finish();
+}
+
+void WebGLRenderingContext::flush()
+{
+    if (isContextLost())
+        return;
+    m_context->flush();
+}
+
+void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
+        return;
+    if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
+        return;
+    }
+    if (buffer && !buffer->validate(contextGroup(), this)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
+        return;
+    }
+    // Don't allow the default framebuffer to be mutated; all current
+    // implementations use an FBO internally in place of the default
+    // FBO.
+    if (!m_framebufferBinding || !m_framebufferBinding->object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
+        return;
+    }
+    Platform3DObject bufferObject = objectOrZero(buffer);
+    switch (attachment) {
+    case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+        m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
+        m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
+        break;
+    default:
+        m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
+    }
+    m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
+    applyStencilTest();
+}
+
+void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
+        return;
+    if (level) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "framebufferTexture2D", "level not 0");
+        return;
+    }
+    if (texture && !texture->validate(contextGroup(), this)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
+        return;
+    }
+    // Don't allow the default framebuffer to be mutated; all current
+    // implementations use an FBO internally in place of the default
+    // FBO.
+    if (!m_framebufferBinding || !m_framebufferBinding->object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
+        return;
+    }
+    Platform3DObject textureObject = objectOrZero(texture);
+    switch (attachment) {
+    case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+        m_context->framebufferTexture2D(target, GraphicsContext3D::DEPTH_ATTACHMENT, textarget, textureObject, level);
+        m_context->framebufferTexture2D(target, GraphicsContext3D::STENCIL_ATTACHMENT, textarget, textureObject, level);
+        break;
+    case GraphicsContext3D::DEPTH_ATTACHMENT:
+        m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
+        break;
+    case GraphicsContext3D::STENCIL_ATTACHMENT:
+        m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
+        break;
+    default:
+        m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
+    }
+    m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
+    applyStencilTest();
+}
+
+void WebGLRenderingContext::frontFace(GC3Denum mode)
+{
+    if (isContextLost())
+        return;
+    m_context->frontFace(mode);
+}
+
+void WebGLRenderingContext::generateMipmap(GC3Denum target)
+{
+    if (isContextLost())
+        return;
+    WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
+    if (!tex)
+        return;
+    if (!tex->canGenerateMipmaps()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
+        return;
+    }
+    if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0)))
+        return;
+
+    // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
+    // on Mac.  Remove the hack once this driver bug is fixed.
+#if OS(DARWIN)
+    bool needToResetMinFilter = false;
+    if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
+        m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
+        needToResetMinFilter = true;
+    }
+#endif
+    m_context->generateMipmap(target);
+#if OS(DARWIN)
+    if (needToResetMinFilter)
+        m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
+#endif
+    tex->generateMipmapLevelInfo();
+}
+
+PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("getActiveAttrib", program))
+        return 0;
+    ActiveInfo info;
+    if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
+        return 0;
+    return WebGLActiveInfo::create(info.name, info.type, info.size);
+}
+
+PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("getActiveUniform", program))
+        return 0;
+    ActiveInfo info;
+    if (!m_context->getActiveUniform(objectOrZero(program), index, info))
+        return 0;
+    return WebGLActiveInfo::create(info.name, info.type, info.size);
+}
+
+bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader> >& shaderObjects, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    shaderObjects.clear();
+    if (isContextLost() || !validateWebGLObject("getAttachedShaders", program))
+        return false;
+
+    const GC3Denum shaderType[] = {
+        GraphicsContext3D::VERTEX_SHADER,
+        GraphicsContext3D::FRAGMENT_SHADER
+    };
+    for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
+        WebGLShader* shader = program->getAttachedShader(shaderType[i]);
+        if (shader)
+            shaderObjects.append(shader);
+    }
+    return true;
+}
+
+GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
+{
+    if (isContextLost() || !validateWebGLObject("getAttribLocation", program))
+        return -1;
+    if (!validateLocationLength("getAttribLocation", name))
+        return -1;
+    if (!validateString("getAttribLocation", name))
+        return -1;
+    if (isPrefixReserved(name))
+        return -1;
+    if (!program->getLinkStatus()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getAttribLocation", "program not linked");
+        return 0;
+    }
+    return m_context->getAttribLocation(objectOrZero(program), name);
+}
+
+WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return WebGLGetInfo();
+    if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid target");
+        return WebGLGetInfo();
+    }
+
+    if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid parameter name");
+        return WebGLGetInfo();
+    }
+
+    GC3Dint value = 0;
+    m_context->getBufferParameteriv(target, pname, &value);
+    if (pname == GraphicsContext3D::BUFFER_SIZE)
+        return WebGLGetInfo(value);
+    return WebGLGetInfo(static_cast<unsigned int>(value));
+}
+
+PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
+{
+    if (isContextLost())
+        return 0;
+    // We always need to return a new WebGLContextAttributes object to
+    // prevent the user from mutating any cached version.
+
+    // Also, we need to enforce requested values of "false" for depth
+    // and stencil, regardless of the properties of the underlying
+    // GraphicsContext3D or DrawingBuffer.
+    RefPtr<WebGLContextAttributes> attributes = WebGLContextAttributes::create(m_context->getContextAttributes());
+    if (!m_attributes.depth)
+        attributes->setDepth(false);
+    if (!m_attributes.stencil)
+        attributes->setStencil(false);
+    // The DrawingBuffer obtains its parameters from GraphicsContext3D::getContextAttributes(),
+    // but it makes its own determination of whether multisampling is supported.
+    attributes->setAntialias(m_drawingBuffer->multisample());
+    return attributes.release();
+}
+
+GC3Denum WebGLRenderingContext::getError()
+{
+    if (lost_context_errors_.size()) {
+        GC3Denum err = lost_context_errors_.first();
+        lost_context_errors_.remove(0);
+        return err;
+    }
+
+    if (isContextLost())
+        return GraphicsContext3D::NO_ERROR;
+
+    return m_context->getError();
+}
+
+bool WebGLRenderingContext::matchesNameWithPrefixes(const String& name, const String& baseName, const char** prefixes)
+{
+    for (; *prefixes; ++prefixes) {
+        String prefixedName = String(*prefixes) + baseName;
+        if (equalIgnoringCase(prefixedName, name)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
+{
+    if (isContextLost())
+        return 0;
+
+    static const char* unprefixed[] = { "", NULL, };
+    static const char* webkitPrefix[] = { "WEBKIT_", NULL, };
+    static const char* bothPrefixes[] = { "", "WEBKIT_", NULL, };
+
+    WebGLExtension* extension = 0;
+    if (getExtensionIfMatch<OESStandardDerivatives>(name, m_oesStandardDerivatives, unprefixed, extension))
+        return extension;
+    if (getExtensionIfMatch<EXTTextureFilterAnisotropic>(name, m_extTextureFilterAnisotropic, webkitPrefix, extension))
+        return extension;
+    if (getExtensionIfMatch<OESTextureFloat>(name, m_oesTextureFloat, unprefixed, extension))
+        return extension;
+    if (getExtensionIfMatch<OESTextureHalfFloat>(name, m_oesTextureHalfFloat, unprefixed, extension))
+        return extension;
+    if (getExtensionIfMatch<OESVertexArrayObject>(name, m_oesVertexArrayObject, unprefixed, extension))
+        return extension;
+    if (getExtensionIfMatch<OESElementIndexUint>(name, m_oesElementIndexUint, unprefixed, extension))
+        return extension;
+    if (getExtensionIfMatch<WebGLLoseContext>(name, m_webglLoseContext, bothPrefixes, extension))
+        return extension;
+    if (getExtensionIfMatch<WebGLCompressedTextureATC>(name, m_webglCompressedTextureATC, webkitPrefix, extension))
+        return extension;
+    if (getExtensionIfMatch<WebGLCompressedTexturePVRTC>(name, m_webglCompressedTexturePVRTC, webkitPrefix, extension))
+        return extension;
+    if (getExtensionIfMatch<WebGLCompressedTextureS3TC>(name, m_webglCompressedTextureS3TC, bothPrefixes, extension))
+        return extension;
+    if (getExtensionIfMatch<WebGLDepthTexture>(name, m_webglDepthTexture, bothPrefixes, extension))
+        return extension;
+    if (getExtensionIfMatch<EXTDrawBuffers>(name, m_extDrawBuffers, unprefixed, extension))
+        return extension;
+    if (allowPrivilegedExtensions()) {
+        if (getExtensionIfMatch<WebGLDebugRendererInfo>(name, m_webglDebugRendererInfo, unprefixed, extension))
+            return extension;
+        if (getExtensionIfMatch<WebGLDebugShaders>(name, m_webglDebugShaders, unprefixed, extension))
+            return extension;
+    }
+
+    return 0;
+}
+
+WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
+        return WebGLGetInfo();
+
+    if (!m_framebufferBinding || !m_framebufferBinding->object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
+        return WebGLGetInfo();
+    }
+
+    WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
+    if (!object) {
+        if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
+            return WebGLGetInfo(GraphicsContext3D::NONE);
+        // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
+        // specifies INVALID_OPERATION.
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
+        return WebGLGetInfo();
+    }
+
+    ASSERT(object->isTexture() || object->isRenderbuffer());
+    if (object->isTexture()) {
+        switch (pname) {
+        case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+            return WebGLGetInfo(GraphicsContext3D::TEXTURE);
+        case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+            return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
+        case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+        case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+            {
+                GC3Dint value = 0;
+                m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
+                return WebGLGetInfo(value);
+            }
+        default:
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
+            return WebGLGetInfo();
+        }
+    } else {
+        switch (pname) {
+        case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+            return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
+        case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+            return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
+        default:
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
+            return WebGLGetInfo();
+        }
+    }
+}
+
+WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return WebGLGetInfo();
+    const int intZero = 0;
+    switch (pname) {
+    case GraphicsContext3D::ACTIVE_TEXTURE:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
+        return getWebGLFloatArrayParameter(pname);
+    case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
+        return getWebGLFloatArrayParameter(pname);
+    case GraphicsContext3D::ALPHA_BITS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::ARRAY_BUFFER_BINDING:
+        return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
+    case GraphicsContext3D::BLEND:
+        return getBooleanParameter(pname);
+    case GraphicsContext3D::BLEND_COLOR:
+        return getWebGLFloatArrayParameter(pname);
+    case GraphicsContext3D::BLEND_DST_ALPHA:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::BLEND_DST_RGB:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::BLEND_EQUATION_ALPHA:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::BLEND_EQUATION_RGB:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::BLEND_SRC_ALPHA:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::BLEND_SRC_RGB:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::BLUE_BITS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::COLOR_CLEAR_VALUE:
+        return getWebGLFloatArrayParameter(pname);
+    case GraphicsContext3D::COLOR_WRITEMASK:
+        return getBooleanArrayParameter(pname);
+    case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
+        return WebGLGetInfo(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()));
+    case GraphicsContext3D::CULL_FACE:
+        return getBooleanParameter(pname);
+    case GraphicsContext3D::CULL_FACE_MODE:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::CURRENT_PROGRAM:
+        return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
+    case GraphicsContext3D::DEPTH_BITS:
+        if (!m_framebufferBinding && !m_attributes.depth)
+            return WebGLGetInfo(intZero);
+        return getIntParameter(pname);
+    case GraphicsContext3D::DEPTH_CLEAR_VALUE:
+        return getFloatParameter(pname);
+    case GraphicsContext3D::DEPTH_FUNC:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::DEPTH_RANGE:
+        return getWebGLFloatArrayParameter(pname);
+    case GraphicsContext3D::DEPTH_TEST:
+        return getBooleanParameter(pname);
+    case GraphicsContext3D::DEPTH_WRITEMASK:
+        return getBooleanParameter(pname);
+    case GraphicsContext3D::DITHER:
+        return getBooleanParameter(pname);
+    case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
+        return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
+    case GraphicsContext3D::FRAMEBUFFER_BINDING:
+        return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
+    case GraphicsContext3D::FRONT_FACE:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::GENERATE_MIPMAP_HINT:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::GREEN_BITS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::LINE_WIDTH:
+        return getFloatParameter(pname);
+    case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_TEXTURE_SIZE:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_VARYING_VECTORS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::MAX_VIEWPORT_DIMS:
+        return getWebGLIntArrayParameter(pname);
+    case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
+        // FIXME: should we always return 0 for this?
+        return getIntParameter(pname);
+    case GraphicsContext3D::PACK_ALIGNMENT:
+        return getIntParameter(pname);
+    case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
+        return getFloatParameter(pname);
+    case GraphicsContext3D::POLYGON_OFFSET_FILL:
+        return getBooleanParameter(pname);
+    case GraphicsContext3D::POLYGON_OFFSET_UNITS:
+        return getFloatParameter(pname);
+    case GraphicsContext3D::RED_BITS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::RENDERBUFFER_BINDING:
+        return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
+    case GraphicsContext3D::RENDERER:
+        return WebGLGetInfo(String("WebKit WebGL"));
+    case GraphicsContext3D::SAMPLE_BUFFERS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
+        return getBooleanParameter(pname);
+    case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
+        return getFloatParameter(pname);
+    case GraphicsContext3D::SAMPLES:
+        return getIntParameter(pname);
+    case GraphicsContext3D::SCISSOR_BOX:
+        return getWebGLIntArrayParameter(pname);
+    case GraphicsContext3D::SCISSOR_TEST:
+        return getBooleanParameter(pname);
+    case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
+        return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
+    case GraphicsContext3D::STENCIL_BACK_FAIL:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_BACK_FUNC:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_BACK_REF:
+        return getIntParameter(pname);
+    case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_BITS:
+        if (!m_framebufferBinding && !m_attributes.stencil)
+            return WebGLGetInfo(intZero);
+        return getIntParameter(pname);
+    case GraphicsContext3D::STENCIL_CLEAR_VALUE:
+        return getIntParameter(pname);
+    case GraphicsContext3D::STENCIL_FAIL:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_FUNC:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_REF:
+        return getIntParameter(pname);
+    case GraphicsContext3D::STENCIL_TEST:
+        return getBooleanParameter(pname);
+    case GraphicsContext3D::STENCIL_VALUE_MASK:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::STENCIL_WRITEMASK:
+        return getUnsignedIntParameter(pname);
+    case GraphicsContext3D::SUBPIXEL_BITS:
+        return getIntParameter(pname);
+    case GraphicsContext3D::TEXTURE_BINDING_2D:
+        return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
+    case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
+        return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
+    case GraphicsContext3D::UNPACK_ALIGNMENT:
+        return getIntParameter(pname);
+    case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
+        return WebGLGetInfo(m_unpackFlipY);
+    case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
+        return WebGLGetInfo(m_unpackPremultiplyAlpha);
+    case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
+        return WebGLGetInfo(m_unpackColorspaceConversion);
+    case GraphicsContext3D::VENDOR:
+        return WebGLGetInfo(String("WebKit"));
+    case GraphicsContext3D::VERSION:
+        return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
+    case GraphicsContext3D::VIEWPORT:
+        return getWebGLIntArrayParameter(pname);
+    case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
+        if (m_oesStandardDerivatives)
+            return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
+        return WebGLGetInfo();
+    case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
+        if (m_webglDebugRendererInfo)
+            return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
+        return WebGLGetInfo();
+    case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
+        if (m_webglDebugRendererInfo)
+            return WebGLGetInfo(m_context->getString(GraphicsContext3D::VENDOR));
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
+        return WebGLGetInfo();
+    case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
+        if (m_oesVertexArrayObject) {
+            if (!m_boundVertexArrayObject->isDefaultObject())
+                return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
+            return WebGLGetInfo();
+        }
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
+        return WebGLGetInfo();
+    case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
+        if (m_extTextureFilterAnisotropic)
+            return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT);
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
+        return WebGLGetInfo();
+    case Extensions3D::MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN
+        if (m_extDrawBuffers)
+            return WebGLGetInfo(getMaxColorAttachments());
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_draw_buffers not enabled");
+        return WebGLGetInfo();
+    case Extensions3D::MAX_DRAW_BUFFERS_EXT:
+        if (m_extDrawBuffers)
+            return WebGLGetInfo(getMaxDrawBuffers());
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_draw_buffers not enabled");
+        return WebGLGetInfo();
+    default:
+        if (m_extDrawBuffers
+            && pname >= Extensions3D::DRAW_BUFFER0_EXT
+            && pname < static_cast<GC3Denum>(Extensions3D::DRAW_BUFFER0_EXT + getMaxDrawBuffers())) {
+            GC3Dint value = GraphicsContext3D::NONE;
+            if (m_framebufferBinding)
+                value = m_framebufferBinding->getDrawBuffer(pname);
+            else // emulated backbuffer
+                value = m_backDrawBuffer;
+            return WebGLGetInfo(value);
+        }
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name");
+        return WebGLGetInfo();
+    }
+}
+
+WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("getProgramParameter", program))
+        return WebGLGetInfo();
+
+    GC3Dint value = 0;
+    switch (pname) {
+    case GraphicsContext3D::DELETE_STATUS:
+        return WebGLGetInfo(program->isDeleted());
+    case GraphicsContext3D::VALIDATE_STATUS:
+        m_context->getProgramiv(objectOrZero(program), pname, &value);
+        return WebGLGetInfo(static_cast<bool>(value));
+    case GraphicsContext3D::LINK_STATUS:
+        return WebGLGetInfo(program->getLinkStatus());
+    case GraphicsContext3D::ATTACHED_SHADERS:
+    case GraphicsContext3D::ACTIVE_ATTRIBUTES:
+    case GraphicsContext3D::ACTIVE_UNIFORMS:
+        m_context->getProgramiv(objectOrZero(program), pname, &value);
+        return WebGLGetInfo(value);
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getProgramParameter", "invalid parameter name");
+        return WebGLGetInfo();
+    }
+}
+
+String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return String();
+    if (!validateWebGLObject("getProgramInfoLog", program))
+        return "";
+    return ensureNotNull(m_context->getProgramInfoLog(objectOrZero(program)));
+}
+
+WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return WebGLGetInfo();
+    if (target != GraphicsContext3D::RENDERBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid target");
+        return WebGLGetInfo();
+    }
+    if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
+        return WebGLGetInfo();
+    }
+
+    if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
+        && !m_renderbufferBinding->isValid()) {
+        ASSERT(!isDepthStencilSupported());
+        int value = 0;
+        switch (pname) {
+        case GraphicsContext3D::RENDERBUFFER_WIDTH:
+            value = m_renderbufferBinding->getWidth();
+            break;
+        case GraphicsContext3D::RENDERBUFFER_HEIGHT:
+            value = m_renderbufferBinding->getHeight();
+            break;
+        case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
+        case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
+        case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
+        case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
+            value = 0;
+            break;
+        case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
+            value = 24;
+            break;
+        case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
+            value = 8;
+            break;
+        case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
+            return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
+        default:
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
+            return WebGLGetInfo();
+        }
+        return WebGLGetInfo(value);
+    }
+
+    GC3Dint value = 0;
+    switch (pname) {
+    case GraphicsContext3D::RENDERBUFFER_WIDTH:
+    case GraphicsContext3D::RENDERBUFFER_HEIGHT:
+    case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
+        m_context->getRenderbufferParameteriv(target, pname, &value);
+        return WebGLGetInfo(value);
+    case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
+        return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
+        return WebGLGetInfo();
+    }
+}
+
+WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("getShaderParameter", shader))
+        return WebGLGetInfo();
+    GC3Dint value = 0;
+    switch (pname) {
+    case GraphicsContext3D::DELETE_STATUS:
+        return WebGLGetInfo(shader->isDeleted());
+    case GraphicsContext3D::COMPILE_STATUS:
+        m_context->getShaderiv(objectOrZero(shader), pname, &value);
+        return WebGLGetInfo(static_cast<bool>(value));
+    case GraphicsContext3D::SHADER_TYPE:
+        m_context->getShaderiv(objectOrZero(shader), pname, &value);
+        return WebGLGetInfo(static_cast<unsigned int>(value));
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderParameter", "invalid parameter name");
+        return WebGLGetInfo();
+    }
+}
+
+String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return String();
+    if (!validateWebGLObject("getShaderInfoLog", shader))
+        return "";
+    return ensureNotNull(m_context->getShaderInfoLog(objectOrZero(shader)));
+}
+
+PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContext::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return 0;
+    switch (shaderType) {
+    case GraphicsContext3D::VERTEX_SHADER:
+    case GraphicsContext3D::FRAGMENT_SHADER:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
+        return 0;
+    }
+    switch (precisionType) {
+    case GraphicsContext3D::LOW_FLOAT:
+    case GraphicsContext3D::MEDIUM_FLOAT:
+    case GraphicsContext3D::HIGH_FLOAT:
+    case GraphicsContext3D::LOW_INT:
+    case GraphicsContext3D::MEDIUM_INT:
+    case GraphicsContext3D::HIGH_INT:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
+        return 0;
+    }
+
+    GC3Dint range[2] = {0, 0};
+    GC3Dint precision = 0;
+    m_context->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
+    return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
+}
+
+String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return String();
+    if (!validateWebGLObject("getShaderSource", shader))
+        return "";
+    return ensureNotNull(shader->getSource());
+}
+
+Vector<String> WebGLRenderingContext::getSupportedExtensions()
+{
+    Vector<String> result;
+    if (isContextLost())
+        return result;
+
+    appendIfSupported<EXTDrawBuffers>(result, false);
+    appendIfSupported<EXTTextureFilterAnisotropic>(result, true);
+    appendIfSupported<OESElementIndexUint>(result, false);
+    appendIfSupported<OESStandardDerivatives>(result, false);
+    appendIfSupported<OESTextureFloat>(result, false);
+    appendIfSupported<OESVertexArrayObject>(result, false);
+    appendIfSupported<WebGLCompressedTextureATC>(result, true);
+    appendIfSupported<WebGLCompressedTexturePVRTC>(result, true);
+    appendIfSupported<WebGLCompressedTextureS3TC>(result, true);
+    appendIfSupported<WebGLDepthTexture>(result, true);
+    appendIfSupported<WebGLLoseContext>(result, false);
+
+    if (allowPrivilegedExtensions()) {
+        appendIfSupported<WebGLDebugShaders>(result, false);
+        appendIfSupported<WebGLDebugRendererInfo>(result, false);
+    }
+
+    return result;
+}
+
+WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return WebGLGetInfo();
+    WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
+    if (!tex)
+        return WebGLGetInfo();
+    GC3Dint value = 0;
+    switch (pname) {
+    case GraphicsContext3D::TEXTURE_MAG_FILTER:
+    case GraphicsContext3D::TEXTURE_MIN_FILTER:
+    case GraphicsContext3D::TEXTURE_WRAP_S:
+    case GraphicsContext3D::TEXTURE_WRAP_T:
+        m_context->getTexParameteriv(target, pname, &value);
+        return WebGLGetInfo(static_cast<unsigned int>(value));
+    case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
+        if (m_extTextureFilterAnisotropic) {
+            m_context->getTexParameteriv(target, pname, &value);
+            return WebGLGetInfo(static_cast<unsigned int>(value));
+        }
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
+        return WebGLGetInfo();
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name");
+        return WebGLGetInfo();
+    }
+}
+
+WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("getUniform", program))
+        return WebGLGetInfo();
+    if (!uniformLocation || uniformLocation->program() != program) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
+        return WebGLGetInfo();
+    }
+    GC3Dint location = uniformLocation->location();
+
+    // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
+    GC3Dint activeUniforms = 0;
+    m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
+    for (GC3Dint i = 0; i < activeUniforms; i++) {
+        ActiveInfo info;
+        if (!m_context->getActiveUniform(objectOrZero(program), i, info))
+            return WebGLGetInfo();
+        // Strip "[0]" from the name if it's an array.
+        if (info.size > 1 && info.name.endsWith("[0]"))
+            info.name = info.name.left(info.name.length() - 3);
+        // If it's an array, we need to iterate through each element, appending "[index]" to the name.
+        for (GC3Dint index = 0; index < info.size; ++index) {
+            String name = info.name;
+            if (info.size > 1 && index >= 1) {
+                name.append('[');
+                name.append(String::number(index));
+                name.append(']');
+            }
+            // Now need to look this up by name again to find its location
+            GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name);
+            if (loc == location) {
+                // Found it. Use the type in the ActiveInfo to determine the return type.
+                GC3Denum baseType;
+                unsigned int length;
+                switch (info.type) {
+                case GraphicsContext3D::BOOL:
+                    baseType = GraphicsContext3D::BOOL;
+                    length = 1;
+                    break;
+                case GraphicsContext3D::BOOL_VEC2:
+                    baseType = GraphicsContext3D::BOOL;
+                    length = 2;
+                    break;
+                case GraphicsContext3D::BOOL_VEC3:
+                    baseType = GraphicsContext3D::BOOL;
+                    length = 3;
+                    break;
+                case GraphicsContext3D::BOOL_VEC4:
+                    baseType = GraphicsContext3D::BOOL;
+                    length = 4;
+                    break;
+                case GraphicsContext3D::INT:
+                    baseType = GraphicsContext3D::INT;
+                    length = 1;
+                    break;
+                case GraphicsContext3D::INT_VEC2:
+                    baseType = GraphicsContext3D::INT;
+                    length = 2;
+                    break;
+                case GraphicsContext3D::INT_VEC3:
+                    baseType = GraphicsContext3D::INT;
+                    length = 3;
+                    break;
+                case GraphicsContext3D::INT_VEC4:
+                    baseType = GraphicsContext3D::INT;
+                    length = 4;
+                    break;
+                case GraphicsContext3D::FLOAT:
+                    baseType = GraphicsContext3D::FLOAT;
+                    length = 1;
+                    break;
+                case GraphicsContext3D::FLOAT_VEC2:
+                    baseType = GraphicsContext3D::FLOAT;
+                    length = 2;
+                    break;
+                case GraphicsContext3D::FLOAT_VEC3:
+                    baseType = GraphicsContext3D::FLOAT;
+                    length = 3;
+                    break;
+                case GraphicsContext3D::FLOAT_VEC4:
+                    baseType = GraphicsContext3D::FLOAT;
+                    length = 4;
+                    break;
+                case GraphicsContext3D::FLOAT_MAT2:
+                    baseType = GraphicsContext3D::FLOAT;
+                    length = 4;
+                    break;
+                case GraphicsContext3D::FLOAT_MAT3:
+                    baseType = GraphicsContext3D::FLOAT;
+                    length = 9;
+                    break;
+                case GraphicsContext3D::FLOAT_MAT4:
+                    baseType = GraphicsContext3D::FLOAT;
+                    length = 16;
+                    break;
+                case GraphicsContext3D::SAMPLER_2D:
+                case GraphicsContext3D::SAMPLER_CUBE:
+                    baseType = GraphicsContext3D::INT;
+                    length = 1;
+                    break;
+                default:
+                    // Can't handle this type
+                    synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unhandled type");
+                    return WebGLGetInfo();
+                }
+                switch (baseType) {
+                case GraphicsContext3D::FLOAT: {
+                    GC3Dfloat value[16] = {0};
+                    if (m_isRobustnessEXTSupported)
+                        m_context->getExtensions()->getnUniformfvEXT(objectOrZero(program), location, 16 * sizeof(GC3Dfloat), value);
+                    else
+                        m_context->getUniformfv(objectOrZero(program), location, value);
+                    if (length == 1)
+                        return WebGLGetInfo(value[0]);
+                    return WebGLGetInfo(Float32Array::create(value, length));
+                }
+                case GraphicsContext3D::INT: {
+                    GC3Dint value[4] = {0};
+                    if (m_isRobustnessEXTSupported)
+                        m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
+                    else
+                        m_context->getUniformiv(objectOrZero(program), location, value);
+                    if (length == 1)
+                        return WebGLGetInfo(value[0]);
+                    return WebGLGetInfo(Int32Array::create(value, length));
+                }
+                case GraphicsContext3D::BOOL: {
+                    GC3Dint value[4] = {0};
+                    if (m_isRobustnessEXTSupported)
+                        m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
+                    else
+                        m_context->getUniformiv(objectOrZero(program), location, value);
+                    if (length > 1) {
+                        bool boolValue[16] = {0};
+                        for (unsigned j = 0; j < length; j++)
+                            boolValue[j] = static_cast<bool>(value[j]);
+                        return WebGLGetInfo(boolValue, length);
+                    }
+                    return WebGLGetInfo(static_cast<bool>(value[0]));
+                }
+                default:
+                    notImplemented();
+                }
+            }
+        }
+    }
+    // If we get here, something went wrong in our unfortunately complex logic above
+    synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unknown error");
+    return WebGLGetInfo();
+}
+
+PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("getUniformLocation", program))
+        return 0;
+    if (!validateLocationLength("getUniformLocation", name))
+        return 0;
+    if (!validateString("getUniformLocation", name))
+        return 0;
+    if (isPrefixReserved(name))
+        return 0;
+    if (!program->getLinkStatus()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniformLocation", "program not linked");
+        return 0;
+    }
+    GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
+    if (uniformLocation == -1)
+        return 0;
+    return WebGLUniformLocation::create(program, uniformLocation);
+}
+
+WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return WebGLGetInfo();
+    if (index >= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
+        return WebGLGetInfo();
+    }
+    const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
+    switch (pname) {
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+        if (!state.bufferBinding || !state.bufferBinding->object())
+            return WebGLGetInfo();
+        return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
+        return WebGLGetInfo(state.enabled);
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
+        return WebGLGetInfo(state.normalized);
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
+        return WebGLGetInfo(state.size);
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
+        return WebGLGetInfo(state.originalStride);
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
+        return WebGLGetInfo(state.type);
+    case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
+        return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
+        return WebGLGetInfo();
+    }
+}
+
+long long WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
+{
+    if (isContextLost())
+        return 0;
+    GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
+    return static_cast<long long>(result);
+}
+
+void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
+{
+    if (isContextLost())
+        return;
+    bool isValid = false;
+    switch (target) {
+    case GraphicsContext3D::GENERATE_MIPMAP_HINT:
+        isValid = true;
+        break;
+    case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
+        if (m_oesStandardDerivatives)
+            isValid = true;
+        break;
+    }
+    if (!isValid) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target");
+        return;
+    }
+    m_context->hint(target, mode);
+}
+
+GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
+{
+    if (!buffer || isContextLost())
+        return 0;
+
+    if (!buffer->hasEverBeenBound())
+        return 0;
+
+    return m_context->isBuffer(buffer->object());
+}
+
+bool WebGLRenderingContext::isContextLost()
+{
+    return m_contextLost;
+}
+
+GC3Dboolean WebGLRenderingContext::isEnabled(GC3Denum cap)
+{
+    if (isContextLost() || !validateCapability("isEnabled", cap))
+        return 0;
+    if (cap == GraphicsContext3D::STENCIL_TEST)
+        return m_stencilEnabled;
+    return m_context->isEnabled(cap);
+}
+
+GC3Dboolean WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer)
+{
+    if (!framebuffer || isContextLost())
+        return 0;
+
+    if (!framebuffer->hasEverBeenBound())
+        return 0;
+
+    return m_context->isFramebuffer(framebuffer->object());
+}
+
+GC3Dboolean WebGLRenderingContext::isProgram(WebGLProgram* program)
+{
+    if (!program || isContextLost())
+        return 0;
+
+    return m_context->isProgram(program->object());
+}
+
+GC3Dboolean WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
+{
+    if (!renderbuffer || isContextLost())
+        return 0;
+
+    if (!renderbuffer->hasEverBeenBound())
+        return 0;
+
+    return m_context->isRenderbuffer(renderbuffer->object());
+}
+
+GC3Dboolean WebGLRenderingContext::isShader(WebGLShader* shader)
+{
+    if (!shader || isContextLost())
+        return 0;
+
+    return m_context->isShader(shader->object());
+}
+
+GC3Dboolean WebGLRenderingContext::isTexture(WebGLTexture* texture)
+{
+    if (!texture || isContextLost())
+        return 0;
+
+    if (!texture->hasEverBeenBound())
+        return 0;
+
+    return m_context->isTexture(texture->object());
+}
+
+void WebGLRenderingContext::lineWidth(GC3Dfloat width)
+{
+    if (isContextLost())
+        return;
+    m_context->lineWidth(width);
+}
+
+void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("linkProgram", program))
+        return;
+
+    m_context->linkProgram(objectOrZero(program));
+    program->increaseLinkCount();
+}
+
+void WebGLRenderingContext::pixelStorei(GC3Denum pname, GC3Dint param)
+{
+    if (isContextLost())
+        return;
+    switch (pname) {
+    case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
+        m_unpackFlipY = param;
+        break;
+    case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
+        m_unpackPremultiplyAlpha = param;
+        break;
+    case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
+        if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
+            m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
+        else {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
+            return;
+        }
+        break;
+    case GraphicsContext3D::PACK_ALIGNMENT:
+    case GraphicsContext3D::UNPACK_ALIGNMENT:
+        if (param == 1 || param == 2 || param == 4 || param == 8) {
+            if (pname == GraphicsContext3D::PACK_ALIGNMENT)
+                m_packAlignment = param;
+            else // GraphicsContext3D::UNPACK_ALIGNMENT:
+                m_unpackAlignment = param;
+            m_context->pixelStorei(pname, param);
+        } else {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
+            return;
+        }
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "pixelStorei", "invalid parameter name");
+        return;
+    }
+}
+
+void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
+{
+    if (isContextLost())
+        return;
+    m_context->polygonOffset(factor, units);
+}
+
+void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&)
+{
+    if (isContextLost())
+        return;
+    // Due to WebGL's same-origin restrictions, it is not possible to
+    // taint the origin using the WebGL API.
+    ASSERT(canvas()->originClean());
+    // Validate input parameters.
+    if (!pixels) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "readPixels", "no destination ArrayBufferView");
+        return;
+    }
+    switch (format) {
+    case GraphicsContext3D::ALPHA:
+    case GraphicsContext3D::RGB:
+    case GraphicsContext3D::RGBA:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid format");
+        return;
+    }
+    switch (type) {
+    case GraphicsContext3D::UNSIGNED_BYTE:
+    case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
+    case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
+    case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid type");
+        return;
+    }
+    if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "format not RGBA or type not UNSIGNED_BYTE");
+        return;
+    }
+    // Validate array type against pixel type.
+    if (pixels->getType() != ArrayBufferView::TypeUint8) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not Uint8Array");
+        return;
+    }
+    const char* reason = "framebuffer incomplete";
+    if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
+        return;
+    }
+    // Calculate array size, taking into consideration of PACK_ALIGNMENT.
+    unsigned int totalBytesRequired = 0;
+    unsigned int padding = 0;
+    if (!m_isRobustnessEXTSupported) {
+        GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
+        if (error != GraphicsContext3D::NO_ERROR) {
+            synthesizeGLError(error, "readPixels", "invalid dimensions");
+            return;
+        }
+        if (pixels->byteLength() < totalBytesRequired) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
+            return;
+        }
+    }
+
+    clearIfComposited();
+    void* data = pixels->baseAddress();
+
+    {
+        ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
+        if (m_isRobustnessEXTSupported)
+            m_context->getExtensions()->readnPixelsEXT(x, y, width, height, format, type, pixels->byteLength(), data);
+        else
+            m_context->readPixels(x, y, width, height, format, type, data);
+    }
+
+#if OS(DARWIN)
+    if (m_isRobustnessEXTSupported) // we haven't computed padding
+        m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
+    // FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
+    // when alpha is off, readPixels should set alpha to 255 instead of 0.
+    if (!m_framebufferBinding && !m_context->getContextAttributes().alpha) {
+        unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
+        for (GC3Dsizei iy = 0; iy < height; ++iy) {
+            for (GC3Dsizei ix = 0; ix < width; ++ix) {
+                pixels[3] = 255;
+                pixels += 4;
+            }
+            pixels += padding;
+        }
+    }
+#endif
+}
+
+void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
+{
+    if (isContextLost())
+        return;
+    if (target != GraphicsContext3D::RENDERBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid target");
+        return;
+    }
+    if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer");
+        return;
+    }
+    if (!validateSize("renderbufferStorage", width, height))
+        return;
+    switch (internalformat) {
+    case GraphicsContext3D::DEPTH_COMPONENT16:
+    case GraphicsContext3D::RGBA4:
+    case GraphicsContext3D::RGB5_A1:
+    case GraphicsContext3D::RGB565:
+    case GraphicsContext3D::STENCIL_INDEX8:
+        m_context->renderbufferStorage(target, internalformat, width, height);
+        m_renderbufferBinding->setInternalFormat(internalformat);
+        m_renderbufferBinding->setIsValid(true);
+        m_renderbufferBinding->setSize(width, height);
+        break;
+    case GraphicsContext3D::DEPTH_STENCIL:
+        if (isDepthStencilSupported()) {
+            m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
+        }
+        m_renderbufferBinding->setSize(width, height);
+        m_renderbufferBinding->setIsValid(isDepthStencilSupported());
+        m_renderbufferBinding->setInternalFormat(internalformat);
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
+        return;
+    }
+    applyStencilTest();
+}
+
+void WebGLRenderingContext::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
+{
+    if (isContextLost())
+        return;
+    m_context->sampleCoverage(value, invert);
+}
+
+void WebGLRenderingContext::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+    if (isContextLost())
+        return;
+    if (!validateSize("scissor", width, height))
+        return;
+    m_context->scissor(x, y, width, height);
+}
+
+void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("shaderSource", shader))
+        return;
+    String stringWithoutComments = StripComments(string).result();
+    if (!validateString("shaderSource", stringWithoutComments))
+        return;
+    shader->setSource(string);
+    m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
+}
+
+void WebGLRenderingContext::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+    if (isContextLost())
+        return;
+    if (!validateStencilFunc("stencilFunc", func))
+        return;
+    m_stencilFuncRef = ref;
+    m_stencilFuncRefBack = ref;
+    m_stencilFuncMask = mask;
+    m_stencilFuncMaskBack = mask;
+    m_context->stencilFunc(func, ref, mask);
+}
+
+void WebGLRenderingContext::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+    if (isContextLost())
+        return;
+    if (!validateStencilFunc("stencilFuncSeparate", func))
+        return;
+    switch (face) {
+    case GraphicsContext3D::FRONT_AND_BACK:
+        m_stencilFuncRef = ref;
+        m_stencilFuncRefBack = ref;
+        m_stencilFuncMask = mask;
+        m_stencilFuncMaskBack = mask;
+        break;
+    case GraphicsContext3D::FRONT:
+        m_stencilFuncRef = ref;
+        m_stencilFuncMask = mask;
+        break;
+    case GraphicsContext3D::BACK:
+        m_stencilFuncRefBack = ref;
+        m_stencilFuncMaskBack = mask;
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilFuncSeparate", "invalid face");
+        return;
+    }
+    m_context->stencilFuncSeparate(face, func, ref, mask);
+}
+
+void WebGLRenderingContext::stencilMask(GC3Duint mask)
+{
+    if (isContextLost())
+        return;
+    m_stencilMask = mask;
+    m_stencilMaskBack = mask;
+    m_context->stencilMask(mask);
+}
+
+void WebGLRenderingContext::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
+{
+    if (isContextLost())
+        return;
+    switch (face) {
+    case GraphicsContext3D::FRONT_AND_BACK:
+        m_stencilMask = mask;
+        m_stencilMaskBack = mask;
+        break;
+    case GraphicsContext3D::FRONT:
+        m_stencilMask = mask;
+        break;
+    case GraphicsContext3D::BACK:
+        m_stencilMaskBack = mask;
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilMaskSeparate", "invalid face");
+        return;
+    }
+    m_context->stencilMaskSeparate(face, mask);
+}
+
+void WebGLRenderingContext::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+    if (isContextLost())
+        return;
+    m_context->stencilOp(fail, zfail, zpass);
+}
+
+void WebGLRenderingContext::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+    if (isContextLost())
+        return;
+    m_context->stencilOpSeparate(face, fail, zfail, zpass);
+}
+
+void WebGLRenderingContext::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode& ec)
+{
+    // All calling functions check isContextLost, so a duplicate check is not needed here.
+    // FIXME: For now we ignore any errors returned
+    ec = 0;
+    WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
+    ASSERT(validateTexFuncParameters("texImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, format, type));
+    ASSERT(tex);
+    ASSERT(!level || !WebGLTexture::isNPOT(width, height));
+    ASSERT(!pixels || validateSettableTexFormat("texImage2D", internalformat));
+    m_context->texImage2D(target, level, internalformat, width, height,
+                          border, format, type, pixels);
+    tex->setLevelInfo(target, level, internalformat, width, height, type);
+}
+
+void WebGLRenderingContext::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
+{
+    // All calling functions check isContextLost, so a duplicate check is not needed here.
+    ec = 0;
+    Vector<uint8_t> data;
+    GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);
+    if (!imageExtractor.extractSucceeded()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
+        return;
+    }
+    GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
+    GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
+    const void* imagePixelData = imageExtractor.imagePixelData();
+
+    bool needConversion = true;
+    if (type == GraphicsContext3D::UNSIGNED_BYTE && sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 && format == GraphicsContext3D::RGBA && alphaOp == GraphicsContext3D::AlphaDoNothing && !flipY)
+        needConversion = false;
+    else {
+        if (!m_context->packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "packImage error");
+            return;
+        }
+    }
+
+    if (m_unpackAlignment != 1)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+    texImage2DBase(target, level, internalformat, image->width(), image->height(), 0, format, type, needConversion ? data.data() : imagePixelData, ec);
+    if (m_unpackAlignment != 1)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
+}
+
+bool WebGLRenderingContext::validateTexFunc(const char* functionName, TexFuncValidationFunctionType functionType, TexFuncValidationSourceType sourceType, GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint xoffset, GC3Dint yoffset)
+{
+    if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, border, format, type))
+        return false;
+
+    WebGLTexture* texture = validateTextureBinding(functionName, target, true);
+    if (!texture)
+        return false;
+
+    if (functionType == NotTexSubImage2D) {
+        if (level && WebGLTexture::isNPOT(width, height)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level > 0 not power of 2");
+            return false;
+        }
+        // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat
+        // by checking if the ArrayBufferView is null or not.
+        if (sourceType != SourceArrayBufferView) {
+            if (!validateSettableTexFormat(functionName, format))
+                return false;
+        }
+    } else {
+        if (!validateSettableTexFormat(functionName, format))
+            return false;
+        if (!validateSize(functionName, xoffset, yoffset))
+            return false;
+        // Before checking if it is in the range, check if overflow happens first.
+        if (xoffset + width < 0 || yoffset + height < 0) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "bad dimensions");
+            return false;
+        }
+        if (xoffset + width > texture->getWidth(target, level) || yoffset + height > texture->getHeight(target, level)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "dimensions out of range");
+            return false;
+        }
+        if (texture->getInternalFormat(target, level) != format || texture->getType(target, level) != type) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type and format do not match texture");
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Dsizei width, GC3Dsizei height, GC3Dint border,
+                                       GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
+{
+    if (isContextLost() || !validateTexFuncData("texImage2D", level, width, height, format, type, pixels, NullAllowed)
+        || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceArrayBufferView, target, level, internalformat, width, height, border, format, type, 0, 0))
+        return;
+    void* data = pixels ? pixels->baseAddress() : 0;
+    Vector<uint8_t> tempData;
+    bool changeUnpackAlignment = false;
+    if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
+        if (!m_context->extractTextureData(width, height, format, type,
+                                           m_unpackAlignment,
+                                           m_unpackFlipY, m_unpackPremultiplyAlpha,
+                                           data,
+                                           tempData))
+            return;
+        data = tempData.data();
+        changeUnpackAlignment = true;
+    }
+    if (changeUnpackAlignment)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+    texImage2DBase(target, level, internalformat, width, height, border,
+                   format, type, data, ec);
+    if (changeUnpackAlignment)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
+}
+
+void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
+{
+    ec = 0;
+    if (isContextLost() || !pixels || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, 0, 0))
+        return;
+    Vector<uint8_t> data;
+    bool needConversion = true;
+    // The data from ImageData is always of format RGBA8.
+    // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
+    if (!m_unpackFlipY && !m_unpackPremultiplyAlpha && format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE)
+        needConversion = false;
+    else {
+        if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
+            return;
+        }
+    }
+    if (m_unpackAlignment != 1)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+    texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, needConversion ? data.data() : pixels->data()->data(), ec);
+    if (m_unpackAlignment != 1)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
+}
+
+void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
+{
+    ec = 0;
+    if (isContextLost() || !validateHTMLImageElement("texImage2D", image, ec))
+        return;
+    Image* imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
+    if (!imageForRender || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLImageElement, target, level, internalformat, imageForRender->width(), imageForRender->height(), 0, format, type, 0, 0))
+        return;
+
+    texImage2DImpl(target, level, internalformat, format, type, imageForRender, GraphicsContext3D::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
+}
+
+void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
+{
+    ec = 0;
+    if (isContextLost() || !validateHTMLCanvasElement("texImage2D", canvas, ec) || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLCanvasElement, target, level, internalformat, canvas->width(), canvas->height(), 0, format, type, 0, 0))
+        return;
+
+    WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
+    // If possible, copy from the canvas element directly to the texture
+    // via the GPU, without a read-back to system memory.
+    //
+    // FIXME: restriction of (RGB || RGBA)/UNSIGNED_BYTE should be lifted when
+    // ImageBuffer::copyToPlatformTexture implementations are fully functional.
+    if (GraphicsContext3D::TEXTURE_2D == target && texture && type == texture->getType(target, level)
+        && (format == GraphicsContext3D::RGB || format == GraphicsContext3D::RGBA) && type == GraphicsContext3D::UNSIGNED_BYTE) {
+        ImageBuffer* buffer = canvas->buffer();
+        if (buffer && buffer->copyToPlatformTexture(*m_context.get(), texture->object(), internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
+            texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type);
+            return;
+        }
+    }
+
+    RefPtr<ImageData> imageData = canvas->getImageData();
+    if (imageData)
+        texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
+    else
+        texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(), GraphicsContext3D::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
+}
+
+PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video, BackingStoreCopy backingStoreCopy, ExceptionCode&)
+{
+    IntSize size(video->videoWidth(), video->videoHeight());
+    ImageBuffer* buf = m_videoCache.imageBuffer(size);
+    if (!buf) {
+        synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "texImage2D", "out of memory");
+        return 0;
+    }
+    IntRect destRect(0, 0, size.width(), size.height());
+    // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
+    video->paintCurrentFrameInContext(buf->context(), destRect);
+    return buf->copyImage(backingStoreCopy);
+}
+
+void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
+{
+    ec = 0;
+    if (isContextLost() || !validateHTMLVideoElement("texImage2D", video, ec)
+        || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLVideoElement, target, level, internalformat, video->videoWidth(), video->videoHeight(), 0, format, type, 0, 0))
+        return;
+
+    // Go through the fast path doing a GPU-GPU textures copy without a readback to system memory if possible.
+    // Otherwise, it will fall back to the normal SW path.
+    // FIXME: The current restrictions require that format shoud be RGB or RGBA,
+    // type should be UNSIGNED_BYTE and level should be 0. It may be lifted in the future.
+    WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
+    if (GraphicsContext3D::TEXTURE_2D == target && texture
+        && (format == GraphicsContext3D::RGB || format == GraphicsContext3D::RGBA)
+        && type == GraphicsContext3D::UNSIGNED_BYTE
+        && (texture->getType(target, level) == GraphicsContext3D::UNSIGNED_BYTE || !texture->isValid(target, level))
+        && !level) {
+        if (video->copyVideoTextureToPlatformTexture(m_context.get(), texture->object(), level, type, internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
+            texture->setLevelInfo(target, level, internalformat, video->videoWidth(), video->videoHeight(), type);
+            return;
+        }
+    }
+
+    // Normal pure SW path.
+    RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode(), ec);
+    if (!image)
+        return;
+    texImage2DImpl(target, level, internalformat, format, type, image.get(), GraphicsContext3D::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
+}
+
+void WebGLRenderingContext::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
+{
+    if (isContextLost())
+        return;
+    WebGLTexture* tex = validateTextureBinding("texParameter", target, false);
+    if (!tex)
+        return;
+    switch (pname) {
+    case GraphicsContext3D::TEXTURE_MIN_FILTER:
+    case GraphicsContext3D::TEXTURE_MAG_FILTER:
+        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)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter");
+            return;
+        }
+        break;
+    case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
+        if (!m_extTextureFilterAnisotropic) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter, EXT_texture_filter_anisotropic not enabled");
+            return;
+        }
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter name");
+        return;
+    }
+    if (isFloat) {
+        tex->setParameterf(pname, paramf);
+        m_context->texParameterf(target, pname, paramf);
+    } else {
+        tex->setParameteri(pname, parami);
+        m_context->texParameteri(target, pname, parami);
+    }
+}
+
+void WebGLRenderingContext::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
+{
+    texParameter(target, pname, param, 0, true);
+}
+
+void WebGLRenderingContext::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
+{
+    texParameter(target, pname, 0, param, false);
+}
+
+void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode& ec)
+{
+    // FIXME: For now we ignore any errors returned
+    ec = 0;
+    ASSERT(!isContextLost());
+    ASSERT(validateTexFuncParameters("texSubImage2D", TexSubImage2D, target, level, format, width, height, 0, format, type));
+    ASSERT(validateSize("texSubImage2D", xoffset, yoffset));
+    ASSERT(validateSettableTexFormat("texSubImage2D", format));
+    WebGLTexture* tex = validateTextureBinding("texSubImage2D", target, true);
+    if (!tex) {
+        ASSERT_NOT_REACHED();
+        return;
+    }
+    ASSERT((xoffset + width) >= 0);
+    ASSERT((yoffset + height) >= 0);
+    ASSERT(tex->getWidth(target, level) >= (xoffset + width));
+    ASSERT(tex->getHeight(target, level) >= (yoffset + height));
+    ASSERT(tex->getInternalFormat(target, level) == format);
+    ASSERT(tex->getType(target, level) == type);
+    m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+
+void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
+{
+    // All calling functions check isContextLost, so a duplicate check is not needed here.
+    ec = 0;
+    Vector<uint8_t> data;
+    GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);  
+    if (!imageExtractor.extractSucceeded()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image");
+        return;
+    }
+    GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
+    GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
+    const void* imagePixelData = imageExtractor.imagePixelData();
+
+    bool needConversion = true;
+    if (type == GraphicsContext3D::UNSIGNED_BYTE && sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 && format == GraphicsContext3D::RGBA && alphaOp == GraphicsContext3D::AlphaDoNothing && !flipY)
+        needConversion = false;
+    else {
+        if (!m_context->packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
+            return;
+        }
+    }
+
+    if (m_unpackAlignment != 1)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+    texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(), format, type,  needConversion ? data.data() : imagePixelData, ec);
+    if (m_unpackAlignment != 1)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
+}
+
+void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                          GC3Dsizei width, GC3Dsizei height,
+                                          GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
+{
+    if (isContextLost() || !validateTexFuncData("texSubImage2D", level, width, height, format, type, pixels, NullNotAllowed)
+        || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceArrayBufferView, target, level, format, width, height, 0, format, type, xoffset, yoffset))
+        return;
+    void* data = pixels->baseAddress();
+    Vector<uint8_t> tempData;
+    bool changeUnpackAlignment = false;
+    if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
+        if (!m_context->extractTextureData(width, height, format, type,
+                                           m_unpackAlignment,
+                                           m_unpackFlipY, m_unpackPremultiplyAlpha,
+                                           data,
+                                           tempData))
+            return;
+        data = tempData.data();
+        changeUnpackAlignment = true;
+    }
+    if (changeUnpackAlignment)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+    texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
+    if (changeUnpackAlignment)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
+}
+
+void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                          GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
+{
+    ec = 0;
+    if (isContextLost() || !pixels || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceImageData, target, level, format,  pixels->width(), pixels->height(), 0, format, type, xoffset, yoffset))
+        return;
+
+    Vector<uint8_t> data;
+    bool needConversion = true;
+    // The data from ImageData is always of format RGBA8.
+    // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
+    if (format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE && !m_unpackFlipY && !m_unpackPremultiplyAlpha)
+        needConversion = false;
+    else {
+        if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image data");
+            return;
+        }
+    }
+    if (m_unpackAlignment != 1)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+    texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(), format, type, needConversion ? data.data() : pixels->data()->data(), ec);
+    if (m_unpackAlignment != 1)
+        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
+}
+
+void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                          GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
+{
+    ec = 0;
+    if (isContextLost() || !validateHTMLImageElement("texSubImage2D", image, ec))
+        return;
+    Image* imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
+    if (!imageForRender || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLImageElement, target, level, format, imageForRender->width(), imageForRender->height(), 0, format, type, xoffset, yoffset))
+        return;
+
+    texSubImage2DImpl(target, level, xoffset, yoffset, format, type, imageForRender, GraphicsContext3D::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
+}
+
+void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                          GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
+{
+    ec = 0;
+    if (isContextLost() || !validateHTMLCanvasElement("texSubImage2D", canvas, ec)
+        || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLCanvasElement, target, level, format, canvas->width(), canvas->height(), 0, format, type, xoffset, yoffset))
+        return;
+
+    RefPtr<ImageData> imageData = canvas->getImageData();
+    if (imageData)
+        texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec);
+    else
+        texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(), GraphicsContext3D::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
+}
+
+void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                          GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
+{
+    ec = 0;
+    if (isContextLost() || !validateHTMLVideoElement("texSubImage2D", video, ec)
+        || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLVideoElement, target, level, format, video->videoWidth(), video->videoHeight(), 0, format, type, xoffset, yoffset))
+        return;
+
+    RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode(), ec);
+    if (!image)
+        return;
+    texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), GraphicsContext3D::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
+}
+
+void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !location)
+        return;
+
+    if (location->program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform1f", "location not for current program");
+        return;
+    }
+
+    m_context->uniform1f(location->location(), x);
+}
+
+void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, 1))
+        return;
+
+    m_context->uniform1fv(location->location(), v->length(), v->data());
+}
+
+void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, size, 1))
+        return;
+
+    m_context->uniform1fv(location->location(), size, v);
+}
+
+void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !location)
+        return;
+
+    if (location->program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform1i", "location not for current program");
+        return;
+    }
+
+    m_context->uniform1i(location->location(), x);
+}
+
+void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, 1))
+        return;
+
+    m_context->uniform1iv(location->location(), v->length(), v->data());
+}
+
+void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, size, 1))
+        return;
+
+    m_context->uniform1iv(location->location(), size, v);
+}
+
+void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !location)
+        return;
+
+    if (location->program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform2f", "location not for current program");
+        return;
+    }
+
+    m_context->uniform2f(location->location(), x, y);
+}
+
+void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, 2))
+        return;
+
+    m_context->uniform2fv(location->location(), v->length() / 2, v->data());
+}
+
+void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, size, 2))
+        return;
+
+    m_context->uniform2fv(location->location(), size / 2, v);
+}
+
+void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !location)
+        return;
+
+    if (location->program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform2i", "location not for current program");
+        return;
+    }
+
+    m_context->uniform2i(location->location(), x, y);
+}
+
+void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, 2))
+        return;
+
+    m_context->uniform2iv(location->location(), v->length() / 2, v->data());
+}
+
+void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, size, 2))
+        return;
+
+    m_context->uniform2iv(location->location(), size / 2, v);
+}
+
+void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !location)
+        return;
+
+    if (location->program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform3f", "location not for current program");
+        return;
+    }
+
+    m_context->uniform3f(location->location(), x, y, z);
+}
+
+void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, 3))
+        return;
+
+    m_context->uniform3fv(location->location(), v->length() / 3, v->data());
+}
+
+void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, size, 3))
+        return;
+
+    m_context->uniform3fv(location->location(), size / 3, v);
+}
+
+void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !location)
+        return;
+
+    if (location->program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform3i", "location not for current program");
+        return;
+    }
+
+    m_context->uniform3i(location->location(), x, y, z);
+}
+
+void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, 3))
+        return;
+
+    m_context->uniform3iv(location->location(), v->length() / 3, v->data());
+}
+
+void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, size, 3))
+        return;
+
+    m_context->uniform3iv(location->location(), size / 3, v);
+}
+
+void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !location)
+        return;
+
+    if (location->program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform4f", "location not for current program");
+        return;
+    }
+
+    m_context->uniform4f(location->location(), x, y, z, w);
+}
+
+void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, 4))
+        return;
+
+    m_context->uniform4fv(location->location(), v->length() / 4, v->data());
+}
+
+void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, size, 4))
+        return;
+
+    m_context->uniform4fv(location->location(), size / 4, v);
+}
+
+void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !location)
+        return;
+
+    if (location->program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform4i", "location not for current program");
+        return;
+    }
+
+    m_context->uniform4i(location->location(), x, y, z, w);
+}
+
+void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, 4))
+        return;
+
+    m_context->uniform4iv(location->location(), v->length() / 4, v->data());
+}
+
+void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, size, 4))
+        return;
+
+    m_context->uniform4iv(location->location(), size / 4, v);
+}
+
+void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, 4))
+        return;
+    m_context->uniformMatrix2fv(location->location(), v->length() / 4, transpose, v->data());
+}
+
+void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, size, 4))
+        return;
+    m_context->uniformMatrix2fv(location->location(), size / 4, transpose, v);
+}
+
+void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, 9))
+        return;
+    m_context->uniformMatrix3fv(location->location(), v->length() / 9, transpose, v->data());
+}
+
+void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, size, 9))
+        return;
+    m_context->uniformMatrix3fv(location->location(), size / 9, transpose, v);
+}
+
+void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, 16))
+        return;
+    m_context->uniformMatrix4fv(location->location(), v->length() / 16, transpose, v->data());
+}
+
+void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, size, 16))
+        return;
+    m_context->uniformMatrix4fv(location->location(), size / 16, transpose, v);
+}
+
+void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound("useProgram", program, deleted))
+        return;
+    if (deleted)
+        program = 0;
+    if (program && !program->getLinkStatus()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "useProgram", "program not valid");
+        return;
+    }
+    if (m_currentProgram != program) {
+        if (m_currentProgram)
+            m_currentProgram->onDetached(graphicsContext3D());
+        m_currentProgram = program;
+        m_context->useProgram(objectOrZero(program));
+        if (program)
+            program->onAttached();
+    }
+}
+
+void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost() || !validateWebGLObject("validateProgram", program))
+        return;
+    m_context->validateProgram(objectOrZero(program));
+}
+
+void WebGLRenderingContext::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
+{
+    vertexAttribfImpl("vertexAttrib1f", index, 1, v0, 0.0f, 0.0f, 1.0f);
+}
+
+void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, Float32Array* v)
+{
+    vertexAttribfvImpl("vertexAttrib1fv", index, v, 1);
+}
+
+void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
+{
+    vertexAttribfvImpl("vertexAttrib1fv", index, v, size, 1);
+}
+
+void WebGLRenderingContext::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
+{
+    vertexAttribfImpl("vertexAttrib2f", index, 2, v0, v1, 0.0f, 1.0f);
+}
+
+void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, Float32Array* v)
+{
+    vertexAttribfvImpl("vertexAttrib2fv", index, v, 2);
+}
+
+void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
+{
+    vertexAttribfvImpl("vertexAttrib2fv", index, v, size, 2);
+}
+
+void WebGLRenderingContext::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
+{
+    vertexAttribfImpl("vertexAttrib3f", index, 3, v0, v1, v2, 1.0f);
+}
+
+void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, Float32Array* v)
+{
+    vertexAttribfvImpl("vertexAttrib3fv", index, v, 3);
+}
+
+void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
+{
+    vertexAttribfvImpl("vertexAttrib3fv", index, v, size, 3);
+}
+
+void WebGLRenderingContext::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+    vertexAttribfImpl("vertexAttrib4f", index, 4, v0, v1, v2, v3);
+}
+
+void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, Float32Array* v)
+{
+    vertexAttribfvImpl("vertexAttrib4fv", index, v, 4);
+}
+
+void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
+{
+    vertexAttribfvImpl("vertexAttrib4fv", index, v, size, 4);
+}
+
+void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, long long offset, ExceptionCode& ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLost())
+        return;
+    switch (type) {
+    case GraphicsContext3D::BYTE:
+    case GraphicsContext3D::UNSIGNED_BYTE:
+    case GraphicsContext3D::SHORT:
+    case GraphicsContext3D::UNSIGNED_SHORT:
+    case GraphicsContext3D::FLOAT:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "vertexAttribPointer", "invalid type");
+        return;
+    }
+    if (index >= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "vertexAttribPointer", "index out of range");
+        return;
+    }
+    if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "vertexAttribPointer", "bad size, stride or offset");
+        return;
+    }
+    if (!m_boundArrayBuffer) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "vertexAttribPointer", "no bound ARRAY_BUFFER");
+        return;
+    }
+    // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
+    unsigned int typeSize = sizeInBytes(type);
+    if (!typeSize) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "vertexAttribPointer", "invalid type");
+        return;
+    }
+    if ((stride % typeSize) || (static_cast<GC3Dintptr>(offset) % typeSize)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "vertexAttribPointer", "stride or offset not valid for type");
+        return;
+    }
+    GC3Dsizei bytesPerElement = size * typeSize;
+
+    m_boundVertexArrayObject->setVertexAttribState(index, bytesPerElement, size, type, normalized, stride, static_cast<GC3Dintptr>(offset), m_boundArrayBuffer);
+    m_context->vertexAttribPointer(index, size, type, normalized, stride, static_cast<GC3Dintptr>(offset));
+}
+
+void WebGLRenderingContext::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+    if (isContextLost())
+        return;
+    if (!validateSize("viewport", width, height))
+        return;
+    m_context->viewport(x, y, width, height);
+}
+
+void WebGLRenderingContext::forceLostContext(WebGLRenderingContext::LostContextMode mode)
+{
+    if (isContextLost()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "loseContext", "context already lost");
+        return;
+    }
+
+    m_contextGroup->loseContextGroup(mode);
+}
+
+void WebGLRenderingContext::loseContextImpl(WebGLRenderingContext::LostContextMode mode)
+{
+    if (isContextLost())
+        return;
+
+    m_contextLost = true;
+    m_contextLostMode = mode;
+
+    if (mode == RealLostContext) {
+        // Inform the embedder that a lost context was received. In response, the embedder might
+        // decide to take action such as asking the user for permission to use WebGL again.
+        if (Document* document = canvas()->document()) {
+            if (Frame* frame = document->frame())
+                frame->loader()->client()->didLoseWebGLContext(m_context->getExtensions()->getGraphicsResetStatusARB());
+        }
+    }
+
+    // Make absolutely sure we do not refer to an already-deleted texture or framebuffer.
+    m_drawingBuffer->setTexture2DBinding(0);
+    m_drawingBuffer->setFramebufferBinding(0);
+
+    detachAndRemoveAllObjects();
+
+    if (mode != RealLostContext)
+        destroyGraphicsContext3D();
+
+    ConsoleDisplayPreference display = (mode == RealLostContext) ? DisplayInConsole: DontDisplayInConsole;
+    synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL, "loseContext", "context lost", display);
+
+    // Don't allow restoration unless the context lost event has both been
+    // dispatched and its default behavior prevented.
+    m_restoreAllowed = false;
+
+    // Always defer the dispatch of the context lost event, to implement
+    // the spec behavior of queueing a task.
+    m_dispatchContextLostEventTimer.startOneShot(0);
+}
+
+void WebGLRenderingContext::forceRestoreContext()
+{
+    if (!isContextLost()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "restoreContext", "context not lost");
+        return;
+    }
+
+    if (!m_restoreAllowed) {
+        if (m_contextLostMode == SyntheticLostContext)
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "restoreContext", "context restoration not allowed");
+        return;
+    }
+
+    if (!m_restoreTimer.isActive())
+        m_restoreTimer.startOneShot(0);
+}
+
+PlatformLayer* WebGLRenderingContext::platformLayer() const
+{
+    return m_drawingBuffer->platformLayer();
+}
+
+void WebGLRenderingContext::removeSharedObject(WebGLSharedObject* object)
+{
+    m_contextGroup->removeObject(object);
+}
+
+void WebGLRenderingContext::addSharedObject(WebGLSharedObject* object)
+{
+    ASSERT(!isContextLost());
+    m_contextGroup->addObject(object);
+}
+
+void WebGLRenderingContext::removeContextObject(WebGLContextObject* object)
+{
+    m_contextObjects.remove(object);
+}
+
+void WebGLRenderingContext::addContextObject(WebGLContextObject* object)
+{
+    ASSERT(!isContextLost());
+    m_contextObjects.add(object);
+}
+
+void WebGLRenderingContext::detachAndRemoveAllObjects()
+{
+    while (m_contextObjects.size() > 0) {
+        HashSet<WebGLContextObject*>::iterator it = m_contextObjects.begin();
+        (*it)->detachContext();
+    }
+}
+
+bool WebGLRenderingContext::hasPendingActivity() const
+{
+    return false;
+}
+
+void WebGLRenderingContext::stop()
+{
+    if (!isContextLost()) {
+        forceLostContext(SyntheticLostContext);
+        destroyGraphicsContext3D();
+    }
+}
+
+WebGLGetInfo WebGLRenderingContext::getBooleanParameter(GC3Denum pname)
+{
+    GC3Dboolean value = 0;
+    if (!isContextLost())
+        m_context->getBooleanv(pname, &value);
+    return WebGLGetInfo(static_cast<bool>(value));
+}
+
+WebGLGetInfo WebGLRenderingContext::getBooleanArrayParameter(GC3Denum pname)
+{
+    if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
+        notImplemented();
+        return WebGLGetInfo(0, 0);
+    }
+    GC3Dboolean value[4] = {0};
+    if (!isContextLost())
+        m_context->getBooleanv(pname, value);
+    bool boolValue[4];
+    for (int ii = 0; ii < 4; ++ii)
+        boolValue[ii] = static_cast<bool>(value[ii]);
+    return WebGLGetInfo(boolValue, 4);
+}
+
+WebGLGetInfo WebGLRenderingContext::getFloatParameter(GC3Denum pname)
+{
+    GC3Dfloat value = 0;
+    if (!isContextLost())
+        m_context->getFloatv(pname, &value);
+    return WebGLGetInfo(value);
+}
+
+WebGLGetInfo WebGLRenderingContext::getIntParameter(GC3Denum pname)
+{
+    GC3Dint value = 0;
+    if (!isContextLost())
+        m_context->getIntegerv(pname, &value);
+    return WebGLGetInfo(value);
+}
+
+WebGLGetInfo WebGLRenderingContext::getUnsignedIntParameter(GC3Denum pname)
+{
+    GC3Dint value = 0;
+    if (!isContextLost())
+        m_context->getIntegerv(pname, &value);
+    return WebGLGetInfo(static_cast<unsigned int>(value));
+}
+
+WebGLGetInfo WebGLRenderingContext::getWebGLFloatArrayParameter(GC3Denum pname)
+{
+    GC3Dfloat value[4] = {0};
+    if (!isContextLost())
+        m_context->getFloatv(pname, value);
+    unsigned length = 0;
+    switch (pname) {
+    case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
+    case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
+    case GraphicsContext3D::DEPTH_RANGE:
+        length = 2;
+        break;
+    case GraphicsContext3D::BLEND_COLOR:
+    case GraphicsContext3D::COLOR_CLEAR_VALUE:
+        length = 4;
+        break;
+    default:
+        notImplemented();
+    }
+    return WebGLGetInfo(Float32Array::create(value, length));
+}
+
+WebGLGetInfo WebGLRenderingContext::getWebGLIntArrayParameter(GC3Denum pname)
+{
+    GC3Dint value[4] = {0};
+    if (!isContextLost())
+        m_context->getIntegerv(pname, value);
+    unsigned length = 0;
+    switch (pname) {
+    case GraphicsContext3D::MAX_VIEWPORT_DIMS:
+        length = 2;
+        break;
+    case GraphicsContext3D::SCISSOR_BOX:
+    case GraphicsContext3D::VIEWPORT:
+        length = 4;
+        break;
+    default:
+        notImplemented();
+    }
+    return WebGLGetInfo(Int32Array::create(value, length));
+}
+
+void WebGLRenderingContext::handleNPOTTextures(const char* functionName, bool prepareToDraw)
+{
+    // All calling functions check isContextLost, so a duplicate check is not needed here.
+    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 (ii != m_activeTextureUnit) {
+                m_context->activeTexture(ii);
+                resetActiveUnit = true;
+            } else if (resetActiveUnit) {
+                m_context->activeTexture(ii);
+                resetActiveUnit = false;
+            }
+            WebGLTexture* tex2D;
+            WebGLTexture* texCubeMap;
+            if (prepareToDraw) {
+                String msg(String("texture bound to texture unit ") + String::number(ii)
+                    + " is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'");
+                printGLWarningToConsole(functionName, msg.utf8().data());
+                tex2D = m_blackTexture2D.get();
+                texCubeMap = m_blackTextureCubeMap.get();
+            } else {
+                tex2D = m_textureUnits[ii].m_texture2DBinding.get();
+                texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
+            }
+            if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
+                m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D));
+            if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())
+                m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
+        }
+    }
+    if (resetActiveUnit)
+        m_context->activeTexture(m_activeTextureUnit);
+}
+
+void WebGLRenderingContext::createFallbackBlackTextures1x1()
+{
+    // All calling functions check isContextLost, so a duplicate check is not needed here.
+    unsigned char black[] = {0, 0, 0, 255};
+    m_blackTexture2D = createTexture();
+    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D->object());
+    m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
+    m_blackTextureCubeMap = createTexture();
+    m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
+    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0);
+}
+
+bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,
+                                                                           GC3Denum colorBufferFormat)
+{
+    unsigned need = GraphicsContext3D::getChannelBitsByFormat(texInternalFormat);
+    unsigned have = GraphicsContext3D::getChannelBitsByFormat(colorBufferFormat);
+    return (need & have) == need;
+}
+
+GC3Denum WebGLRenderingContext::getBoundFramebufferColorFormat()
+{
+    if (m_framebufferBinding && m_framebufferBinding->object())
+        return m_framebufferBinding->getColorBufferFormat();
+    if (m_attributes.alpha)
+        return GraphicsContext3D::RGBA;
+    return GraphicsContext3D::RGB;
+}
+
+int WebGLRenderingContext::getBoundFramebufferWidth()
+{
+    if (m_framebufferBinding && m_framebufferBinding->object())
+        return m_framebufferBinding->getColorBufferWidth();
+    return m_drawingBuffer->size().width();
+}
+
+int WebGLRenderingContext::getBoundFramebufferHeight()
+{
+    if (m_framebufferBinding && m_framebufferBinding->object())
+        return m_framebufferBinding->getColorBufferHeight();
+    return m_drawingBuffer->size().height();
+}
+
+WebGLTexture* WebGLRenderingContext::validateTextureBinding(const char* functionName, GC3Denum target, bool useSixEnumsForCubeMap)
+{
+    WebGLTexture* tex = 0;
+    switch (target) {
+    case GraphicsContext3D::TEXTURE_2D:
+        tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
+        break;
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        if (!useSixEnumsForCubeMap) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture target");
+            return 0;
+        }
+        tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
+        break;
+    case GraphicsContext3D::TEXTURE_CUBE_MAP:
+        if (useSixEnumsForCubeMap) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture target");
+            return 0;
+        }
+        tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture target");
+        return 0;
+    }
+    if (!tex)
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no texture");
+    return tex;
+}
+
+bool WebGLRenderingContext::validateLocationLength(const char* functionName, const String& string)
+{
+    const unsigned maxWebGLLocationLength = 256;
+    if (string.length() > maxWebGLLocationLength) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "location length > 256");
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateSize(const char* functionName, GC3Dint x, GC3Dint y)
+{
+    if (x < 0 || y < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "size < 0");
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateString(const char* functionName, const String& string)
+{
+    for (size_t i = 0; i < string.length(); ++i) {
+        if (!validateCharacter(string[i])) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "string not ASCII");
+            return false;
+        }
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateTexFuncFormatAndType(const char* functionName, GC3Denum format, GC3Denum type, GC3Dint level)
+{
+    switch (format) {
+    case GraphicsContext3D::ALPHA:
+    case GraphicsContext3D::LUMINANCE:
+    case GraphicsContext3D::LUMINANCE_ALPHA:
+    case GraphicsContext3D::RGB:
+    case GraphicsContext3D::RGBA:
+        break;
+    case GraphicsContext3D::DEPTH_STENCIL:
+    case GraphicsContext3D::DEPTH_COMPONENT:
+        if (m_webglDepthTexture)
+            break;
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "depth texture formats not enabled");
+        return false;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture format");
+        return false;
+    }
+
+    switch (type) {
+    case GraphicsContext3D::UNSIGNED_BYTE:
+    case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
+    case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
+    case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
+        break;
+    case GraphicsContext3D::FLOAT:
+        if (m_oesTextureFloat)
+            break;
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
+        return false;
+    case GraphicsContext3D::HALF_FLOAT_OES:
+        if (m_oesTextureHalfFloat)
+            break;
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
+        return false;
+    case GraphicsContext3D::UNSIGNED_INT:
+    case GraphicsContext3D::UNSIGNED_INT_24_8:
+    case GraphicsContext3D::UNSIGNED_SHORT:
+        if (m_webglDepthTexture)
+            break;
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
+        return false;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
+        return false;
+    }
+
+    // Verify that the combination of format and type is supported.
+    switch (format) {
+    case GraphicsContext3D::ALPHA:
+    case GraphicsContext3D::LUMINANCE:
+    case GraphicsContext3D::LUMINANCE_ALPHA:
+        if (type != GraphicsContext3D::UNSIGNED_BYTE
+            && type != GraphicsContext3D::FLOAT
+            && type != GraphicsContext3D::HALF_FLOAT_OES) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for format");
+            return false;
+        }
+        break;
+    case GraphicsContext3D::RGB:
+        if (type != GraphicsContext3D::UNSIGNED_BYTE
+            && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5
+            && type != GraphicsContext3D::FLOAT
+            && type != GraphicsContext3D::HALF_FLOAT_OES) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for RGB format");
+            return false;
+        }
+        break;
+    case GraphicsContext3D::RGBA:
+        if (type != GraphicsContext3D::UNSIGNED_BYTE
+            && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4
+            && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1
+            && type != GraphicsContext3D::FLOAT
+            && type != GraphicsContext3D::HALF_FLOAT_OES) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for RGBA format");
+            return false;
+        }
+        break;
+    case GraphicsContext3D::DEPTH_COMPONENT:
+        if (!m_webglDepthTexture) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format. DEPTH_COMPONENT not enabled");
+            return false;
+        }
+        if (type != GraphicsContext3D::UNSIGNED_SHORT
+            && type != GraphicsContext3D::UNSIGNED_INT) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for DEPTH_COMPONENT format");
+            return false;
+        }
+        if (level > 0) {
+          synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "level must be 0 for DEPTH_COMPONENT format");
+          return false;
+        }
+        break;
+    case GraphicsContext3D::DEPTH_STENCIL:
+        if (!m_webglDepthTexture) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format. DEPTH_STENCIL not enabled");
+            return false;
+        }
+        if (type != GraphicsContext3D::UNSIGNED_INT_24_8) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for DEPTH_STENCIL format");
+            return false;
+        }
+        if (level > 0) {
+          synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "level must be 0 for DEPTH_STENCIL format");
+          return false;
+        }
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    return true;
+}
+
+bool WebGLRenderingContext::validateTexFuncLevel(const char* functionName, GC3Denum target, GC3Dint level)
+{
+    if (level < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level < 0");
+        return false;
+    }
+    switch (target) {
+    case GraphicsContext3D::TEXTURE_2D:
+        if (level > m_maxTextureLevel) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level out of range");
+            return false;
+        }
+        break;
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        if (level > m_maxCubeMapTextureLevel) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level out of range");
+            return false;
+        }
+        break;
+    }
+    // This function only checks if level is legal, so we return true and don't
+    // generate INVALID_ENUM if target is illegal.
+    return true;
+}
+
+bool WebGLRenderingContext::validateTexFuncParameters(const char* functionName,
+                                                      TexFuncValidationFunctionType functionType,
+                                                      GC3Denum target, GC3Dint level,
+                                                      GC3Denum internalformat,
+                                                      GC3Dsizei width, GC3Dsizei height, GC3Dint border,
+                                                      GC3Denum format, GC3Denum type)
+{
+    // We absolutely have to validate the format and type combination.
+    // The texImage2D entry points taking HTMLImage, etc. will produce
+    // temporary data based on this combination, so it must be legal.
+    if (!validateTexFuncFormatAndType(functionName, format, type, level) || !validateTexFuncLevel(functionName, target, level))
+        return false;
+
+    if (width < 0 || height < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height < 0");
+        return false;
+    }
+
+    switch (target) {
+    case GraphicsContext3D::TEXTURE_2D:
+        if (width > m_maxTextureSize || height > m_maxTextureSize) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range");
+            return false;
+        }
+        break;
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        if (functionType != TexSubImage2D && width != height) {
+          synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width != height for cube map");
+          return false;
+        }
+        // No need to check height here. For texImage width == height.
+        // For texSubImage that will be checked when checking yoffset + height is in range.
+        if (width > m_maxCubeMapTextureSize) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range for cube map");
+            return false;
+        }
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
+        return false;
+    }
+
+    if (format != internalformat) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format != internalformat");
+        return false;
+    }
+
+    if (border) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "border != 0");
+        return false;
+    }
+
+    return true;
+}
+
+bool WebGLRenderingContext::validateTexFuncData(const char* functionName, GC3Dint level,
+                                                GC3Dsizei width, GC3Dsizei height,
+                                                GC3Denum format, GC3Denum type,
+                                                ArrayBufferView* pixels,
+                                                NullDisposition disposition)
+{
+    // All calling functions check isContextLost, so a duplicate check is not needed here.
+    if (!pixels) {
+        if (disposition == NullAllowed)
+            return true;
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no pixels");
+        return false;
+    }
+
+    if (!validateTexFuncFormatAndType(functionName, format, type, level))
+        return false;
+    if (!validateSettableTexFormat(functionName, format))
+        return false;
+
+    switch (type) {
+    case GraphicsContext3D::UNSIGNED_BYTE:
+        if (pixels->getType() != ArrayBufferView::TypeUint8) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array");
+            return false;
+        }
+        break;
+    case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
+    case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
+    case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
+        if (pixels->getType() != ArrayBufferView::TypeUint16) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
+            return false;
+        }
+        break;
+    case GraphicsContext3D::FLOAT: // OES_texture_float
+        if (pixels->getType() != ArrayBufferView::TypeFloat32) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type FLOAT but ArrayBufferView not Float32Array");
+            return false;
+        }
+        break;
+    case GraphicsContext3D::HALF_FLOAT_OES: // OES_texture_half_float
+        // As per the specification, ArrayBufferView should be null when
+        // OES_texture_half_float is enabled.
+        if (pixels) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type HALF_FLOAT_OES but ArrayBufferView is not NULL");
+            return false;
+        }
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    unsigned int totalBytesRequired;
+    GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
+    if (error != GraphicsContext3D::NO_ERROR) {
+        synthesizeGLError(error, functionName, "invalid texture dimensions");
+        return false;
+    }
+    if (pixels->byteLength() < totalBytesRequired) {
+        if (m_unpackAlignment != 1) {
+          error = m_context->computeImageSizeInBytes(format, type, width, height, 1, &totalBytesRequired, 0);
+          if (pixels->byteLength() == totalBytesRequired) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request with UNPACK_ALIGNMENT > 1");
+            return false;
+          }
+        }
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request");
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateCompressedTexFormat(GC3Denum format)
+{
+    return m_compressedTextureFormats.contains(format);
+}
+
+bool WebGLRenderingContext::validateCompressedTexFuncData(const char* functionName,
+                                                          GC3Dsizei width, GC3Dsizei height,
+                                                          GC3Denum format, ArrayBufferView* pixels)
+{
+    if (!pixels) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no pixels");
+        return false;
+    }
+    if (width < 0 || height < 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height < 0");
+        return false;
+    }
+
+    unsigned int bytesRequired = 0;
+
+    switch (format) {
+    case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
+        {
+            const int kBlockWidth = 4;
+            const int kBlockHeight = 4;
+            const int kBlockSize = 8;
+            int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
+            int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
+            int numBlocks = numBlocksAcross * numBlocksDown;
+            bytesRequired = numBlocks * kBlockSize;
+        }
+        break;
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT:
+        {
+            const int kBlockWidth = 4;
+            const int kBlockHeight = 4;
+            const int kBlockSize = 16;
+            int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
+            int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
+            int numBlocks = numBlocksAcross * numBlocksDown;
+            bytesRequired = numBlocks * kBlockSize;
+        }
+        break;
+    case Extensions3D::COMPRESSED_ATC_RGB_AMD:
+        {
+            bytesRequired = floor(static_cast<double>((width + 3) / 4)) * floor(static_cast<double>((height + 3) / 4)) * 8;
+        }
+        break;
+    case Extensions3D::COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
+    case Extensions3D::COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
+        {
+            bytesRequired = floor(static_cast<double>((width + 3) / 4)) * floor(static_cast<double>((height + 3) / 4)) * 16;
+        }
+    case Extensions3D::COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
+        {
+            bytesRequired = max(width, 8) * max(height, 8) / 2;
+        }
+        break;
+    case Extensions3D::COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
+        {
+            bytesRequired = max(width, 8) * max(height, 8) / 4;
+        }
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format");
+        return false;
+    }
+
+    if (pixels->byteLength() != bytesRequired) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "length of ArrayBufferView is not correct for dimensions");
+        return false;
+    }
+
+    return true;
+}
+
+bool WebGLRenderingContext::validateCompressedTexDimensions(const char* functionName, GC3Dint level, GC3Dsizei width, GC3Dsizei height, GC3Denum format)
+{
+    switch (format) {
+    case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT: {
+        const int kBlockWidth = 4;
+        const int kBlockHeight = 4;
+        bool widthValid = (level && width == 1) || (level && width == 2) || !(width % kBlockWidth);
+        bool heightValid = (level && height == 1) || (level && height == 2) || !(height % kBlockHeight);
+        if (!widthValid || !heightValid) {
+          synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "width or height invalid for level");
+          return false;
+        }
+        return true;
+    }
+    default:
+        return false;
+    }
+}
+
+bool WebGLRenderingContext::validateCompressedTexSubDimensions(const char* functionName, GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                                               GC3Dsizei width, GC3Dsizei height, GC3Denum format, WebGLTexture* tex)
+{
+    if (xoffset < 0 || yoffset < 0) {
+      synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "xoffset or yoffset < 0");
+      return false;
+    }
+
+    switch (format) {
+    case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT: {
+        const int kBlockWidth = 4;
+        const int kBlockHeight = 4;
+        if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "xoffset or yoffset not multiple of 4");
+            return false;
+        }
+        if (width - xoffset > tex->getWidth(target, level)
+            || height - yoffset > tex->getHeight(target, level)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "dimensions out of range");
+            return false;
+        }
+        return validateCompressedTexDimensions(functionName, level, width, height, format);
+    }
+    default:
+        return false;
+    }
+}
+
+bool WebGLRenderingContext::validateDrawMode(const char* functionName, GC3Denum mode)
+{
+    switch (mode) {
+    case GraphicsContext3D::POINTS:
+    case GraphicsContext3D::LINE_STRIP:
+    case GraphicsContext3D::LINE_LOOP:
+    case GraphicsContext3D::LINES:
+    case GraphicsContext3D::TRIANGLE_STRIP:
+    case GraphicsContext3D::TRIANGLE_FAN:
+    case GraphicsContext3D::TRIANGLES:
+        return true;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid draw mode");
+        return false;
+    }
+}
+
+bool WebGLRenderingContext::validateStencilSettings(const char* functionName)
+{
+    if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "front and back stencils settings do not match");
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateStencilFunc(const char* functionName, GC3Denum func)
+{
+    switch (func) {
+    case GraphicsContext3D::NEVER:
+    case GraphicsContext3D::LESS:
+    case GraphicsContext3D::LEQUAL:
+    case GraphicsContext3D::GREATER:
+    case GraphicsContext3D::GEQUAL:
+    case GraphicsContext3D::EQUAL:
+    case GraphicsContext3D::NOTEQUAL:
+    case GraphicsContext3D::ALWAYS:
+        return true;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid function");
+        return false;
+    }
+}
+
+void WebGLRenderingContext::printGLErrorToConsole(const String& message)
+{
+    if (!m_numGLErrorsToConsoleAllowed)
+        return;
+
+    --m_numGLErrorsToConsoleAllowed;
+    printWarningToConsole(message);
+
+    if (!m_numGLErrorsToConsoleAllowed)
+        printWarningToConsole("WebGL: too many errors, no more errors will be reported to the console for this context.");
+}
+
+void WebGLRenderingContext::printWarningToConsole(const String& message)
+{
+    if (!canvas())
+        return;
+    Document* document = canvas()->document();
+    if (!document)
+        return;
+    document->addConsoleMessage(RenderingMessageSource, WarningMessageLevel, message);
+}
+
+bool WebGLRenderingContext::validateFramebufferFuncParameters(const char* functionName, GC3Denum target, GC3Denum attachment)
+{
+    if (target != GraphicsContext3D::FRAMEBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
+        return false;
+    }
+    switch (attachment) {
+    case GraphicsContext3D::COLOR_ATTACHMENT0:
+    case GraphicsContext3D::DEPTH_ATTACHMENT:
+    case GraphicsContext3D::STENCIL_ATTACHMENT:
+    case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+        break;
+    default:
+        if (m_extDrawBuffers
+            && attachment > GraphicsContext3D::COLOR_ATTACHMENT0
+            && attachment < static_cast<GC3Denum>(GraphicsContext3D::COLOR_ATTACHMENT0 + getMaxColorAttachments()))
+            break;
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid attachment");
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateBlendEquation(const char* functionName, GC3Denum mode)
+{
+    switch (mode) {
+    case GraphicsContext3D::FUNC_ADD:
+    case GraphicsContext3D::FUNC_SUBTRACT:
+    case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
+        return true;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode");
+        return false;
+    }
+}
+
+bool WebGLRenderingContext::validateBlendFuncFactors(const char* functionName, GC3Denum src, GC3Denum dst)
+{
+    if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
+         && (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))
+        || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
+            && (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "incompatible src and dst");
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateCapability(const char* functionName, GC3Denum cap)
+{
+    switch (cap) {
+    case GraphicsContext3D::BLEND:
+    case GraphicsContext3D::CULL_FACE:
+    case GraphicsContext3D::DEPTH_TEST:
+    case GraphicsContext3D::DITHER:
+    case GraphicsContext3D::POLYGON_OFFSET_FILL:
+    case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
+    case GraphicsContext3D::SAMPLE_COVERAGE:
+    case GraphicsContext3D::SCISSOR_TEST:
+    case GraphicsContext3D::STENCIL_TEST:
+        return true;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid capability");
+        return false;
+    }
+}
+
+bool WebGLRenderingContext::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Float32Array* v, GC3Dsizei requiredMinSize)
+{
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
+        return false;
+    }
+    return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
+}
+
+bool WebGLRenderingContext::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Int32Array* v, GC3Dsizei requiredMinSize)
+{
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
+        return false;
+    }
+    return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
+}
+
+bool WebGLRenderingContext::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
+{
+    return validateUniformMatrixParameters(functionName, location, false, v, size, requiredMinSize);
+}
+
+bool WebGLRenderingContext::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, GC3Dsizei requiredMinSize)
+{
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
+        return false;
+    }
+    return validateUniformMatrixParameters(functionName, location, transpose, v->data(), v->length(), requiredMinSize);
+}
+
+bool WebGLRenderingContext::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GC3Dboolean transpose, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
+{
+    if (!location)
+        return false;
+    if (location->program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "location is not from current program");
+        return false;
+    }
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
+        return false;
+    }
+    if (transpose) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "transpose not FALSE");
+        return false;
+    }
+    if (size < requiredMinSize || (size % requiredMinSize)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "invalid size");
+        return false;
+    }
+    return true;
+}
+
+WebGLBuffer* WebGLRenderingContext::validateBufferDataParameters(const char* functionName, GC3Denum target, GC3Denum usage)
+{
+    WebGLBuffer* buffer = 0;
+    switch (target) {
+    case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
+        buffer = m_boundVertexArrayObject->getElementArrayBuffer().get();
+        break;
+    case GraphicsContext3D::ARRAY_BUFFER:
+        buffer = m_boundArrayBuffer.get();
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
+        return 0;
+    }
+    if (!buffer) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no buffer");
+        return 0;
+    }
+    switch (usage) {
+    case GraphicsContext3D::STREAM_DRAW:
+    case GraphicsContext3D::STATIC_DRAW:
+    case GraphicsContext3D::DYNAMIC_DRAW:
+        return buffer;
+    }
+    synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid usage");
+    return 0;
+}
+
+bool WebGLRenderingContext::validateHTMLImageElement(const char* functionName, HTMLImageElement* image, ExceptionCode& ec)
+{
+    if (!image || !image->cachedImage()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no image");
+        return false;
+    }
+    const KURL& url = image->cachedImage()->response().url();
+    if (url.isNull() || url.isEmpty() || !url.isValid()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "invalid image");
+        return false;
+    }
+    if (wouldTaintOrigin(image)) {
+        ec = SECURITY_ERR;
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateHTMLCanvasElement(const char* functionName, HTMLCanvasElement* canvas, ExceptionCode& ec)
+{
+    if (!canvas || !canvas->buffer()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no canvas");
+        return false;
+    }
+    if (wouldTaintOrigin(canvas)) {
+        ec = SECURITY_ERR;
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateHTMLVideoElement(const char* functionName, HTMLVideoElement* video, ExceptionCode& ec)
+{
+    if (!video || !video->videoWidth() || !video->videoHeight()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no video");
+        return false;
+    }
+    if (wouldTaintOrigin(video)) {
+        ec = SECURITY_ERR;
+        return false;
+    }
+    return true;
+}
+
+void WebGLRenderingContext::vertexAttribfImpl(const char* functionName, GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+    if (isContextLost())
+        return;
+    if (index >= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "index out of range");
+        return;
+    }
+    // In GL, we skip setting vertexAttrib0 values.
+    switch (expectedSize) {
+    case 1:
+        m_context->vertexAttrib1f(index, v0);
+        break;
+    case 2:
+        m_context->vertexAttrib2f(index, v0, v1);
+        break;
+    case 3:
+        m_context->vertexAttrib3f(index, v0, v1, v2);
+        break;
+    case 4:
+        m_context->vertexAttrib4f(index, v0, v1, v2, v3);
+        break;
+    }
+    VertexAttribValue& attribValue = m_vertexAttribValue[index];
+    attribValue.value[0] = v0;
+    attribValue.value[1] = v1;
+    attribValue.value[2] = v2;
+    attribValue.value[3] = v3;
+}
+
+void WebGLRenderingContext::vertexAttribfvImpl(const char* functionName, GC3Duint index, Float32Array* v, GC3Dsizei expectedSize)
+{
+    if (isContextLost())
+        return;
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
+        return;
+    }
+    vertexAttribfvImpl(functionName, index, v->data(), v->length(), expectedSize);
+}
+
+void WebGLRenderingContext::vertexAttribfvImpl(const char* functionName, GC3Duint index, GC3Dfloat* v, GC3Dsizei size, GC3Dsizei expectedSize)
+{
+    if (isContextLost())
+        return;
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
+        return;
+    }
+    if (size < expectedSize) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "invalid size");
+        return;
+    }
+    if (index >= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "index out of range");
+        return;
+    }
+    // In GL, we skip setting vertexAttrib0 values.
+    switch (expectedSize) {
+    case 1:
+        m_context->vertexAttrib1fv(index, v);
+        break;
+    case 2:
+        m_context->vertexAttrib2fv(index, v);
+        break;
+    case 3:
+        m_context->vertexAttrib3fv(index, v);
+        break;
+    case 4:
+        m_context->vertexAttrib4fv(index, v);
+        break;
+    }
+    VertexAttribValue& attribValue = m_vertexAttribValue[index];
+    attribValue.initValue();
+    for (int ii = 0; ii < expectedSize; ++ii)
+        attribValue.value[ii] = v[ii];
+}
+
+void WebGLRenderingContext::dispatchContextLostEvent(Timer<WebGLRenderingContext>*)
+{
+    RefPtr<WebGLContextEvent> event = WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, "");
+    canvas()->dispatchEvent(event);
+    m_restoreAllowed = event->defaultPrevented();
+    deactivateContext(this, m_contextLostMode != RealLostContext && m_restoreAllowed);
+    if (m_contextLostMode == RealLostContext && m_restoreAllowed)
+        m_restoreTimer.startOneShot(0);
+}
+
+void WebGLRenderingContext::maybeRestoreContext(Timer<WebGLRenderingContext>*)
+{
+    ASSERT(isContextLost());
+
+    // The rendering context is not restored unless the default behavior of the
+    // webglcontextlost event was prevented earlier.
+    //
+    // Because of the way m_restoreTimer is set up for real vs. synthetic lost
+    // context events, we don't have to worry about this test short-circuiting
+    // the retry loop for real context lost events.
+    if (!m_restoreAllowed)
+        return;
+
+    Document* document = canvas()->document();
+    if (!document)
+        return;
+    Frame* frame = document->frame();
+    if (!frame)
+        return;
+
+    if (!frame->loader()->client()->allowWebGL(frame->settings() && frame->settings()->webGLEnabled()))
+        return;
+
+    FrameView* view = frame->view();
+    if (!view)
+        return;
+    ScrollView* root = view->root();
+    if (!root)
+        return;
+    HostWindow* hostWindow = root->hostWindow();
+    if (!hostWindow)
+        return;
+
+    RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, hostWindow));
+    if (!context) {
+        if (m_contextLostMode == RealLostContext)
+            m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
+        else
+            // This likely shouldn't happen but is the best way to report it to the WebGL app.
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "", "error restoring context");
+        return;
+    }
+
+    RefPtr<WebGLRenderingContextEvictionManager> contextEvictionManager = adoptRef(new WebGLRenderingContextEvictionManager());
+
+    // Construct a new drawing buffer with the new GraphicsContext3D.
+    m_drawingBuffer->releaseResources();
+    DrawingBuffer::PreserveDrawingBuffer preserve = m_attributes.preserveDrawingBuffer ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
+    m_drawingBuffer = DrawingBuffer::create(context.get(), clampedCanvasSize(), preserve, contextEvictionManager.release());
+
+    if (m_drawingBuffer->isZeroSized())
+        return;
+
+    m_drawingBuffer->bind();
+
+    lost_context_errors_.clear();
+
+    m_context = context;
+    m_contextLost = false;
+
+    setupFlags();
+    initializeNewContext();
+    canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, ""));
+}
+
+String WebGLRenderingContext::ensureNotNull(const String& text) const
+{
+    if (text.isNull())
+        return WTF::emptyString();
+    return text;
+}
+
+WebGLRenderingContext::LRUImageBufferCache::LRUImageBufferCache(int capacity)
+    : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity]))
+    , m_capacity(capacity)
+{
+}
+
+ImageBuffer* WebGLRenderingContext::LRUImageBufferCache::imageBuffer(const IntSize& size)
+{
+    int i;
+    for (i = 0; i < m_capacity; ++i) {
+        ImageBuffer* buf = m_buffers[i].get();
+        if (!buf)
+            break;
+        if (buf->logicalSize() != size)
+            continue;
+        bubbleToFront(i);
+        return buf;
+    }
+
+    OwnPtr<ImageBuffer> temp = ImageBuffer::create(size, 1);
+    if (!temp)
+        return 0;
+    i = std::min(m_capacity - 1, i);
+    m_buffers[i] = temp.release();
+
+    ImageBuffer* buf = m_buffers[i].get();
+    bubbleToFront(i);
+    return buf;
+}
+
+void WebGLRenderingContext::LRUImageBufferCache::bubbleToFront(int idx)
+{
+    for (int i = idx; i > 0; --i)
+        m_buffers[i].swap(m_buffers[i-1]);
+}
+
+namespace {
+
+    String GetErrorString(GC3Denum error)
+    {
+        switch (error) {
+        case GraphicsContext3D::INVALID_ENUM:
+            return "INVALID_ENUM";
+        case GraphicsContext3D::INVALID_VALUE:
+            return "INVALID_VALUE";
+        case GraphicsContext3D::INVALID_OPERATION:
+            return "INVALID_OPERATION";
+        case GraphicsContext3D::OUT_OF_MEMORY:
+            return "OUT_OF_MEMORY";
+        case GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION:
+            return "INVALID_FRAMEBUFFER_OPERATION";
+        case GraphicsContext3D::CONTEXT_LOST_WEBGL:
+            return "CONTEXT_LOST_WEBGL";
+        default:
+            return String::format("WebGL ERROR(%04x)", error);
+        }
+    }
+
+} // namespace anonymous
+
+void WebGLRenderingContext::synthesizeGLError(GC3Denum error, const char* functionName, const char* description, ConsoleDisplayPreference display)
+{
+    if (m_synthesizedErrorsToConsole && display == DisplayInConsole) {
+      String str = String("WebGL: ") + GetErrorString(error) +  ": " + String(functionName) + ": " + String(description);
+      printGLErrorToConsole(str);
+    }
+    if (!isContextLost())
+        m_context->synthesizeGLError(error);
+    else {
+        if (lost_context_errors_.find(error) == WTF::notFound)
+            lost_context_errors_.append(error);
+    }
+}
+
+
+void WebGLRenderingContext::printGLWarningToConsole(const char* functionName, const char* description)
+{
+    if (m_synthesizedErrorsToConsole) {
+        String str = String("WebGL: ") + String(functionName) + ": " + String(description);
+        printGLErrorToConsole(str);
+    }
+}
+
+void WebGLRenderingContext::applyStencilTest()
+{
+    bool haveStencilBuffer = false;
+
+    if (m_framebufferBinding)
+        haveStencilBuffer = m_framebufferBinding->hasStencilBuffer();
+    else {
+        RefPtr<WebGLContextAttributes> attributes = getContextAttributes();
+        haveStencilBuffer = attributes->stencil();
+    }
+    enableOrDisable(GraphicsContext3D::STENCIL_TEST,
+                    m_stencilEnabled && haveStencilBuffer);
+}
+
+void WebGLRenderingContext::enableOrDisable(GC3Denum capability, bool enable)
+{
+    if (isContextLost())
+        return;
+    if (enable)
+        m_context->enable(capability);
+    else
+        m_context->disable(capability);
+}
+
+IntSize WebGLRenderingContext::clampedCanvasSize()
+{
+    return IntSize(clamp(canvas()->width(), 1, m_maxViewportDims[0]),
+                   clamp(canvas()->height(), 1, m_maxViewportDims[1]));
+}
+
+GC3Dint WebGLRenderingContext::getMaxDrawBuffers()
+{
+    if (isContextLost() || !m_extDrawBuffers)
+        return 0;
+    if (!m_maxDrawBuffers)
+        m_context->getIntegerv(Extensions3D::MAX_DRAW_BUFFERS_EXT, &m_maxDrawBuffers);
+    if (!m_maxColorAttachments)
+        m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
+    // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
+    return std::min(m_maxDrawBuffers, m_maxColorAttachments);
+}
+
+GC3Dint WebGLRenderingContext::getMaxColorAttachments()
+{
+    if (isContextLost() || !m_extDrawBuffers)
+        return 0;
+    if (!m_maxColorAttachments)
+        m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
+    return m_maxColorAttachments;
+}
+
+void WebGLRenderingContext::setBackDrawBuffer(GC3Denum buf)
+{
+    m_backDrawBuffer = buf;
+}
+
+void WebGLRenderingContext::restoreCurrentFramebuffer()
+{
+    ExceptionCode ec;
+    bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_framebufferBinding.get(), ec);
+}
+
+void WebGLRenderingContext::restoreCurrentTexture2D()
+{
+    ExceptionCode ec;
+    bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get(), ec);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/canvas/WebGLRenderingContext.h b/Source/core/html/canvas/WebGLRenderingContext.h
new file mode 100644
index 0000000..5314306
--- /dev/null
+++ b/Source/core/html/canvas/WebGLRenderingContext.h
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 WebGLRenderingContext_h
+#define WebGLRenderingContext_h
+
+#include "core/dom/ActiveDOMObject.h"
+#include "core/html/canvas/CanvasRenderingContext.h"
+#include "core/html/canvas/WebGLGetInfo.h"
+#include "core/platform/Timer.h"
+#include "core/platform/graphics/GraphicsContext3D.h"
+#include "core/platform/graphics/ImageBuffer.h"
+
+#include <wtf/Float32Array.h>
+#include <wtf/Int32Array.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Uint8Array.h>
+
+namespace WebCore {
+
+class DrawingBuffer;
+class EXTDrawBuffers;
+class EXTTextureFilterAnisotropic;
+class HTMLImageElement;
+class HTMLVideoElement;
+class ImageBuffer;
+class ImageData;
+class IntSize;
+class OESStandardDerivatives;
+class OESTextureFloat;
+class OESTextureHalfFloat;
+class OESVertexArrayObject;
+class OESElementIndexUint;
+class WebGLActiveInfo;
+class WebGLBuffer;
+class WebGLContextGroup;
+class WebGLContextObject;
+class WebGLCompressedTextureATC;
+class WebGLCompressedTexturePVRTC;
+class WebGLCompressedTextureS3TC;
+class WebGLContextAttributes;
+class WebGLDebugRendererInfo;
+class WebGLDebugShaders;
+class WebGLDepthTexture;
+class WebGLExtension;
+class WebGLFramebuffer;
+class WebGLLoseContext;
+class WebGLObject;
+class WebGLProgram;
+class WebGLRenderbuffer;
+class WebGLShader;
+class WebGLSharedObject;
+class WebGLShaderPrecisionFormat;
+class WebGLTexture;
+class WebGLUniformLocation;
+class WebGLVertexArrayObjectOES;
+
+typedef int ExceptionCode;
+
+class WebGLRenderingContext : public CanvasRenderingContext, public ActiveDOMObject {
+public:
+    static PassOwnPtr<WebGLRenderingContext> create(HTMLCanvasElement*, WebGLContextAttributes*);
+    virtual ~WebGLRenderingContext();
+
+    virtual bool is3d() const { return true; }
+    virtual bool isAccelerated() const { return true; }
+
+    int drawingBufferWidth() const;
+    int drawingBufferHeight() const;
+
+    void activeTexture(GC3Denum texture, ExceptionCode&);
+    void attachShader(WebGLProgram*, WebGLShader*, ExceptionCode&);
+    void bindAttribLocation(WebGLProgram*, GC3Duint index, const String& name, ExceptionCode&);
+    void bindBuffer(GC3Denum target, WebGLBuffer*, ExceptionCode&);
+    void bindFramebuffer(GC3Denum target, WebGLFramebuffer*, ExceptionCode&);
+    void bindRenderbuffer(GC3Denum target, WebGLRenderbuffer*, ExceptionCode&);
+    void bindTexture(GC3Denum target, WebGLTexture*, ExceptionCode&);
+    void blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha);
+    void blendEquation(GC3Denum mode);
+    void blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha);
+    void blendFunc(GC3Denum sfactor, GC3Denum dfactor);
+    void blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha);
+
+    void bufferData(GC3Denum target, long long size, GC3Denum usage, ExceptionCode&);
+    void bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode&);
+    void bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode&);
+    void bufferSubData(GC3Denum target, long long offset, ArrayBuffer* data, ExceptionCode&);
+    void bufferSubData(GC3Denum target, long long offset, ArrayBufferView* data, ExceptionCode&);
+
+    GC3Denum checkFramebufferStatus(GC3Denum target);
+    void clear(GC3Dbitfield mask);
+    void clearColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha);
+    void clearDepth(GC3Dfloat);
+    void clearStencil(GC3Dint);
+    void colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha);
+    void compileShader(WebGLShader*, ExceptionCode&);
+
+    void compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width,
+                              GC3Dsizei height, GC3Dint border, ArrayBufferView* data);
+    void compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                 GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView* data);
+
+    void copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border);
+    void copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height);
+
+    PassRefPtr<WebGLBuffer> createBuffer();
+    PassRefPtr<WebGLFramebuffer> createFramebuffer();
+    PassRefPtr<WebGLProgram> createProgram();
+    PassRefPtr<WebGLRenderbuffer> createRenderbuffer();
+    PassRefPtr<WebGLShader> createShader(GC3Denum type, ExceptionCode&);
+    PassRefPtr<WebGLTexture> createTexture();
+
+    void cullFace(GC3Denum mode);
+
+    void deleteBuffer(WebGLBuffer*);
+    void deleteFramebuffer(WebGLFramebuffer*);
+    void deleteProgram(WebGLProgram*);
+    void deleteRenderbuffer(WebGLRenderbuffer*);
+    void deleteShader(WebGLShader*);
+    void deleteTexture(WebGLTexture*);
+
+    void depthFunc(GC3Denum);
+    void depthMask(GC3Dboolean);
+    void depthRange(GC3Dfloat zNear, GC3Dfloat zFar);
+    void detachShader(WebGLProgram*, WebGLShader*, ExceptionCode&);
+    void disable(GC3Denum cap);
+    void disableVertexAttribArray(GC3Duint index, ExceptionCode&);
+    void drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode&);
+    void drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode&);
+
+    void enable(GC3Denum cap);
+    void enableVertexAttribArray(GC3Duint index, ExceptionCode&);
+    void finish();
+    void flush();
+    void framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer*, ExceptionCode&);
+    void framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture*, GC3Dint level, ExceptionCode&);
+    void frontFace(GC3Denum mode);
+    void generateMipmap(GC3Denum target);
+
+    PassRefPtr<WebGLActiveInfo> getActiveAttrib(WebGLProgram*, GC3Duint index, ExceptionCode&);
+    PassRefPtr<WebGLActiveInfo> getActiveUniform(WebGLProgram*, GC3Duint index, ExceptionCode&);
+    bool getAttachedShaders(WebGLProgram*, Vector<RefPtr<WebGLShader> >&, ExceptionCode&);
+    GC3Dint getAttribLocation(WebGLProgram*, const String& name);
+    WebGLGetInfo getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode&);
+    PassRefPtr<WebGLContextAttributes> getContextAttributes();
+    GC3Denum getError();
+    WebGLExtension* getExtension(const String& name);
+    WebGLGetInfo getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode&);
+    WebGLGetInfo getParameter(GC3Denum pname, ExceptionCode&);
+    WebGLGetInfo getProgramParameter(WebGLProgram*, GC3Denum pname, ExceptionCode&);
+    String getProgramInfoLog(WebGLProgram*, ExceptionCode&);
+    WebGLGetInfo getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode&);
+    WebGLGetInfo getShaderParameter(WebGLShader*, GC3Denum pname, ExceptionCode&);
+    String getShaderInfoLog(WebGLShader*, ExceptionCode&);
+    PassRefPtr<WebGLShaderPrecisionFormat> getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode&);
+    String getShaderSource(WebGLShader*, ExceptionCode&);
+    Vector<String> getSupportedExtensions();
+    WebGLGetInfo getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode&);
+    WebGLGetInfo getUniform(WebGLProgram*, const WebGLUniformLocation*, ExceptionCode&);
+    PassRefPtr<WebGLUniformLocation> getUniformLocation(WebGLProgram*, const String&, ExceptionCode&);
+    WebGLGetInfo getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode&);
+    long long getVertexAttribOffset(GC3Duint index, GC3Denum pname);
+
+    void hint(GC3Denum target, GC3Denum mode);
+    GC3Dboolean isBuffer(WebGLBuffer*);
+    bool isContextLost();
+    GC3Dboolean isEnabled(GC3Denum cap);
+    GC3Dboolean isFramebuffer(WebGLFramebuffer*);
+    GC3Dboolean isProgram(WebGLProgram*);
+    GC3Dboolean isRenderbuffer(WebGLRenderbuffer*);
+    GC3Dboolean isShader(WebGLShader*);
+    GC3Dboolean isTexture(WebGLTexture*);
+
+    void lineWidth(GC3Dfloat);
+    void linkProgram(WebGLProgram*, ExceptionCode&);
+    void pixelStorei(GC3Denum pname, GC3Dint param);
+    void polygonOffset(GC3Dfloat factor, GC3Dfloat units);
+    void readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&);
+    void renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height);
+    void sampleCoverage(GC3Dfloat value, GC3Dboolean invert);
+    void scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height);
+    void shaderSource(WebGLShader*, const String&, ExceptionCode&);
+    void stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask);
+    void stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask);
+    void stencilMask(GC3Duint);
+    void stencilMaskSeparate(GC3Denum face, GC3Duint mask);
+    void stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass);
+    void stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass);
+
+    void texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                    GC3Dsizei width, GC3Dsizei height, GC3Dint border,
+                    GC3Denum format, GC3Denum type, ArrayBufferView*, ExceptionCode&);
+    void texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                    GC3Denum format, GC3Denum type, ImageData*, ExceptionCode&);
+    void texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                    GC3Denum format, GC3Denum type, HTMLImageElement*, ExceptionCode&);
+    void texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                    GC3Denum format, GC3Denum type, HTMLCanvasElement*, ExceptionCode&);
+    void texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                    GC3Denum format, GC3Denum type, HTMLVideoElement*, ExceptionCode&);
+
+    void texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param);
+    void texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param);
+
+    void texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                       GC3Dsizei width, GC3Dsizei height,
+                       GC3Denum format, GC3Denum type, ArrayBufferView*, ExceptionCode&);
+    void texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                       GC3Denum format, GC3Denum type, ImageData*, ExceptionCode&);
+    void texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                       GC3Denum format, GC3Denum type, HTMLImageElement*, ExceptionCode&);
+    void texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                       GC3Denum format, GC3Denum type, HTMLCanvasElement*, ExceptionCode&);
+    void texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                       GC3Denum format, GC3Denum type, HTMLVideoElement*, ExceptionCode&);
+
+    void uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode&);
+    void uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode&);
+    void uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&);
+    void uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode&);
+    void uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode&);
+    void uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode&);
+    void uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode&);
+    void uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode&);
+    void uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&);
+    void uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode&);
+    void uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode&);
+    void uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode&);
+    void uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode&);
+    void uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode&);
+    void uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&);
+    void uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode&);
+    void uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode&);
+    void uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode&);
+    void uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode&);
+    void uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode&);
+    void uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&);
+    void uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode&);
+    void uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode&);
+    void uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode&);
+    void uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* value, ExceptionCode&);
+    void uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* value, GC3Dsizei size, ExceptionCode&);
+    void uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* value, ExceptionCode&);
+    void uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* value, GC3Dsizei size, ExceptionCode&);
+    void uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* value, ExceptionCode&);
+    void uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* value, GC3Dsizei size, ExceptionCode&);
+
+    void useProgram(WebGLProgram*, ExceptionCode&);
+    void validateProgram(WebGLProgram*, ExceptionCode&);
+
+    void vertexAttrib1f(GC3Duint index, GC3Dfloat x);
+    void vertexAttrib1fv(GC3Duint index, Float32Array* values);
+    void vertexAttrib1fv(GC3Duint index, GC3Dfloat* values, GC3Dsizei size);
+    void vertexAttrib2f(GC3Duint index, GC3Dfloat x, GC3Dfloat y);
+    void vertexAttrib2fv(GC3Duint index, Float32Array* values);
+    void vertexAttrib2fv(GC3Duint index, GC3Dfloat* values, GC3Dsizei size);
+    void vertexAttrib3f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z);
+    void vertexAttrib3fv(GC3Duint index, Float32Array* values);
+    void vertexAttrib3fv(GC3Duint index, GC3Dfloat* values, GC3Dsizei size);
+    void vertexAttrib4f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w);
+    void vertexAttrib4fv(GC3Duint index, Float32Array* values);
+    void vertexAttrib4fv(GC3Duint index, GC3Dfloat* values, GC3Dsizei size);
+    void vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized,
+                             GC3Dsizei stride, long long offset, ExceptionCode&);
+
+    void viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height);
+
+    // WEBKIT_lose_context support
+    enum LostContextMode {
+        // Lost context occurred at the graphics system level.
+        RealLostContext,
+
+        // Lost context provoked by WEBKIT_lose_context.
+        SyntheticLostContext
+    };
+    void forceLostContext(LostContextMode);
+    void forceRestoreContext();
+    void loseContextImpl(LostContextMode);
+
+    GraphicsContext3D* graphicsContext3D() const { return m_context.get(); }
+    WebGLContextGroup* contextGroup() const { return m_contextGroup.get(); }
+    virtual PlatformLayer* platformLayer() const;
+
+    void reshape(int width, int height);
+
+    void markLayerComposited();
+    virtual void paintRenderingResultsToCanvas();
+    virtual PassRefPtr<ImageData> paintRenderingResultsToImageData();
+
+    void removeSharedObject(WebGLSharedObject*);
+    void removeContextObject(WebGLContextObject*);
+    
+    unsigned getMaxVertexAttribs() const { return m_maxVertexAttribs; }
+
+    // ActiveDOMObject notifications
+    virtual bool hasPendingActivity() const;
+    virtual void stop();
+
+  private:
+    friend class EXTDrawBuffers;
+    friend class WebGLFramebuffer;
+    friend class WebGLObject;
+    friend class OESVertexArrayObject;
+    friend class WebGLDebugShaders;
+    friend class WebGLCompressedTextureATC;
+    friend class WebGLCompressedTexturePVRTC;
+    friend class WebGLCompressedTextureS3TC;
+    friend class WebGLRenderingContextErrorMessageCallback;
+    friend class WebGLVertexArrayObjectOES;
+
+    WebGLRenderingContext(HTMLCanvasElement*, PassRefPtr<GraphicsContext3D>, GraphicsContext3D::Attributes);
+    void initializeNewContext();
+    void setupFlags();
+
+    void addSharedObject(WebGLSharedObject*);
+    void addContextObject(WebGLContextObject*);
+    void detachAndRemoveAllObjects();
+
+    void destroyGraphicsContext3D();
+    void markContextChanged();
+
+    // Query if the GL implementation is NPOT strict.
+    bool isGLES2NPOTStrict() { return m_isGLES2NPOTStrict; }
+    // Query if depth_stencil buffer is supported.
+    bool isDepthStencilSupported() { return m_isDepthStencilSupported; }
+
+    // Helper to return the size in bytes of OpenGL data types
+    // like GL_FLOAT, GL_INT, etc.
+    unsigned int sizeInBytes(GC3Denum type);
+
+    // Check if each enabled vertex attribute is bound to a buffer.
+    bool validateRenderingState();
+
+    bool validateWebGLObject(const char*, WebGLObject*);
+
+    // Adds a compressed texture format.
+    void addCompressedTextureFormat(GC3Denum);
+
+    // Template to help getSupportedExtensions
+    template<typename T>
+    void appendIfSupported(Vector<String>& strings, bool prefixed)
+    {
+        if (T::supported(this))
+            strings.append(String(prefixed ? "WEBKIT_" : "") + T::getExtensionName());
+    }
+
+    bool matchesNameWithPrefixes(const String& name, const String& baseName, const char** prefixes);
+
+    // Templates to help getExtension
+    template<typename T>
+    bool getExtensionIfMatch(const String& name, OwnPtr<T>& extensionPtr, const char** prefixes, WebGLExtension*& extension)
+    {
+        if (matchesNameWithPrefixes(name, T::getExtensionName(), prefixes) && (extensionPtr || T::supported(this))) {
+            if (!extensionPtr) {
+                extensionPtr = T::create(this);
+            }
+            extension = extensionPtr.get();
+            return true;
+        }
+        return false;
+    }
+
+    PassRefPtr<Image> videoFrameToImage(HTMLVideoElement*, BackingStoreCopy, ExceptionCode&);
+
+    RefPtr<GraphicsContext3D> m_context;
+    RefPtr<WebGLContextGroup> m_contextGroup;
+
+    // Structure for rendering to a DrawingBuffer, instead of directly
+    // to the back-buffer of m_context.
+    RefPtr<DrawingBuffer> m_drawingBuffer;
+
+    // Dispatches a context lost event once it is determined that one is needed.
+    // This is used both for synthetic and real context losses. For real ones, it's
+    // likely that there's no JavaScript on the stack, but that might be dependent
+    // on how exactly the platform discovers that the context was lost. For better
+    // portability we always defer the dispatch of the event.
+    Timer<WebGLRenderingContext> m_dispatchContextLostEventTimer;
+    bool m_restoreAllowed;
+    Timer<WebGLRenderingContext> m_restoreTimer;
+
+    bool m_needsUpdate;
+    bool m_markedCanvasDirty;
+    HashSet<WebGLContextObject*> m_contextObjects;
+
+    // List of bound VBO's. Used to maintain info about sizes for ARRAY_BUFFER and stored values for ELEMENT_ARRAY_BUFFER
+    RefPtr<WebGLBuffer> m_boundArrayBuffer;
+    
+    RefPtr<WebGLVertexArrayObjectOES> m_defaultVertexArrayObject;
+    RefPtr<WebGLVertexArrayObjectOES> m_boundVertexArrayObject;
+    void setBoundVertexArrayObject(PassRefPtr<WebGLVertexArrayObjectOES> arrayObject)
+    {
+        if (arrayObject)
+            m_boundVertexArrayObject = arrayObject;
+        else
+            m_boundVertexArrayObject = m_defaultVertexArrayObject;
+    }
+    
+    class VertexAttribValue {
+    public:
+        VertexAttribValue()
+        {
+            initValue();
+        }
+        
+        void initValue()
+        {
+            value[0] = 0.0f;
+            value[1] = 0.0f;
+            value[2] = 0.0f;
+            value[3] = 1.0f;
+        }
+        
+        GC3Dfloat value[4];
+    };
+    Vector<VertexAttribValue> m_vertexAttribValue;
+    unsigned m_maxVertexAttribs;
+    RefPtr<WebGLBuffer> m_vertexAttrib0Buffer;
+    long m_vertexAttrib0BufferSize;
+    GC3Dfloat m_vertexAttrib0BufferValue[4];
+    bool m_forceAttrib0BufferRefill;
+    bool m_vertexAttrib0UsedBefore;
+
+    RefPtr<WebGLProgram> m_currentProgram;
+    RefPtr<WebGLFramebuffer> m_framebufferBinding;
+    RefPtr<WebGLRenderbuffer> m_renderbufferBinding;
+    class TextureUnitState {
+    public:
+        RefPtr<WebGLTexture> m_texture2DBinding;
+        RefPtr<WebGLTexture> m_textureCubeMapBinding;
+    };
+    Vector<TextureUnitState> m_textureUnits;
+    unsigned long m_activeTextureUnit;
+
+    RefPtr<WebGLTexture> m_blackTexture2D;
+    RefPtr<WebGLTexture> m_blackTextureCubeMap;
+
+    Vector<GC3Denum> m_compressedTextureFormats;
+
+    // Fixed-size cache of reusable image buffers for video texImage2D calls.
+    class LRUImageBufferCache {
+    public:
+        LRUImageBufferCache(int capacity);
+        // The pointer returned is owned by the image buffer map.
+        ImageBuffer* imageBuffer(const IntSize& size);
+    private:
+        void bubbleToFront(int idx);
+        OwnArrayPtr<OwnPtr<ImageBuffer> > m_buffers;
+        int m_capacity;
+    };
+    LRUImageBufferCache m_videoCache;
+
+    GC3Dint m_maxTextureSize;
+    GC3Dint m_maxCubeMapTextureSize;
+    GC3Dint m_maxRenderbufferSize;
+    GC3Dint m_maxViewportDims[2];
+    GC3Dint m_maxTextureLevel;
+    GC3Dint m_maxCubeMapTextureLevel;
+
+    GC3Dint m_maxDrawBuffers;
+    GC3Dint m_maxColorAttachments;
+    GC3Denum m_backDrawBuffer;
+    bool m_drawBuffersWebGLRequirementsChecked;
+    bool m_drawBuffersSupported;
+
+    GC3Dint m_packAlignment;
+    GC3Dint m_unpackAlignment;
+    bool m_unpackFlipY;
+    bool m_unpackPremultiplyAlpha;
+    GC3Denum m_unpackColorspaceConversion;
+    bool m_contextLost;
+    LostContextMode m_contextLostMode;
+    GraphicsContext3D::Attributes m_attributes;
+
+    bool m_layerCleared;
+    GC3Dfloat m_clearColor[4];
+    bool m_scissorEnabled;
+    GC3Dfloat m_clearDepth;
+    GC3Dint m_clearStencil;
+    GC3Dboolean m_colorMask[4];
+    GC3Dboolean m_depthMask;
+
+    bool m_stencilEnabled;
+    GC3Duint m_stencilMask, m_stencilMaskBack;
+    GC3Dint m_stencilFuncRef, m_stencilFuncRefBack; // Note that these are the user specified values, not the internal clamped value.
+    GC3Duint m_stencilFuncMask, m_stencilFuncMaskBack;
+
+    bool m_isGLES2NPOTStrict;
+    bool m_isDepthStencilSupported;
+    bool m_isRobustnessEXTSupported;
+
+    bool m_synthesizedErrorsToConsole;
+    int m_numGLErrorsToConsoleAllowed;
+
+    // Enabled extension objects.
+    OwnPtr<EXTDrawBuffers> m_extDrawBuffers;
+    OwnPtr<EXTTextureFilterAnisotropic> m_extTextureFilterAnisotropic;
+    OwnPtr<OESTextureFloat> m_oesTextureFloat;
+    OwnPtr<OESTextureHalfFloat> m_oesTextureHalfFloat;
+    OwnPtr<OESStandardDerivatives> m_oesStandardDerivatives;
+    OwnPtr<OESVertexArrayObject> m_oesVertexArrayObject;
+    OwnPtr<OESElementIndexUint> m_oesElementIndexUint;
+    OwnPtr<WebGLLoseContext> m_webglLoseContext;
+    OwnPtr<WebGLDebugRendererInfo> m_webglDebugRendererInfo;
+    OwnPtr<WebGLDebugShaders> m_webglDebugShaders;
+    OwnPtr<WebGLCompressedTextureATC> m_webglCompressedTextureATC;
+    OwnPtr<WebGLCompressedTexturePVRTC> m_webglCompressedTexturePVRTC;
+    OwnPtr<WebGLCompressedTextureS3TC> m_webglCompressedTextureS3TC;
+    OwnPtr<WebGLDepthTexture> m_webglDepthTexture;
+
+    // Errors raised by synthesizeGLError() while the context is lost.
+    Vector<GC3Denum> lost_context_errors_;
+
+    // Helpers for getParameter and others
+    WebGLGetInfo getBooleanParameter(GC3Denum);
+    WebGLGetInfo getBooleanArrayParameter(GC3Denum);
+    WebGLGetInfo getFloatParameter(GC3Denum);
+    WebGLGetInfo getIntParameter(GC3Denum);
+    WebGLGetInfo getUnsignedIntParameter(GC3Denum);
+    WebGLGetInfo getWebGLFloatArrayParameter(GC3Denum);
+    WebGLGetInfo getWebGLIntArrayParameter(GC3Denum);
+
+    // Clear the backbuffer if it was composited since the last operation.
+    // clearMask is set to the bitfield of any clear that would happen anyway at this time
+    // and the function returns true if that clear is now unnecessary.
+    bool clearIfComposited(GC3Dbitfield clearMask = 0);
+
+    // Helper to restore state that clearing the framebuffer may destroy.
+    void restoreStateAfterClear();
+
+    void texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode&);
+    void texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Denum format, GC3Denum type, Image*, GraphicsContext3D::ImageHtmlDomSource, bool flipY, bool premultiplyAlpha, ExceptionCode&);
+    void texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode&);
+    void texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Denum format, GC3Denum type, Image*, GraphicsContext3D::ImageHtmlDomSource, bool flipY, bool premultiplyAlpha, ExceptionCode&);
+
+    void handleNPOTTextures(const char*, bool);
+
+    void createFallbackBlackTextures1x1();
+
+    // Helper function for copyTex{Sub}Image, check whether the internalformat
+    // and the color buffer format of the current bound framebuffer combination
+    // is valid.
+    bool isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,
+                                                        GC3Denum colorBufferFormat);
+
+    // Helper function to get the bound framebuffer's color buffer format.
+    GC3Denum getBoundFramebufferColorFormat();
+
+    // Helper function to get the bound framebuffer's width.
+    int getBoundFramebufferWidth();
+
+    // Helper function to get the bound framebuffer's height.
+    int getBoundFramebufferHeight();
+
+    // Helper function to verify limits on the length of uniform and attribute locations.
+    bool validateLocationLength(const char* functionName, const String&);
+
+    // Helper function to check if size is non-negative.
+    // Generate GL error and return false for negative inputs; otherwise, return true.
+    bool validateSize(const char* functionName, GC3Dint x, GC3Dint y);
+
+    // Helper function to check if all characters in the string belong to the
+    // ASCII subset as defined in GLSL ES 1.0 spec section 3.1.
+    bool validateString(const char* functionName, const String&);
+
+    // Helper function to check target and texture bound to the target.
+    // Generate GL errors and return 0 if target is invalid or texture bound is
+    // null.  Otherwise, return the texture bound to the target.
+    WebGLTexture* validateTextureBinding(const char* functionName, GC3Denum target, bool useSixEnumsForCubeMap);
+
+    // Helper function to check input format/type for functions {copy}Tex{Sub}Image.
+    // Generates GL error and returns false if parameters are invalid.
+    bool validateTexFuncFormatAndType(const char* functionName, GC3Denum format, GC3Denum type, GC3Dint level);
+
+    // Helper function to check input level for functions {copy}Tex{Sub}Image.
+    // Generates GL error and returns false if level is invalid.
+    bool validateTexFuncLevel(const char* functionName, GC3Denum target, GC3Dint level);
+
+    enum TexFuncValidationFunctionType {
+        NotTexSubImage2D,
+        TexSubImage2D,
+    };
+
+    enum TexFuncValidationSourceType {
+        SourceArrayBufferView,
+        SourceImageData,
+        SourceHTMLImageElement,
+        SourceHTMLCanvasElement,
+        SourceHTMLVideoElement,
+    };
+
+    // Helper function for tex{Sub}Image2D to check if the input format/type/level/target/width/height/border/xoffset/yoffset are valid.
+    // Otherwise, it would return quickly without doing other work.
+    bool validateTexFunc(const char* functionName, TexFuncValidationFunctionType, TexFuncValidationSourceType, GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width,
+        GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint xoffset, GC3Dint yoffset);
+
+    // Helper function to check input parameters for functions {copy}Tex{Sub}Image.
+    // Generates GL error and returns false if parameters are invalid.
+    bool validateTexFuncParameters(const char* functionName,
+                                   TexFuncValidationFunctionType,
+                                   GC3Denum target, GC3Dint level,
+                                   GC3Denum internalformat,
+                                   GC3Dsizei width, GC3Dsizei height, GC3Dint border,
+                                   GC3Denum format, GC3Denum type);
+
+    enum NullDisposition {
+        NullAllowed,
+        NullNotAllowed
+    };
+
+    // Helper function to validate that the given ArrayBufferView
+    // is of the correct type and contains enough data for the texImage call.
+    // Generates GL error and returns false if parameters are invalid.
+    bool validateTexFuncData(const char* functionName, GC3Dint level,
+                             GC3Dsizei width, GC3Dsizei height,
+                             GC3Denum format, GC3Denum type,
+                             ArrayBufferView* pixels,
+                             NullDisposition);
+
+    // Helper function to validate a given texture format is settable as in
+    // you can supply data to texImage2D, or call texImage2D, copyTexImage2D and
+    // copyTexSubImage2D.
+    // Generates GL error and returns false if the format is not settable.
+    bool validateSettableTexFormat(const char* functionName, GC3Denum format);
+
+    // Helper function to validate compressed texture data is correct size
+    // for the given format and dimensions.
+    bool validateCompressedTexFuncData(const char* functionName,
+                                       GC3Dsizei width, GC3Dsizei height,
+                                       GC3Denum format, ArrayBufferView* pixels);
+
+    // Helper function for validating compressed texture formats.
+    bool validateCompressedTexFormat(GC3Denum format);
+
+    // Helper function to validate compressed texture dimensions are valid for
+    // the given format.
+    bool validateCompressedTexDimensions(const char* functionName, GC3Dint level, GC3Dsizei width, GC3Dsizei height, GC3Denum format);
+
+    // Helper function to validate compressed texture dimensions are valid for
+    // the given format.
+    bool validateCompressedTexSubDimensions(const char* functionName, GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                            GC3Dsizei width, GC3Dsizei height, GC3Denum format, WebGLTexture*);
+
+    // Helper function to validate mode for draw{Arrays/Elements}.
+    bool validateDrawMode(const char* functionName, GC3Denum);
+
+    // Helper function to validate if front/back stencilMask and stencilFunc settings are the same.
+    bool validateStencilSettings(const char* functionName);
+
+    // Helper function to validate stencil func.
+    bool validateStencilFunc(const char* functionName, GC3Denum);
+
+    // Helper function for texParameterf and texParameteri.
+    void texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat parami, GC3Dint paramf, bool isFloat);
+
+    // Helper function to print GL errors to console.
+    void printGLErrorToConsole(const String&);
+    void printGLWarningToConsole(const char* function, const char* reason);
+
+    // Helper function to print warnings to console. Currently
+    // used only to warn about use of obsolete functions.
+    void printWarningToConsole(const String&);
+
+    // Helper function to validate input parameters for framebuffer functions.
+    // Generate GL error if parameters are illegal.
+    bool validateFramebufferFuncParameters(const char* functionName, GC3Denum target, GC3Denum attachment);
+
+    // Helper function to validate blend equation mode.
+    bool validateBlendEquation(const char* functionName, GC3Denum);
+
+    // Helper function to validate blend func factors.
+    bool validateBlendFuncFactors(const char* functionName, GC3Denum src, GC3Denum dst);
+
+    // Helper function to validate a GL capability.
+    bool validateCapability(const char* functionName, GC3Denum);
+
+    // Helper function to validate input parameters for uniform functions.
+    bool validateUniformParameters(const char* functionName, const WebGLUniformLocation*, Float32Array*, GC3Dsizei mod);
+    bool validateUniformParameters(const char* functionName, const WebGLUniformLocation*, Int32Array*, GC3Dsizei mod);
+    bool validateUniformParameters(const char* functionName, const WebGLUniformLocation*, void*, GC3Dsizei, GC3Dsizei mod);
+    bool validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation*, GC3Dboolean transpose, Float32Array*, GC3Dsizei mod);
+    bool validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation*, GC3Dboolean transpose, void*, GC3Dsizei, GC3Dsizei mod);
+
+    // Helper function to validate parameters for bufferData.
+    // Return the current bound buffer to target, or 0 if parameters are invalid.
+    WebGLBuffer* validateBufferDataParameters(const char* functionName, GC3Denum target, GC3Denum usage);
+
+    // Helper function for tex{Sub}Image2D to make sure image is ready and wouldn't taint Origin.
+    bool validateHTMLImageElement(const char* functionName, HTMLImageElement*, ExceptionCode&);
+
+    // Helper function for tex{Sub}Image2D to make sure canvas is ready and wouldn't taint Origin.
+    bool validateHTMLCanvasElement(const char* functionName, HTMLCanvasElement*, ExceptionCode&);
+
+    // Helper function for tex{Sub}Image2D to make sure video is ready wouldn't taint Origin.
+    bool validateHTMLVideoElement(const char* functionName, HTMLVideoElement*, ExceptionCode&);
+
+    // Helper functions for vertexAttribNf{v}.
+    void vertexAttribfImpl(const char* functionName, GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat, GC3Dfloat, GC3Dfloat, GC3Dfloat);
+    void vertexAttribfvImpl(const char* functionName, GC3Duint index, Float32Array*, GC3Dsizei expectedSize);
+    void vertexAttribfvImpl(const char* functionName, GC3Duint index, GC3Dfloat*, GC3Dsizei, GC3Dsizei expectedSize);
+
+    // Helper function for delete* (deleteBuffer, deleteProgram, etc) functions.
+    // Return false if caller should return without further processing.
+    bool deleteObject(WebGLObject*);
+
+    // Helper function for bind* (bindBuffer, bindTexture, etc) and useProgram.
+    // If the object has already been deleted, set deleted to true upon return.
+    // Return false if caller should return without further processing.
+    bool checkObjectToBeBound(const char* functionName, WebGLObject*, bool& deleted);
+
+    void dispatchContextLostEvent(Timer<WebGLRenderingContext>*);
+    // Helper for restoration after context lost.
+    void maybeRestoreContext(Timer<WebGLRenderingContext>*);
+
+    // Determine if we are running privileged code in the browser, for example,
+    // a Safari or Chrome extension.
+    bool allowPrivilegedExtensions() const;
+
+    enum ConsoleDisplayPreference {
+        DisplayInConsole,
+        DontDisplayInConsole
+    };
+
+    // Wrapper for GraphicsContext3D::synthesizeGLError that sends a message
+    // to the JavaScript console.
+    void synthesizeGLError(GC3Denum, const char* functionName, const char* description, ConsoleDisplayPreference = DisplayInConsole);
+
+    String ensureNotNull(const String&) const;
+
+    // Enable or disable stencil test based on user setting and
+    // whether the current FBO has a stencil buffer.
+    void applyStencilTest();
+
+    // Helper for enabling or disabling a capability.
+    void enableOrDisable(GC3Denum capability, bool enable);
+
+    // Clamp the width and height to GL_MAX_VIEWPORT_DIMS.
+    IntSize clampedCanvasSize();
+
+    // First time called, if EXT_draw_buffers is supported, query the value; otherwise return 0.
+    // Later, return the cached value.
+    GC3Dint getMaxDrawBuffers();
+    GC3Dint getMaxColorAttachments();
+
+    void setBackDrawBuffer(GC3Denum);
+
+    void restoreCurrentFramebuffer();
+    void restoreCurrentTexture2D();
+
+    friend class WebGLStateRestorer;
+    friend class WebGLRenderingContextEvictionManager;
+
+    static Vector<WebGLRenderingContext*>& activeContexts();
+    static Vector<WebGLRenderingContext*>& forciblyEvictedContexts();
+
+    static void activateContext(WebGLRenderingContext*);
+    static void deactivateContext(WebGLRenderingContext*, bool addToInactiveList);
+    static void willDestroyContext(WebGLRenderingContext*);
+    static void forciblyLoseOldestContext(const String& reason);
+    static IntSize oldestContextSize();
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/canvas/WebGLRenderingContext.idl b/Source/core/html/canvas/WebGLRenderingContext.idl
new file mode 100644
index 0000000..dc5761f
--- /dev/null
+++ b/Source/core/html/canvas/WebGLRenderingContext.idl
@@ -0,0 +1,663 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+typedef unsigned long  GLenum;
+typedef boolean        GLboolean;
+typedef unsigned long  GLbitfield;
+typedef byte           GLbyte;         /* 'byte' should be a signed 8 bit type. */
+typedef short          GLshort;
+typedef long           GLint;
+typedef long           GLsizei;
+typedef long long      GLintptr;
+typedef long long      GLsizeiptr;
+typedef octet          GLubyte;        /* 'octet' should be an unsigned 8 bit type. */
+typedef unsigned short GLushort;
+typedef unsigned long  GLuint;
+typedef /*unrestricted*/ float GLfloat;
+typedef /*unrestricted*/ float GLclampf;
+
+[
+    Conditional=WEBGL,
+    DoNotCheckConstants
+] interface WebGLRenderingContext : CanvasRenderingContext {
+
+    /* ClearBufferMask */
+    const GLenum DEPTH_BUFFER_BIT               = 0x00000100;
+    const GLenum STENCIL_BUFFER_BIT             = 0x00000400;
+    const GLenum COLOR_BUFFER_BIT               = 0x00004000;
+
+    /* BeginMode */
+    const GLenum POINTS                         = 0x0000;
+    const GLenum LINES                          = 0x0001;
+    const GLenum LINE_LOOP                      = 0x0002;
+    const GLenum LINE_STRIP                     = 0x0003;
+    const GLenum TRIANGLES                      = 0x0004;
+    const GLenum TRIANGLE_STRIP                 = 0x0005;
+    const GLenum TRIANGLE_FAN                   = 0x0006;
+
+    /* AlphaFunction (not supported in ES20) */
+    /*      NEVER */
+    /*      LESS */
+    /*      EQUAL */
+    /*      LEQUAL */
+    /*      GREATER */
+    /*      NOTEQUAL */
+    /*      GEQUAL */
+    /*      ALWAYS */
+
+    /* BlendingFactorDest */
+    const GLenum ZERO                           = 0;
+    const GLenum ONE                            = 1;
+    const GLenum SRC_COLOR                      = 0x0300;
+    const GLenum ONE_MINUS_SRC_COLOR            = 0x0301;
+    const GLenum SRC_ALPHA                      = 0x0302;
+    const GLenum ONE_MINUS_SRC_ALPHA            = 0x0303;
+    const GLenum DST_ALPHA                      = 0x0304;
+    const GLenum ONE_MINUS_DST_ALPHA            = 0x0305;
+
+    /* BlendingFactorSrc */
+    /*      ZERO */
+    /*      ONE */
+    const GLenum DST_COLOR                      = 0x0306;
+    const GLenum ONE_MINUS_DST_COLOR            = 0x0307;
+    const GLenum SRC_ALPHA_SATURATE             = 0x0308;
+    /*      SRC_ALPHA */
+    /*      ONE_MINUS_SRC_ALPHA */
+    /*      DST_ALPHA */
+    /*      ONE_MINUS_DST_ALPHA */
+
+    /* BlendEquationSeparate */
+    const GLenum FUNC_ADD                       = 0x8006;
+    const GLenum BLEND_EQUATION                 = 0x8009;
+    const GLenum BLEND_EQUATION_RGB             = 0x8009;   /* same as BLEND_EQUATION */
+    const GLenum BLEND_EQUATION_ALPHA           = 0x883D;
+
+    /* BlendSubtract */
+    const GLenum FUNC_SUBTRACT                  = 0x800A;
+    const GLenum FUNC_REVERSE_SUBTRACT          = 0x800B;
+
+    /* Separate Blend Functions */
+    const GLenum BLEND_DST_RGB                  = 0x80C8;
+    const GLenum BLEND_SRC_RGB                  = 0x80C9;
+    const GLenum BLEND_DST_ALPHA                = 0x80CA;
+    const GLenum BLEND_SRC_ALPHA                = 0x80CB;
+    const GLenum CONSTANT_COLOR                 = 0x8001;
+    const GLenum ONE_MINUS_CONSTANT_COLOR       = 0x8002;
+    const GLenum CONSTANT_ALPHA                 = 0x8003;
+    const GLenum ONE_MINUS_CONSTANT_ALPHA       = 0x8004;
+    const GLenum BLEND_COLOR                    = 0x8005;
+
+    /* Buffer Objects */
+    const GLenum ARRAY_BUFFER                   = 0x8892;
+    const GLenum ELEMENT_ARRAY_BUFFER           = 0x8893;
+    const GLenum ARRAY_BUFFER_BINDING           = 0x8894;
+    const GLenum ELEMENT_ARRAY_BUFFER_BINDING   = 0x8895;
+
+    const GLenum STREAM_DRAW                    = 0x88E0;
+    const GLenum STATIC_DRAW                    = 0x88E4;
+    const GLenum DYNAMIC_DRAW                   = 0x88E8;
+
+    const GLenum BUFFER_SIZE                    = 0x8764;
+    const GLenum BUFFER_USAGE                   = 0x8765;
+
+    const GLenum CURRENT_VERTEX_ATTRIB          = 0x8626;
+
+    /* CullFaceMode */
+    const GLenum FRONT                          = 0x0404;
+    const GLenum BACK                           = 0x0405;
+    const GLenum FRONT_AND_BACK                 = 0x0408;
+
+    /* DepthFunction */
+    /*      NEVER */
+    /*      LESS */
+    /*      EQUAL */
+    /*      LEQUAL */
+    /*      GREATER */
+    /*      NOTEQUAL */
+    /*      GEQUAL */
+    /*      ALWAYS */
+
+    /* EnableCap */
+    const GLenum TEXTURE_2D                     = 0x0DE1;
+    const GLenum CULL_FACE                      = 0x0B44;
+    const GLenum BLEND                          = 0x0BE2;
+    const GLenum DITHER                         = 0x0BD0;
+    const GLenum STENCIL_TEST                   = 0x0B90;
+    const GLenum DEPTH_TEST                     = 0x0B71;
+    const GLenum SCISSOR_TEST                   = 0x0C11;
+    const GLenum POLYGON_OFFSET_FILL            = 0x8037;
+    const GLenum SAMPLE_ALPHA_TO_COVERAGE       = 0x809E;
+    const GLenum SAMPLE_COVERAGE                = 0x80A0;
+
+    /* ErrorCode */
+    const GLenum NO_ERROR                       = 0;
+    const GLenum INVALID_ENUM                   = 0x0500;
+    const GLenum INVALID_VALUE                  = 0x0501;
+    const GLenum INVALID_OPERATION              = 0x0502;
+    const GLenum OUT_OF_MEMORY                  = 0x0505;
+
+    /* FrontFaceDirection */
+    const GLenum CW                             = 0x0900;
+    const GLenum CCW                            = 0x0901;
+
+    /* GetPName */
+    const GLenum LINE_WIDTH                     = 0x0B21;
+    const GLenum ALIASED_POINT_SIZE_RANGE       = 0x846D;
+    const GLenum ALIASED_LINE_WIDTH_RANGE       = 0x846E;
+    const GLenum CULL_FACE_MODE                 = 0x0B45;
+    const GLenum FRONT_FACE                     = 0x0B46;
+    const GLenum DEPTH_RANGE                    = 0x0B70;
+    const GLenum DEPTH_WRITEMASK                = 0x0B72;
+    const GLenum DEPTH_CLEAR_VALUE              = 0x0B73;
+    const GLenum DEPTH_FUNC                     = 0x0B74;
+    const GLenum STENCIL_CLEAR_VALUE            = 0x0B91;
+    const GLenum STENCIL_FUNC                   = 0x0B92;
+    const GLenum STENCIL_FAIL                   = 0x0B94;
+    const GLenum STENCIL_PASS_DEPTH_FAIL        = 0x0B95;
+    const GLenum STENCIL_PASS_DEPTH_PASS        = 0x0B96;
+    const GLenum STENCIL_REF                    = 0x0B97;
+    const GLenum STENCIL_VALUE_MASK             = 0x0B93;
+    const GLenum STENCIL_WRITEMASK              = 0x0B98;
+    const GLenum STENCIL_BACK_FUNC              = 0x8800;
+    const GLenum STENCIL_BACK_FAIL              = 0x8801;
+    const GLenum STENCIL_BACK_PASS_DEPTH_FAIL   = 0x8802;
+    const GLenum STENCIL_BACK_PASS_DEPTH_PASS   = 0x8803;
+    const GLenum STENCIL_BACK_REF               = 0x8CA3;
+    const GLenum STENCIL_BACK_VALUE_MASK        = 0x8CA4;
+    const GLenum STENCIL_BACK_WRITEMASK         = 0x8CA5;
+    const GLenum VIEWPORT                       = 0x0BA2;
+    const GLenum SCISSOR_BOX                    = 0x0C10;
+    /*      SCISSOR_TEST */
+    const GLenum COLOR_CLEAR_VALUE              = 0x0C22;
+    const GLenum COLOR_WRITEMASK                = 0x0C23;
+    const GLenum UNPACK_ALIGNMENT               = 0x0CF5;
+    const GLenum PACK_ALIGNMENT                 = 0x0D05;
+    const GLenum MAX_TEXTURE_SIZE               = 0x0D33;
+    const GLenum MAX_VIEWPORT_DIMS              = 0x0D3A;
+    const GLenum SUBPIXEL_BITS                  = 0x0D50;
+    const GLenum RED_BITS                       = 0x0D52;
+    const GLenum GREEN_BITS                     = 0x0D53;
+    const GLenum BLUE_BITS                      = 0x0D54;
+    const GLenum ALPHA_BITS                     = 0x0D55;
+    const GLenum DEPTH_BITS                     = 0x0D56;
+    const GLenum STENCIL_BITS                   = 0x0D57;
+    const GLenum POLYGON_OFFSET_UNITS           = 0x2A00;
+    /*      POLYGON_OFFSET_FILL */
+    const GLenum POLYGON_OFFSET_FACTOR          = 0x8038;
+    const GLenum TEXTURE_BINDING_2D             = 0x8069;
+    const GLenum SAMPLE_BUFFERS                 = 0x80A8;
+    const GLenum SAMPLES                        = 0x80A9;
+    const GLenum SAMPLE_COVERAGE_VALUE          = 0x80AA;
+    const GLenum SAMPLE_COVERAGE_INVERT         = 0x80AB;
+
+    /* GetTextureParameter */
+    /*      TEXTURE_MAG_FILTER */
+    /*      TEXTURE_MIN_FILTER */
+    /*      TEXTURE_WRAP_S */
+    /*      TEXTURE_WRAP_T */
+
+    const GLenum COMPRESSED_TEXTURE_FORMATS     = 0x86A3;
+
+    /* HintMode */
+    const GLenum DONT_CARE                      = 0x1100;
+    const GLenum FASTEST                        = 0x1101;
+    const GLenum NICEST                         = 0x1102;
+
+    /* HintTarget */
+    const GLenum GENERATE_MIPMAP_HINT            = 0x8192;
+
+    /* DataType */
+    const GLenum BYTE                           = 0x1400;
+    const GLenum UNSIGNED_BYTE                  = 0x1401;
+    const GLenum SHORT                          = 0x1402;
+    const GLenum UNSIGNED_SHORT                 = 0x1403;
+    const GLenum INT                            = 0x1404;
+    const GLenum UNSIGNED_INT                   = 0x1405;
+    const GLenum FLOAT                          = 0x1406;
+
+    /* PixelFormat */
+    const GLenum DEPTH_COMPONENT                = 0x1902;
+    const GLenum ALPHA                          = 0x1906;
+    const GLenum RGB                            = 0x1907;
+    const GLenum RGBA                           = 0x1908;
+    const GLenum LUMINANCE                      = 0x1909;
+    const GLenum LUMINANCE_ALPHA                = 0x190A;
+
+    /* PixelType */
+    /*      UNSIGNED_BYTE */
+    const GLenum UNSIGNED_SHORT_4_4_4_4         = 0x8033;
+    const GLenum UNSIGNED_SHORT_5_5_5_1         = 0x8034;
+    const GLenum UNSIGNED_SHORT_5_6_5           = 0x8363;
+
+    /* Shaders */
+    const GLenum FRAGMENT_SHADER                  = 0x8B30;
+    const GLenum VERTEX_SHADER                    = 0x8B31;
+    const GLenum MAX_VERTEX_ATTRIBS               = 0x8869;
+    const GLenum MAX_VERTEX_UNIFORM_VECTORS       = 0x8DFB;
+    const GLenum MAX_VARYING_VECTORS              = 0x8DFC;
+    const GLenum MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D;
+    const GLenum MAX_VERTEX_TEXTURE_IMAGE_UNITS   = 0x8B4C;
+    const GLenum MAX_TEXTURE_IMAGE_UNITS          = 0x8872;
+    const GLenum MAX_FRAGMENT_UNIFORM_VECTORS     = 0x8DFD;
+    const GLenum SHADER_TYPE                      = 0x8B4F;
+    const GLenum DELETE_STATUS                    = 0x8B80;
+    const GLenum LINK_STATUS                      = 0x8B82;
+    const GLenum VALIDATE_STATUS                  = 0x8B83;
+    const GLenum ATTACHED_SHADERS                 = 0x8B85;
+    const GLenum ACTIVE_UNIFORMS                  = 0x8B86;
+    const GLenum ACTIVE_ATTRIBUTES                = 0x8B89;
+    const GLenum SHADING_LANGUAGE_VERSION         = 0x8B8C;
+    const GLenum CURRENT_PROGRAM                  = 0x8B8D;
+
+    /* StencilFunction */
+    const GLenum NEVER                          = 0x0200;
+    const GLenum LESS                           = 0x0201;
+    const GLenum EQUAL                          = 0x0202;
+    const GLenum LEQUAL                         = 0x0203;
+    const GLenum GREATER                        = 0x0204;
+    const GLenum NOTEQUAL                       = 0x0205;
+    const GLenum GEQUAL                         = 0x0206;
+    const GLenum ALWAYS                         = 0x0207;
+
+    /* StencilOp */
+    /*      ZERO */
+    const GLenum KEEP                           = 0x1E00;
+    const GLenum REPLACE                        = 0x1E01;
+    const GLenum INCR                           = 0x1E02;
+    const GLenum DECR                           = 0x1E03;
+    const GLenum INVERT                         = 0x150A;
+    const GLenum INCR_WRAP                      = 0x8507;
+    const GLenum DECR_WRAP                      = 0x8508;
+
+    /* StringName */
+    const GLenum VENDOR                         = 0x1F00;
+    const GLenum RENDERER                       = 0x1F01;
+    const GLenum VERSION                        = 0x1F02;
+
+    /* TextureMagFilter */
+    const GLenum NEAREST                        = 0x2600;
+    const GLenum LINEAR                         = 0x2601;
+
+    /* TextureMinFilter */
+    /*      NEAREST */
+    /*      LINEAR */
+    const GLenum NEAREST_MIPMAP_NEAREST         = 0x2700;
+    const GLenum LINEAR_MIPMAP_NEAREST          = 0x2701;
+    const GLenum NEAREST_MIPMAP_LINEAR          = 0x2702;
+    const GLenum LINEAR_MIPMAP_LINEAR           = 0x2703;
+
+    /* TextureParameterName */
+    const GLenum TEXTURE_MAG_FILTER             = 0x2800;
+    const GLenum TEXTURE_MIN_FILTER             = 0x2801;
+    const GLenum TEXTURE_WRAP_S                 = 0x2802;
+    const GLenum TEXTURE_WRAP_T                 = 0x2803;
+
+    /* TextureTarget */
+    /*      TEXTURE_2D */
+    const GLenum TEXTURE                        = 0x1702;
+
+    const GLenum TEXTURE_CUBE_MAP               = 0x8513;
+    const GLenum TEXTURE_BINDING_CUBE_MAP       = 0x8514;
+    const GLenum TEXTURE_CUBE_MAP_POSITIVE_X    = 0x8515;
+    const GLenum TEXTURE_CUBE_MAP_NEGATIVE_X    = 0x8516;
+    const GLenum TEXTURE_CUBE_MAP_POSITIVE_Y    = 0x8517;
+    const GLenum TEXTURE_CUBE_MAP_NEGATIVE_Y    = 0x8518;
+    const GLenum TEXTURE_CUBE_MAP_POSITIVE_Z    = 0x8519;
+    const GLenum TEXTURE_CUBE_MAP_NEGATIVE_Z    = 0x851A;
+    const GLenum MAX_CUBE_MAP_TEXTURE_SIZE      = 0x851C;
+
+    /* TextureUnit */
+    const GLenum TEXTURE0                       = 0x84C0;
+    const GLenum TEXTURE1                       = 0x84C1;
+    const GLenum TEXTURE2                       = 0x84C2;
+    const GLenum TEXTURE3                       = 0x84C3;
+    const GLenum TEXTURE4                       = 0x84C4;
+    const GLenum TEXTURE5                       = 0x84C5;
+    const GLenum TEXTURE6                       = 0x84C6;
+    const GLenum TEXTURE7                       = 0x84C7;
+    const GLenum TEXTURE8                       = 0x84C8;
+    const GLenum TEXTURE9                       = 0x84C9;
+    const GLenum TEXTURE10                      = 0x84CA;
+    const GLenum TEXTURE11                      = 0x84CB;
+    const GLenum TEXTURE12                      = 0x84CC;
+    const GLenum TEXTURE13                      = 0x84CD;
+    const GLenum TEXTURE14                      = 0x84CE;
+    const GLenum TEXTURE15                      = 0x84CF;
+    const GLenum TEXTURE16                      = 0x84D0;
+    const GLenum TEXTURE17                      = 0x84D1;
+    const GLenum TEXTURE18                      = 0x84D2;
+    const GLenum TEXTURE19                      = 0x84D3;
+    const GLenum TEXTURE20                      = 0x84D4;
+    const GLenum TEXTURE21                      = 0x84D5;
+    const GLenum TEXTURE22                      = 0x84D6;
+    const GLenum TEXTURE23                      = 0x84D7;
+    const GLenum TEXTURE24                      = 0x84D8;
+    const GLenum TEXTURE25                      = 0x84D9;
+    const GLenum TEXTURE26                      = 0x84DA;
+    const GLenum TEXTURE27                      = 0x84DB;
+    const GLenum TEXTURE28                      = 0x84DC;
+    const GLenum TEXTURE29                      = 0x84DD;
+    const GLenum TEXTURE30                      = 0x84DE;
+    const GLenum TEXTURE31                      = 0x84DF;
+    const GLenum ACTIVE_TEXTURE                 = 0x84E0;
+
+    /* TextureWrapMode */
+    const GLenum REPEAT                         = 0x2901;
+    const GLenum CLAMP_TO_EDGE                  = 0x812F;
+    const GLenum MIRRORED_REPEAT                = 0x8370;
+
+    /* Uniform Types */
+    const GLenum FLOAT_VEC2                     = 0x8B50;
+    const GLenum FLOAT_VEC3                     = 0x8B51;
+    const GLenum FLOAT_VEC4                     = 0x8B52;
+    const GLenum INT_VEC2                       = 0x8B53;
+    const GLenum INT_VEC3                       = 0x8B54;
+    const GLenum INT_VEC4                       = 0x8B55;
+    const GLenum BOOL                           = 0x8B56;
+    const GLenum BOOL_VEC2                      = 0x8B57;
+    const GLenum BOOL_VEC3                      = 0x8B58;
+    const GLenum BOOL_VEC4                      = 0x8B59;
+    const GLenum FLOAT_MAT2                     = 0x8B5A;
+    const GLenum FLOAT_MAT3                     = 0x8B5B;
+    const GLenum FLOAT_MAT4                     = 0x8B5C;
+    const GLenum SAMPLER_2D                     = 0x8B5E;
+    const GLenum SAMPLER_CUBE                   = 0x8B60;
+
+    /* Vertex Arrays */
+    const GLenum VERTEX_ATTRIB_ARRAY_ENABLED        = 0x8622;
+    const GLenum VERTEX_ATTRIB_ARRAY_SIZE           = 0x8623;
+    const GLenum VERTEX_ATTRIB_ARRAY_STRIDE         = 0x8624;
+    const GLenum VERTEX_ATTRIB_ARRAY_TYPE           = 0x8625;
+    const GLenum VERTEX_ATTRIB_ARRAY_NORMALIZED     = 0x886A;
+    const GLenum VERTEX_ATTRIB_ARRAY_POINTER        = 0x8645;
+    const GLenum VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F;
+
+    /* Shader Source */
+    const GLenum COMPILE_STATUS                 = 0x8B81;
+
+    /* Shader Precision-Specified Types */
+    const GLenum LOW_FLOAT                      = 0x8DF0;
+    const GLenum MEDIUM_FLOAT                   = 0x8DF1;
+    const GLenum HIGH_FLOAT                     = 0x8DF2;
+    const GLenum LOW_INT                        = 0x8DF3;
+    const GLenum MEDIUM_INT                     = 0x8DF4;
+    const GLenum HIGH_INT                       = 0x8DF5;
+
+    /* Framebuffer Object. */
+    const GLenum FRAMEBUFFER                    = 0x8D40;
+    const GLenum RENDERBUFFER                   = 0x8D41;
+
+    const GLenum RGBA4                          = 0x8056;
+    const GLenum RGB5_A1                        = 0x8057;
+    const GLenum RGB565                         = 0x8D62;
+    const GLenum DEPTH_COMPONENT16              = 0x81A5;
+    const GLenum STENCIL_INDEX                  = 0x1901;
+    const GLenum STENCIL_INDEX8                 = 0x8D48;
+    const GLenum DEPTH_STENCIL                  = 0x84F9;
+
+    const GLenum RENDERBUFFER_WIDTH             = 0x8D42;
+    const GLenum RENDERBUFFER_HEIGHT            = 0x8D43;
+    const GLenum RENDERBUFFER_INTERNAL_FORMAT   = 0x8D44;
+    const GLenum RENDERBUFFER_RED_SIZE          = 0x8D50;
+    const GLenum RENDERBUFFER_GREEN_SIZE        = 0x8D51;
+    const GLenum RENDERBUFFER_BLUE_SIZE         = 0x8D52;
+    const GLenum RENDERBUFFER_ALPHA_SIZE        = 0x8D53;
+    const GLenum RENDERBUFFER_DEPTH_SIZE        = 0x8D54;
+    const GLenum RENDERBUFFER_STENCIL_SIZE      = 0x8D55;
+
+    const GLenum FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE           = 0x8CD0;
+    const GLenum FRAMEBUFFER_ATTACHMENT_OBJECT_NAME           = 0x8CD1;
+    const GLenum FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL         = 0x8CD2;
+    const GLenum FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3;
+
+    const GLenum COLOR_ATTACHMENT0              = 0x8CE0;
+    const GLenum DEPTH_ATTACHMENT               = 0x8D00;
+    const GLenum STENCIL_ATTACHMENT             = 0x8D20;
+    const GLenum DEPTH_STENCIL_ATTACHMENT       = 0x821A;
+
+    const GLenum NONE                           = 0;
+
+    const GLenum FRAMEBUFFER_COMPLETE                      = 0x8CD5;
+    const GLenum FRAMEBUFFER_INCOMPLETE_ATTACHMENT         = 0x8CD6;
+    const GLenum FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7;
+    const GLenum FRAMEBUFFER_INCOMPLETE_DIMENSIONS         = 0x8CD9;
+    const GLenum FRAMEBUFFER_UNSUPPORTED                   = 0x8CDD;
+
+    const GLenum FRAMEBUFFER_BINDING            = 0x8CA6;
+    const GLenum RENDERBUFFER_BINDING           = 0x8CA7;
+    const GLenum MAX_RENDERBUFFER_SIZE          = 0x84E8;
+
+    const GLenum INVALID_FRAMEBUFFER_OPERATION  = 0x0506;
+
+    /* WebGL-specific enums */
+    const GLenum UNPACK_FLIP_Y_WEBGL                = 0x9240;
+    const GLenum UNPACK_PREMULTIPLY_ALPHA_WEBGL     = 0x9241;
+    const GLenum CONTEXT_LOST_WEBGL                 = 0x9242;
+    const GLenum UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
+    const GLenum BROWSER_DEFAULT_WEBGL              = 0x9244;
+
+    readonly attribute GLsizei drawingBufferWidth;
+    readonly attribute GLsizei drawingBufferHeight;
+
+    [StrictTypeChecking, RaisesException] void         activeTexture(GLenum texture);
+    [StrictTypeChecking, RaisesException] void         attachShader(WebGLProgram program, WebGLShader shader);
+    [StrictTypeChecking, RaisesException] void         bindAttribLocation(WebGLProgram program, GLuint index, DOMString name);
+    [StrictTypeChecking, RaisesException] void         bindBuffer(GLenum target, WebGLBuffer buffer);
+    [StrictTypeChecking, RaisesException] void         bindFramebuffer(GLenum target, WebGLFramebuffer framebuffer);
+    [StrictTypeChecking, RaisesException] void         bindRenderbuffer(GLenum target, WebGLRenderbuffer renderbuffer);
+    [StrictTypeChecking, RaisesException] void         bindTexture(GLenum target, WebGLTexture texture);
+    [StrictTypeChecking] void         blendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    [StrictTypeChecking] void         blendEquation(GLenum mode);
+    [StrictTypeChecking] void         blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
+    [StrictTypeChecking] void         blendFunc(GLenum sfactor, GLenum dfactor);
+    [StrictTypeChecking] void         blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+    [StrictTypeChecking, RaisesException] void         bufferData(GLenum target, ArrayBuffer? data, GLenum usage);
+    [StrictTypeChecking, RaisesException] void         bufferData(GLenum target, ArrayBufferView? data, GLenum usage);
+    [StrictTypeChecking, RaisesException] void         bufferData(GLenum target, GLsizeiptr size, GLenum usage);
+    [StrictTypeChecking, RaisesException] void         bufferSubData(GLenum target, GLintptr offset, ArrayBuffer? data);
+    [StrictTypeChecking, RaisesException] void         bufferSubData(GLenum target, GLintptr offset, ArrayBufferView? data);
+
+    [StrictTypeChecking] GLenum       checkFramebufferStatus(GLenum target);
+    [StrictTypeChecking] void         clear(GLbitfield mask);
+    [StrictTypeChecking] void         clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    [StrictTypeChecking] void         clearDepth(GLclampf depth);
+    [StrictTypeChecking] void         clearStencil(GLint s);
+    [StrictTypeChecking] void         colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+    [StrictTypeChecking, RaisesException] void         compileShader(WebGLShader shader);
+
+    [StrictTypeChecking] void         compressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
+                                                           GLsizei width, GLsizei height, GLint border, ArrayBufferView data);
+    [StrictTypeChecking] void         compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+                                                              GLsizei width, GLsizei height, GLenum format, ArrayBufferView data);
+    
+    [StrictTypeChecking] void         copyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+    [StrictTypeChecking] void         copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+
+    [StrictTypeChecking] WebGLBuffer createBuffer();
+    [StrictTypeChecking] WebGLFramebuffer createFramebuffer();
+    [StrictTypeChecking] WebGLProgram createProgram();
+    [StrictTypeChecking] WebGLRenderbuffer createRenderbuffer();
+    [StrictTypeChecking, RaisesException] WebGLShader createShader(GLenum type);
+    [StrictTypeChecking] WebGLTexture createTexture();
+
+    [StrictTypeChecking] void         cullFace(GLenum mode);
+
+    [StrictTypeChecking] void         deleteBuffer(WebGLBuffer buffer);
+    [StrictTypeChecking] void         deleteFramebuffer(WebGLFramebuffer framebuffer);
+    [StrictTypeChecking] void         deleteProgram(WebGLProgram program);
+    [StrictTypeChecking] void         deleteRenderbuffer(WebGLRenderbuffer renderbuffer);
+    [StrictTypeChecking] void         deleteShader(WebGLShader shader);
+    [StrictTypeChecking] void         deleteTexture(WebGLTexture texture);
+
+    [StrictTypeChecking] void         depthFunc(GLenum func);
+    [StrictTypeChecking] void         depthMask(GLboolean flag);
+    [StrictTypeChecking] void         depthRange(GLclampf zNear, GLclampf zFar);
+    [StrictTypeChecking, RaisesException] void         detachShader(WebGLProgram program, WebGLShader shader);
+    [StrictTypeChecking] void         disable(GLenum cap);
+    [StrictTypeChecking, RaisesException] void         disableVertexAttribArray(GLuint index);
+    [StrictTypeChecking, RaisesException] void         drawArrays(GLenum mode, GLint first, GLsizei count);
+    [StrictTypeChecking, RaisesException] void         drawElements(GLenum mode, GLsizei count, GLenum type, GLintptr offset);
+
+    [StrictTypeChecking] void         enable(GLenum cap);
+    [StrictTypeChecking, RaisesException] void         enableVertexAttribArray(GLuint index);
+    [StrictTypeChecking] void         finish();
+    [StrictTypeChecking] void         flush();
+    [StrictTypeChecking, RaisesException] void         framebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, WebGLRenderbuffer renderbuffer);
+    [StrictTypeChecking, RaisesException] void         framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, WebGLTexture texture, GLint level);
+    [StrictTypeChecking] void         frontFace(GLenum mode);
+    [StrictTypeChecking] void         generateMipmap(GLenum target);
+    
+    [StrictTypeChecking, RaisesException] WebGLActiveInfo getActiveAttrib(WebGLProgram program, GLuint index);
+    [StrictTypeChecking, RaisesException] WebGLActiveInfo getActiveUniform(WebGLProgram program, GLuint index);
+
+    [StrictTypeChecking, Custom, RaisesException] void getAttachedShaders(WebGLProgram program);
+
+    [StrictTypeChecking] GLint        getAttribLocation(WebGLProgram program, DOMString name);
+
+    [StrictTypeChecking, Custom] any getBufferParameter(GLenum target, GLenum pname);
+
+    [StrictTypeChecking] WebGLContextAttributes getContextAttributes();
+
+    [StrictTypeChecking] GLenum getError();
+
+    // object getExtension(DOMString name);
+    [StrictTypeChecking, Custom] any getExtension(DOMString name);
+
+    [StrictTypeChecking, Custom, RaisesException] any getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname);
+    [StrictTypeChecking, Custom, RaisesException] any getParameter(GLenum pname);
+    [StrictTypeChecking, Custom, RaisesException] any getProgramParameter(WebGLProgram program, GLenum pname);
+    [StrictTypeChecking, TreatReturnedNullStringAs=Null, RaisesException] DOMString getProgramInfoLog(WebGLProgram program);
+    [StrictTypeChecking, Custom, RaisesException] any getRenderbufferParameter(GLenum target, GLenum pname);
+    [StrictTypeChecking, Custom, RaisesException] any getShaderParameter(WebGLShader shader, GLenum pname);
+
+    [StrictTypeChecking, TreatReturnedNullStringAs=Null, RaisesException] DOMString    getShaderInfoLog(WebGLShader shader);
+
+    [StrictTypeChecking, RaisesException] WebGLShaderPrecisionFormat getShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype);
+
+    [StrictTypeChecking, TreatReturnedNullStringAs=Null, RaisesException] DOMString    getShaderSource(WebGLShader shader);
+
+    [StrictTypeChecking, Custom] sequence<DOMString> getSupportedExtensions();
+
+    [StrictTypeChecking, Custom, RaisesException] any getTexParameter(GLenum target, GLenum pname);
+
+    [StrictTypeChecking, Custom, RaisesException] any getUniform(WebGLProgram program, WebGLUniformLocation location);
+
+    [StrictTypeChecking, RaisesException] WebGLUniformLocation getUniformLocation(WebGLProgram program, DOMString name);
+
+    [StrictTypeChecking, Custom, RaisesException] any getVertexAttrib(GLuint index, GLenum pname);
+
+    [StrictTypeChecking] GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname);
+
+    [StrictTypeChecking] void         hint(GLenum target, GLenum mode);
+    [StrictTypeChecking] GLboolean    isBuffer(WebGLBuffer buffer);
+    [StrictTypeChecking] GLboolean    isContextLost();
+    [StrictTypeChecking] GLboolean    isEnabled(GLenum cap);
+    [StrictTypeChecking] GLboolean    isFramebuffer(WebGLFramebuffer framebuffer);
+    [StrictTypeChecking] GLboolean    isProgram(WebGLProgram program);
+    [StrictTypeChecking] GLboolean    isRenderbuffer(WebGLRenderbuffer renderbuffer);
+    [StrictTypeChecking] GLboolean    isShader(WebGLShader shader);
+    [StrictTypeChecking] GLboolean    isTexture(WebGLTexture texture);
+    [StrictTypeChecking] void         lineWidth(GLfloat width);
+    [StrictTypeChecking, RaisesException] void         linkProgram(WebGLProgram program);
+    [StrictTypeChecking] void         pixelStorei(GLenum pname, GLint param);
+    [StrictTypeChecking] void         polygonOffset(GLfloat factor, GLfloat units);
+
+    [StrictTypeChecking, RaisesException] void         readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, ArrayBufferView pixels);
+    
+    [StrictTypeChecking] void         renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+    [StrictTypeChecking] void         sampleCoverage(GLclampf value, GLboolean invert);
+    [StrictTypeChecking] void         scissor(GLint x, GLint y, GLsizei width, GLsizei height);
+    [StrictTypeChecking, RaisesException] void         shaderSource(WebGLShader shader, DOMString string);
+    [StrictTypeChecking] void         stencilFunc(GLenum func, GLint ref, GLuint mask);
+    [StrictTypeChecking] void         stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
+    [StrictTypeChecking] void         stencilMask(GLuint mask);
+    [StrictTypeChecking] void         stencilMaskSeparate(GLenum face, GLuint mask);
+    [StrictTypeChecking] void         stencilOp(GLenum fail, GLenum zfail, GLenum zpass);
+    [StrictTypeChecking] void         stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+
+    [StrictTypeChecking] void         texParameterf(GLenum target, GLenum pname, GLfloat param);
+    [StrictTypeChecking] void         texParameteri(GLenum target, GLenum pname, GLint param);
+
+    // Supported forms:
+    [StrictTypeChecking, RaisesException] void         texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, 
+                                                 GLint border, GLenum format, GLenum type, ArrayBufferView? pixels);
+    [StrictTypeChecking, RaisesException] void         texImage2D(GLenum target, GLint level, GLenum internalformat,
+                                                 GLenum format, GLenum type, ImageData? pixels);
+    [StrictTypeChecking, RaisesException] void         texImage2D(GLenum target, GLint level, GLenum internalformat,
+                                                 GLenum format, GLenum type, HTMLImageElement? image);
+    [StrictTypeChecking, RaisesException] void         texImage2D(GLenum target, GLint level, GLenum internalformat,
+                                                 GLenum format, GLenum type, HTMLCanvasElement? canvas);
+    [StrictTypeChecking, RaisesException] void         texImage2D(GLenum target, GLint level, GLenum internalformat,
+                                                 GLenum format, GLenum type, HTMLVideoElement? video);
+
+    [StrictTypeChecking, RaisesException] void         texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, 
+                                                    GLsizei width, GLsizei height, 
+                                                    GLenum format, GLenum type, ArrayBufferView? pixels);
+    [StrictTypeChecking, RaisesException] void         texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+                                                    GLenum format, GLenum type, ImageData? pixels);
+    [StrictTypeChecking, RaisesException] void         texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+                                                    GLenum format, GLenum type, HTMLImageElement? image);
+    [StrictTypeChecking, RaisesException] void         texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+                                                    GLenum format, GLenum type, HTMLCanvasElement? canvas);
+    [StrictTypeChecking, RaisesException] void         texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+                                                    GLenum format, GLenum type, HTMLVideoElement? video);
+
+    [StrictTypeChecking, RaisesException] void uniform1f(WebGLUniformLocation location, GLfloat x);
+    [StrictTypeChecking, Custom, RaisesException] void uniform1fv(WebGLUniformLocation location, Float32Array v);
+    [StrictTypeChecking, RaisesException] void uniform1i(WebGLUniformLocation location, GLint x);
+    [StrictTypeChecking, Custom, RaisesException] void uniform1iv(WebGLUniformLocation location, Int32Array v);
+    [StrictTypeChecking, RaisesException] void uniform2f(WebGLUniformLocation location, GLfloat x, GLfloat y);
+    [StrictTypeChecking, Custom, RaisesException] void uniform2fv(WebGLUniformLocation location, Float32Array v);
+    [StrictTypeChecking, RaisesException] void uniform2i(WebGLUniformLocation location, GLint x, GLint y);
+    [StrictTypeChecking, Custom, RaisesException] void uniform2iv(WebGLUniformLocation location, Int32Array v);
+    [StrictTypeChecking, RaisesException] void uniform3f(WebGLUniformLocation location, GLfloat x, GLfloat y, GLfloat z);
+    [StrictTypeChecking, Custom, RaisesException] void uniform3fv(WebGLUniformLocation location, Float32Array v);
+    [StrictTypeChecking, RaisesException] void uniform3i(WebGLUniformLocation location, GLint x, GLint y, GLint z);
+    [StrictTypeChecking, Custom, RaisesException] void uniform3iv(WebGLUniformLocation location, Int32Array v);
+    [StrictTypeChecking, RaisesException] void uniform4f(WebGLUniformLocation location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+    [StrictTypeChecking, Custom, RaisesException] void uniform4fv(WebGLUniformLocation location, Float32Array v);
+    [StrictTypeChecking, RaisesException] void uniform4i(WebGLUniformLocation location, GLint x, GLint y, GLint z, GLint w);
+    [StrictTypeChecking, Custom, RaisesException] void uniform4iv(WebGLUniformLocation location, Int32Array v);
+
+    [StrictTypeChecking, Custom, RaisesException] void uniformMatrix2fv(WebGLUniformLocation location, GLboolean transpose, Float32Array array);
+    [StrictTypeChecking, Custom, RaisesException] void uniformMatrix3fv(WebGLUniformLocation location, GLboolean transpose, Float32Array array);
+    [StrictTypeChecking, Custom, RaisesException] void uniformMatrix4fv(WebGLUniformLocation location, GLboolean transpose, Float32Array array);
+
+    [StrictTypeChecking, RaisesException] void         useProgram(WebGLProgram program);
+    [StrictTypeChecking, RaisesException] void         validateProgram(WebGLProgram program);
+
+    [StrictTypeChecking] void         vertexAttrib1f(GLuint indx, GLfloat x);
+    [StrictTypeChecking, Custom] void vertexAttrib1fv(GLuint indx, Float32Array values);
+    [StrictTypeChecking] void         vertexAttrib2f(GLuint indx, GLfloat x, GLfloat y);
+    [StrictTypeChecking, Custom] void vertexAttrib2fv(GLuint indx, Float32Array values);
+    [StrictTypeChecking] void         vertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+    [StrictTypeChecking, Custom] void vertexAttrib3fv(GLuint indx, Float32Array values);
+    [StrictTypeChecking] void         vertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+    [StrictTypeChecking, Custom] void vertexAttrib4fv(GLuint indx, Float32Array values);
+    [StrictTypeChecking, RaisesException] void         vertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, 
+                                                          GLsizei stride, GLintptr offset);
+
+    [StrictTypeChecking] void         viewport(GLint x, GLint y, GLsizei width, GLsizei height);
+};
diff --git a/Source/core/html/canvas/WebGLShader.cpp b/Source/core/html/canvas/WebGLShader.cpp
new file mode 100644
index 0000000..7192028
--- /dev/null
+++ b/Source/core/html/canvas/WebGLShader.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLShader.h"
+
+#include "core/html/canvas/WebGLContextGroup.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLShader> WebGLShader::create(WebGLRenderingContext* ctx, GC3Denum type)
+{
+    return adoptRef(new WebGLShader(ctx, type));
+}
+
+WebGLShader::WebGLShader(WebGLRenderingContext* ctx, GC3Denum type)
+    : WebGLSharedObject(ctx)
+    , m_type(type)
+    , m_source("")
+{
+    setObject(ctx->graphicsContext3D()->createShader(type));
+}
+
+WebGLShader::~WebGLShader()
+{
+    deleteObject(0);
+}
+
+void WebGLShader::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
+{
+    context3d->deleteShader(object);
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLShader.h b/Source/core/html/canvas/WebGLShader.h
new file mode 100644
index 0000000..b0d0b76
--- /dev/null
+++ b/Source/core/html/canvas/WebGLShader.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 WebGLShader_h
+#define WebGLShader_h
+
+#include "core/html/canvas/WebGLSharedObject.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WebGLShader : public WebGLSharedObject {
+public:
+    virtual ~WebGLShader();
+
+    static PassRefPtr<WebGLShader> create(WebGLRenderingContext*, GC3Denum);
+
+    GC3Denum getType() const { return m_type; }
+    const String& getSource() const { return m_source; }
+
+    void setSource(const String& source) { m_source = source; }
+
+private:
+    WebGLShader(WebGLRenderingContext*, GC3Denum);
+
+    virtual void deleteObjectImpl(GraphicsContext3D*, Platform3DObject);
+
+    virtual bool isShader() const { return true; }
+
+    GC3Denum m_type;
+    String m_source;
+};
+
+} // namespace WebCore
+
+#endif // WebGLShader_h
diff --git a/Source/core/html/canvas/WebGLShader.idl b/Source/core/html/canvas/WebGLShader.idl
new file mode 100644
index 0000000..0ebae38
--- /dev/null
+++ b/Source/core/html/canvas/WebGLShader.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBGL
+] interface WebGLShader {
+};
diff --git a/Source/core/html/canvas/WebGLShaderPrecisionFormat.cpp b/Source/core/html/canvas/WebGLShaderPrecisionFormat.cpp
new file mode 100644
index 0000000..4153f88
--- /dev/null
+++ b/Source/core/html/canvas/WebGLShaderPrecisionFormat.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLShaderPrecisionFormat.h"
+
+namespace WebCore {
+
+// static
+PassRefPtr<WebGLShaderPrecisionFormat> WebGLShaderPrecisionFormat::create(GC3Dint rangeMin, GC3Dint rangeMax, GC3Dint precision)
+{
+    return adoptRef(new WebGLShaderPrecisionFormat(rangeMin, rangeMax, precision));
+}
+
+GC3Dint WebGLShaderPrecisionFormat::rangeMin() const
+{
+    return m_rangeMin;
+}
+
+GC3Dint WebGLShaderPrecisionFormat::rangeMax() const
+{
+    return m_rangeMax;
+}
+
+GC3Dint WebGLShaderPrecisionFormat::precision() const
+{
+    return m_precision;
+}
+
+WebGLShaderPrecisionFormat::WebGLShaderPrecisionFormat(GC3Dint rangeMin, GC3Dint rangeMax, GC3Dint precision)
+    : m_rangeMin(rangeMin)
+    , m_rangeMax(rangeMax)
+    , m_precision(precision)
+{
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLShaderPrecisionFormat.h b/Source/core/html/canvas/WebGLShaderPrecisionFormat.h
new file mode 100644
index 0000000..2976108
--- /dev/null
+++ b/Source/core/html/canvas/WebGLShaderPrecisionFormat.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 WebGLShaderPrecisionFormat_h
+#define WebGLShaderPrecisionFormat_h
+
+#include "core/platform/graphics/GraphicsContext3D.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WebGLShaderPrecisionFormat : public RefCounted<WebGLShaderPrecisionFormat> {
+public:
+    static PassRefPtr<WebGLShaderPrecisionFormat> create(GC3Dint rangeMin, GC3Dint rangeMax, GC3Dint precision);
+
+    GC3Dint rangeMin() const;
+    GC3Dint rangeMax() const;
+    GC3Dint precision() const;
+
+private:
+    WebGLShaderPrecisionFormat(GC3Dint rangeMin, GC3Dint rangeMax, GC3Dint precision);
+
+    GC3Dint m_rangeMin;
+    GC3Dint m_rangeMax;
+    GC3Dint m_precision;
+};
+
+}
+
+#endif // WebGLShaderPrecisionFormat_h
diff --git a/Source/core/html/canvas/WebGLShaderPrecisionFormat.idl b/Source/core/html/canvas/WebGLShaderPrecisionFormat.idl
new file mode 100644
index 0000000..b31a58d
--- /dev/null
+++ b/Source/core/html/canvas/WebGLShaderPrecisionFormat.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 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:
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+[
+    Conditional=WEBGL,
+    ImplementationLacksVTable
+] interface WebGLShaderPrecisionFormat {
+    readonly attribute long rangeMin;
+    readonly attribute long rangeMax;
+    readonly attribute long precision;
+};
+
diff --git a/Source/core/html/canvas/WebGLSharedObject.cpp b/Source/core/html/canvas/WebGLSharedObject.cpp
new file mode 100644
index 0000000..f5d6365
--- /dev/null
+++ b/Source/core/html/canvas/WebGLSharedObject.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLSharedObject.h"
+
+#include "core/html/canvas/WebGLContextGroup.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+WebGLSharedObject::WebGLSharedObject(WebGLRenderingContext* context)
+    : WebGLObject(context),
+      m_contextGroup(context->contextGroup())
+{
+}
+
+WebGLSharedObject::~WebGLSharedObject()
+{
+    if (m_contextGroup)
+        m_contextGroup->removeObject(this);
+}
+
+void WebGLSharedObject::detachContextGroup()
+{
+    detach();
+    if (m_contextGroup) {
+        deleteObject(0);
+        m_contextGroup->removeObject(this);
+        m_contextGroup = 0;
+    }
+}
+
+GraphicsContext3D* WebGLSharedObject::getAGraphicsContext3D() const
+{
+    return m_contextGroup ? m_contextGroup->getAGraphicsContext3D() : 0;
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLSharedObject.h b/Source/core/html/canvas/WebGLSharedObject.h
new file mode 100644
index 0000000..6c33471
--- /dev/null
+++ b/Source/core/html/canvas/WebGLSharedObject.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 WebGLSharedObject_h
+#define WebGLSharedObject_h
+
+#include "core/html/canvas/WebGLObject.h"
+
+namespace WebCore {
+
+class GraphicsContext3D;
+class WebGLContextGroup;
+class WebGLRenderingContext;
+
+// WebGLSharedObject the base class for objects that can be shared by multiple
+// WebGLRenderingContexts.
+class WebGLSharedObject : public WebGLObject {
+public:
+    virtual ~WebGLSharedObject();
+
+    WebGLContextGroup* contextGroup() const { return m_contextGroup; }
+
+    virtual bool isBuffer() const { return false; }
+    virtual bool isFramebuffer() const { return false; }
+    virtual bool isProgram() const { return false; }
+    virtual bool isRenderbuffer() const { return false; }
+    virtual bool isShader() const { return false; }
+    virtual bool isTexture() const { return false; }
+
+    virtual bool validate(const WebGLContextGroup* contextGroup, const WebGLRenderingContext*) const
+    {
+        return contextGroup == m_contextGroup;
+    }
+
+    void detachContextGroup();
+
+protected:
+    WebGLSharedObject(WebGLRenderingContext*);
+
+    virtual bool hasGroupOrContext() const
+    {
+        return m_contextGroup;
+    }
+
+    virtual GraphicsContext3D* getAGraphicsContext3D() const;
+
+private:
+    WebGLContextGroup* m_contextGroup;
+};
+
+} // namespace WebCore
+
+#endif // WebGLSharedObject_h
diff --git a/Source/core/html/canvas/WebGLTexture.cpp b/Source/core/html/canvas/WebGLTexture.cpp
new file mode 100644
index 0000000..c8c23bd
--- /dev/null
+++ b/Source/core/html/canvas/WebGLTexture.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLTexture.h"
+
+#include "core/html/canvas/WebGLContextGroup.h"
+#include "core/html/canvas/WebGLFramebuffer.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLTexture> WebGLTexture::create(WebGLRenderingContext* ctx)
+{
+    return adoptRef(new WebGLTexture(ctx));
+}
+
+WebGLTexture::WebGLTexture(WebGLRenderingContext* ctx)
+    : WebGLSharedObject(ctx)
+    , m_target(0)
+    , m_minFilter(GraphicsContext3D::NEAREST_MIPMAP_LINEAR)
+    , m_magFilter(GraphicsContext3D::LINEAR)
+    , m_wrapS(GraphicsContext3D::REPEAT)
+    , m_wrapT(GraphicsContext3D::REPEAT)
+    , m_isNPOT(false)
+    , m_isComplete(false)
+    , m_needToUseBlackTexture(false)
+{
+    setObject(ctx->graphicsContext3D()->createTexture());
+}
+
+WebGLTexture::~WebGLTexture()
+{
+    deleteObject(0);
+}
+
+void WebGLTexture::setTarget(GC3Denum target, GC3Dint maxLevel)
+{
+    if (!object())
+        return;
+    // Target is finalized the first time bindTexture() is called.
+    if (m_target)
+        return;
+    switch (target) {
+    case GraphicsContext3D::TEXTURE_2D:
+        m_target = target;
+        m_info.resize(1);
+        m_info[0].resize(maxLevel);
+        break;
+    case GraphicsContext3D::TEXTURE_CUBE_MAP:
+        m_target = target;
+        m_info.resize(6);
+        for (int ii = 0; ii < 6; ++ii)
+            m_info[ii].resize(maxLevel);
+        break;
+    }
+}
+
+void WebGLTexture::setParameteri(GC3Denum pname, GC3Dint param)
+{
+    if (!object() || !m_target)
+        return;
+    switch (pname) {
+    case GraphicsContext3D::TEXTURE_MIN_FILTER:
+        switch (param) {
+        case GraphicsContext3D::NEAREST:
+        case GraphicsContext3D::LINEAR:
+        case GraphicsContext3D::NEAREST_MIPMAP_NEAREST:
+        case GraphicsContext3D::LINEAR_MIPMAP_NEAREST:
+        case GraphicsContext3D::NEAREST_MIPMAP_LINEAR:
+        case GraphicsContext3D::LINEAR_MIPMAP_LINEAR:
+            m_minFilter = param;
+            break;
+        }
+        break;
+    case GraphicsContext3D::TEXTURE_MAG_FILTER:
+        switch (param) {
+        case GraphicsContext3D::NEAREST:
+        case GraphicsContext3D::LINEAR:
+            m_magFilter = param;
+            break;
+        }
+        break;
+    case GraphicsContext3D::TEXTURE_WRAP_S:
+        switch (param) {
+        case GraphicsContext3D::CLAMP_TO_EDGE:
+        case GraphicsContext3D::MIRRORED_REPEAT:
+        case GraphicsContext3D::REPEAT:
+            m_wrapS = param;
+            break;
+        }
+        break;
+    case GraphicsContext3D::TEXTURE_WRAP_T:
+        switch (param) {
+        case GraphicsContext3D::CLAMP_TO_EDGE:
+        case GraphicsContext3D::MIRRORED_REPEAT:
+        case GraphicsContext3D::REPEAT:
+            m_wrapT = param;
+            break;
+        }
+        break;
+    default:
+        return;
+    }
+    update();
+}
+
+void WebGLTexture::setParameterf(GC3Denum pname, GC3Dfloat param)
+{
+    if (!object() || !m_target)
+        return;
+    GC3Dint iparam = static_cast<GC3Dint>(param);
+    setParameteri(pname, iparam);
+}
+
+void WebGLTexture::setLevelInfo(GC3Denum target, GC3Dint level, GC3Denum internalFormat, GC3Dsizei width, GC3Dsizei height, GC3Denum type)
+{
+    if (!object() || !m_target)
+        return;
+    // We assume level, internalFormat, width, height, and type have all been
+    // validated already.
+    int index = mapTargetToIndex(target);
+    if (index < 0)
+        return;
+    m_info[index][level].setInfo(internalFormat, width, height, type);
+    update();
+}
+
+void WebGLTexture::generateMipmapLevelInfo()
+{
+    if (!object() || !m_target)
+        return;
+    if (!canGenerateMipmaps())
+        return;
+    if (!m_isComplete) {
+        for (size_t ii = 0; ii < m_info.size(); ++ii) {
+            const LevelInfo& info0 = m_info[ii][0];
+            GC3Dsizei width = info0.width;
+            GC3Dsizei height = info0.height;
+            GC3Dint levelCount = computeLevelCount(width, height);
+            for (GC3Dint level = 1; level < levelCount; ++level) {
+                width = std::max(1, width >> 1);
+                height = std::max(1, height >> 1);
+                LevelInfo& info = m_info[ii][level];
+                info.setInfo(info0.internalFormat, width, height, info0.type);
+            }
+        }
+        m_isComplete = true;
+    }
+    m_needToUseBlackTexture = false;
+}
+
+GC3Denum WebGLTexture::getInternalFormat(GC3Denum target, GC3Dint level) const
+{
+    const LevelInfo* info = getLevelInfo(target, level);
+    if (!info)
+        return 0;
+    return info->internalFormat;
+}
+
+GC3Denum WebGLTexture::getType(GC3Denum target, GC3Dint level) const
+{
+    const LevelInfo* info = getLevelInfo(target, level);
+    if (!info)
+        return 0;
+    return info->type;
+}
+
+GC3Dsizei WebGLTexture::getWidth(GC3Denum target, GC3Dint level) const
+{
+    const LevelInfo* info = getLevelInfo(target, level);
+    if (!info)
+        return 0;
+    return info->width;
+}
+
+GC3Dsizei WebGLTexture::getHeight(GC3Denum target, GC3Dint level) const
+{
+    const LevelInfo* info = getLevelInfo(target, level);
+    if (!info)
+        return 0;
+    return info->height;
+}
+
+bool WebGLTexture::isValid(GC3Denum target, GC3Dint level) const
+{
+    const LevelInfo* info = getLevelInfo(target, level);
+    if (!info)
+        return 0;
+    return info->valid;
+}
+
+bool WebGLTexture::isNPOT(GC3Dsizei width, GC3Dsizei height)
+{
+    ASSERT(width >= 0 && height >= 0);
+    if (!width || !height)
+        return false;
+    if ((width & (width - 1)) || (height & (height - 1)))
+        return true;
+    return false;
+}
+
+bool WebGLTexture::isNPOT() const
+{
+    if (!object())
+        return false;
+    return m_isNPOT;
+}
+
+bool WebGLTexture::needToUseBlackTexture() const
+{
+    if (!object())
+        return false;
+    return m_needToUseBlackTexture;
+}
+
+void WebGLTexture::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
+{
+    context3d->deleteTexture(object);
+}
+
+int WebGLTexture::mapTargetToIndex(GC3Denum target) const
+{
+    if (m_target == GraphicsContext3D::TEXTURE_2D) {
+        if (target == GraphicsContext3D::TEXTURE_2D)
+            return 0;
+    } else if (m_target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
+        switch (target) {
+        case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
+            return 0;
+        case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
+            return 1;
+        case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
+            return 2;
+        case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
+            return 3;
+        case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
+            return 4;
+        case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
+            return 5;
+        }
+    }
+    return -1;
+}
+
+bool WebGLTexture::canGenerateMipmaps()
+{
+    if (isNPOT())
+        return false;
+    const LevelInfo& first = m_info[0][0];
+    for (size_t ii = 0; ii < m_info.size(); ++ii) {
+        const LevelInfo& info = m_info[ii][0];
+        if (!info.valid
+            || info.width != first.width || info.height != first.height
+            || info.internalFormat != first.internalFormat || info.type != first.type)
+            return false;
+    }
+    return true;
+}
+
+GC3Dint WebGLTexture::computeLevelCount(GC3Dsizei width, GC3Dsizei height)
+{
+    // return 1 + log2Floor(std::max(width, height));
+    GC3Dsizei n = std::max(width, height);
+    if (n <= 0)
+        return 0;
+    GC3Dint log = 0;
+    GC3Dsizei value = n;
+    for (int ii = 4; ii >= 0; --ii) {
+        int shift = (1 << ii);
+        GC3Dsizei x = (value >> shift);
+        if (x) {
+            value = x;
+            log += shift;
+        }
+    }
+    ASSERT(value == 1);
+    return log + 1;
+}
+
+void WebGLTexture::update()
+{
+    m_isNPOT = false;
+    for (size_t ii = 0; ii < m_info.size(); ++ii) {
+        if (isNPOT(m_info[ii][0].width, m_info[ii][0].height)) {
+            m_isNPOT = true;
+            break;
+        }
+    }
+    m_isComplete = true;
+    const LevelInfo& first = m_info[0][0];
+    GC3Dint levelCount = computeLevelCount(first.width, first.height);
+    if (levelCount < 1)
+        m_isComplete = false;
+    else {
+        for (size_t ii = 0; ii < m_info.size() && m_isComplete; ++ii) {
+            const LevelInfo& info0 = m_info[ii][0];
+            if (!info0.valid
+                || info0.width != first.width || info0.height != first.height
+                || info0.internalFormat != first.internalFormat || info0.type != first.type) {
+                m_isComplete = false;
+                break;
+            }
+            GC3Dsizei width = info0.width;
+            GC3Dsizei height = info0.height;
+            for (GC3Dint level = 1; level < levelCount; ++level) {
+                width = std::max(1, width >> 1);
+                height = std::max(1, height >> 1);
+                const LevelInfo& info = m_info[ii][level];
+                if (!info.valid
+                    || info.width != width || info.height != height
+                    || info.internalFormat != info0.internalFormat || info.type != info0.type) {
+                    m_isComplete = false;
+                    break;
+                }
+
+            }
+        }
+    }
+
+    m_needToUseBlackTexture = false;
+    // NPOT
+    if (m_isNPOT && ((m_minFilter != GraphicsContext3D::NEAREST && m_minFilter != GraphicsContext3D::LINEAR)
+                     || m_wrapS != GraphicsContext3D::CLAMP_TO_EDGE || m_wrapT != GraphicsContext3D::CLAMP_TO_EDGE))
+        m_needToUseBlackTexture = true;
+    // Completeness
+    if (!m_isComplete && m_minFilter != GraphicsContext3D::NEAREST && m_minFilter != GraphicsContext3D::LINEAR)
+        m_needToUseBlackTexture = true;
+}
+
+const WebGLTexture::LevelInfo* WebGLTexture::getLevelInfo(GC3Denum target, GC3Dint level) const
+{
+    if (!object() || !m_target)
+        return 0;
+    int targetIndex = mapTargetToIndex(target);
+    if (targetIndex < 0 || targetIndex >= static_cast<int>(m_info.size()))
+        return 0;
+    if (level < 0 || level >= static_cast<GC3Dint>(m_info[targetIndex].size()))
+        return 0;
+    return &(m_info[targetIndex][level]);
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLTexture.h b/Source/core/html/canvas/WebGLTexture.h
new file mode 100644
index 0000000..d766c3f
--- /dev/null
+++ b/Source/core/html/canvas/WebGLTexture.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 WebGLTexture_h
+#define WebGLTexture_h
+
+#include "core/html/canvas/WebGLSharedObject.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class WebGLTexture : public WebGLSharedObject {
+public:
+    virtual ~WebGLTexture();
+
+    static PassRefPtr<WebGLTexture> create(WebGLRenderingContext*);
+
+    void setTarget(GC3Denum target, GC3Dint maxLevel);
+    void setParameteri(GC3Denum pname, GC3Dint param);
+    void setParameterf(GC3Denum pname, GC3Dfloat param);
+
+    GC3Denum getTarget() const { return m_target; }
+
+    int getMinFilter() const { return m_minFilter; }
+
+    void setLevelInfo(GC3Denum target, GC3Dint level, GC3Denum internalFormat, GC3Dsizei width, GC3Dsizei height, GC3Denum type);
+
+    bool canGenerateMipmaps();
+    // Generate all level information.
+    void generateMipmapLevelInfo();
+
+    GC3Denum getInternalFormat(GC3Denum target, GC3Dint level) const;
+    GC3Denum getType(GC3Denum target, GC3Dint level) const;
+    GC3Dsizei getWidth(GC3Denum target, GC3Dint level) const;
+    GC3Dsizei getHeight(GC3Denum target, GC3Dint level) const;
+    bool isValid(GC3Denum target, GC3Dint level) const;
+
+    // Whether width/height is NotPowerOfTwo.
+    static bool isNPOT(GC3Dsizei, GC3Dsizei);
+
+    bool isNPOT() const;
+    // Determine if texture sampling should always return [0, 0, 0, 1] (OpenGL ES 2.0 Sec 3.8.2).
+    bool needToUseBlackTexture() const;
+
+    bool hasEverBeenBound() const { return object() && m_target; }
+
+    static GC3Dint computeLevelCount(GC3Dsizei width, GC3Dsizei height);
+
+protected:
+    WebGLTexture(WebGLRenderingContext*);
+
+    virtual void deleteObjectImpl(GraphicsContext3D*, Platform3DObject);
+
+private:
+    class LevelInfo {
+    public:
+        LevelInfo()
+            : valid(false)
+            , internalFormat(0)
+            , width(0)
+            , height(0)
+            , type(0)
+        {
+        }
+
+        void setInfo(GC3Denum internalFmt, GC3Dsizei w, GC3Dsizei h, GC3Denum tp)
+        {
+            valid = true;
+            internalFormat = internalFmt;
+            width = w;
+            height = h;
+            type = tp;
+        }
+
+        bool valid;
+        GC3Denum internalFormat;
+        GC3Dsizei width;
+        GC3Dsizei height;
+        GC3Denum type;
+    };
+
+    virtual bool isTexture() const { return true; }
+
+    void update();
+
+    int mapTargetToIndex(GC3Denum) const;
+
+    const LevelInfo* getLevelInfo(GC3Denum target, GC3Dint level) const;
+
+    GC3Denum m_target;
+
+    GC3Denum m_minFilter;
+    GC3Denum m_magFilter;
+    GC3Denum m_wrapS;
+    GC3Denum m_wrapT;
+
+    Vector<Vector<LevelInfo> > m_info;
+
+    bool m_isNPOT;
+    bool m_isComplete;
+    bool m_needToUseBlackTexture;
+};
+
+} // namespace WebCore
+
+#endif // WebGLTexture_h
diff --git a/Source/core/html/canvas/WebGLTexture.idl b/Source/core/html/canvas/WebGLTexture.idl
new file mode 100644
index 0000000..1ea2f2b
--- /dev/null
+++ b/Source/core/html/canvas/WebGLTexture.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBGL
+] interface WebGLTexture {
+};
diff --git a/Source/core/html/canvas/WebGLUniformLocation.cpp b/Source/core/html/canvas/WebGLUniformLocation.cpp
new file mode 100644
index 0000000..d83f5e7
--- /dev/null
+++ b/Source/core/html/canvas/WebGLUniformLocation.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLUniformLocation.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLUniformLocation> WebGLUniformLocation::create(WebGLProgram* program, GC3Dint location)
+{
+    return adoptRef(new WebGLUniformLocation(program, location));
+}
+
+WebGLUniformLocation::WebGLUniformLocation(WebGLProgram* program, GC3Dint location)
+    : m_program(program)
+    , m_location(location)
+{
+    ASSERT(m_program);
+    m_linkCount = m_program->getLinkCount();
+}
+
+WebGLProgram* WebGLUniformLocation::program() const
+{
+    // If the program has been linked again, then this UniformLocation is no
+    // longer valid.
+    if (m_program->getLinkCount() != m_linkCount)
+        return 0;
+    return m_program.get();
+}
+
+GC3Dint WebGLUniformLocation::location() const
+{
+    // If the program has been linked again, then this UniformLocation is no
+    // longer valid.
+    ASSERT(m_program->getLinkCount() == m_linkCount);
+    return m_location;
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLUniformLocation.h b/Source/core/html/canvas/WebGLUniformLocation.h
new file mode 100644
index 0000000..4398159
--- /dev/null
+++ b/Source/core/html/canvas/WebGLUniformLocation.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 WebGLUniformLocation_h
+#define WebGLUniformLocation_h
+
+#include "core/html/canvas/WebGLObject.h"
+#include "core/html/canvas/WebGLProgram.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WebGLUniformLocation : public RefCounted<WebGLUniformLocation> {
+public:
+    virtual ~WebGLUniformLocation() { }
+
+    static PassRefPtr<WebGLUniformLocation> create(WebGLProgram*, GC3Dint location);
+
+    WebGLProgram* program() const;
+
+    GC3Dint location() const;
+
+protected:
+    WebGLUniformLocation(WebGLProgram*, GC3Dint location);
+
+private:
+    RefPtr<WebGLProgram> m_program;
+    GC3Dint m_location;
+    unsigned m_linkCount;
+};
+
+} // namespace WebCore
+
+#endif // WebGLUniformLocation_h
diff --git a/Source/core/html/canvas/WebGLUniformLocation.idl b/Source/core/html/canvas/WebGLUniformLocation.idl
new file mode 100644
index 0000000..c211189
--- /dev/null
+++ b/Source/core/html/canvas/WebGLUniformLocation.idl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBGL
+] interface WebGLUniformLocation {
+};
diff --git a/Source/core/html/canvas/WebGLVertexArrayObjectOES.cpp b/Source/core/html/canvas/WebGLVertexArrayObjectOES.cpp
new file mode 100644
index 0000000..15d1f32
--- /dev/null
+++ b/Source/core/html/canvas/WebGLVertexArrayObjectOES.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/canvas/WebGLVertexArrayObjectOES.h"
+
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include "core/platform/graphics/Extensions3D.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLVertexArrayObjectOES> WebGLVertexArrayObjectOES::create(WebGLRenderingContext* ctx, VaoType type)
+{
+    return adoptRef(new WebGLVertexArrayObjectOES(ctx, type));
+}
+
+WebGLVertexArrayObjectOES::WebGLVertexArrayObjectOES(WebGLRenderingContext* ctx, VaoType type)
+    : WebGLContextObject(ctx)
+    , m_type(type)
+    , m_hasEverBeenBound(false)
+    , m_boundElementArrayBuffer(0)
+{
+    m_vertexAttribState.resize(ctx->getMaxVertexAttribs());
+    
+    Extensions3D* extensions = context()->graphicsContext3D()->getExtensions();
+    switch (m_type) {
+    case VaoTypeDefault:
+        break;
+    default:
+        setObject(extensions->createVertexArrayOES());
+        break;
+    }
+}
+
+WebGLVertexArrayObjectOES::~WebGLVertexArrayObjectOES()
+{
+    deleteObject(0);
+}
+
+void WebGLVertexArrayObjectOES::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
+{
+    Extensions3D* extensions = context3d->getExtensions();
+    switch (m_type) {
+    case VaoTypeDefault:
+        break;
+    default:
+        extensions->deleteVertexArrayOES(object);
+        break;
+    }
+
+    if (m_boundElementArrayBuffer)
+        m_boundElementArrayBuffer->onDetached(context3d);
+
+    for (size_t i = 0; i < m_vertexAttribState.size(); ++i) {
+        VertexAttribState& state = m_vertexAttribState[i];
+        if (state.bufferBinding)
+            state.bufferBinding->onDetached(context3d);
+    }
+}
+
+void WebGLVertexArrayObjectOES::setElementArrayBuffer(PassRefPtr<WebGLBuffer> buffer)
+{
+    if (buffer)
+        buffer->onAttached();
+    if (m_boundElementArrayBuffer)
+        m_boundElementArrayBuffer->onDetached(context()->graphicsContext3D());
+    m_boundElementArrayBuffer = buffer;
+    
+}
+
+void WebGLVertexArrayObjectOES::setVertexAttribState(
+    GC3Duint index, GC3Dsizei bytesPerElement, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset, PassRefPtr<WebGLBuffer> buffer)
+{
+    GC3Dsizei validatedStride = stride ? stride : bytesPerElement;
+
+    VertexAttribState& state = m_vertexAttribState[index];
+
+    if (buffer)
+        buffer->onAttached();
+    if (state.bufferBinding)
+        state.bufferBinding->onDetached(context()->graphicsContext3D());
+
+    state.bufferBinding = buffer;
+    state.bytesPerElement = bytesPerElement;
+    state.size = size;
+    state.type = type;
+    state.normalized = normalized;
+    state.stride = validatedStride;
+    state.originalStride = stride;
+    state.offset = offset;
+}
+
+void WebGLVertexArrayObjectOES::unbindBuffer(PassRefPtr<WebGLBuffer> buffer)
+{
+    if (m_boundElementArrayBuffer == buffer) {
+        m_boundElementArrayBuffer->onDetached(context()->graphicsContext3D());
+        m_boundElementArrayBuffer = 0;
+    }
+
+    for (size_t i = 0; i < m_vertexAttribState.size(); ++i) {
+        VertexAttribState& state = m_vertexAttribState[i];
+        if (state.bufferBinding == buffer) {
+            buffer->onDetached(context()->graphicsContext3D());
+            state.bufferBinding = 0;
+        }
+    }
+}
+
+}
diff --git a/Source/core/html/canvas/WebGLVertexArrayObjectOES.h b/Source/core/html/canvas/WebGLVertexArrayObjectOES.h
new file mode 100644
index 0000000..2284e2b
--- /dev/null
+++ b/Source/core/html/canvas/WebGLVertexArrayObjectOES.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 WebGLVertexArrayObjectOES_h
+#define WebGLVertexArrayObjectOES_h
+
+#include "core/html/canvas/WebGLBuffer.h"
+#include "core/html/canvas/WebGLContextObject.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WebGLVertexArrayObjectOES : public WebGLContextObject {
+public:
+    enum VaoType {
+        VaoTypeDefault,
+        VaoTypeUser,
+    };
+    
+    virtual ~WebGLVertexArrayObjectOES();
+
+    static PassRefPtr<WebGLVertexArrayObjectOES> create(WebGLRenderingContext*, VaoType);
+    
+    // Cached values for vertex attrib range checks
+    struct VertexAttribState {
+        VertexAttribState()
+            : enabled(false)
+            , bytesPerElement(0)
+            , size(4)
+            , type(GraphicsContext3D::FLOAT)
+            , normalized(false)
+            , stride(16)
+            , originalStride(0)
+            , offset(0)
+        {
+        }
+        
+        bool enabled;
+        RefPtr<WebGLBuffer> bufferBinding;
+        GC3Dsizei bytesPerElement;
+        GC3Dint size;
+        GC3Denum type;
+        bool normalized;
+        GC3Dsizei stride;
+        GC3Dsizei originalStride;
+        GC3Dintptr offset;
+    };
+    
+    bool isDefaultObject() const { return m_type == VaoTypeDefault; }
+    
+    bool hasEverBeenBound() const { return object() && m_hasEverBeenBound; }
+    void setHasEverBeenBound() { m_hasEverBeenBound = true; }
+    
+    PassRefPtr<WebGLBuffer> getElementArrayBuffer() const { return m_boundElementArrayBuffer; }
+    void setElementArrayBuffer(PassRefPtr<WebGLBuffer>);
+    
+    VertexAttribState& getVertexAttribState(int index) { return m_vertexAttribState[index]; }
+    void setVertexAttribState(GC3Duint, GC3Dsizei, GC3Dint, GC3Denum, GC3Dboolean, GC3Dsizei, GC3Dintptr, PassRefPtr<WebGLBuffer>);
+    void unbindBuffer(PassRefPtr<WebGLBuffer>);
+
+private:
+    WebGLVertexArrayObjectOES(WebGLRenderingContext*, VaoType);
+
+    virtual void deleteObjectImpl(GraphicsContext3D*, Platform3DObject);
+
+    virtual bool isVertexArray() const { return true; }
+    
+    VaoType m_type;
+    bool m_hasEverBeenBound;
+    RefPtr<WebGLBuffer> m_boundElementArrayBuffer;
+    Vector<VertexAttribState> m_vertexAttribState;
+};
+
+} // namespace WebCore
+
+#endif // WebGLVertexArrayObjectOES_h
diff --git a/Source/core/html/canvas/WebGLVertexArrayObjectOES.idl b/Source/core/html/canvas/WebGLVertexArrayObjectOES.idl
new file mode 100644
index 0000000..1e78ddd
--- /dev/null
+++ b/Source/core/html/canvas/WebGLVertexArrayObjectOES.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBGL
+] interface WebGLVertexArrayObjectOES {
+};
diff --git a/Source/core/html/parser/AtomicHTMLToken.h b/Source/core/html/parser/AtomicHTMLToken.h
new file mode 100644
index 0000000..4f8ec4c
--- /dev/null
+++ b/Source/core/html/parser/AtomicHTMLToken.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2013 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 AtomicHTMLToken_h
+#define AtomicHTMLToken_h
+
+#include "core/dom/Attribute.h"
+#include "core/html/parser/CompactHTMLToken.h"
+#include "core/html/parser/HTMLToken.h"
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class AtomicHTMLToken {
+    WTF_MAKE_NONCOPYABLE(AtomicHTMLToken);
+public:
+
+    bool forceQuirks() const
+    {
+        ASSERT(m_type == HTMLToken::DOCTYPE);
+        return m_doctypeData->m_forceQuirks;
+    }
+
+    HTMLToken::Type type() const { return m_type; }
+
+    const AtomicString& name() const
+    {
+        ASSERT(usesName());
+        return m_name;
+    }
+
+    void setName(const AtomicString& name)
+    {
+        ASSERT(usesName());
+        m_name = name;
+    }
+
+    bool selfClosing() const
+    {
+        ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
+        return m_selfClosing;
+    }
+
+    Attribute* getAttributeItem(const QualifiedName& attributeName)
+    {
+        ASSERT(usesAttributes());
+        return findAttributeInVector(m_attributes, attributeName);
+    }
+
+    Vector<Attribute>& attributes()
+    {
+        ASSERT(usesAttributes());
+        return m_attributes;
+    }
+
+    const Vector<Attribute>& attributes() const
+    {
+        ASSERT(usesAttributes());
+        return m_attributes;
+    }
+
+    const UChar* characters() const
+    {
+        ASSERT(m_type == HTMLToken::Character);
+        return m_externalCharacters;
+    }
+
+    size_t charactersLength() const
+    {
+        ASSERT(m_type == HTMLToken::Character);
+        return m_externalCharactersLength;
+    }
+
+    bool isAll8BitData() const
+    {
+        return m_isAll8BitData;
+    }
+
+    const String& comment() const
+    {
+        ASSERT(m_type == HTMLToken::Comment);
+        return m_data;
+    }
+
+    // FIXME: Distinguish between a missing public identifer and an empty one.
+    Vector<UChar>& publicIdentifier() const
+    {
+        ASSERT(m_type == HTMLToken::DOCTYPE);
+        return m_doctypeData->m_publicIdentifier;
+    }
+
+    // FIXME: Distinguish between a missing system identifer and an empty one.
+    Vector<UChar>& systemIdentifier() const
+    {
+        ASSERT(m_type == HTMLToken::DOCTYPE);
+        return m_doctypeData->m_systemIdentifier;
+    }
+
+    explicit AtomicHTMLToken(HTMLToken& token)
+        : m_type(token.type())
+    {
+        switch (m_type) {
+        case HTMLToken::Uninitialized:
+            ASSERT_NOT_REACHED();
+            break;
+        case HTMLToken::DOCTYPE:
+            m_name = AtomicString(token.name());
+            m_doctypeData = token.releaseDoctypeData();
+            break;
+        case HTMLToken::EndOfFile:
+            break;
+        case HTMLToken::StartTag:
+        case HTMLToken::EndTag: {
+            m_selfClosing = token.selfClosing();
+            m_name = AtomicString(token.name());
+            initializeAttributes(token.attributes());
+            break;
+        }
+        case HTMLToken::Comment:
+            if (token.isAll8BitData())
+                m_data = String::make8BitFrom16BitSource(token.comment());
+            else
+                m_data = String(token.comment());
+            break;
+        case HTMLToken::Character:
+            m_externalCharacters = token.characters().data();
+            m_externalCharactersLength = token.characters().size();
+            m_isAll8BitData = token.isAll8BitData();
+            break;
+        }
+    }
+
+    explicit AtomicHTMLToken(const CompactHTMLToken& token)
+        : m_type(token.type())
+    {
+        switch (m_type) {
+        case HTMLToken::Uninitialized:
+            ASSERT_NOT_REACHED();
+            break;
+        case HTMLToken::DOCTYPE:
+            m_name = token.data().asString();
+            m_doctypeData = adoptPtr(new DoctypeData());
+            m_doctypeData->m_hasPublicIdentifier = true;
+            append(m_doctypeData->m_publicIdentifier, token.publicIdentifier().asString());
+            m_doctypeData->m_hasSystemIdentifier = true;
+            append(m_doctypeData->m_systemIdentifier, token.systemIdentifier());
+            m_doctypeData->m_forceQuirks = token.doctypeForcesQuirks();
+            break;
+        case HTMLToken::EndOfFile:
+            break;
+        case HTMLToken::StartTag:
+            m_attributes.reserveInitialCapacity(token.attributes().size());
+            for (Vector<CompactHTMLToken::Attribute>::const_iterator it = token.attributes().begin(); it != token.attributes().end(); ++it) {
+                QualifiedName name(nullAtom, it->name.asString(), nullAtom);
+                // FIXME: This is N^2 for the number of attributes.
+                if (!findAttributeInVector(m_attributes, name))
+                    m_attributes.append(Attribute(name, it->value));
+            }
+            // Fall through!
+        case HTMLToken::EndTag:
+            m_selfClosing = token.selfClosing();
+            m_name = token.data().asString();
+            break;
+        case HTMLToken::Comment:
+            m_data = token.data().asString();
+            break;
+        case HTMLToken::Character: {
+            const String& string = token.data().asString();
+            m_externalCharacters = string.characters();
+            m_externalCharactersLength = string.length();
+            m_isAll8BitData = token.isAll8BitData();
+            // FIXME: We would like a stronger ASSERT here:
+            // ASSERT(string.is8Bit() == token.isAll8BitData());
+            // but currently that fires, likely due to bugs in HTMLTokenizer
+            // not setting isAll8BitData in all the times it could.
+            ASSERT(!token.isAll8BitData() || string.is8Bit());
+            break;
+        }
+        }
+    }
+
+    explicit AtomicHTMLToken(HTMLToken::Type type)
+        : m_type(type)
+        , m_externalCharacters(0)
+        , m_externalCharactersLength(0)
+        , m_isAll8BitData(false)
+        , m_selfClosing(false)
+    {
+    }
+
+    AtomicHTMLToken(HTMLToken::Type type, const AtomicString& name, const Vector<Attribute>& attributes = Vector<Attribute>())
+        : m_type(type)
+        , m_name(name)
+        , m_externalCharacters(0)
+        , m_externalCharactersLength(0)
+        , m_isAll8BitData(false)
+        , m_selfClosing(false)
+        , m_attributes(attributes)
+    {
+        ASSERT(usesName());
+    }
+
+private:
+    HTMLToken::Type m_type;
+
+    void initializeAttributes(const HTMLToken::AttributeList& attributes);
+    QualifiedName nameForAttribute(const HTMLToken::Attribute&) const;
+
+    bool usesName() const;
+
+    bool usesAttributes() const;
+
+    // "name" for DOCTYPE, StartTag, and EndTag
+    AtomicString m_name;
+
+    // "data" for Comment
+    String m_data;
+
+    // "characters" for Character
+    //
+    // We don't want to copy the the characters out of the Token, so we
+    // keep a pointer to its buffer instead. This buffer is owned by the
+    // Token and causes a lifetime dependence between these objects.
+    //
+    // FIXME: Add a mechanism for "internalizing" the characters when the
+    //        HTMLToken is destructed.
+    const UChar* m_externalCharacters;
+    size_t m_externalCharactersLength;
+    bool m_isAll8BitData;
+
+    // For DOCTYPE
+    OwnPtr<DoctypeData> m_doctypeData;
+
+    // For StartTag and EndTag
+    bool m_selfClosing;
+
+    Vector<Attribute> m_attributes;
+};
+
+inline void AtomicHTMLToken::initializeAttributes(const HTMLToken::AttributeList& attributes)
+{
+    size_t size = attributes.size();
+    if (!size)
+        return;
+
+    m_attributes.clear();
+    m_attributes.reserveInitialCapacity(size);
+    for (size_t i = 0; i < size; ++i) {
+        const HTMLToken::Attribute& attribute = attributes[i];
+        if (attribute.name.isEmpty())
+            continue;
+
+        // FIXME: We should be able to add the following ASSERT once we fix
+        // https://bugs.webkit.org/show_bug.cgi?id=62971
+        //   ASSERT(attribute.nameRange.start);
+        ASSERT(attribute.nameRange.end);
+        ASSERT(attribute.valueRange.start);
+        ASSERT(attribute.valueRange.end);
+
+        AtomicString value(attribute.value);
+        const QualifiedName& name = nameForAttribute(attribute);
+        // FIXME: This is N^2 for the number of attributes.
+        if (!findAttributeInVector(m_attributes, name))
+            m_attributes.append(Attribute(name, value));
+    }
+}
+
+}
+
+#endif
diff --git a/Source/core/html/parser/BackgroundHTMLInputStream.cpp b/Source/core/html/parser/BackgroundHTMLInputStream.cpp
new file mode 100644
index 0000000..6f53608
--- /dev/null
+++ b/Source/core/html/parser/BackgroundHTMLInputStream.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/BackgroundHTMLInputStream.h"
+
+namespace WebCore {
+
+BackgroundHTMLInputStream::BackgroundHTMLInputStream()
+    : m_firstValidCheckpointIndex(0)
+    , m_firstValidSegmentIndex(0)
+{
+}
+
+void BackgroundHTMLInputStream::append(const String& input)
+{
+    m_current.append(SegmentedString(input));
+    m_segments.append(input);
+}
+
+void BackgroundHTMLInputStream::close()
+{
+    m_current.close();
+}
+
+HTMLInputCheckpoint BackgroundHTMLInputStream::createCheckpoint()
+{
+    HTMLInputCheckpoint checkpoint = m_checkpoints.size();
+    m_checkpoints.append(Checkpoint(m_current, m_segments.size()));
+    return checkpoint;
+}
+
+void BackgroundHTMLInputStream::invalidateCheckpointsBefore(HTMLInputCheckpoint newFirstValidCheckpointIndex)
+{
+    ASSERT(newFirstValidCheckpointIndex < m_checkpoints.size());
+    // There is nothing to do for the first valid checkpoint.
+    if (m_firstValidCheckpointIndex == newFirstValidCheckpointIndex)
+        return;
+
+    ASSERT(newFirstValidCheckpointIndex > m_firstValidCheckpointIndex);
+    const Checkpoint& lastInvalidCheckpoint = m_checkpoints[newFirstValidCheckpointIndex - 1];
+
+    ASSERT(m_firstValidSegmentIndex <= lastInvalidCheckpoint.numberOfSegmentsAlreadyAppended);
+    for (size_t i = m_firstValidSegmentIndex; i < lastInvalidCheckpoint.numberOfSegmentsAlreadyAppended; ++i)
+        m_segments[i] = String();
+    m_firstValidSegmentIndex = lastInvalidCheckpoint.numberOfSegmentsAlreadyAppended;
+
+    for (size_t i = m_firstValidCheckpointIndex; i < newFirstValidCheckpointIndex; ++i)
+        m_checkpoints[i].clear();
+    m_firstValidCheckpointIndex = newFirstValidCheckpointIndex;
+}
+
+void BackgroundHTMLInputStream::rewindTo(HTMLInputCheckpoint checkpointIndex, const String& unparsedInput)
+{
+    ASSERT(checkpointIndex < m_checkpoints.size()); // If this ASSERT fires, checkpointIndex is invalid.
+    const Checkpoint& checkpoint = m_checkpoints[checkpointIndex];
+    ASSERT(!checkpoint.isNull());
+
+    bool isClosed = m_current.isClosed();
+
+    m_current = checkpoint.input;
+
+    for (size_t i = checkpoint.numberOfSegmentsAlreadyAppended; i < m_segments.size(); ++i) {
+        ASSERT(!m_segments[i].isNull());
+        m_current.append(SegmentedString(m_segments[i]));
+    }
+
+    if (!unparsedInput.isEmpty())
+        m_current.prepend(SegmentedString(unparsedInput));
+
+    if (isClosed && !m_current.isClosed())
+        m_current.close();
+
+    ASSERT(m_current.isClosed() == isClosed);
+
+    m_segments.clear();
+    m_checkpoints.clear();
+    m_firstValidCheckpointIndex = 0;
+    m_firstValidSegmentIndex = 0;
+}
+
+}
diff --git a/Source/core/html/parser/BackgroundHTMLInputStream.h b/Source/core/html/parser/BackgroundHTMLInputStream.h
new file mode 100644
index 0000000..58b76d5
--- /dev/null
+++ b/Source/core/html/parser/BackgroundHTMLInputStream.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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 BackgroundHTMLInputStream_h
+#define BackgroundHTMLInputStream_h
+
+#include "core/platform/text/SegmentedString.h"
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+typedef size_t HTMLInputCheckpoint;
+
+class BackgroundHTMLInputStream {
+    WTF_MAKE_NONCOPYABLE(BackgroundHTMLInputStream);
+public:
+    BackgroundHTMLInputStream();
+
+    void append(const String&);
+    void close();
+
+    SegmentedString& current() { return m_current; }
+
+    // An HTMLInputCheckpoint is valid until the next call to rewindTo, at which
+    // point all outstanding checkpoints are invalidated.
+    HTMLInputCheckpoint createCheckpoint();
+    void rewindTo(HTMLInputCheckpoint, const String& unparsedInput);
+    void invalidateCheckpointsBefore(HTMLInputCheckpoint);
+
+    size_t outstandingCheckpointCount() const { return m_checkpoints.size() - m_firstValidCheckpointIndex; }
+
+private:
+    struct Checkpoint {
+        Checkpoint(const SegmentedString& i, size_t n) : input(i), numberOfSegmentsAlreadyAppended(n) { }
+
+        SegmentedString input;
+        size_t numberOfSegmentsAlreadyAppended;
+
+#ifndef NDEBUG
+        bool isNull() const { return input.isEmpty() && !numberOfSegmentsAlreadyAppended; }
+#endif
+        void clear() { input.clear(); numberOfSegmentsAlreadyAppended = 0; }
+    };
+
+    SegmentedString m_current;
+    Vector<String> m_segments;
+    Vector<Checkpoint> m_checkpoints;
+
+    // Note: These indicies may === vector.size(), in which case there are no valid checkpoints/segments at this time.
+    size_t m_firstValidCheckpointIndex;
+    size_t m_firstValidSegmentIndex;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/BackgroundHTMLParser.cpp b/Source/core/html/parser/BackgroundHTMLParser.cpp
new file mode 100644
index 0000000..d14adf8
--- /dev/null
+++ b/Source/core/html/parser/BackgroundHTMLParser.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/BackgroundHTMLParser.h"
+
+#include "core/html/parser/HTMLDocumentParser.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/parser/HTMLParserThread.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/html/parser/XSSAuditor.h"
+#include <wtf/MainThread.h>
+#include <wtf/text/TextPosition.h>
+
+namespace WebCore {
+
+// On a network with high latency and high bandwidth, using a device
+// with a fast CPU, we could end up speculatively tokenizing
+// the whole document, well ahead of when the main-thread actually needs it.
+// This is a waste of memory (and potentially time if the speculation fails).
+// So we limit our outstanding speculations arbitrarily to 10.
+// Our maximal memory spent speculating will be approximately:
+// outstandingCheckpointLimit * pendingTokenLimit * sizeof(CompactToken)
+// We use a separate low and high water mark to avoid constantly topping
+// off the main thread's token buffer.
+// At time of writing, this is 10 * 1000 * 28 bytes = appox 280kb of memory.
+// These numbers have not been tuned.
+static const size_t outstandingCheckpointLimit = 10;
+
+// We limit our chucks to 1000 tokens, to make sure the main
+// thread is never waiting on the parser thread for tokens.
+// This was tuned in https://bugs.webkit.org/show_bug.cgi?id=110408.
+static const size_t pendingTokenLimit = 1000;
+
+using namespace HTMLNames;
+
+#ifndef NDEBUG
+
+static void checkThatTokensAreSafeToSendToAnotherThread(const CompactHTMLTokenStream* tokens)
+{
+    for (size_t i = 0; i < tokens->size(); ++i)
+        ASSERT(tokens->at(i).isSafeToSendToAnotherThread());
+}
+
+static void checkThatPreloadsAreSafeToSendToAnotherThread(const PreloadRequestStream& preloads)
+{
+    for (size_t i = 0; i < preloads.size(); ++i)
+        ASSERT(preloads[i]->isSafeToSendToAnotherThread());
+}
+
+#endif
+
+BackgroundHTMLParser::BackgroundHTMLParser(PassRefPtr<WeakReference<BackgroundHTMLParser> > reference, PassOwnPtr<Configuration> config)
+    : m_weakFactory(reference, this)
+    , m_token(adoptPtr(new HTMLToken))
+    , m_tokenizer(HTMLTokenizer::create(config->options))
+    , m_treeBuilderSimulator(config->options)
+    , m_options(config->options)
+    , m_parser(config->parser)
+    , m_pendingTokens(adoptPtr(new CompactHTMLTokenStream))
+    , m_xssAuditor(config->xssAuditor.release())
+    , m_preloadScanner(config->preloadScanner.release())
+{
+}
+
+void BackgroundHTMLParser::append(const String& input)
+{
+    ASSERT(!m_input.current().isClosed());
+    m_input.append(input);
+    pumpTokenizer();
+}
+
+void BackgroundHTMLParser::resumeFrom(PassOwnPtr<Checkpoint> checkpoint)
+{
+    m_parser = checkpoint->parser;
+    m_token = checkpoint->token.release();
+    m_tokenizer = checkpoint->tokenizer.release();
+    m_treeBuilderSimulator.setState(checkpoint->treeBuilderState);
+    m_input.rewindTo(checkpoint->inputCheckpoint, checkpoint->unparsedInput);
+    m_preloadScanner->rewindTo(checkpoint->preloadScannerCheckpoint);
+    pumpTokenizer();
+}
+
+void BackgroundHTMLParser::startedChunkWithCheckpoint(HTMLInputCheckpoint inputCheckpoint)
+{
+    // Note, we should not have to worry about the index being invalid
+    // as messages from the main thread will be processed in FIFO order.
+    m_input.invalidateCheckpointsBefore(inputCheckpoint);
+    pumpTokenizer();
+}
+
+void BackgroundHTMLParser::finish()
+{
+    markEndOfFile();
+    pumpTokenizer();
+}
+
+void BackgroundHTMLParser::stop()
+{
+    delete this;
+}
+
+void BackgroundHTMLParser::forcePlaintextForTextDocument()
+{
+    // This is only used by the TextDocumentParser (a subclass of HTMLDocumentParser)
+    // to force us into the PLAINTEXT state w/o using a <plaintext> tag.
+    // The TextDocumentParser uses a <pre> tag for historical/compatibility reasons.
+    m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
+}
+
+void BackgroundHTMLParser::markEndOfFile()
+{
+    ASSERT(!m_input.current().isClosed());
+    m_input.append(String(&kEndOfFileMarker, 1));
+    m_input.close();
+}
+
+void BackgroundHTMLParser::pumpTokenizer()
+{
+    // No need to start speculating until the main thread has almost caught up.
+    if (m_input.outstandingCheckpointCount() > outstandingCheckpointLimit)
+        return;
+
+    while (true) {
+        m_sourceTracker.start(m_input.current(), m_tokenizer.get(), *m_token);
+        if (!m_tokenizer->nextToken(m_input.current(), *m_token.get())) {
+            // We've reached the end of our current input.
+            sendTokensToMainThread();
+            break;
+        }
+        m_sourceTracker.end(m_input.current(), m_tokenizer.get(), *m_token);
+
+        {
+            TextPosition position = TextPosition(m_input.current().currentLine(), m_input.current().currentColumn());
+
+            if (OwnPtr<XSSInfo> xssInfo = m_xssAuditor->filterToken(FilterTokenRequest(*m_token, m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) {
+                xssInfo->m_textPosition = position;
+                m_pendingXSSInfos.append(xssInfo.release());
+            }
+
+            CompactHTMLToken token(m_token.get(), TextPosition(m_input.current().currentLine(), m_input.current().currentColumn()));
+
+            m_preloadScanner->scan(token, m_pendingPreloads);
+
+            m_pendingTokens->append(token);
+        }
+
+        m_token->clear();
+
+        if (!m_treeBuilderSimulator.simulate(m_pendingTokens->last(), m_tokenizer.get()) || m_pendingTokens->size() >= pendingTokenLimit) {
+            sendTokensToMainThread();
+            // If we're far ahead of the main thread, yield for a bit to avoid consuming too much memory.
+            if (m_input.outstandingCheckpointCount() > outstandingCheckpointLimit)
+                break;
+        }
+    }
+}
+
+void BackgroundHTMLParser::sendTokensToMainThread()
+{
+    if (m_pendingTokens->isEmpty())
+        return;
+
+#ifndef NDEBUG
+    checkThatTokensAreSafeToSendToAnotherThread(m_pendingTokens.get());
+    checkThatPreloadsAreSafeToSendToAnotherThread(m_pendingPreloads);
+#endif
+
+    OwnPtr<HTMLDocumentParser::ParsedChunk> chunk = adoptPtr(new HTMLDocumentParser::ParsedChunk);
+    chunk->tokens = m_pendingTokens.release();
+    chunk->preloads.swap(m_pendingPreloads);
+    chunk->xssInfos.swap(m_pendingXSSInfos);
+    chunk->tokenizerState = m_tokenizer->state();
+    chunk->treeBuilderState = m_treeBuilderSimulator.state();
+    chunk->inputCheckpoint = m_input.createCheckpoint();
+    chunk->preloadScannerCheckpoint = m_preloadScanner->createCheckpoint();
+    callOnMainThread(bind(&HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser, m_parser, chunk.release()));
+
+    m_pendingTokens = adoptPtr(new CompactHTMLTokenStream);
+}
+
+}
diff --git a/Source/core/html/parser/BackgroundHTMLParser.h b/Source/core/html/parser/BackgroundHTMLParser.h
new file mode 100644
index 0000000..14a0df5
--- /dev/null
+++ b/Source/core/html/parser/BackgroundHTMLParser.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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 BackgroundHTMLParser_h
+#define BackgroundHTMLParser_h
+
+#include "core/html/parser/BackgroundHTMLInputStream.h"
+#include "core/html/parser/CompactHTMLToken.h"
+#include "core/html/parser/HTMLParserOptions.h"
+#include "core/html/parser/HTMLPreloadScanner.h"
+#include "core/html/parser/HTMLSourceTracker.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/html/parser/HTMLTreeBuilderSimulator.h"
+#include "core/html/parser/XSSAuditorDelegate.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class HTMLDocumentParser;
+class XSSAuditor;
+
+class BackgroundHTMLParser {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    struct Configuration {
+        HTMLParserOptions options;
+        WeakPtr<HTMLDocumentParser> parser;
+        OwnPtr<XSSAuditor> xssAuditor;
+        OwnPtr<TokenPreloadScanner> preloadScanner;
+    };
+
+    static void create(PassRefPtr<WeakReference<BackgroundHTMLParser> > reference, PassOwnPtr<Configuration> config)
+    {
+        new BackgroundHTMLParser(reference, config);
+        // Caller must free by calling stop().
+    }
+
+    struct Checkpoint {
+        WeakPtr<HTMLDocumentParser> parser;
+        OwnPtr<HTMLToken> token;
+        OwnPtr<HTMLTokenizer> tokenizer;
+        HTMLTreeBuilderSimulator::State treeBuilderState;
+        HTMLInputCheckpoint inputCheckpoint;
+        TokenPreloadScannerCheckpoint preloadScannerCheckpoint;
+        String unparsedInput;
+    };
+
+    void append(const String&);
+    void resumeFrom(PassOwnPtr<Checkpoint>);
+    void startedChunkWithCheckpoint(HTMLInputCheckpoint);
+    void finish();
+    void stop();
+
+    void forcePlaintextForTextDocument();
+
+private:
+    BackgroundHTMLParser(PassRefPtr<WeakReference<BackgroundHTMLParser> >, PassOwnPtr<Configuration>);
+
+    void markEndOfFile();
+    void pumpTokenizer();
+    void sendTokensToMainThread();
+
+    WeakPtrFactory<BackgroundHTMLParser> m_weakFactory;
+    BackgroundHTMLInputStream m_input;
+    HTMLSourceTracker m_sourceTracker;
+    OwnPtr<HTMLToken> m_token;
+    OwnPtr<HTMLTokenizer> m_tokenizer;
+    HTMLTreeBuilderSimulator m_treeBuilderSimulator;
+    HTMLParserOptions m_options;
+    WeakPtr<HTMLDocumentParser> m_parser;
+
+    OwnPtr<CompactHTMLTokenStream> m_pendingTokens;
+    PreloadRequestStream m_pendingPreloads;
+    XSSInfoStream m_pendingXSSInfos;
+
+    OwnPtr<XSSAuditor> m_xssAuditor;
+    OwnPtr<TokenPreloadScanner> m_preloadScanner;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/CSSPreloadScanner.cpp b/Source/core/html/parser/CSSPreloadScanner.cpp
new file mode 100644
index 0000000..295da31
--- /dev/null
+++ b/Source/core/html/parser/CSSPreloadScanner.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/
+ * 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. 
+ */
+
+#include "config.h"
+#include "core/html/parser/CSSPreloadScanner.h"
+
+#include "core/html/parser/HTMLIdentifier.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/loader/cache/CachedResourceRequestInitiators.h"
+
+namespace WebCore {
+
+CSSPreloadScanner::CSSPreloadScanner()
+    : m_state(Initial)
+    , m_requests(0)
+{
+}
+
+CSSPreloadScanner::~CSSPreloadScanner()
+{
+}
+
+void CSSPreloadScanner::reset()
+{
+    m_state = Initial;
+    m_rule.clear();
+    m_ruleValue.clear();
+}
+
+template<typename Char>
+void CSSPreloadScanner::scanCommon(const Char* begin, const Char* end, PreloadRequestStream& requests)
+{
+    m_requests = &requests;
+    for (const Char* it = begin; it != end && m_state != DoneParsingImportRules; ++it)
+        tokenize(*it);
+    m_requests = 0;
+}
+
+void CSSPreloadScanner::scan(const HTMLToken::DataVector& data, PreloadRequestStream& requests)
+{
+    scanCommon(data.data(), data.data() + data.size(), requests);
+}
+
+void CSSPreloadScanner::scan(const HTMLIdentifier& identifier, PreloadRequestStream& requests)
+{
+    const StringImpl* data = identifier.asStringImpl();
+    if (data->is8Bit()) {
+        const LChar* begin = data->characters8();
+        scanCommon(begin, begin + data->length(), requests);
+        return;
+    }
+    const UChar* begin = data->characters16();
+    scanCommon(begin, begin + data->length(), requests);
+}
+
+inline void CSSPreloadScanner::tokenize(UChar c)
+{
+    // We are just interested in @import rules, no need for real tokenization here
+    // Searching for other types of resources is probably low payoff.
+    switch (m_state) {
+    case Initial:
+        if (isHTMLSpace(c))
+            break;
+        if (c == '@')
+            m_state = RuleStart;
+        else if (c == '/')
+            m_state = MaybeComment;
+        else
+            m_state = DoneParsingImportRules;
+        break;
+    case MaybeComment:
+        if (c == '*')
+            m_state = Comment;
+        else
+            m_state = Initial;
+        break;
+    case Comment:
+        if (c == '*')
+            m_state = MaybeCommentEnd;
+        break;
+    case MaybeCommentEnd:
+        if (c == '*')
+            break;
+        if (c == '/')
+            m_state = Initial;
+        else
+            m_state = Comment;
+        break;
+    case RuleStart:
+        if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+            m_rule.clear();
+            m_ruleValue.clear();
+            m_rule.append(c);
+            m_state = Rule;
+        } else
+            m_state = Initial;
+        break;
+    case Rule:
+        if (isHTMLSpace(c))
+            m_state = AfterRule;
+        else if (c == ';')
+            m_state = Initial;
+        else
+            m_rule.append(c);
+        break;
+    case AfterRule:
+        if (isHTMLSpace(c))
+            break;
+        if (c == ';')
+            m_state = Initial;
+        else if (c == '{')
+            m_state = DoneParsingImportRules;
+        else {
+            m_state = RuleValue;
+            m_ruleValue.append(c);
+        }
+        break;
+    case RuleValue:
+        if (isHTMLSpace(c))
+            m_state = AfterRuleValue;
+        else if (c == ';')
+            emitRule();
+        else
+            m_ruleValue.append(c);
+        break;
+    case AfterRuleValue:
+        if (isHTMLSpace(c))
+            break;
+        if (c == ';')
+            emitRule();
+        else if (c == '{')
+            m_state = DoneParsingImportRules;
+        else {
+            // FIXME: media rules
+            m_state = Initial;
+        }
+        break;
+    case DoneParsingImportRules:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+static String parseCSSStringOrURL(const UChar* characters, size_t length)
+{
+    size_t offset = 0;
+    size_t reducedLength = length;
+
+    while (reducedLength && isHTMLSpace(characters[offset])) {
+        ++offset;
+        --reducedLength;
+    }
+    while (reducedLength && isHTMLSpace(characters[offset + reducedLength - 1]))
+        --reducedLength;
+
+    if (reducedLength >= 5
+            && (characters[offset] == 'u' || characters[offset] == 'U')
+            && (characters[offset + 1] == 'r' || characters[offset + 1] == 'R')
+            && (characters[offset + 2] == 'l' || characters[offset + 2] == 'L')
+            && characters[offset + 3] == '('
+            && characters[offset + reducedLength - 1] == ')') {
+        offset += 4;
+        reducedLength -= 5;
+    }
+
+    while (reducedLength && isHTMLSpace(characters[offset])) {
+        ++offset;
+        --reducedLength;
+    }
+    while (reducedLength && isHTMLSpace(characters[offset + reducedLength - 1]))
+        --reducedLength;
+
+    if (reducedLength < 2 || characters[offset] != characters[offset + reducedLength - 1] || !(characters[offset] == '\'' || characters[offset] == '"'))
+        return String();
+    offset++;
+    reducedLength -= 2;
+
+    while (reducedLength && isHTMLSpace(characters[offset])) {
+        ++offset;
+        --reducedLength;
+    }
+    while (reducedLength && isHTMLSpace(characters[offset + reducedLength - 1]))
+        --reducedLength;
+
+    return String(characters + offset, reducedLength);
+}
+
+void CSSPreloadScanner::emitRule()
+{
+    if (equalIgnoringCase("import", m_rule.characters(), m_rule.length())) {
+        String url = parseCSSStringOrURL(m_ruleValue.characters(), m_ruleValue.length());
+        if (!url.isEmpty()) {
+            KURL baseElementURL; // FIXME: This should be passed in from the HTMLPreloadScaner via scan()!
+            OwnPtr<PreloadRequest> request = PreloadRequest::create("css", url, baseElementURL, CachedResource::CSSStyleSheet);
+            // FIXME: Should this be including the charset in the preload request?
+            m_requests->append(request.release());
+        }
+        m_state = Initial;
+    } else if (equalIgnoringCase("charset", m_rule.characters(), m_rule.length()))
+        m_state = Initial;
+    else
+        m_state = DoneParsingImportRules;
+    m_rule.clear();
+    m_ruleValue.clear();
+}
+
+}
diff --git a/Source/core/html/parser/CSSPreloadScanner.h b/Source/core/html/parser/CSSPreloadScanner.h
new file mode 100644
index 0000000..0218afa
--- /dev/null
+++ b/Source/core/html/parser/CSSPreloadScanner.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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 CSSPreloadScanner_h
+#define CSSPreloadScanner_h
+
+#include "core/html/parser/HTMLResourcePreloader.h"
+#include "core/html/parser/HTMLToken.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+class HTMLIdentifier;
+
+class CSSPreloadScanner {
+    WTF_MAKE_NONCOPYABLE(CSSPreloadScanner);
+public:
+    CSSPreloadScanner();
+    ~CSSPreloadScanner();
+
+    void reset();
+
+    void scan(const HTMLToken::DataVector&, PreloadRequestStream&);
+    void scan(const HTMLIdentifier&, PreloadRequestStream&);
+
+private:
+    enum State {
+        Initial,
+        MaybeComment,
+        Comment,
+        MaybeCommentEnd,
+        RuleStart,
+        Rule,
+        AfterRule,
+        RuleValue,
+        AfterRuleValue,
+        DoneParsingImportRules,
+    };
+
+    template<typename Char>
+    void scanCommon(const Char* begin, const Char* end, PreloadRequestStream&);
+
+    inline void tokenize(UChar);
+    void emitRule();
+
+    State m_state;
+    StringBuilder m_rule;
+    StringBuilder m_ruleValue;
+
+    // Only non-zero during scan()
+    PreloadRequestStream* m_requests;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/CompactHTMLToken.cpp b/Source/core/html/parser/CompactHTMLToken.cpp
new file mode 100644
index 0000000..1342c55
--- /dev/null
+++ b/Source/core/html/parser/CompactHTMLToken.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/CompactHTMLToken.h"
+
+#include "core/dom/QualifiedName.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/html/parser/XSSAuditorDelegate.h"
+
+namespace WebCore {
+
+struct SameSizeAsCompactHTMLToken  {
+    unsigned bitfields;
+    HTMLIdentifier data;
+    Vector<Attribute> vector;
+    TextPosition textPosition;
+};
+
+COMPILE_ASSERT(sizeof(CompactHTMLToken) == sizeof(SameSizeAsCompactHTMLToken), CompactHTMLToken_should_stay_small);
+
+CompactHTMLToken::CompactHTMLToken(const HTMLToken* token, const TextPosition& textPosition)
+    : m_type(token->type())
+    , m_isAll8BitData(false)
+    , m_doctypeForcesQuirks(false)
+    , m_textPosition(textPosition)
+{
+    switch (m_type) {
+    case HTMLToken::Uninitialized:
+        ASSERT_NOT_REACHED();
+        break;
+    case HTMLToken::DOCTYPE: {
+        m_data = HTMLIdentifier(token->name(), Likely8Bit);
+        // There is only 1 DOCTYPE token per document, so to avoid increasing the
+        // size of CompactHTMLToken, we just use the m_attributes vector.
+        m_attributes.append(Attribute(HTMLIdentifier(token->publicIdentifier(), Likely8Bit), String(token->systemIdentifier())));
+        m_doctypeForcesQuirks = token->forceQuirks();
+        break;
+    }
+    case HTMLToken::EndOfFile:
+        break;
+    case HTMLToken::StartTag:
+        m_attributes.reserveInitialCapacity(token->attributes().size());
+        for (Vector<HTMLToken::Attribute>::const_iterator it = token->attributes().begin(); it != token->attributes().end(); ++it)
+            m_attributes.append(Attribute(HTMLIdentifier(it->name, Likely8Bit), StringImpl::create8BitIfPossible(it->value)));
+        // Fall through!
+    case HTMLToken::EndTag:
+        m_selfClosing = token->selfClosing();
+        // Fall through!
+    case HTMLToken::Comment:
+    case HTMLToken::Character: {
+        m_isAll8BitData = token->isAll8BitData();
+        m_data = HTMLIdentifier(token->data(), token->isAll8BitData() ? Force8Bit : Force16Bit);
+        break;
+    }
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+const CompactHTMLToken::Attribute* CompactHTMLToken::getAttributeItem(const QualifiedName& name) const
+{
+    for (unsigned i = 0; i < m_attributes.size(); ++i) {
+        if (threadSafeMatch(m_attributes.at(i).name, name))
+            return &m_attributes.at(i);
+    }
+    return 0;
+}
+
+bool CompactHTMLToken::isSafeToSendToAnotherThread() const
+{
+    for (Vector<Attribute>::const_iterator it = m_attributes.begin(); it != m_attributes.end(); ++it) {
+        if (!it->name.isSafeToSendToAnotherThread())
+            return false;
+        if (!it->value.isSafeToSendToAnotherThread())
+            return false;
+    }
+    return m_data.isSafeToSendToAnotherThread();
+}
+
+}
diff --git a/Source/core/html/parser/CompactHTMLToken.h b/Source/core/html/parser/CompactHTMLToken.h
new file mode 100644
index 0000000..04f1fab
--- /dev/null
+++ b/Source/core/html/parser/CompactHTMLToken.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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 CompactHTMLToken_h
+#define CompactHTMLToken_h
+
+#include "core/html/parser/HTMLIdentifier.h"
+#include "core/html/parser/HTMLToken.h"
+#include <wtf/text/TextPosition.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class QualifiedName;
+
+class CompactHTMLToken {
+public:
+    struct Attribute {
+        Attribute(const HTMLIdentifier& name, const String& value)
+            : name(name)
+            , value(value)
+        {
+        }
+
+        HTMLIdentifier name;
+        String value;
+    };
+
+    CompactHTMLToken(const HTMLToken*, const TextPosition&);
+
+    bool isSafeToSendToAnotherThread() const;
+
+    HTMLToken::Type type() const { return static_cast<HTMLToken::Type>(m_type); }
+    const HTMLIdentifier& data() const { return m_data; }
+    bool selfClosing() const { return m_selfClosing; }
+    bool isAll8BitData() const { return m_isAll8BitData; }
+    const Vector<Attribute>& attributes() const { return m_attributes; }
+    const Attribute* getAttributeItem(const QualifiedName&) const;
+    const TextPosition& textPosition() const { return m_textPosition; }
+
+    // There is only 1 DOCTYPE token per document, so to avoid increasing the
+    // size of CompactHTMLToken, we just use the m_attributes vector.
+    const HTMLIdentifier& publicIdentifier() const { return m_attributes[0].name; }
+    const String& systemIdentifier() const { return m_attributes[0].value; }
+    bool doctypeForcesQuirks() const { return m_doctypeForcesQuirks; }
+
+private:
+    unsigned m_type : 4;
+    unsigned m_selfClosing : 1;
+    unsigned m_isAll8BitData : 1;
+    unsigned m_doctypeForcesQuirks: 1;
+
+    HTMLIdentifier m_data; // "name", "characters", or "data" depending on m_type
+    Vector<Attribute> m_attributes;
+    TextPosition m_textPosition;
+};
+
+typedef Vector<CompactHTMLToken> CompactHTMLTokenStream;
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLConstructionSite.cpp b/Source/core/html/parser/HTMLConstructionSite.cpp
new file mode 100644
index 0000000..104e073
--- /dev/null
+++ b/Source/core/html/parser/HTMLConstructionSite.cpp
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 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 GOOGLE 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 GOOGLE 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLTreeBuilder.h"
+
+#include "HTMLElementFactory.h"
+#include "HTMLNames.h"
+#include "core/dom/Comment.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/dom/DocumentType.h"
+#include "core/dom/Element.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLHtmlElement.h"
+#include "core/html/HTMLPlugInElement.h"
+#include "core/html/HTMLScriptElement.h"
+#include "core/html/HTMLTemplateElement.h"
+#include "core/html/parser/AtomicHTMLToken.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/parser/HTMLStackItem.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/page/Frame.h"
+#include "core/page/Settings.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/NotImplemented.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const unsigned maximumHTMLParserDOMTreeDepth = 512;
+
+static inline void setAttributes(Element* element, AtomicHTMLToken* token, ParserContentPolicy parserContentPolicy)
+{
+    if (!scriptingContentIsAllowed(parserContentPolicy))
+        element->stripScriptingAttributes(token->attributes());
+    element->parserSetAttributes(token->attributes());
+}
+
+static bool hasImpliedEndTag(const HTMLStackItem* item)
+{
+    return item->hasTagName(ddTag)
+        || item->hasTagName(dtTag)
+        || item->hasTagName(liTag)
+        || item->hasTagName(optionTag)
+        || item->hasTagName(optgroupTag)
+        || item->hasTagName(pTag)
+        || item->hasTagName(rpTag)
+        || item->hasTagName(rtTag);
+}
+
+static inline bool isAllWhitespace(const String& string)
+{
+    return string.isAllSpecialCharacters<isHTMLSpace>();
+}
+
+static inline void executeTask(HTMLConstructionSiteTask& task)
+{
+    if (task.parent->hasTagName(templateTag))
+        task.parent = toHTMLTemplateElement(task.parent.get())->content();
+
+    if (task.nextChild)
+        task.parent->parserInsertBefore(task.child.get(), task.nextChild.get());
+    else
+        task.parent->parserAppendChild(task.child.get());
+
+    // JavaScript run from beforeload (or DOM Mutation or event handlers)
+    // might have removed the child, in which case we should not attach it.
+
+    if (task.child->parentNode() && task.parent->attached() && !task.child->attached())
+        task.child->attach();
+
+    task.child->beginParsingChildren();
+
+    if (task.selfClosing)
+        task.child->finishParsingChildren();
+}
+
+void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> prpChild, bool selfClosing)
+{
+    ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !prpChild.get()->isElementNode() || !toScriptElementIfPossible(toElement(prpChild.get())));
+    ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !prpChild->isPluginElement());
+
+    HTMLConstructionSiteTask task;
+    task.parent = parent;
+    task.child = prpChild;
+    task.selfClosing = selfClosing;
+
+    if (shouldFosterParent()) {
+        fosterParent(task.child);
+        return;
+    }
+
+    // Add as a sibling of the parent if we have reached the maximum depth allowed.
+    if (m_openElements.stackDepth() > maximumHTMLParserDOMTreeDepth && task.parent->parentNode())
+        task.parent = task.parent->parentNode();
+
+    ASSERT(task.parent);
+    m_attachmentQueue.append(task);
+}
+
+void HTMLConstructionSite::executeQueuedTasks()
+{
+    const size_t size = m_attachmentQueue.size();
+    if (!size)
+        return;
+
+    // Copy the task queue into a local variable in case executeTask
+    // re-enters the parser.
+    AttachmentQueue queue;
+    queue.swap(m_attachmentQueue);
+
+    for (size_t i = 0; i < size; ++i)
+        executeTask(queue[i]);
+
+    // We might be detached now.
+}
+
+HTMLConstructionSite::HTMLConstructionSite(Document* document, ParserContentPolicy parserContentPolicy)
+    : m_document(document)
+    , m_attachmentRoot(document)
+    , m_parserContentPolicy(parserContentPolicy)
+    , m_isParsingFragment(false)
+    , m_redirectAttachToFosterParent(false)
+    , m_inQuirksMode(document->inQuirksMode())
+{
+    ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
+}
+
+HTMLConstructionSite::HTMLConstructionSite(DocumentFragment* fragment, ParserContentPolicy parserContentPolicy)
+    : m_document(fragment->document())
+    , m_attachmentRoot(fragment)
+    , m_parserContentPolicy(parserContentPolicy)
+    , m_isParsingFragment(true)
+    , m_redirectAttachToFosterParent(false)
+    , m_inQuirksMode(fragment->document()->inQuirksMode())
+{
+    ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
+}
+
+HTMLConstructionSite::~HTMLConstructionSite()
+{
+}
+
+void HTMLConstructionSite::detach()
+{
+    m_document = 0;
+    m_attachmentRoot = 0;
+}
+
+void HTMLConstructionSite::setForm(HTMLFormElement* form)
+{
+    // This method should only be needed for HTMLTreeBuilder in the fragment case.
+    ASSERT(!m_form);
+    m_form = form;
+}
+
+PassRefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
+{
+    return m_form.release();
+}
+
+void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded()
+{
+    ASSERT(m_document);
+    if (m_document->frame() && !m_isParsingFragment)
+        m_document->frame()->loader()->dispatchDocumentElementAvailable();
+}
+
+void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken* token)
+{
+    RefPtr<HTMLHtmlElement> element = HTMLHtmlElement::create(m_document);
+    setAttributes(element.get(), token, m_parserContentPolicy);
+    attachLater(m_attachmentRoot, element);
+    m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element, token));
+
+    executeQueuedTasks();
+    element->insertedByParser();
+    dispatchDocumentElementAvailableIfNeeded();
+}
+
+void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken* token, Element* element)
+{
+    if (token->attributes().isEmpty())
+        return;
+
+    for (unsigned i = 0; i < token->attributes().size(); ++i) {
+        const Attribute& tokenAttribute = token->attributes().at(i);
+        if (!element->elementData() || !element->getAttributeItem(tokenAttribute.name()))
+            element->setAttribute(tokenAttribute.name(), tokenAttribute.value());
+    }
+}
+
+void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken* token)
+{
+    // Fragments do not have a root HTML element, so any additional HTML elements
+    // encountered during fragment parsing should be ignored.
+    if (m_isParsingFragment)
+        return;
+
+    mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
+}
+
+void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken* token)
+{
+    mergeAttributesFromTokenIntoElement(token, m_openElements.bodyElement());
+}
+
+void HTMLConstructionSite::setDefaultCompatibilityMode()
+{
+    if (m_isParsingFragment)
+        return;
+    if (m_document->isSrcdocDocument())
+        return;
+    setCompatibilityMode(Document::QuirksMode);
+}
+
+void HTMLConstructionSite::setCompatibilityMode(Document::CompatibilityMode mode)
+{
+    m_inQuirksMode = (mode == Document::QuirksMode);
+    m_document->setCompatibilityMode(mode);
+}
+
+void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId)
+{
+    // There are three possible compatibility modes:
+    // Quirks - quirks mode emulates WinIE and NS4. CSS parsing is also relaxed in this mode, e.g., unit types can
+    // be omitted from numbers.
+    // Limited Quirks - This mode is identical to no-quirks mode except for its treatment of line-height in the inline box model.  
+    // No Quirks - no quirks apply. Web pages will obey the specifications to the letter.
+
+    // Check for Quirks Mode.
+    if (name != "html"
+        || publicId.startsWith("+//Silmaril//dtd html Pro v0r11 19970101//", false)
+        || publicId.startsWith("-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//", false)
+        || publicId.startsWith("-//AS//DTD HTML 3.0 asWedit + extensions//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 1//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 2//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 1//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 2//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 2.0//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 2.1E//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 3.0//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 3.2 Final//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 3.2//", false)
+        || publicId.startsWith("-//IETF//DTD HTML 3//", false)
+        || publicId.startsWith("-//IETF//DTD HTML Level 0//", false)
+        || publicId.startsWith("-//IETF//DTD HTML Level 1//", false)
+        || publicId.startsWith("-//IETF//DTD HTML Level 2//", false)
+        || publicId.startsWith("-//IETF//DTD HTML Level 3//", false)
+        || publicId.startsWith("-//IETF//DTD HTML Strict Level 0//", false)
+        || publicId.startsWith("-//IETF//DTD HTML Strict Level 1//", false)
+        || publicId.startsWith("-//IETF//DTD HTML Strict Level 2//", false)
+        || publicId.startsWith("-//IETF//DTD HTML Strict Level 3//", false)
+        || publicId.startsWith("-//IETF//DTD HTML Strict//", false)
+        || publicId.startsWith("-//IETF//DTD HTML//", false)
+        || publicId.startsWith("-//Metrius//DTD Metrius Presentational//", false)
+        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//", false)
+        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML//", false)
+        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 Tables//", false)
+        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//", false)
+        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML//", false)
+        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 Tables//", false)
+        || publicId.startsWith("-//Netscape Comm. Corp.//DTD HTML//", false)
+        || publicId.startsWith("-//Netscape Comm. Corp.//DTD Strict HTML//", false)
+        || publicId.startsWith("-//O'Reilly and Associates//DTD HTML 2.0//", false)
+        || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended 1.0//", false)
+        || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//", false)
+        || publicId.startsWith("-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::extensions to HTML 4.0//", false)
+        || publicId.startsWith("-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//", false)
+        || publicId.startsWith("-//Spyglass//DTD HTML 2.0 Extended//", false)
+        || publicId.startsWith("-//SQ//DTD HTML 2.0 HoTMetaL + extensions//", false)
+        || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava HTML//", false)
+        || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava Strict HTML//", false)
+        || publicId.startsWith("-//W3C//DTD HTML 3 1995-03-24//", false)
+        || publicId.startsWith("-//W3C//DTD HTML 3.2 Draft//", false)
+        || publicId.startsWith("-//W3C//DTD HTML 3.2 Final//", false)
+        || publicId.startsWith("-//W3C//DTD HTML 3.2//", false)
+        || publicId.startsWith("-//W3C//DTD HTML 3.2S Draft//", false)
+        || publicId.startsWith("-//W3C//DTD HTML 4.0 Frameset//", false)
+        || publicId.startsWith("-//W3C//DTD HTML 4.0 Transitional//", false)
+        || publicId.startsWith("-//W3C//DTD HTML Experimental 19960712//", false)
+        || publicId.startsWith("-//W3C//DTD HTML Experimental 970421//", false)
+        || publicId.startsWith("-//W3C//DTD W3 HTML//", false)
+        || publicId.startsWith("-//W3O//DTD W3 HTML 3.0//", false)
+        || equalIgnoringCase(publicId, "-//W3O//DTD W3 HTML Strict 3.0//EN//")
+        || publicId.startsWith("-//WebTechs//DTD Mozilla HTML 2.0//", false)
+        || publicId.startsWith("-//WebTechs//DTD Mozilla HTML//", false)
+        || equalIgnoringCase(publicId, "-/W3C/DTD HTML 4.0 Transitional/EN")
+        || equalIgnoringCase(publicId, "HTML")
+        || equalIgnoringCase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
+        || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
+        || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
+        setCompatibilityMode(Document::QuirksMode);
+        return;
+    }
+
+    // Check for Limited Quirks Mode.
+    if (publicId.startsWith("-//W3C//DTD XHTML 1.0 Frameset//", false)
+        || publicId.startsWith("-//W3C//DTD XHTML 1.0 Transitional//", false)
+        || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
+        || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
+        setCompatibilityMode(Document::LimitedQuirksMode);
+        return;
+    }
+
+    // Otherwise we are No Quirks Mode.
+    setCompatibilityMode(Document::NoQuirksMode);
+}
+
+void HTMLConstructionSite::finishedParsing()
+{
+    m_document->finishedParsing();
+}
+
+void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::DOCTYPE);
+
+    const String& publicId = String::adopt(token->publicIdentifier());
+    const String& systemId = String::adopt(token->systemIdentifier());
+    RefPtr<DocumentType> doctype = DocumentType::create(m_document, token->name(), publicId, systemId);
+    attachLater(m_attachmentRoot, doctype.release());
+
+    // DOCTYPE nodes are only processed when parsing fragments w/o contextElements, which
+    // never occurs.  However, if we ever chose to support such, this code is subtly wrong,
+    // because context-less fragments can determine their own quirks mode, and thus change
+    // parsing rules (like <p> inside <table>).  For now we ASSERT that we never hit this code
+    // in a fragment, as changing the owning document's compatibility mode would be wrong.
+    ASSERT(!m_isParsingFragment);
+    if (m_isParsingFragment)
+        return;
+
+    if (token->forceQuirks())
+        setCompatibilityMode(Document::QuirksMode);
+    else {
+        setCompatibilityModeFromDoctype(token->name(), publicId, systemId);
+    }
+}
+
+void HTMLConstructionSite::insertComment(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::Comment);
+    attachLater(currentNode(), Comment::create(ownerDocumentForCurrentNode(), token->comment()));
+}
+
+void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::Comment);
+    attachLater(m_attachmentRoot, Comment::create(m_document, token->comment()));
+}
+
+void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::Comment);
+    ContainerNode* parent = m_openElements.rootNode();
+    attachLater(parent, Comment::create(parent->document(), token->comment()));
+}
+
+void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken* token)
+{
+    ASSERT(!shouldFosterParent());
+    m_head = HTMLStackItem::create(createHTMLElement(token), token);
+    attachLater(currentNode(), m_head->element());
+    m_openElements.pushHTMLHeadElement(m_head);
+}
+
+void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token)
+{
+    ASSERT(!shouldFosterParent());
+    RefPtr<Element> body = createHTMLElement(token);
+    attachLater(currentNode(), body);
+    m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body.release(), token));
+    if (Frame* frame = m_document->frame())
+        frame->loader()->client()->dispatchWillInsertBody();
+}
+
+void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
+{
+    RefPtr<Element> element = createHTMLElement(token);
+    ASSERT(element->hasTagName(formTag));
+    m_form = static_pointer_cast<HTMLFormElement>(element.release());
+    m_form->setDemoted(isDemoted);
+    attachLater(currentNode(), m_form);
+    m_openElements.push(HTMLStackItem::create(m_form, token));
+}
+
+void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
+{
+    RefPtr<Element> element = createHTMLElement(token);
+    attachLater(currentNode(), element);
+    m_openElements.push(HTMLStackItem::create(element.release(), token));
+}
+
+void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    // Normally HTMLElementStack is responsible for calling finishParsingChildren,
+    // but self-closing elements are never in the element stack so the stack
+    // doesn't get a chance to tell them that we're done parsing their children.
+    attachLater(currentNode(), createHTMLElement(token), true);
+    // FIXME: Do we want to acknowledge the token's self-closing flag?
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
+}
+
+void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
+    // Possible active formatting elements include:
+    // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
+    insertHTMLElement(token);
+    m_activeFormattingElements.append(currentElementRecord()->stackItem());
+}
+
+void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#already-started
+    // http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment
+    // For createContextualFragment, the specifications say to mark it parser-inserted and already-started and later unmark them.
+    // However, we short circuit that logic to avoid the subtree traversal to find script elements since scripts can never see
+    // those flags or effects thereof.
+    const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted;
+    const bool alreadyStarted = m_isParsingFragment && parserInserted;
+    RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
+    setAttributes(element.get(), token, m_parserContentPolicy);
+    if (scriptingContentIsAllowed(m_parserContentPolicy))
+        attachLater(currentNode(), element);
+    m_openElements.push(HTMLStackItem::create(element.release(), token));
+}
+
+void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    notImplemented(); // parseError when xmlns or xmlns:xlink are wrong.
+
+    RefPtr<Element> element = createElement(token, namespaceURI);
+    if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptElementIfPossible(element.get()))
+        attachLater(currentNode(), element, token->selfClosing());
+    if (!token->selfClosing())
+        m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI));
+}
+
+void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
+{
+    HTMLConstructionSiteTask task;
+    task.parent = currentNode();
+
+    if (shouldFosterParent())
+        findFosterSite(task);
+
+    if (task.parent->hasTagName(templateTag))
+        task.parent = toHTMLTemplateElement(task.parent.get())->content();
+
+    // Strings composed entirely of whitespace are likely to be repeated.
+    // Turn them into AtomicString so we share a single string for each.
+    bool shouldUseAtomicString = whitespaceMode == AllWhitespace
+        || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
+
+    unsigned currentPosition = 0;
+
+    // FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary
+    // for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>.
+
+    Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild();
+    if (previousChild && previousChild->isTextNode()) {
+        // FIXME: We're only supposed to append to this text node if it
+        // was the last text node inserted by the parser.
+        CharacterData* textNode = static_cast<CharacterData*>(previousChild);
+        currentPosition = textNode->parserAppendData(characters, 0, Text::defaultLengthLimit);
+    }
+
+    while (currentPosition < characters.length()) {
+        RefPtr<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition);
+        // If we have a whole string of unbreakable characters the above could lead to an infinite loop. Exceeding the length limit is the lesser evil.
+        if (!textNode->length()) {
+            String substring = characters.substring(currentPosition);
+            textNode = Text::create(task.parent->document(), shouldUseAtomicString ? AtomicString(substring).string() : substring);
+        }
+
+        currentPosition += textNode->length();
+        ASSERT(currentPosition <= characters.length());
+        task.child = textNode.release();
+
+        executeTask(task);
+    }
+}
+
+PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
+{
+    QualifiedName tagName(nullAtom, token->name(), namespaceURI);
+    RefPtr<Element> element = ownerDocumentForCurrentNode()->createElement(tagName, true);
+    setAttributes(element.get(), token, m_parserContentPolicy);
+    return element.release();
+}
+
+inline Document* HTMLConstructionSite::ownerDocumentForCurrentNode()
+{
+    if (currentNode()->hasTagName(templateTag))
+        return toHTMLTemplateElement(currentElement())->content()->document();
+    return currentNode()->document();
+}
+
+PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
+{
+    QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
+    // FIXME: This can't use HTMLConstructionSite::createElement because we
+    // have to pass the current form element.  We should rework form association
+    // to occur after construction to allow better code sharing here.
+    RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, ownerDocumentForCurrentNode(), form(), true);
+    setAttributes(element.get(), token, m_parserContentPolicy);
+    ASSERT(element->isHTMLElement());
+    return element.release();
+}
+
+PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
+{
+    RefPtr<Element> element;
+    // NOTE: Moving from item -> token -> item copies the Attribute vector twice!
+    AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), item->attributes());
+    if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
+        element = createHTMLElement(&fakeToken);
+    else
+        element = createElement(&fakeToken, item->namespaceURI());
+    return HTMLStackItem::create(element.release(), &fakeToken, item->namespaceURI());
+}
+
+bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
+{
+    if (m_activeFormattingElements.isEmpty())
+        return false;
+    unsigned index = m_activeFormattingElements.size();
+    do {
+        --index;
+        const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index);
+        if (entry.isMarker() || m_openElements.contains(entry.element())) {
+            firstUnopenElementIndex = index + 1;
+            return firstUnopenElementIndex < m_activeFormattingElements.size();
+        }
+    } while (index);
+    firstUnopenElementIndex = index;
+    return true;
+}
+
+void HTMLConstructionSite::reconstructTheActiveFormattingElements()
+{
+    unsigned firstUnopenElementIndex;
+    if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
+        return;
+
+    unsigned unopenEntryIndex = firstUnopenElementIndex;
+    ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
+    for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
+        HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
+        RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem().get());
+        attachLater(currentNode(), reconstructed->node());
+        m_openElements.push(reconstructed);
+        unopenedEntry.replaceElement(reconstructed.release());
+    }
+}
+
+void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
+{
+    while (hasImpliedEndTag(currentStackItem()) && !currentStackItem()->matchesHTMLTag(tagName))
+        m_openElements.pop();
+}
+
+void HTMLConstructionSite::generateImpliedEndTags()
+{
+    while (hasImpliedEndTag(currentStackItem()))
+        m_openElements.pop();
+}
+
+bool HTMLConstructionSite::inQuirksMode()
+{
+    return m_inQuirksMode;
+}
+
+void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
+{
+    // When a node is to be foster parented, the last template element with no table element is below it in the stack of open elements is the foster parent element (NOT the template's parent!)
+    HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
+    if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
+        task.parent = lastTemplateElement->element();
+        return;
+    }
+
+    HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
+    if (lastTableElementRecord) {
+        Element* lastTableElement = lastTableElementRecord->element();
+        ContainerNode* parent;
+        if (lastTableElementRecord->next()->stackItem()->hasTagName(templateTag))
+            parent = lastTableElementRecord->next()->element();
+        else
+            parent = lastTableElement->parentNode();
+
+        // When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
+        // and instead use the DocumentFragment as a root node. So we must treat the root node (DocumentFragment) as if it is a html element here.
+        if (parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()))) {
+            task.parent = parent;
+            task.nextChild = lastTableElement;
+            return;
+        }
+        task.parent = lastTableElementRecord->next()->element();
+        return;
+    }
+    // Fragment case
+    task.parent = m_openElements.rootNode(); // DocumentFragment
+}
+
+bool HTMLConstructionSite::shouldFosterParent() const
+{
+    return m_redirectAttachToFosterParent
+        && currentStackItem()->isElementNode()
+        && currentStackItem()->causesFosterParenting();
+}
+
+void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node)
+{
+    HTMLConstructionSiteTask task;
+    findFosterSite(task);
+    task.child = node;
+    ASSERT(task.parent);
+
+    m_attachmentQueue.append(task);
+}
+
+}
diff --git a/Source/core/html/parser/HTMLConstructionSite.h b/Source/core/html/parser/HTMLConstructionSite.h
new file mode 100644
index 0000000..fc9e3ff2
--- /dev/null
+++ b/Source/core/html/parser/HTMLConstructionSite.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 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 GOOGLE 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 GOOGLE 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 HTMLConstructionSite_h
+#define HTMLConstructionSite_h
+
+#include "core/dom/FragmentScriptingPermission.h"
+#include "core/html/parser/HTMLElementStack.h"
+#include "core/html/parser/HTMLFormattingElementList.h"
+#include "core/platform/NotImplemented.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+struct HTMLConstructionSiteTask {
+    HTMLConstructionSiteTask()
+        : selfClosing(false)
+    {
+    }
+
+    RefPtr<ContainerNode> parent;
+    RefPtr<Node> nextChild;
+    RefPtr<Node> child;
+    bool selfClosing;
+};
+
+} // namespace WebCore
+
+namespace WTF {
+template<> struct VectorTraits<WebCore::HTMLConstructionSiteTask> : SimpleClassVectorTraits { };
+} // namespace WTF
+
+namespace WebCore {
+
+enum WhitespaceMode {
+    AllWhitespace,
+    NotAllWhitespace,
+    WhitespaceUnknown
+};
+
+class AtomicHTMLToken;
+class Document;
+class Element;
+class HTMLFormElement;
+
+class HTMLConstructionSite {
+    WTF_MAKE_NONCOPYABLE(HTMLConstructionSite);
+public:
+    HTMLConstructionSite(Document*, ParserContentPolicy);
+    HTMLConstructionSite(DocumentFragment*, ParserContentPolicy);
+    ~HTMLConstructionSite();
+
+    void detach();
+    void executeQueuedTasks();
+
+    void setDefaultCompatibilityMode();
+    void finishedParsing();
+
+    void insertDoctype(AtomicHTMLToken*);
+    void insertComment(AtomicHTMLToken*);
+    void insertCommentOnDocument(AtomicHTMLToken*);
+    void insertCommentOnHTMLHtmlElement(AtomicHTMLToken*);
+    void insertHTMLElement(AtomicHTMLToken*);
+    void insertSelfClosingHTMLElement(AtomicHTMLToken*);
+    void insertFormattingElement(AtomicHTMLToken*);
+    void insertHTMLHeadElement(AtomicHTMLToken*);
+    void insertHTMLBodyElement(AtomicHTMLToken*);
+    void insertHTMLFormElement(AtomicHTMLToken*, bool isDemoted = false);
+    void insertScriptElement(AtomicHTMLToken*);
+    void insertTextNode(const String&, WhitespaceMode = WhitespaceUnknown);
+    void insertForeignElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
+
+    void insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken*);
+    void insertHTMLHtmlStartTagInBody(AtomicHTMLToken*);
+    void insertHTMLBodyStartTagInBody(AtomicHTMLToken*);
+
+    PassRefPtr<HTMLStackItem> createElementFromSavedToken(HTMLStackItem*);
+
+    bool shouldFosterParent() const;
+    void fosterParent(PassRefPtr<Node>);
+
+    bool indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const;
+    void reconstructTheActiveFormattingElements();
+
+    void generateImpliedEndTags();
+    void generateImpliedEndTagsWithExclusion(const AtomicString& tagName);
+
+    bool inQuirksMode();
+
+    bool isEmpty() const { return !m_openElements.stackDepth(); }
+    HTMLElementStack::ElementRecord* currentElementRecord() const { return m_openElements.topRecord(); }
+    Element* currentElement() const { return m_openElements.top(); }
+    ContainerNode* currentNode() const { return m_openElements.topNode(); }
+    HTMLStackItem* currentStackItem() const { return m_openElements.topStackItem(); }
+    HTMLStackItem* oneBelowTop() const { return m_openElements.oneBelowTop(); }
+    Document* ownerDocumentForCurrentNode();
+    HTMLElementStack* openElements() const { return &m_openElements; }
+    HTMLFormattingElementList* activeFormattingElements() const { return &m_activeFormattingElements; }
+    bool currentIsRootNode() { return m_openElements.topNode() == m_openElements.rootNode(); }
+
+    Element* head() const { return m_head->element(); }
+    HTMLStackItem* headStackItem() const { return m_head.get(); }
+
+    void setForm(HTMLFormElement*);
+    HTMLFormElement* form() const { return m_form.get(); }
+    PassRefPtr<HTMLFormElement> takeForm();
+
+    ParserContentPolicy parserContentPolicy() { return m_parserContentPolicy; }
+
+    class RedirectToFosterParentGuard {
+        WTF_MAKE_NONCOPYABLE(RedirectToFosterParentGuard);
+    public:
+        RedirectToFosterParentGuard(HTMLConstructionSite& tree)
+            : m_tree(tree)
+            , m_wasRedirectingBefore(tree.m_redirectAttachToFosterParent)
+        {
+            m_tree.m_redirectAttachToFosterParent = true;
+        }
+
+        ~RedirectToFosterParentGuard()
+        {
+            m_tree.m_redirectAttachToFosterParent = m_wasRedirectingBefore;
+        }
+
+    private:
+        HTMLConstructionSite& m_tree;
+        bool m_wasRedirectingBefore;
+    };
+
+private:
+    // In the common case, this queue will have only one task because most
+    // tokens produce only one DOM mutation.
+    typedef Vector<HTMLConstructionSiteTask, 1> AttachmentQueue;
+
+    void setCompatibilityMode(Document::CompatibilityMode);
+    void setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId);
+
+    void attachLater(ContainerNode* parent, PassRefPtr<Node> child, bool selfClosing = false);
+
+    void findFosterSite(HTMLConstructionSiteTask&);
+
+    PassRefPtr<Element> createHTMLElement(AtomicHTMLToken*);
+    PassRefPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
+
+    void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*);
+    void dispatchDocumentElementAvailableIfNeeded();
+
+    Document* m_document;
+    
+    // This is the root ContainerNode to which the parser attaches all newly
+    // constructed nodes. It points to a DocumentFragment when parsing fragments
+    // and a Document in all other cases.
+    ContainerNode* m_attachmentRoot;
+    
+    RefPtr<HTMLStackItem> m_head;
+    RefPtr<HTMLFormElement> m_form;
+    mutable HTMLElementStack m_openElements;
+    mutable HTMLFormattingElementList m_activeFormattingElements;
+
+    AttachmentQueue m_attachmentQueue;
+
+    ParserContentPolicy m_parserContentPolicy;
+    bool m_isParsingFragment;
+
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-intable
+    // In the "in table" insertion mode, we sometimes get into a state where
+    // "whenever a node would be inserted into the current node, it must instead
+    // be foster parented."  This flag tracks whether we're in that state.
+    bool m_redirectAttachToFosterParent;
+
+    bool m_inQuirksMode;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/parser/HTMLDocumentParser.cpp b/Source/core/html/parser/HTMLDocumentParser.cpp
new file mode 100644
index 0000000..863f038
--- /dev/null
+++ b/Source/core/html/parser/HTMLDocumentParser.cpp
@@ -0,0 +1,945 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLDocumentParser.h"
+
+#include "HTMLNames.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/dom/Element.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/parser/AtomicHTMLToken.h"
+#include "core/html/parser/BackgroundHTMLParser.h"
+#include "core/html/parser/CompactHTMLToken.h"
+#include "core/html/parser/HTMLIdentifier.h"
+#include "core/html/parser/HTMLParserScheduler.h"
+#include "core/html/parser/HTMLParserThread.h"
+#include "core/html/parser/HTMLPreloadScanner.h"
+#include "core/html/parser/HTMLScriptRunner.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/html/parser/HTMLTreeBuilder.h"
+#include "core/html/parser/NestingLevelIncrementer.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/page/ContentSecurityPolicy.h"
+#include "core/page/Frame.h"
+#include "core/page/Settings.h"
+#include <wtf/Functional.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// This is a direct transcription of step 4 from:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
+static HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElement, bool reportErrors, const HTMLParserOptions& options)
+{
+    if (!contextElement)
+        return HTMLTokenizer::DataState;
+
+    const QualifiedName& contextTag = contextElement->tagQName();
+
+    if (contextTag.matches(titleTag) || contextTag.matches(textareaTag))
+        return HTMLTokenizer::RCDATAState;
+    if (contextTag.matches(styleTag)
+        || contextTag.matches(xmpTag)
+        || contextTag.matches(iframeTag)
+        || (contextTag.matches(noembedTag) && options.pluginsEnabled)
+        || (contextTag.matches(noscriptTag) && options.scriptEnabled)
+        || contextTag.matches(noframesTag))
+        return reportErrors ? HTMLTokenizer::RAWTEXTState : HTMLTokenizer::PLAINTEXTState;
+    if (contextTag.matches(scriptTag))
+        return reportErrors ? HTMLTokenizer::ScriptDataState : HTMLTokenizer::PLAINTEXTState;
+    if (contextTag.matches(plaintextTag))
+        return HTMLTokenizer::PLAINTEXTState;
+    return HTMLTokenizer::DataState;
+}
+
+HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors)
+    : ScriptableDocumentParser(document)
+    , m_options(document)
+    , m_token(m_options.useThreading ? nullptr : adoptPtr(new HTMLToken))
+    , m_tokenizer(m_options.useThreading ? nullptr : HTMLTokenizer::create(m_options))
+    , m_scriptRunner(HTMLScriptRunner::create(document, this))
+    , m_treeBuilder(HTMLTreeBuilder::create(this, document, parserContentPolicy(), reportErrors, m_options))
+    , m_parserScheduler(HTMLParserScheduler::create(this))
+    , m_xssAuditorDelegate(document)
+    , m_weakFactory(this)
+    , m_preloader(adoptPtr(new HTMLResourcePreloader(document)))
+    , m_isPinnedToMainThread(false)
+    , m_endWasDelayed(false)
+    , m_haveBackgroundParser(false)
+    , m_pumpSessionNestingLevel(0)
+{
+    ASSERT(shouldUseThreading() || (m_token && m_tokenizer));
+}
+
+// FIXME: Member variables should be grouped into self-initializing structs to
+// minimize code duplication between these constructors.
+HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
+    : ScriptableDocumentParser(fragment->document(), parserContentPolicy)
+    , m_options(fragment->document())
+    , m_token(adoptPtr(new HTMLToken))
+    , m_tokenizer(HTMLTokenizer::create(m_options))
+    , m_treeBuilder(HTMLTreeBuilder::create(this, fragment, contextElement, this->parserContentPolicy(), m_options))
+    , m_xssAuditorDelegate(fragment->document())
+    , m_weakFactory(this)
+    , m_isPinnedToMainThread(true)
+    , m_endWasDelayed(false)
+    , m_haveBackgroundParser(false)
+    , m_pumpSessionNestingLevel(0)
+{
+    ASSERT(!shouldUseThreading());
+    bool reportErrors = false; // For now document fragment parsing never reports errors.
+    m_tokenizer->setState(tokenizerStateForContextElement(contextElement, reportErrors, m_options));
+    m_xssAuditor.initForFragment();
+}
+
+HTMLDocumentParser::~HTMLDocumentParser()
+{
+    ASSERT(!m_parserScheduler);
+    ASSERT(!m_pumpSessionNestingLevel);
+    ASSERT(!m_preloadScanner);
+    ASSERT(!m_insertionPreloadScanner);
+    ASSERT(!m_haveBackgroundParser);
+    // FIXME: We should be able to ASSERT(m_speculations.isEmpty()),
+    // but there are cases where that's not true currently. For example,
+    // we we're told to stop parsing before we've consumed all the input.
+}
+
+void HTMLDocumentParser::pinToMainThread()
+{
+    ASSERT(!m_haveBackgroundParser);
+    ASSERT(!m_isPinnedToMainThread);
+    m_isPinnedToMainThread = true;
+    if (!m_tokenizer) {
+        ASSERT(!m_token);
+        m_token = adoptPtr(new HTMLToken);
+        m_tokenizer = HTMLTokenizer::create(m_options);
+    }
+}
+
+void HTMLDocumentParser::detach()
+{
+    if (m_haveBackgroundParser)
+        stopBackgroundParser();
+    DocumentParser::detach();
+    if (m_scriptRunner)
+        m_scriptRunner->detach();
+    m_treeBuilder->detach();
+    // FIXME: It seems wrong that we would have a preload scanner here.
+    // Yet during fast/dom/HTMLScriptElement/script-load-events.html we do.
+    m_preloadScanner.clear();
+    m_insertionPreloadScanner.clear();
+    m_parserScheduler.clear(); // Deleting the scheduler will clear any timers.
+}
+
+void HTMLDocumentParser::stopParsing()
+{
+    DocumentParser::stopParsing();
+    m_parserScheduler.clear(); // Deleting the scheduler will clear any timers.
+    if (m_haveBackgroundParser)
+        stopBackgroundParser();
+}
+
+// This kicks off "Once the user agent stops parsing" as described by:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-end
+void HTMLDocumentParser::prepareToStopParsing()
+{
+    // FIXME: It may not be correct to disable this for the background parser.
+    // That means hasInsertionPoint() may not be correct in some cases.
+    ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
+
+    // pumpTokenizer can cause this parser to be detached from the Document,
+    // but we need to ensure it isn't deleted yet.
+    RefPtr<HTMLDocumentParser> protect(this);
+
+    // NOTE: This pump should only ever emit buffered character tokens,
+    // so ForceSynchronous vs. AllowYield should be meaningless.
+    if (m_tokenizer) {
+        ASSERT(!m_haveBackgroundParser);
+        pumpTokenizerIfPossible(ForceSynchronous);
+    }
+
+    if (isStopped())
+        return;
+
+    DocumentParser::prepareToStopParsing();
+
+    // We will not have a scriptRunner when parsing a DocumentFragment.
+    if (m_scriptRunner)
+        document()->setReadyState(Document::Interactive);
+
+    // Setting the ready state above can fire mutation event and detach us
+    // from underneath. In that case, just bail out.
+    if (isDetached())
+        return;
+
+    attemptToRunDeferredScriptsAndEnd();
+}
+
+bool HTMLDocumentParser::isParsingFragment() const
+{
+    return m_treeBuilder->isParsingFragment();
+}
+
+bool HTMLDocumentParser::processingData() const
+{
+    return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser;
+}
+
+void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode)
+{
+    if (isStopped() || isWaitingForScripts())
+        return;
+
+    // Once a resume is scheduled, HTMLParserScheduler controls when we next pump.
+    if (isScheduledForResume()) {
+        ASSERT(mode == AllowYield);
+        return;
+    }
+
+    pumpTokenizer(mode);
+}
+
+bool HTMLDocumentParser::isScheduledForResume() const
+{
+    return m_parserScheduler && m_parserScheduler->isScheduledForResume();
+}
+
+// Used by HTMLParserScheduler
+void HTMLDocumentParser::resumeParsingAfterYield()
+{
+    // pumpTokenizer can cause this parser to be detached from the Document,
+    // but we need to ensure it isn't deleted yet.
+    RefPtr<HTMLDocumentParser> protect(this);
+
+    if (m_haveBackgroundParser) {
+        pumpPendingSpeculations();
+        return;
+    }
+
+    // We should never be here unless we can pump immediately.  Call pumpTokenizer()
+    // directly so that ASSERTS will fire if we're wrong.
+    pumpTokenizer(AllowYield);
+    endIfDelayed();
+}
+
+void HTMLDocumentParser::runScriptsForPausedTreeBuilder()
+{
+    ASSERT(scriptingContentIsAllowed(parserContentPolicy()));
+
+    TextPosition scriptStartPosition = TextPosition::belowRangePosition();
+    RefPtr<Element> scriptElement = m_treeBuilder->takeScriptToProcess(scriptStartPosition);
+    // We will not have a scriptRunner when parsing a DocumentFragment.
+    if (m_scriptRunner)
+        m_scriptRunner->execute(scriptElement.release(), scriptStartPosition);
+}
+
+bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& session)
+{
+    if (isStopped())
+        return false;
+
+    ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
+
+    if (isWaitingForScripts()) {
+        if (mode == AllowYield)
+            m_parserScheduler->checkForYieldBeforeScript(session);
+
+        // If we don't run the script, we cannot allow the next token to be taken.
+        if (session.needsYield)
+            return false;
+
+        // If we're paused waiting for a script, we try to execute scripts before continuing.
+        runScriptsForPausedTreeBuilder();
+        if (isWaitingForScripts() || isStopped())
+            return false;
+    }
+
+    // FIXME: It's wrong for the HTMLDocumentParser to reach back to the
+    //        Frame, but this approach is how the old parser handled
+    //        stopping when the page assigns window.location.  What really
+    //        should happen is that assigning window.location causes the
+    //        parser to stop parsing cleanly.  The problem is we're not
+    //        perpared to do that at every point where we run JavaScript.
+    if (!isParsingFragment()
+        && document()->frame() && document()->frame()->navigationScheduler()->locationChangePending())
+        return false;
+
+    if (mode == AllowYield)
+        m_parserScheduler->checkForYieldBeforeToken(session);
+
+    return true;
+}
+
+void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> chunk)
+{
+    // alert(), runModalDialog, and the JavaScript Debugger all run nested event loops
+    // which can cause this method to be re-entered. We detect re-entry using
+    // hasActiveParser(), save the chunk as a speculation, and return.
+    if (isWaitingForScripts() || !m_speculations.isEmpty() || document()->activeParserCount() > 0) {
+        m_preloader->takeAndPreload(chunk->preloads);
+        m_speculations.append(chunk);
+        return;
+    }
+
+    // processParsedChunkFromBackgroundParser can cause this parser to be detached from the Document,
+    // but we need to ensure it isn't deleted yet.
+    RefPtr<HTMLDocumentParser> protect(this);
+
+    ASSERT(m_speculations.isEmpty());
+    chunk->preloads.clear(); // We don't need to preload because we're going to parse immediately.
+    m_speculations.append(chunk);
+    pumpPendingSpeculations();
+}
+
+void HTMLDocumentParser::validateSpeculations(PassOwnPtr<ParsedChunk> chunk)
+{
+    ASSERT(chunk);
+    if (isWaitingForScripts()) {
+        // We're waiting on a network script, just save the chunk, we'll get
+        // a second validateSpeculations call after the script completes.
+        // This call should have been made immediately after runScriptsForPausedTreeBuilder
+        // which may have started a network load and left us waiting.
+        ASSERT(!m_lastChunkBeforeScript);
+        m_lastChunkBeforeScript = chunk;
+        return;
+    }
+
+    ASSERT(!m_lastChunkBeforeScript);
+    OwnPtr<HTMLTokenizer> tokenizer = m_tokenizer.release();
+    OwnPtr<HTMLToken> token = m_token.release();
+
+    if (!tokenizer) {
+        // There must not have been any changes to the HTMLTokenizer state on
+        // the main thread, which means the speculation buffer is correct.
+        return;
+    }
+
+    // Currently we're only smart enough to reuse the speculation buffer if the tokenizer
+    // both starts and ends in the DataState. That state is simplest because the HTMLToken
+    // is always in the Uninitialized state. We should consider whether we can reuse the
+    // speculation buffer in other states, but we'd likely need to do something more
+    // sophisticated with the HTMLToken.
+    if (chunk->tokenizerState == HTMLTokenizer::DataState
+        && tokenizer->state() == HTMLTokenizer::DataState
+        && m_input.current().isEmpty()
+        && chunk->treeBuilderState == HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) {
+        ASSERT(token->isUninitialized());
+        return;
+    }
+
+    discardSpeculationsAndResumeFrom(chunk, token.release(), tokenizer.release());
+}
+
+void HTMLDocumentParser::discardSpeculationsAndResumeFrom(PassOwnPtr<ParsedChunk> lastChunkBeforeScript, PassOwnPtr<HTMLToken> token, PassOwnPtr<HTMLTokenizer> tokenizer)
+{
+    m_weakFactory.revokeAll();
+    m_speculations.clear();
+
+    OwnPtr<BackgroundHTMLParser::Checkpoint> checkpoint = adoptPtr(new BackgroundHTMLParser::Checkpoint);
+    checkpoint->parser = m_weakFactory.createWeakPtr();
+    checkpoint->token = token;
+    checkpoint->tokenizer = tokenizer;
+    checkpoint->treeBuilderState = HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get());
+    checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint;
+    checkpoint->preloadScannerCheckpoint = lastChunkBeforeScript->preloadScannerCheckpoint;
+    checkpoint->unparsedInput = m_input.current().toString().isolatedCopy();
+    m_input.current().clear(); // FIXME: This should be passed in instead of cleared.
+
+    ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread());
+    HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, checkpoint.release()));
+}
+
+void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> popChunk)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!document()->activeParserCount());
+    ASSERT(!isParsingFragment());
+    ASSERT(!isWaitingForScripts());
+    ASSERT(!isStopped());
+    // ASSERT that this object is both attached to the Document and protected.
+    ASSERT(refCount() >= 2);
+    ASSERT(shouldUseThreading());
+    ASSERT(!m_tokenizer);
+    ASSERT(!m_token);
+    ASSERT(!m_lastChunkBeforeScript);
+
+    ActiveParserSession session(contextForParsingSession());
+
+    OwnPtr<ParsedChunk> chunk(popChunk);
+    OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release();
+
+    HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, m_backgroundParser, chunk->inputCheckpoint));
+
+    for (XSSInfoStream::const_iterator it = chunk->xssInfos.begin(); it != chunk->xssInfos.end(); ++it) {
+        m_textPosition = (*it)->m_textPosition;
+        m_xssAuditorDelegate.didBlockScript(**it); 
+        if (isStopped())
+            break;
+    }
+
+    for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); it != tokens->end(); ++it) {
+        ASSERT(!isWaitingForScripts());
+
+        m_textPosition = it->textPosition();
+
+        constructTreeFromCompactHTMLToken(*it);
+
+        if (isStopped())
+            break;
+
+        if (!isParsingFragment()
+            && document()->frame() && document()->frame()->navigationScheduler()->locationChangePending()) {
+
+            // To match main-thread parser behavior (which never checks locationChangePending on the EOF path)
+            // we peek to see if this chunk has an EOF and process it anyway.
+            if (tokens->last().type() == HTMLToken::EndOfFile) {
+                ASSERT(m_speculations.isEmpty()); // There should never be any chunks after the EOF.
+                prepareToStopParsing();
+            }
+            break;
+        }
+
+        if (isWaitingForScripts()) {
+            ASSERT(it + 1 == tokens->end()); // The </script> is assumed to be the last token of this bunch.
+            runScriptsForPausedTreeBuilder();
+            validateSpeculations(chunk.release());
+            break;
+        }
+
+        if (it->type() == HTMLToken::EndOfFile) {
+            ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the last token of this bunch.
+            ASSERT(m_speculations.isEmpty()); // There should never be any chunks after the EOF.
+            prepareToStopParsing();
+            break;
+        }
+
+        ASSERT(!m_tokenizer);
+        ASSERT(!m_token);
+    }
+}
+
+void HTMLDocumentParser::pumpPendingSpeculations()
+{
+    // FIXME: Share this constant with the parser scheduler.
+    const double parserTimeLimit = 0.500;
+
+    // ASSERT that this object is both attached to the Document and protected.
+    ASSERT(refCount() >= 2);
+    // If this assert fails, you need to call validateSpeculations to make sure
+    // m_tokenizer and m_token don't have state that invalidates m_speculations.
+    ASSERT(!m_tokenizer);
+    ASSERT(!m_token);
+    ASSERT(!m_lastChunkBeforeScript);
+    ASSERT(!isWaitingForScripts());
+    ASSERT(!isStopped());
+
+    // FIXME: Pass in current input length.
+    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), lineNumber().zeroBasedInt());
+
+    double startTime = currentTime();
+
+    while (!m_speculations.isEmpty()) {
+        processParsedChunkFromBackgroundParser(m_speculations.takeFirst());
+
+        if (isWaitingForScripts() || isStopped())
+            break;
+
+        if (currentTime() - startTime > parserTimeLimit && !m_speculations.isEmpty()) {
+            m_parserScheduler->scheduleForResume();
+            break;
+        }
+    }
+
+    InspectorInstrumentation::didWriteHTML(cookie, lineNumber().zeroBasedInt());
+}
+
+void HTMLDocumentParser::forcePlaintextForTextDocument()
+{
+    if (shouldUseThreading()) {
+        // This method is called before any data is appended, so we have to start
+        // the background parser ourselves.
+        if (!m_haveBackgroundParser)
+            startBackgroundParser();
+
+        HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::forcePlaintextForTextDocument, m_backgroundParser));
+    } else
+        m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
+}
+
+Document* HTMLDocumentParser::contextForParsingSession()
+{
+    // The parsing session should interact with the document only when parsing
+    // non-fragments. Otherwise, we might delay the load event mistakenly.
+    if (isParsingFragment())
+        return 0;
+    return document();
+}
+
+void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
+{
+    ASSERT(!isStopped());
+    ASSERT(!isScheduledForResume());
+    // ASSERT that this object is both attached to the Document and protected.
+    ASSERT(refCount() >= 2);
+    ASSERT(m_tokenizer);
+    ASSERT(m_token);
+    ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
+
+    PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession());
+
+    // We tell the InspectorInstrumentation about every pump, even if we
+    // end up pumping nothing.  It can filter out empty pumps itself.
+    // FIXME: m_input.current().length() is only accurate if we
+    // end up parsing the whole buffer in this pump.  We should pass how
+    // much we parsed as part of didWriteHTML instead of willWriteHTML.
+    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), m_input.current().currentLine().zeroBasedInt());
+
+    m_xssAuditor.init(document(), &m_xssAuditorDelegate);
+
+    while (canTakeNextToken(mode, session) && !session.needsYield) {
+        if (!isParsingFragment())
+            m_sourceTracker.start(m_input.current(), m_tokenizer.get(), token());
+
+        if (!m_tokenizer->nextToken(m_input.current(), token()))
+            break;
+
+        if (!isParsingFragment()) {
+            m_sourceTracker.end(m_input.current(), m_tokenizer.get(), token());
+
+            // We do not XSS filter innerHTML, which means we (intentionally) fail
+            // http/tests/security/xssAuditor/dom-write-innerHTML.html
+            if (OwnPtr<XSSInfo> xssInfo = m_xssAuditor.filterToken(FilterTokenRequest(token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA())))
+                m_xssAuditorDelegate.didBlockScript(*xssInfo);
+        }
+
+        constructTreeFromHTMLToken(token());
+        ASSERT(token().isUninitialized());
+    }
+
+    // Ensure we haven't been totally deref'ed after pumping. Any caller of this
+    // function should be holding a RefPtr to this to ensure we weren't deleted.
+    ASSERT(refCount() >= 1);
+
+    if (isStopped())
+        return;
+
+    if (session.needsYield)
+        m_parserScheduler->scheduleForResume();
+
+    if (isWaitingForScripts()) {
+        ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState);
+        if (!m_preloadScanner) {
+            m_preloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, document()->url()));
+            m_preloadScanner->appendToEnd(m_input.current());
+        }
+        m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+    }
+
+    InspectorInstrumentation::didWriteHTML(cookie, m_input.current().currentLine().zeroBasedInt());
+}
+
+void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken)
+{
+    AtomicHTMLToken token(rawToken);
+
+    // We clear the rawToken in case constructTreeFromAtomicToken
+    // synchronously re-enters the parser. We don't clear the token immedately
+    // for Character tokens because the AtomicHTMLToken avoids copying the
+    // characters by keeping a pointer to the underlying buffer in the
+    // HTMLToken. Fortunately, Character tokens can't cause us to re-enter
+    // the parser.
+    //
+    // FIXME: Stop clearing the rawToken once we start running the parser off
+    // the main thread or once we stop allowing synchronous JavaScript
+    // execution from parseAttribute.
+    if (rawToken.type() != HTMLToken::Character)
+        rawToken.clear();
+
+    m_treeBuilder->constructTree(&token);
+
+    if (!rawToken.isUninitialized()) {
+        ASSERT(rawToken.type() == HTMLToken::Character);
+        rawToken.clear();
+    }
+}
+
+void HTMLDocumentParser::constructTreeFromCompactHTMLToken(const CompactHTMLToken& compactToken)
+{
+    AtomicHTMLToken token(compactToken);
+    m_treeBuilder->constructTree(&token);
+}
+
+bool HTMLDocumentParser::hasInsertionPoint()
+{
+    // FIXME: The wasCreatedByScript() branch here might not be fully correct.
+    //        Our model of the EOF character differs slightly from the one in
+    //        the spec because our treatment is uniform between network-sourced
+    //        and script-sourced input streams whereas the spec treats them
+    //        differently.
+    return m_input.hasInsertionPoint() || (wasCreatedByScript() && !m_input.haveSeenEndOfFile());
+}
+
+void HTMLDocumentParser::insert(const SegmentedString& source)
+{
+    if (isStopped())
+        return;
+
+    // pumpTokenizer can cause this parser to be detached from the Document,
+    // but we need to ensure it isn't deleted yet.
+    RefPtr<HTMLDocumentParser> protect(this);
+
+    if (!m_tokenizer) {
+        ASSERT(!inPumpSession());
+        ASSERT(m_haveBackgroundParser || wasCreatedByScript());
+        m_token = adoptPtr(new HTMLToken);
+        m_tokenizer = HTMLTokenizer::create(m_options);
+    }
+
+    SegmentedString excludedLineNumberSource(source);
+    excludedLineNumberSource.setExcludeLineNumbers();
+    m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource);
+    pumpTokenizerIfPossible(ForceSynchronous);
+
+    if (isWaitingForScripts()) {
+        // Check the document.write() output with a separate preload scanner as
+        // the main scanner can't deal with insertions.
+        if (!m_insertionPreloadScanner)
+            m_insertionPreloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, document()->url()));
+        m_insertionPreloadScanner->appendToEnd(source);
+        m_insertionPreloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+    }
+
+    endIfDelayed();
+}
+
+void HTMLDocumentParser::startBackgroundParser()
+{
+    ASSERT(shouldUseThreading());
+    ASSERT(!m_haveBackgroundParser);
+    m_haveBackgroundParser = true;
+
+    HTMLIdentifier::init();
+
+    RefPtr<WeakReference<BackgroundHTMLParser> > reference = WeakReference<BackgroundHTMLParser>::createUnbound();
+    m_backgroundParser = WeakPtr<BackgroundHTMLParser>(reference);
+
+    OwnPtr<BackgroundHTMLParser::Configuration> config = adoptPtr(new BackgroundHTMLParser::Configuration);
+    config->options = m_options;
+    config->parser = m_weakFactory.createWeakPtr();
+    config->xssAuditor = adoptPtr(new XSSAuditor);
+    config->xssAuditor->init(document(), &m_xssAuditorDelegate);
+    config->preloadScanner = adoptPtr(new TokenPreloadScanner(document()->url().copy()));
+
+    ASSERT(config->xssAuditor->isSafeToSendToAnotherThread());
+    ASSERT(config->preloadScanner->isSafeToSendToAnotherThread());
+    HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::create, reference.release(), config.release()));
+}
+
+void HTMLDocumentParser::stopBackgroundParser()
+{
+    ASSERT(shouldUseThreading());
+    ASSERT(m_haveBackgroundParser);
+    m_haveBackgroundParser = false;
+
+    HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::stop, m_backgroundParser));
+    m_weakFactory.revokeAll();
+}
+
+void HTMLDocumentParser::append(PassRefPtr<StringImpl> inputSource)
+{
+    if (isStopped())
+        return;
+
+    if (shouldUseThreading()) {
+        if (!m_haveBackgroundParser)
+            startBackgroundParser();
+
+        ASSERT(inputSource->hasOneRef());
+        Closure closure = bind(&BackgroundHTMLParser::append, m_backgroundParser, String(inputSource));
+        // NOTE: Important that the String temporary is destroyed before we post the task
+        // otherwise the String could call deref() on a StringImpl now owned by the background parser.
+        // We would like to ASSERT(closure.arg3()->hasOneRef()) but sadly the args are private.
+        HTMLParserThread::shared()->postTask(closure);
+        return;
+    }
+
+    // pumpTokenizer can cause this parser to be detached from the Document,
+    // but we need to ensure it isn't deleted yet.
+    RefPtr<HTMLDocumentParser> protect(this);
+    String source(inputSource);
+
+    if (m_preloadScanner) {
+        if (m_input.current().isEmpty() && !isWaitingForScripts()) {
+            // We have parsed until the end of the current input and so are now moving ahead of the preload scanner.
+            // Clear the scanner so we know to scan starting from the current input point if we block again.
+            m_preloadScanner.clear();
+        } else {
+            m_preloadScanner->appendToEnd(source);
+            if (isWaitingForScripts())
+                m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+        }
+    }
+
+    m_input.appendToEnd(source);
+
+    if (inPumpSession()) {
+        // We've gotten data off the network in a nested write.
+        // We don't want to consume any more of the input stream now.  Do
+        // not worry.  We'll consume this data in a less-nested write().
+        return;
+    }
+
+    pumpTokenizerIfPossible(AllowYield);
+
+    endIfDelayed();
+}
+
+void HTMLDocumentParser::end()
+{
+    ASSERT(!isDetached());
+    ASSERT(!isScheduledForResume());
+
+    if (m_haveBackgroundParser)
+        stopBackgroundParser();
+
+    // Informs the the rest of WebCore that parsing is really finished (and deletes this).
+    m_treeBuilder->finished();
+}
+
+void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd()
+{
+    ASSERT(isStopping());
+    // FIXME: It may not be correct to disable this for the background parser.
+    // That means hasInsertionPoint() may not be correct in some cases.
+    ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
+    if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing())
+        return;
+    end();
+}
+
+void HTMLDocumentParser::attemptToEnd()
+{
+    // finish() indicates we will not receive any more data. If we are waiting on
+    // an external script to load, we can't finish parsing quite yet.
+
+    if (shouldDelayEnd()) {
+        m_endWasDelayed = true;
+        return;
+    }
+    prepareToStopParsing();
+}
+
+void HTMLDocumentParser::endIfDelayed()
+{
+    // If we've already been detached, don't bother ending.
+    if (isDetached())
+        return;
+
+    if (!m_endWasDelayed || shouldDelayEnd())
+        return;
+
+    m_endWasDelayed = false;
+    prepareToStopParsing();
+}
+
+void HTMLDocumentParser::finish()
+{
+    // FIXME: We should ASSERT(!m_parserStopped) here, since it does not
+    // makes sense to call any methods on DocumentParser once it's been stopped.
+    // However, FrameLoader::stop calls DocumentParser::finish unconditionally.
+
+    // Empty documents never got an append() call, and thus have never started
+    // a background parser. In those cases, we ignore shouldUseThreading()
+    // and fall through to the non-threading case.
+    if (m_haveBackgroundParser) {
+        if (!m_input.haveSeenEndOfFile())
+            m_input.closeWithoutMarkingEndOfFile();
+        HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::finish, m_backgroundParser));
+        return;
+    }
+
+    if (!m_tokenizer) {
+        ASSERT(!m_token);
+        // We're finishing before receiving any data. Rather than booting up
+        // the background parser just to spin it down, we finish parsing
+        // synchronously.
+        m_token = adoptPtr(new HTMLToken);
+        m_tokenizer = HTMLTokenizer::create(m_options);
+    }
+
+    // We're not going to get any more data off the network, so we tell the
+    // input stream we've reached the end of file. finish() can be called more
+    // than once, if the first time does not call end().
+    if (!m_input.haveSeenEndOfFile())
+        m_input.markEndOfFile();
+
+    attemptToEnd();
+}
+
+bool HTMLDocumentParser::isExecutingScript() const
+{
+    if (!m_scriptRunner)
+        return false;
+    return m_scriptRunner->isExecutingScript();
+}
+
+OrdinalNumber HTMLDocumentParser::lineNumber() const
+{
+    if (m_haveBackgroundParser)
+        return m_textPosition.m_line;
+
+    return m_input.current().currentLine();
+}
+
+TextPosition HTMLDocumentParser::textPosition() const
+{
+    if (m_haveBackgroundParser)
+        return m_textPosition;
+
+    const SegmentedString& currentString = m_input.current();
+    OrdinalNumber line = currentString.currentLine();
+    OrdinalNumber column = currentString.currentColumn();
+
+    return TextPosition(line, column);
+}
+
+bool HTMLDocumentParser::isWaitingForScripts() const
+{
+    // When the TreeBuilder encounters a </script> tag, it returns to the HTMLDocumentParser
+    // where the script is transfered from the treebuilder to the script runner.
+    // The script runner will hold the script until its loaded and run. During
+    // any of this time, we want to count ourselves as "waiting for a script" and thus
+    // run the preload scanner, as well as delay completion of parsing.
+    bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript();
+    bool scriptRunnerHasBlockingScript = m_scriptRunner && m_scriptRunner->hasParserBlockingScript();
+    // Since the parser is paused while a script runner has a blocking script, it should
+    // never be possible to end up with both objects holding a blocking script.
+    ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript));
+    // If either object has a blocking script, the parser should be paused.
+    return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript;
+}
+
+void HTMLDocumentParser::resumeParsingAfterScriptExecution()
+{
+    ASSERT(!isExecutingScript());
+    ASSERT(!isWaitingForScripts());
+
+    if (m_haveBackgroundParser) {
+        validateSpeculations(m_lastChunkBeforeScript.release());
+        ASSERT(!m_lastChunkBeforeScript);
+        // processParsedChunkFromBackgroundParser can cause this parser to be detached from the Document,
+        // but we need to ensure it isn't deleted yet.
+        RefPtr<HTMLDocumentParser> protect(this);
+        pumpPendingSpeculations();
+        return;
+    }
+
+    m_insertionPreloadScanner.clear();
+    pumpTokenizerIfPossible(AllowYield);
+    endIfDelayed();
+}
+
+void HTMLDocumentParser::watchForLoad(CachedResource* cachedScript)
+{
+    ASSERT(!cachedScript->isLoaded());
+    // addClient would call notifyFinished if the load were complete.
+    // Callers do not expect to be re-entered from this call, so they should
+    // not an already-loaded CachedResource.
+    cachedScript->addClient(this);
+}
+
+void HTMLDocumentParser::stopWatchingForLoad(CachedResource* cachedScript)
+{
+    cachedScript->removeClient(this);
+}
+    
+void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan()
+{
+    ASSERT(m_preloadScanner);
+    m_preloadScanner->appendToEnd(m_input.current());
+    m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+}
+
+void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
+{
+    // pumpTokenizer can cause this parser to be detached from the Document,
+    // but we need to ensure it isn't deleted yet.
+    RefPtr<HTMLDocumentParser> protect(this);
+
+    ASSERT(m_scriptRunner);
+    ASSERT(!isExecutingScript());
+    if (isStopping()) {
+        attemptToRunDeferredScriptsAndEnd();
+        return;
+    }
+
+    m_scriptRunner->executeScriptsWaitingForLoad(cachedResource);
+    if (!isWaitingForScripts())
+        resumeParsingAfterScriptExecution();
+}
+
+void HTMLDocumentParser::executeScriptsWaitingForStylesheets()
+{
+    // Document only calls this when the Document owns the DocumentParser
+    // so this will not be called in the DocumentFragment case.
+    ASSERT(m_scriptRunner);
+    // Ignore calls unless we have a script blocking the parser waiting on a
+    // stylesheet load.  Otherwise we are currently parsing and this
+    // is a re-entrant call from encountering a </ style> tag.
+    if (!m_scriptRunner->hasScriptsWaitingForStylesheets())
+        return;
+
+    // pumpTokenizer can cause this parser to be detached from the Document,
+    // but we need to ensure it isn't deleted yet.
+    RefPtr<HTMLDocumentParser> protect(this);
+    m_scriptRunner->executeScriptsWaitingForStylesheets();
+    if (!isWaitingForScripts())
+        resumeParsingAfterScriptExecution();
+}
+
+void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment* fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
+{
+    RefPtr<HTMLDocumentParser> parser = HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy);
+    parser->insert(source); // Use insert() so that the parser will not yield.
+    parser->finish();
+    ASSERT(!parser->processingData()); // Make sure we're done. <rdar://problem/3963151>
+    parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction.
+}
+    
+void HTMLDocumentParser::suspendScheduledTasks()
+{
+    if (m_parserScheduler)
+        m_parserScheduler->suspend();
+}
+
+void HTMLDocumentParser::resumeScheduledTasks()
+{
+    if (m_parserScheduler)
+        m_parserScheduler->resume();
+}
+
+}
diff --git a/Source/core/html/parser/HTMLDocumentParser.h b/Source/core/html/parser/HTMLDocumentParser.h
new file mode 100644
index 0000000..38aa2a9
--- /dev/null
+++ b/Source/core/html/parser/HTMLDocumentParser.h
@@ -0,0 +1,206 @@
+/*
+ * 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 HTMLDocumentParser_h
+#define HTMLDocumentParser_h
+
+#include "core/dom/FragmentScriptingPermission.h"
+#include "core/dom/ScriptableDocumentParser.h"
+#include "core/html/parser/BackgroundHTMLInputStream.h"
+#include "core/html/parser/CompactHTMLToken.h"
+#include "core/html/parser/HTMLInputStream.h"
+#include "core/html/parser/HTMLParserOptions.h"
+#include "core/html/parser/HTMLPreloadScanner.h"
+#include "core/html/parser/HTMLScriptRunnerHost.h"
+#include "core/html/parser/HTMLSourceTracker.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/html/parser/HTMLTreeBuilderSimulator.h"
+#include "core/html/parser/XSSAuditor.h"
+#include "core/html/parser/XSSAuditorDelegate.h"
+#include "core/loader/cache/CachedResourceClient.h"
+#include "core/platform/Timer.h"
+#include "core/platform/text/SegmentedString.h"
+#include <wtf/Deque.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/text/TextPosition.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class BackgroundHTMLParser;
+class CompactHTMLToken;
+class Document;
+class DocumentFragment;
+class HTMLDocument;
+class HTMLParserScheduler;
+class HTMLScriptRunner;
+class HTMLTreeBuilder;
+class HTMLResourcePreloader;
+class ScriptController;
+class ScriptSourceCode;
+
+class PumpSession;
+
+class HTMLDocumentParser :  public ScriptableDocumentParser, HTMLScriptRunnerHost, CachedResourceClient {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassRefPtr<HTMLDocumentParser> create(HTMLDocument* document, bool reportErrors)
+    {
+        return adoptRef(new HTMLDocumentParser(document, reportErrors));
+    }
+    virtual ~HTMLDocumentParser();
+
+    // Exposed for HTMLParserScheduler
+    void resumeParsingAfterYield();
+
+    static void parseDocumentFragment(const String&, DocumentFragment*, Element* contextElement, ParserContentPolicy = AllowScriptingContent);
+
+    HTMLTokenizer* tokenizer() const { return m_tokenizer.get(); }
+
+    virtual TextPosition textPosition() const;
+    virtual OrdinalNumber lineNumber() const;
+
+    virtual void suspendScheduledTasks();
+    virtual void resumeScheduledTasks();
+
+    struct ParsedChunk {
+        OwnPtr<CompactHTMLTokenStream> tokens;
+        PreloadRequestStream preloads;
+        XSSInfoStream xssInfos;
+        HTMLTokenizer::State tokenizerState;
+        HTMLTreeBuilderSimulator::State treeBuilderState;
+        HTMLInputCheckpoint inputCheckpoint;
+        TokenPreloadScannerCheckpoint preloadScannerCheckpoint;
+    };
+    void didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk>);
+
+protected:
+    virtual void insert(const SegmentedString&) OVERRIDE;
+    virtual void append(PassRefPtr<StringImpl>) OVERRIDE;
+    virtual void finish() OVERRIDE;
+
+    HTMLDocumentParser(HTMLDocument*, bool reportErrors);
+    HTMLDocumentParser(DocumentFragment*, Element* contextElement, ParserContentPolicy);
+
+    HTMLTreeBuilder* treeBuilder() const { return m_treeBuilder.get(); }
+
+    void forcePlaintextForTextDocument();
+
+private:
+    static PassRefPtr<HTMLDocumentParser> create(DocumentFragment* fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
+    {
+        return adoptRef(new HTMLDocumentParser(fragment, contextElement, parserContentPolicy));
+    }
+
+    // DocumentParser
+    virtual void pinToMainThread() OVERRIDE;
+    virtual void detach() OVERRIDE;
+    virtual bool hasInsertionPoint() OVERRIDE;
+    virtual bool processingData() const OVERRIDE;
+    virtual void prepareToStopParsing() OVERRIDE;
+    virtual void stopParsing() OVERRIDE;
+    virtual bool isWaitingForScripts() const OVERRIDE;
+    virtual bool isExecutingScript() const OVERRIDE;
+    virtual void executeScriptsWaitingForStylesheets() OVERRIDE;
+
+    // HTMLScriptRunnerHost
+    virtual void watchForLoad(CachedResource*) OVERRIDE;
+    virtual void stopWatchingForLoad(CachedResource*) OVERRIDE;
+    virtual HTMLInputStream& inputStream() { return m_input; }
+    virtual bool hasPreloadScanner() const { return m_preloadScanner.get() && !shouldUseThreading(); }
+    virtual void appendCurrentInputStreamToPreloadScannerAndScan() OVERRIDE;
+
+    // CachedResourceClient
+    virtual void notifyFinished(CachedResource*);
+
+    void startBackgroundParser();
+    void stopBackgroundParser();
+    void validateSpeculations(PassOwnPtr<ParsedChunk> lastChunk);
+    void discardSpeculationsAndResumeFrom(PassOwnPtr<ParsedChunk> lastChunk, PassOwnPtr<HTMLToken>, PassOwnPtr<HTMLTokenizer>);
+    void processParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk>);
+    void pumpPendingSpeculations();
+
+    Document* contextForParsingSession();
+
+    enum SynchronousMode {
+        AllowYield,
+        ForceSynchronous,
+    };
+    bool canTakeNextToken(SynchronousMode, PumpSession&);
+    void pumpTokenizer(SynchronousMode);
+    void pumpTokenizerIfPossible(SynchronousMode);
+    void constructTreeFromHTMLToken(HTMLToken&);
+    void constructTreeFromCompactHTMLToken(const CompactHTMLToken&);
+
+    void runScriptsForPausedTreeBuilder();
+    void resumeParsingAfterScriptExecution();
+
+    void attemptToEnd();
+    void endIfDelayed();
+    void attemptToRunDeferredScriptsAndEnd();
+    void end();
+
+    bool shouldUseThreading() const { return m_options.useThreading && !m_isPinnedToMainThread; }
+
+    bool isParsingFragment() const;
+    bool isScheduledForResume() const;
+    bool inPumpSession() const { return m_pumpSessionNestingLevel > 0; }
+    bool shouldDelayEnd() const { return inPumpSession() || isWaitingForScripts() || isScheduledForResume() || isExecutingScript(); }
+
+    HTMLToken& token() { return *m_token.get(); }
+
+    HTMLParserOptions m_options;
+    HTMLInputStream m_input;
+
+    OwnPtr<HTMLToken> m_token;
+    OwnPtr<HTMLTokenizer> m_tokenizer;
+    OwnPtr<HTMLScriptRunner> m_scriptRunner;
+    OwnPtr<HTMLTreeBuilder> m_treeBuilder;
+    OwnPtr<HTMLPreloadScanner> m_preloadScanner;
+    OwnPtr<HTMLPreloadScanner> m_insertionPreloadScanner;
+    OwnPtr<HTMLParserScheduler> m_parserScheduler;
+    HTMLSourceTracker m_sourceTracker;
+    TextPosition m_textPosition;
+    XSSAuditor m_xssAuditor;
+    XSSAuditorDelegate m_xssAuditorDelegate;
+
+    // FIXME: m_lastChunkBeforeScript, m_tokenizer, m_token, and m_input should be combined into a single state object
+    // so they can be set and cleared together and passed between threads together.
+    OwnPtr<ParsedChunk> m_lastChunkBeforeScript;
+    Deque<OwnPtr<ParsedChunk> > m_speculations;
+    WeakPtrFactory<HTMLDocumentParser> m_weakFactory;
+    WeakPtr<BackgroundHTMLParser> m_backgroundParser;
+    OwnPtr<HTMLResourcePreloader> m_preloader;
+
+    bool m_isPinnedToMainThread;
+    bool m_endWasDelayed;
+    bool m_haveBackgroundParser;
+    unsigned m_pumpSessionNestingLevel;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLElementStack.cpp b/Source/core/html/parser/HTMLElementStack.cpp
new file mode 100644
index 0000000..f202ede
--- /dev/null
+++ b/Source/core/html/parser/HTMLElementStack.cpp
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 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 GOOGLE 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 GOOGLE 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. 
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLElementStack.h"
+
+#include "HTMLNames.h"
+#include "MathMLNames.h"
+#include "SVGNames.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/dom/Element.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+
+namespace {
+
+inline bool isRootNode(HTMLStackItem* item)
+{
+    return item->isDocumentFragmentNode()
+        || item->hasTagName(htmlTag);
+}
+
+inline bool isScopeMarker(HTMLStackItem* item)
+{
+    return item->hasTagName(appletTag)
+        || item->hasTagName(captionTag)
+        || item->hasTagName(marqueeTag)
+        || item->hasTagName(objectTag)
+        || item->hasTagName(tableTag)
+        || item->hasTagName(tdTag)
+        || item->hasTagName(thTag)
+        || item->hasTagName(MathMLNames::miTag)
+        || item->hasTagName(MathMLNames::moTag)
+        || item->hasTagName(MathMLNames::mnTag)
+        || item->hasTagName(MathMLNames::msTag)
+        || item->hasTagName(MathMLNames::mtextTag)
+        || item->hasTagName(MathMLNames::annotation_xmlTag)
+        || item->hasTagName(SVGNames::foreignObjectTag)
+        || item->hasTagName(SVGNames::descTag)
+        || item->hasTagName(SVGNames::titleTag)
+        || item->hasTagName(templateTag)
+        || isRootNode(item);
+}
+
+inline bool isListItemScopeMarker(HTMLStackItem* item)
+{
+    return isScopeMarker(item)
+        || item->hasTagName(olTag)
+        || item->hasTagName(ulTag);
+}
+
+inline bool isTableScopeMarker(HTMLStackItem* item)
+{
+    return item->hasTagName(tableTag)
+        || item->hasTagName(templateTag)
+        || isRootNode(item);
+}
+
+inline bool isTableBodyScopeMarker(HTMLStackItem* item)
+{
+    return item->hasTagName(tbodyTag)
+        || item->hasTagName(tfootTag)
+        || item->hasTagName(theadTag)
+        || item->hasTagName(templateTag)
+        || isRootNode(item);
+}
+
+inline bool isTableRowScopeMarker(HTMLStackItem* item)
+{
+    return item->hasTagName(trTag)
+        || item->hasTagName(templateTag)
+        || isRootNode(item);
+}
+
+inline bool isForeignContentScopeMarker(HTMLStackItem* item)
+{
+    return HTMLElementStack::isMathMLTextIntegrationPoint(item)
+        || HTMLElementStack::isHTMLIntegrationPoint(item)
+        || item->isInHTMLNamespace();
+}
+
+inline bool isButtonScopeMarker(HTMLStackItem* item)
+{
+    return isScopeMarker(item)
+        || item->hasTagName(buttonTag);
+}
+
+inline bool isSelectScopeMarker(HTMLStackItem* item)
+{
+    return !item->hasTagName(optgroupTag)
+        && !item->hasTagName(optionTag);
+}
+
+}
+
+HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<HTMLStackItem> item, PassOwnPtr<ElementRecord> next)
+    : m_item(item)
+    , m_next(next)
+{
+    ASSERT(m_item);
+}
+
+HTMLElementStack::ElementRecord::~ElementRecord()
+{
+}
+
+void HTMLElementStack::ElementRecord::replaceElement(PassRefPtr<HTMLStackItem> item)
+{
+    ASSERT(item);
+    ASSERT(!m_item || m_item->isElementNode());
+    // FIXME: Should this call finishParsingChildren?
+    m_item = item;
+}
+
+bool HTMLElementStack::ElementRecord::isAbove(ElementRecord* other) const
+{
+    for (ElementRecord* below = next(); below; below = below->next()) {
+        if (below == other)
+            return true;
+    }
+    return false;
+}
+
+HTMLElementStack::HTMLElementStack()
+    : m_rootNode(0)
+    , m_headElement(0)
+    , m_bodyElement(0)
+    , m_stackDepth(0)
+{
+}
+
+HTMLElementStack::~HTMLElementStack()
+{
+}
+
+bool HTMLElementStack::hasOnlyOneElement() const
+{
+    return !topRecord()->next();
+}
+
+bool HTMLElementStack::secondElementIsHTMLBodyElement() const
+{
+    // This is used the fragment case of <body> and <frameset> in the "in body"
+    // insertion mode.
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
+    ASSERT(m_rootNode);
+    // If we have a body element, it must always be the second element on the
+    // stack, as we always start with an html element, and any other element
+    // would cause the implicit creation of a body element.
+    return !!m_bodyElement;
+}
+
+void HTMLElementStack::popHTMLHeadElement()
+{
+    ASSERT(top() == m_headElement);
+    m_headElement = 0;
+    popCommon();
+}
+
+void HTMLElementStack::popHTMLBodyElement()
+{
+    ASSERT(top() == m_bodyElement);
+    m_bodyElement = 0;
+    popCommon();
+}
+
+void HTMLElementStack::popAll()
+{
+    m_rootNode = 0;
+    m_headElement = 0;
+    m_bodyElement = 0;
+    m_stackDepth = 0;
+    while (m_top) {
+        topNode()->finishParsingChildren();
+        m_top = m_top->releaseNext();
+    }
+}
+
+void HTMLElementStack::pop()
+{
+    ASSERT(!topStackItem()->hasTagName(HTMLNames::headTag));
+    popCommon();
+}
+
+void HTMLElementStack::popUntil(const AtomicString& tagName)
+{
+    while (!topStackItem()->matchesHTMLTag(tagName)) {
+        // pop() will ASSERT if a <body>, <head> or <html> will be popped.
+        pop();
+    }
+}
+
+void HTMLElementStack::popUntilPopped(const AtomicString& tagName)
+{
+    popUntil(tagName);
+    pop();
+}
+
+void HTMLElementStack::popUntilNumberedHeaderElementPopped()
+{
+    while (!topStackItem()->isNumberedHeaderElement())
+        pop();
+    pop();
+}
+
+void HTMLElementStack::popUntil(Element* element)
+{
+    while (top() != element)
+        pop();
+}
+
+void HTMLElementStack::popUntilPopped(Element* element)
+{
+    popUntil(element);
+    pop();
+}
+
+void HTMLElementStack::popUntilTableScopeMarker()
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-context
+    while (!isTableScopeMarker(topStackItem()))
+        pop();
+}
+
+void HTMLElementStack::popUntilTableBodyScopeMarker()
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-body-context
+    while (!isTableBodyScopeMarker(topStackItem()))
+        pop();
+}
+
+void HTMLElementStack::popUntilTableRowScopeMarker()
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-row-context
+    while (!isTableRowScopeMarker(topStackItem()))
+        pop();
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#mathml-text-integration-point
+bool HTMLElementStack::isMathMLTextIntegrationPoint(HTMLStackItem* item)
+{
+    if (!item->isElementNode())
+        return false;
+    return item->hasTagName(MathMLNames::miTag)
+        || item->hasTagName(MathMLNames::moTag)
+        || item->hasTagName(MathMLNames::mnTag)
+        || item->hasTagName(MathMLNames::msTag)
+        || item->hasTagName(MathMLNames::mtextTag);
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#html-integration-point
+bool HTMLElementStack::isHTMLIntegrationPoint(HTMLStackItem* item)
+{
+    if (!item->isElementNode())
+        return false;
+    if (item->hasTagName(MathMLNames::annotation_xmlTag)) {
+        Attribute* encodingAttr = item->getAttributeItem(MathMLNames::encodingAttr);
+        if (encodingAttr) {
+            const String& encoding = encodingAttr->value();
+            return equalIgnoringCase(encoding, "text/html")
+                || equalIgnoringCase(encoding, "application/xhtml+xml");
+        }
+        return false;
+    }
+    return item->hasTagName(SVGNames::foreignObjectTag)
+        || item->hasTagName(SVGNames::descTag)
+        || item->hasTagName(SVGNames::titleTag);
+}
+
+void HTMLElementStack::popUntilForeignContentScopeMarker()
+{
+    while (!isForeignContentScopeMarker(topStackItem()))
+        pop();
+}
+    
+void HTMLElementStack::pushRootNode(PassRefPtr<HTMLStackItem> rootItem)
+{
+    ASSERT(rootItem->isDocumentFragmentNode());
+    pushRootNodeCommon(rootItem);
+}
+
+void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<HTMLStackItem> item)
+{
+    ASSERT(item->hasTagName(HTMLNames::htmlTag));
+    pushRootNodeCommon(item);
+}
+    
+void HTMLElementStack::pushRootNodeCommon(PassRefPtr<HTMLStackItem> rootItem)
+{
+    ASSERT(!m_top);
+    ASSERT(!m_rootNode);
+    m_rootNode = rootItem->node();
+    pushCommon(rootItem);
+}
+
+void HTMLElementStack::pushHTMLHeadElement(PassRefPtr<HTMLStackItem> item)
+{
+    ASSERT(item->hasTagName(HTMLNames::headTag));
+    ASSERT(!m_headElement);
+    m_headElement = item->element();
+    pushCommon(item);
+}
+
+void HTMLElementStack::pushHTMLBodyElement(PassRefPtr<HTMLStackItem> item)
+{
+    ASSERT(item->hasTagName(HTMLNames::bodyTag));
+    ASSERT(!m_bodyElement);
+    m_bodyElement = item->element();
+    pushCommon(item);
+}
+
+void HTMLElementStack::push(PassRefPtr<HTMLStackItem> item)
+{
+    ASSERT(!item->hasTagName(HTMLNames::htmlTag));
+    ASSERT(!item->hasTagName(HTMLNames::headTag));
+    ASSERT(!item->hasTagName(HTMLNames::bodyTag));
+    ASSERT(m_rootNode);
+    pushCommon(item);
+}
+
+void HTMLElementStack::insertAbove(PassRefPtr<HTMLStackItem> item, ElementRecord* recordBelow)
+{
+    ASSERT(item);
+    ASSERT(recordBelow);
+    ASSERT(m_top);
+    ASSERT(!item->hasTagName(HTMLNames::htmlTag));
+    ASSERT(!item->hasTagName(HTMLNames::headTag));
+    ASSERT(!item->hasTagName(HTMLNames::bodyTag));
+    ASSERT(m_rootNode);
+    if (recordBelow == m_top) {
+        push(item);
+        return;
+    }
+
+    for (ElementRecord* recordAbove = m_top.get(); recordAbove; recordAbove = recordAbove->next()) {
+        if (recordAbove->next() != recordBelow)
+            continue;
+
+        m_stackDepth++;
+        recordAbove->setNext(adoptPtr(new ElementRecord(item, recordAbove->releaseNext())));
+        recordAbove->next()->element()->beginParsingChildren();
+        return;
+    }
+    ASSERT_NOT_REACHED();
+}
+
+HTMLElementStack::ElementRecord* HTMLElementStack::topRecord() const
+{
+    ASSERT(m_top);
+    return m_top.get();
+}
+
+HTMLStackItem* HTMLElementStack::oneBelowTop() const
+{
+    // We should never call this if there are fewer than 2 elements on the stack.
+    ASSERT(m_top);
+    ASSERT(m_top->next());
+    if (m_top->next()->stackItem()->isElementNode())
+        return m_top->next()->stackItem().get();
+    return 0;
+}
+
+void HTMLElementStack::removeHTMLHeadElement(Element* element)
+{
+    ASSERT(m_headElement == element);
+    if (m_top->element() == element) {
+        popHTMLHeadElement();
+        return;
+    }
+    m_headElement = 0;
+    removeNonTopCommon(element);
+}
+
+void HTMLElementStack::remove(Element* element)
+{
+    ASSERT(!element->hasTagName(HTMLNames::headTag));
+    if (m_top->element() == element) {
+        pop();
+        return;
+    }
+    removeNonTopCommon(element);
+}
+
+HTMLElementStack::ElementRecord* HTMLElementStack::find(Element* element) const
+{
+    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
+        if (pos->node() == element)
+            return pos;
+    }
+    return 0;
+}
+
+HTMLElementStack::ElementRecord* HTMLElementStack::topmost(const AtomicString& tagName) const
+{
+    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
+        if (pos->stackItem()->matchesHTMLTag(tagName))
+            return pos;
+    }
+    return 0;
+}
+
+bool HTMLElementStack::contains(Element* element) const
+{
+    return !!find(element);
+}
+
+bool HTMLElementStack::contains(const AtomicString& tagName) const
+{
+    return !!topmost(tagName);
+}
+
+template <bool isMarker(HTMLStackItem*)>
+bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag)
+{
+    for (HTMLElementStack::ElementRecord* pos = top; pos; pos = pos->next()) {
+        HTMLStackItem* item = pos->stackItem().get();
+        if (item->matchesHTMLTag(targetTag))
+            return true;
+        if (isMarker(item))
+            return false;
+    }
+    ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker.
+    return false;
+}
+
+bool HTMLElementStack::hasNumberedHeaderElementInScope() const
+{
+    for (ElementRecord* record = m_top.get(); record; record = record->next()) {
+        HTMLStackItem* item = record->stackItem().get();
+        if (item->isNumberedHeaderElement())
+            return true;
+        if (isScopeMarker(item))
+            return false;
+    }
+    ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker.
+    return false;
+}
+
+bool HTMLElementStack::inScope(Element* targetElement) const
+{
+    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
+        HTMLStackItem* item = pos->stackItem().get();
+        if (item->node() == targetElement)
+            return true;
+        if (isScopeMarker(item))
+            return false;
+    }
+    ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker.
+    return false;
+}
+
+bool HTMLElementStack::inScope(const AtomicString& targetTag) const
+{
+    return inScopeCommon<isScopeMarker>(m_top.get(), targetTag);
+}
+
+bool HTMLElementStack::inScope(const QualifiedName& tagName) const
+{
+    return inScope(tagName.localName());
+}
+
+bool HTMLElementStack::inListItemScope(const AtomicString& targetTag) const
+{
+    return inScopeCommon<isListItemScopeMarker>(m_top.get(), targetTag);
+}
+
+bool HTMLElementStack::inListItemScope(const QualifiedName& tagName) const
+{
+    return inListItemScope(tagName.localName());
+}
+
+bool HTMLElementStack::inTableScope(const AtomicString& targetTag) const
+{
+    return inScopeCommon<isTableScopeMarker>(m_top.get(), targetTag);
+}
+
+bool HTMLElementStack::inTableScope(const QualifiedName& tagName) const
+{
+    return inTableScope(tagName.localName());
+}
+
+bool HTMLElementStack::inButtonScope(const AtomicString& targetTag) const
+{
+    return inScopeCommon<isButtonScopeMarker>(m_top.get(), targetTag);
+}
+
+bool HTMLElementStack::inButtonScope(const QualifiedName& tagName) const
+{
+    return inButtonScope(tagName.localName());
+}
+
+bool HTMLElementStack::inSelectScope(const AtomicString& targetTag) const
+{
+    return inScopeCommon<isSelectScopeMarker>(m_top.get(), targetTag);
+}
+
+bool HTMLElementStack::inSelectScope(const QualifiedName& tagName) const
+{
+    return inSelectScope(tagName.localName());
+}
+
+bool HTMLElementStack::hasTemplateInHTMLScope() const
+{
+    return inScopeCommon<isRootNode>(m_top.get(), templateTag.localName());
+}
+
+Element* HTMLElementStack::htmlElement() const
+{
+    ASSERT(m_rootNode);
+    return toElement(m_rootNode);
+}
+
+Element* HTMLElementStack::headElement() const
+{
+    ASSERT(m_headElement);
+    return m_headElement;
+}
+
+Element* HTMLElementStack::bodyElement() const
+{
+    ASSERT(m_bodyElement);
+    return m_bodyElement;
+}
+    
+ContainerNode* HTMLElementStack::rootNode() const
+{
+    ASSERT(m_rootNode);
+    return m_rootNode;
+}
+
+void HTMLElementStack::pushCommon(PassRefPtr<HTMLStackItem> item)
+{
+    ASSERT(m_rootNode);
+
+    m_stackDepth++;
+    m_top = adoptPtr(new ElementRecord(item, m_top.release()));
+}
+
+void HTMLElementStack::popCommon()
+{
+    ASSERT(!topStackItem()->hasTagName(HTMLNames::htmlTag));
+    ASSERT(!topStackItem()->hasTagName(HTMLNames::headTag) || !m_headElement);
+    ASSERT(!topStackItem()->hasTagName(HTMLNames::bodyTag) || !m_bodyElement);
+    top()->finishParsingChildren();
+    m_top = m_top->releaseNext();
+
+    m_stackDepth--;
+}
+
+void HTMLElementStack::removeNonTopCommon(Element* element)
+{
+    ASSERT(!element->hasTagName(HTMLNames::htmlTag));
+    ASSERT(!element->hasTagName(HTMLNames::bodyTag));
+    ASSERT(top() != element);
+    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
+        if (pos->next()->element() == element) {
+            // FIXME: Is it OK to call finishParsingChildren()
+            // when the children aren't actually finished?
+            element->finishParsingChildren();
+            pos->setNext(pos->next()->releaseNext());
+            m_stackDepth--;
+            return;
+        }
+    }
+    ASSERT_NOT_REACHED();
+}
+
+HTMLElementStack::ElementRecord* HTMLElementStack::furthestBlockForFormattingElement(Element* formattingElement) const
+{
+    ElementRecord* furthestBlock = 0;
+    for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
+        if (pos->element() == formattingElement)
+            return furthestBlock;
+        if (pos->stackItem()->isSpecialNode())
+            furthestBlock = pos;
+    }
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+#ifndef NDEBUG
+
+void HTMLElementStack::show()
+{
+    for (ElementRecord* record = m_top.get(); record; record = record->next())
+        record->element()->showNode();
+}
+
+#endif
+
+}
diff --git a/Source/core/html/parser/HTMLElementStack.h b/Source/core/html/parser/HTMLElementStack.h
new file mode 100644
index 0000000..1a90a46
--- /dev/null
+++ b/Source/core/html/parser/HTMLElementStack.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 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 GOOGLE 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 GOOGLE 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 HTMLElementStack_h
+#define HTMLElementStack_h
+
+#include "HTMLNames.h"
+#include "core/html/parser/HTMLStackItem.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class ContainerNode;
+class DocumentFragment;
+class Element;
+class QualifiedName;
+
+// NOTE: The HTML5 spec uses a backwards (grows downward) stack.  We're using
+// more standard (grows upwards) stack terminology here.
+class HTMLElementStack {
+    WTF_MAKE_NONCOPYABLE(HTMLElementStack); WTF_MAKE_FAST_ALLOCATED;
+public:
+    HTMLElementStack();
+    ~HTMLElementStack();
+
+    class ElementRecord {
+        WTF_MAKE_NONCOPYABLE(ElementRecord); WTF_MAKE_FAST_ALLOCATED;
+    public:
+        ~ElementRecord(); // Public for ~PassOwnPtr()
+    
+        Element* element() const { return m_item->element(); }
+        ContainerNode* node() const { return m_item->node(); }
+        const AtomicString& namespaceURI() const { return m_item->namespaceURI(); }
+        PassRefPtr<HTMLStackItem> stackItem() const { return m_item; }
+        void replaceElement(PassRefPtr<HTMLStackItem>);
+
+        bool isAbove(ElementRecord*) const;
+
+        ElementRecord* next() const { return m_next.get(); }
+    private:
+        friend class HTMLElementStack;
+
+        ElementRecord(PassRefPtr<HTMLStackItem>, PassOwnPtr<ElementRecord>);
+
+        PassOwnPtr<ElementRecord> releaseNext() { return m_next.release(); }
+        void setNext(PassOwnPtr<ElementRecord> next) { m_next = next; }
+
+        RefPtr<HTMLStackItem> m_item;
+        OwnPtr<ElementRecord> m_next;
+    };
+
+    unsigned stackDepth() const { return m_stackDepth; }
+
+    // Inlining this function is a (small) performance win on the parsing
+    // benchmark.
+    Element* top() const
+    {
+        ASSERT(m_top->element());
+        return m_top->element();
+    }
+
+    ContainerNode* topNode() const
+    {
+        ASSERT(m_top->node());
+        return m_top->node();
+    }
+
+    HTMLStackItem* topStackItem() const
+    {
+        ASSERT(m_top->stackItem());
+        return m_top->stackItem().get();
+    }
+
+    HTMLStackItem* oneBelowTop() const;
+    ElementRecord* topRecord() const;
+    ElementRecord* find(Element*) const;
+    ElementRecord* furthestBlockForFormattingElement(Element*) const;
+    ElementRecord* topmost(const AtomicString& tagName) const;
+
+    void insertAbove(PassRefPtr<HTMLStackItem>, ElementRecord*);
+
+    void push(PassRefPtr<HTMLStackItem>);
+    void pushRootNode(PassRefPtr<HTMLStackItem>);
+    void pushHTMLHtmlElement(PassRefPtr<HTMLStackItem>);
+    void pushHTMLHeadElement(PassRefPtr<HTMLStackItem>);
+    void pushHTMLBodyElement(PassRefPtr<HTMLStackItem>);
+
+    void pop();
+    void popUntil(const AtomicString& tagName);
+    void popUntil(Element*);
+    void popUntilPopped(const AtomicString& tagName);
+    void popUntilPopped(const QualifiedName& tagName) { popUntilPopped(tagName.localName()); }
+
+    void popUntilPopped(Element*);
+    void popUntilNumberedHeaderElementPopped();
+    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();
+
+    static bool isMathMLTextIntegrationPoint(HTMLStackItem*);
+    static bool isHTMLIntegrationPoint(HTMLStackItem*);
+
+    void remove(Element*);
+    void removeHTMLHeadElement(Element*);
+
+    bool contains(Element*) const;
+    bool contains(const AtomicString& tagName) const;
+
+    bool inScope(Element*) const;
+    bool inScope(const AtomicString& tagName) const;
+    bool inScope(const QualifiedName&) const;
+    bool inListItemScope(const AtomicString& tagName) const;
+    bool inListItemScope(const QualifiedName&) const;
+    bool inTableScope(const AtomicString& tagName) const;
+    bool inTableScope(const QualifiedName&) const;
+    bool inButtonScope(const AtomicString& tagName) const;
+    bool inButtonScope(const QualifiedName&) const;
+    bool inSelectScope(const AtomicString& tagName) const;
+    bool inSelectScope(const QualifiedName&) const;
+
+    bool hasNumberedHeaderElementInScope() const;
+
+    bool hasOnlyOneElement() const;
+    bool secondElementIsHTMLBodyElement() const;
+    bool hasTemplateInHTMLScope() const;
+    Element* htmlElement() const;
+    Element* headElement() const;
+    Element* bodyElement() const;
+    
+    ContainerNode* rootNode() const;
+
+#ifndef NDEBUG
+    void show();
+#endif
+
+private:
+    void pushCommon(PassRefPtr<HTMLStackItem>);
+    void pushRootNodeCommon(PassRefPtr<HTMLStackItem>);
+    void popCommon();
+    void removeNonTopCommon(Element*);
+
+    OwnPtr<ElementRecord> m_top;
+
+    // We remember the root node, <head> and <body> as they are pushed. Their
+    // ElementRecords keep them alive. The root node is never popped.
+    // FIXME: We don't currently require type-specific information about
+    // these elements so we haven't yet bothered to plumb the types all the
+    // way down through createElement, etc.
+    ContainerNode* m_rootNode;
+    Element* m_headElement;
+    Element* m_bodyElement;
+    unsigned m_stackDepth;
+};
+    
+} // namespace WebCore
+
+#endif // HTMLElementStack_h
diff --git a/Source/core/html/parser/HTMLEntityNames.in b/Source/core/html/parser/HTMLEntityNames.in
new file mode 100644
index 0000000..9940a62
--- /dev/null
+++ b/Source/core/html/parser/HTMLEntityNames.in
@@ -0,0 +1,2231 @@
+"AElig;","U+000C6"
+"AElig","U+000C6"
+"AMP;","U+00026"
+"AMP","U+00026"
+"Aacute;","U+000C1"
+"Aacute","U+000C1"
+"Abreve;","U+00102"
+"Acirc;","U+000C2"
+"Acirc","U+000C2"
+"Acy;","U+00410"
+"Afr;","U+1D504"
+"Agrave;","U+000C0"
+"Agrave","U+000C0"
+"Alpha;","U+00391"
+"Amacr;","U+00100"
+"And;","U+02A53"
+"Aogon;","U+00104"
+"Aopf;","U+1D538"
+"ApplyFunction;","U+02061"
+"Aring;","U+000C5"
+"Aring","U+000C5"
+"Ascr;","U+1D49C"
+"Assign;","U+02254"
+"Atilde;","U+000C3"
+"Atilde","U+000C3"
+"Auml;","U+000C4"
+"Auml","U+000C4"
+"Backslash;","U+02216"
+"Barv;","U+02AE7"
+"Barwed;","U+02306"
+"Bcy;","U+00411"
+"Because;","U+02235"
+"Bernoullis;","U+0212C"
+"Beta;","U+00392"
+"Bfr;","U+1D505"
+"Bopf;","U+1D539"
+"Breve;","U+002D8"
+"Bscr;","U+0212C"
+"Bumpeq;","U+0224E"
+"CHcy;","U+00427"
+"COPY;","U+000A9"
+"COPY","U+000A9"
+"Cacute;","U+00106"
+"Cap;","U+022D2"
+"CapitalDifferentialD;","U+02145"
+"Cayleys;","U+0212D"
+"Ccaron;","U+0010C"
+"Ccedil;","U+000C7"
+"Ccedil","U+000C7"
+"Ccirc;","U+00108"
+"Cconint;","U+02230"
+"Cdot;","U+0010A"
+"Cedilla;","U+000B8"
+"CenterDot;","U+000B7"
+"Cfr;","U+0212D"
+"Chi;","U+003A7"
+"CircleDot;","U+02299"
+"CircleMinus;","U+02296"
+"CirclePlus;","U+02295"
+"CircleTimes;","U+02297"
+"ClockwiseContourIntegral;","U+02232"
+"CloseCurlyDoubleQuote;","U+0201D"
+"CloseCurlyQuote;","U+02019"
+"Colon;","U+02237"
+"Colone;","U+02A74"
+"Congruent;","U+02261"
+"Conint;","U+0222F"
+"ContourIntegral;","U+0222E"
+"Copf;","U+02102"
+"Coproduct;","U+02210"
+"CounterClockwiseContourIntegral;","U+02233"
+"Cross;","U+02A2F"
+"Cscr;","U+1D49E"
+"Cup;","U+022D3"
+"CupCap;","U+0224D"
+"DD;","U+02145"
+"DDotrahd;","U+02911"
+"DJcy;","U+00402"
+"DScy;","U+00405"
+"DZcy;","U+0040F"
+"Dagger;","U+02021"
+"Darr;","U+021A1"
+"Dashv;","U+02AE4"
+"Dcaron;","U+0010E"
+"Dcy;","U+00414"
+"Del;","U+02207"
+"Delta;","U+00394"
+"Dfr;","U+1D507"
+"DiacriticalAcute;","U+000B4"
+"DiacriticalDot;","U+002D9"
+"DiacriticalDoubleAcute;","U+002DD"
+"DiacriticalGrave;","U+00060"
+"DiacriticalTilde;","U+002DC"
+"Diamond;","U+022C4"
+"DifferentialD;","U+02146"
+"Dopf;","U+1D53B"
+"Dot;","U+000A8"
+"DotDot;","U+020DC"
+"DotEqual;","U+02250"
+"DoubleContourIntegral;","U+0222F"
+"DoubleDot;","U+000A8"
+"DoubleDownArrow;","U+021D3"
+"DoubleLeftArrow;","U+021D0"
+"DoubleLeftRightArrow;","U+021D4"
+"DoubleLeftTee;","U+02AE4"
+"DoubleLongLeftArrow;","U+027F8"
+"DoubleLongLeftRightArrow;","U+027FA"
+"DoubleLongRightArrow;","U+027F9"
+"DoubleRightArrow;","U+021D2"
+"DoubleRightTee;","U+022A8"
+"DoubleUpArrow;","U+021D1"
+"DoubleUpDownArrow;","U+021D5"
+"DoubleVerticalBar;","U+02225"
+"DownArrow;","U+02193"
+"DownArrowBar;","U+02913"
+"DownArrowUpArrow;","U+021F5"
+"DownBreve;","U+00311"
+"DownLeftRightVector;","U+02950"
+"DownLeftTeeVector;","U+0295E"
+"DownLeftVector;","U+021BD"
+"DownLeftVectorBar;","U+02956"
+"DownRightTeeVector;","U+0295F"
+"DownRightVector;","U+021C1"
+"DownRightVectorBar;","U+02957"
+"DownTee;","U+022A4"
+"DownTeeArrow;","U+021A7"
+"Downarrow;","U+021D3"
+"Dscr;","U+1D49F"
+"Dstrok;","U+00110"
+"ENG;","U+0014A"
+"ETH;","U+000D0"
+"ETH","U+000D0"
+"Eacute;","U+000C9"
+"Eacute","U+000C9"
+"Ecaron;","U+0011A"
+"Ecirc;","U+000CA"
+"Ecirc","U+000CA"
+"Ecy;","U+0042D"
+"Edot;","U+00116"
+"Efr;","U+1D508"
+"Egrave;","U+000C8"
+"Egrave","U+000C8"
+"Element;","U+02208"
+"Emacr;","U+00112"
+"EmptySmallSquare;","U+025FB"
+"EmptyVerySmallSquare;","U+025AB"
+"Eogon;","U+00118"
+"Eopf;","U+1D53C"
+"Epsilon;","U+00395"
+"Equal;","U+02A75"
+"EqualTilde;","U+02242"
+"Equilibrium;","U+021CC"
+"Escr;","U+02130"
+"Esim;","U+02A73"
+"Eta;","U+00397"
+"Euml;","U+000CB"
+"Euml","U+000CB"
+"Exists;","U+02203"
+"ExponentialE;","U+02147"
+"Fcy;","U+00424"
+"Ffr;","U+1D509"
+"FilledSmallSquare;","U+025FC"
+"FilledVerySmallSquare;","U+025AA"
+"Fopf;","U+1D53D"
+"ForAll;","U+02200"
+"Fouriertrf;","U+02131"
+"Fscr;","U+02131"
+"GJcy;","U+00403"
+"GT;","U+0003E"
+"GT","U+0003E"
+"Gamma;","U+00393"
+"Gammad;","U+003DC"
+"Gbreve;","U+0011E"
+"Gcedil;","U+00122"
+"Gcirc;","U+0011C"
+"Gcy;","U+00413"
+"Gdot;","U+00120"
+"Gfr;","U+1D50A"
+"Gg;","U+022D9"
+"Gopf;","U+1D53E"
+"GreaterEqual;","U+02265"
+"GreaterEqualLess;","U+022DB"
+"GreaterFullEqual;","U+02267"
+"GreaterGreater;","U+02AA2"
+"GreaterLess;","U+02277"
+"GreaterSlantEqual;","U+02A7E"
+"GreaterTilde;","U+02273"
+"Gscr;","U+1D4A2"
+"Gt;","U+0226B"
+"HARDcy;","U+0042A"
+"Hacek;","U+002C7"
+"Hat;","U+0005E"
+"Hcirc;","U+00124"
+"Hfr;","U+0210C"
+"HilbertSpace;","U+0210B"
+"Hopf;","U+0210D"
+"HorizontalLine;","U+02500"
+"Hscr;","U+0210B"
+"Hstrok;","U+00126"
+"HumpDownHump;","U+0224E"
+"HumpEqual;","U+0224F"
+"IEcy;","U+00415"
+"IJlig;","U+00132"
+"IOcy;","U+00401"
+"Iacute;","U+000CD"
+"Iacute","U+000CD"
+"Icirc;","U+000CE"
+"Icirc","U+000CE"
+"Icy;","U+00418"
+"Idot;","U+00130"
+"Ifr;","U+02111"
+"Igrave;","U+000CC"
+"Igrave","U+000CC"
+"Im;","U+02111"
+"Imacr;","U+0012A"
+"ImaginaryI;","U+02148"
+"Implies;","U+021D2"
+"Int;","U+0222C"
+"Integral;","U+0222B"
+"Intersection;","U+022C2"
+"InvisibleComma;","U+02063"
+"InvisibleTimes;","U+02062"
+"Iogon;","U+0012E"
+"Iopf;","U+1D540"
+"Iota;","U+00399"
+"Iscr;","U+02110"
+"Itilde;","U+00128"
+"Iukcy;","U+00406"
+"Iuml;","U+000CF"
+"Iuml","U+000CF"
+"Jcirc;","U+00134"
+"Jcy;","U+00419"
+"Jfr;","U+1D50D"
+"Jopf;","U+1D541"
+"Jscr;","U+1D4A5"
+"Jsercy;","U+00408"
+"Jukcy;","U+00404"
+"KHcy;","U+00425"
+"KJcy;","U+0040C"
+"Kappa;","U+0039A"
+"Kcedil;","U+00136"
+"Kcy;","U+0041A"
+"Kfr;","U+1D50E"
+"Kopf;","U+1D542"
+"Kscr;","U+1D4A6"
+"LJcy;","U+00409"
+"LT;","U+0003C"
+"LT","U+0003C"
+"Lacute;","U+00139"
+"Lambda;","U+0039B"
+"Lang;","U+027EA"
+"Laplacetrf;","U+02112"
+"Larr;","U+0219E"
+"Lcaron;","U+0013D"
+"Lcedil;","U+0013B"
+"Lcy;","U+0041B"
+"LeftAngleBracket;","U+027E8"
+"LeftArrow;","U+02190"
+"LeftArrowBar;","U+021E4"
+"LeftArrowRightArrow;","U+021C6"
+"LeftCeiling;","U+02308"
+"LeftDoubleBracket;","U+027E6"
+"LeftDownTeeVector;","U+02961"
+"LeftDownVector;","U+021C3"
+"LeftDownVectorBar;","U+02959"
+"LeftFloor;","U+0230A"
+"LeftRightArrow;","U+02194"
+"LeftRightVector;","U+0294E"
+"LeftTee;","U+022A3"
+"LeftTeeArrow;","U+021A4"
+"LeftTeeVector;","U+0295A"
+"LeftTriangle;","U+022B2"
+"LeftTriangleBar;","U+029CF"
+"LeftTriangleEqual;","U+022B4"
+"LeftUpDownVector;","U+02951"
+"LeftUpTeeVector;","U+02960"
+"LeftUpVector;","U+021BF"
+"LeftUpVectorBar;","U+02958"
+"LeftVector;","U+021BC"
+"LeftVectorBar;","U+02952"
+"Leftarrow;","U+021D0"
+"Leftrightarrow;","U+021D4"
+"LessEqualGreater;","U+022DA"
+"LessFullEqual;","U+02266"
+"LessGreater;","U+02276"
+"LessLess;","U+02AA1"
+"LessSlantEqual;","U+02A7D"
+"LessTilde;","U+02272"
+"Lfr;","U+1D50F"
+"Ll;","U+022D8"
+"Lleftarrow;","U+021DA"
+"Lmidot;","U+0013F"
+"LongLeftArrow;","U+027F5"
+"LongLeftRightArrow;","U+027F7"
+"LongRightArrow;","U+027F6"
+"Longleftarrow;","U+027F8"
+"Longleftrightarrow;","U+027FA"
+"Longrightarrow;","U+027F9"
+"Lopf;","U+1D543"
+"LowerLeftArrow;","U+02199"
+"LowerRightArrow;","U+02198"
+"Lscr;","U+02112"
+"Lsh;","U+021B0"
+"Lstrok;","U+00141"
+"Lt;","U+0226A"
+"Map;","U+02905"
+"Mcy;","U+0041C"
+"MediumSpace;","U+0205F"
+"Mellintrf;","U+02133"
+"Mfr;","U+1D510"
+"MinusPlus;","U+02213"
+"Mopf;","U+1D544"
+"Mscr;","U+02133"
+"Mu;","U+0039C"
+"NJcy;","U+0040A"
+"Nacute;","U+00143"
+"Ncaron;","U+00147"
+"Ncedil;","U+00145"
+"Ncy;","U+0041D"
+"NegativeMediumSpace;","U+0200B"
+"NegativeThickSpace;","U+0200B"
+"NegativeThinSpace;","U+0200B"
+"NegativeVeryThinSpace;","U+0200B"
+"NestedGreaterGreater;","U+0226B"
+"NestedLessLess;","U+0226A"
+"NewLine;","U+0000A"
+"Nfr;","U+1D511"
+"NoBreak;","U+02060"
+"NonBreakingSpace;","U+000A0"
+"Nopf;","U+02115"
+"Not;","U+02AEC"
+"NotCongruent;","U+02262"
+"NotCupCap;","U+0226D"
+"NotDoubleVerticalBar;","U+02226"
+"NotElement;","U+02209"
+"NotEqual;","U+02260"
+"NotExists;","U+02204"
+"NotGreater;","U+0226F"
+"NotGreaterEqual;","U+02271"
+"NotGreaterLess;","U+02279"
+"NotGreaterTilde;","U+02275"
+"NotLeftTriangle;","U+022EA"
+"NotLeftTriangleEqual;","U+022EC"
+"NotLess;","U+0226E"
+"NotLessEqual;","U+02270"
+"NotLessGreater;","U+02278"
+"NotLessTilde;","U+02274"
+"NotPrecedes;","U+02280"
+"NotPrecedesSlantEqual;","U+022E0"
+"NotReverseElement;","U+0220C"
+"NotRightTriangle;","U+022EB"
+"NotRightTriangleEqual;","U+022ED"
+"NotSquareSubsetEqual;","U+022E2"
+"NotSquareSupersetEqual;","U+022E3"
+"NotSubsetEqual;","U+02288"
+"NotSucceeds;","U+02281"
+"NotSucceedsSlantEqual;","U+022E1"
+"NotSupersetEqual;","U+02289"
+"NotTilde;","U+02241"
+"NotTildeEqual;","U+02244"
+"NotTildeFullEqual;","U+02247"
+"NotTildeTilde;","U+02249"
+"NotVerticalBar;","U+02224"
+"Nscr;","U+1D4A9"
+"Ntilde;","U+000D1"
+"Ntilde","U+000D1"
+"Nu;","U+0039D"
+"OElig;","U+00152"
+"Oacute;","U+000D3"
+"Oacute","U+000D3"
+"Ocirc;","U+000D4"
+"Ocirc","U+000D4"
+"Ocy;","U+0041E"
+"Odblac;","U+00150"
+"Ofr;","U+1D512"
+"Ograve;","U+000D2"
+"Ograve","U+000D2"
+"Omacr;","U+0014C"
+"Omega;","U+003A9"
+"Omicron;","U+0039F"
+"Oopf;","U+1D546"
+"OpenCurlyDoubleQuote;","U+0201C"
+"OpenCurlyQuote;","U+02018"
+"Or;","U+02A54"
+"Oscr;","U+1D4AA"
+"Oslash;","U+000D8"
+"Oslash","U+000D8"
+"Otilde;","U+000D5"
+"Otilde","U+000D5"
+"Otimes;","U+02A37"
+"Ouml;","U+000D6"
+"Ouml","U+000D6"
+"OverBar;","U+0203E"
+"OverBrace;","U+023DE"
+"OverBracket;","U+023B4"
+"OverParenthesis;","U+023DC"
+"PartialD;","U+02202"
+"Pcy;","U+0041F"
+"Pfr;","U+1D513"
+"Phi;","U+003A6"
+"Pi;","U+003A0"
+"PlusMinus;","U+000B1"
+"Poincareplane;","U+0210C"
+"Popf;","U+02119"
+"Pr;","U+02ABB"
+"Precedes;","U+0227A"
+"PrecedesEqual;","U+02AAF"
+"PrecedesSlantEqual;","U+0227C"
+"PrecedesTilde;","U+0227E"
+"Prime;","U+02033"
+"Product;","U+0220F"
+"Proportion;","U+02237"
+"Proportional;","U+0221D"
+"Pscr;","U+1D4AB"
+"Psi;","U+003A8"
+"QUOT;","U+00022"
+"QUOT","U+00022"
+"Qfr;","U+1D514"
+"Qopf;","U+0211A"
+"Qscr;","U+1D4AC"
+"RBarr;","U+02910"
+"REG;","U+000AE"
+"REG","U+000AE"
+"Racute;","U+00154"
+"Rang;","U+027EB"
+"Rarr;","U+021A0"
+"Rarrtl;","U+02916"
+"Rcaron;","U+00158"
+"Rcedil;","U+00156"
+"Rcy;","U+00420"
+"Re;","U+0211C"
+"ReverseElement;","U+0220B"
+"ReverseEquilibrium;","U+021CB"
+"ReverseUpEquilibrium;","U+0296F"
+"Rfr;","U+0211C"
+"Rho;","U+003A1"
+"RightAngleBracket;","U+027E9"
+"RightArrow;","U+02192"
+"RightArrowBar;","U+021E5"
+"RightArrowLeftArrow;","U+021C4"
+"RightCeiling;","U+02309"
+"RightDoubleBracket;","U+027E7"
+"RightDownTeeVector;","U+0295D"
+"RightDownVector;","U+021C2"
+"RightDownVectorBar;","U+02955"
+"RightFloor;","U+0230B"
+"RightTee;","U+022A2"
+"RightTeeArrow;","U+021A6"
+"RightTeeVector;","U+0295B"
+"RightTriangle;","U+022B3"
+"RightTriangleBar;","U+029D0"
+"RightTriangleEqual;","U+022B5"
+"RightUpDownVector;","U+0294F"
+"RightUpTeeVector;","U+0295C"
+"RightUpVector;","U+021BE"
+"RightUpVectorBar;","U+02954"
+"RightVector;","U+021C0"
+"RightVectorBar;","U+02953"
+"Rightarrow;","U+021D2"
+"Ropf;","U+0211D"
+"RoundImplies;","U+02970"
+"Rrightarrow;","U+021DB"
+"Rscr;","U+0211B"
+"Rsh;","U+021B1"
+"RuleDelayed;","U+029F4"
+"SHCHcy;","U+00429"
+"SHcy;","U+00428"
+"SOFTcy;","U+0042C"
+"Sacute;","U+0015A"
+"Sc;","U+02ABC"
+"Scaron;","U+00160"
+"Scedil;","U+0015E"
+"Scirc;","U+0015C"
+"Scy;","U+00421"
+"Sfr;","U+1D516"
+"ShortDownArrow;","U+02193"
+"ShortLeftArrow;","U+02190"
+"ShortRightArrow;","U+02192"
+"ShortUpArrow;","U+02191"
+"Sigma;","U+003A3"
+"SmallCircle;","U+02218"
+"Sopf;","U+1D54A"
+"Sqrt;","U+0221A"
+"Square;","U+025A1"
+"SquareIntersection;","U+02293"
+"SquareSubset;","U+0228F"
+"SquareSubsetEqual;","U+02291"
+"SquareSuperset;","U+02290"
+"SquareSupersetEqual;","U+02292"
+"SquareUnion;","U+02294"
+"Sscr;","U+1D4AE"
+"Star;","U+022C6"
+"Sub;","U+022D0"
+"Subset;","U+022D0"
+"SubsetEqual;","U+02286"
+"Succeeds;","U+0227B"
+"SucceedsEqual;","U+02AB0"
+"SucceedsSlantEqual;","U+0227D"
+"SucceedsTilde;","U+0227F"
+"SuchThat;","U+0220B"
+"Sum;","U+02211"
+"Sup;","U+022D1"
+"Superset;","U+02283"
+"SupersetEqual;","U+02287"
+"Supset;","U+022D1"
+"THORN;","U+000DE"
+"THORN","U+000DE"
+"TRADE;","U+02122"
+"TSHcy;","U+0040B"
+"TScy;","U+00426"
+"Tab;","U+00009"
+"Tau;","U+003A4"
+"Tcaron;","U+00164"
+"Tcedil;","U+00162"
+"Tcy;","U+00422"
+"Tfr;","U+1D517"
+"Therefore;","U+02234"
+"Theta;","U+00398"
+"ThinSpace;","U+02009"
+"Tilde;","U+0223C"
+"TildeEqual;","U+02243"
+"TildeFullEqual;","U+02245"
+"TildeTilde;","U+02248"
+"Topf;","U+1D54B"
+"TripleDot;","U+020DB"
+"Tscr;","U+1D4AF"
+"Tstrok;","U+00166"
+"Uacute;","U+000DA"
+"Uacute","U+000DA"
+"Uarr;","U+0219F"
+"Uarrocir;","U+02949"
+"Ubrcy;","U+0040E"
+"Ubreve;","U+0016C"
+"Ucirc;","U+000DB"
+"Ucirc","U+000DB"
+"Ucy;","U+00423"
+"Udblac;","U+00170"
+"Ufr;","U+1D518"
+"Ugrave;","U+000D9"
+"Ugrave","U+000D9"
+"Umacr;","U+0016A"
+"UnderBar;","U+0005F"
+"UnderBrace;","U+023DF"
+"UnderBracket;","U+023B5"
+"UnderParenthesis;","U+023DD"
+"Union;","U+022C3"
+"UnionPlus;","U+0228E"
+"Uogon;","U+00172"
+"Uopf;","U+1D54C"
+"UpArrow;","U+02191"
+"UpArrowBar;","U+02912"
+"UpArrowDownArrow;","U+021C5"
+"UpDownArrow;","U+02195"
+"UpEquilibrium;","U+0296E"
+"UpTee;","U+022A5"
+"UpTeeArrow;","U+021A5"
+"Uparrow;","U+021D1"
+"Updownarrow;","U+021D5"
+"UpperLeftArrow;","U+02196"
+"UpperRightArrow;","U+02197"
+"Upsi;","U+003D2"
+"Upsilon;","U+003A5"
+"Uring;","U+0016E"
+"Uscr;","U+1D4B0"
+"Utilde;","U+00168"
+"Uuml;","U+000DC"
+"Uuml","U+000DC"
+"VDash;","U+022AB"
+"Vbar;","U+02AEB"
+"Vcy;","U+00412"
+"Vdash;","U+022A9"
+"Vdashl;","U+02AE6"
+"Vee;","U+022C1"
+"Verbar;","U+02016"
+"Vert;","U+02016"
+"VerticalBar;","U+02223"
+"VerticalLine;","U+0007C"
+"VerticalSeparator;","U+02758"
+"VerticalTilde;","U+02240"
+"VeryThinSpace;","U+0200A"
+"Vfr;","U+1D519"
+"Vopf;","U+1D54D"
+"Vscr;","U+1D4B1"
+"Vvdash;","U+022AA"
+"Wcirc;","U+00174"
+"Wedge;","U+022C0"
+"Wfr;","U+1D51A"
+"Wopf;","U+1D54E"
+"Wscr;","U+1D4B2"
+"Xfr;","U+1D51B"
+"Xi;","U+0039E"
+"Xopf;","U+1D54F"
+"Xscr;","U+1D4B3"
+"YAcy;","U+0042F"
+"YIcy;","U+00407"
+"YUcy;","U+0042E"
+"Yacute;","U+000DD"
+"Yacute","U+000DD"
+"Ycirc;","U+00176"
+"Ycy;","U+0042B"
+"Yfr;","U+1D51C"
+"Yopf;","U+1D550"
+"Yscr;","U+1D4B4"
+"Yuml;","U+00178"
+"ZHcy;","U+00416"
+"Zacute;","U+00179"
+"Zcaron;","U+0017D"
+"Zcy;","U+00417"
+"Zdot;","U+0017B"
+"ZeroWidthSpace;","U+0200B"
+"Zeta;","U+00396"
+"Zfr;","U+02128"
+"Zopf;","U+02124"
+"Zscr;","U+1D4B5"
+"aacute;","U+000E1"
+"aacute","U+000E1"
+"abreve;","U+00103"
+"ac;","U+0223E"
+"acd;","U+0223F"
+"acirc;","U+000E2"
+"acirc","U+000E2"
+"acute;","U+000B4"
+"acute","U+000B4"
+"acy;","U+00430"
+"aelig;","U+000E6"
+"aelig","U+000E6"
+"af;","U+02061"
+"afr;","U+1D51E"
+"agrave;","U+000E0"
+"agrave","U+000E0"
+"alefsym;","U+02135"
+"aleph;","U+02135"
+"alpha;","U+003B1"
+"amacr;","U+00101"
+"amalg;","U+02A3F"
+"amp;","U+00026"
+"amp","U+00026"
+"and;","U+02227"
+"andand;","U+02A55"
+"andd;","U+02A5C"
+"andslope;","U+02A58"
+"andv;","U+02A5A"
+"ang;","U+02220"
+"ange;","U+029A4"
+"angle;","U+02220"
+"angmsd;","U+02221"
+"angmsdaa;","U+029A8"
+"angmsdab;","U+029A9"
+"angmsdac;","U+029AA"
+"angmsdad;","U+029AB"
+"angmsdae;","U+029AC"
+"angmsdaf;","U+029AD"
+"angmsdag;","U+029AE"
+"angmsdah;","U+029AF"
+"angrt;","U+0221F"
+"angrtvb;","U+022BE"
+"angrtvbd;","U+0299D"
+"angsph;","U+02222"
+"angst;","U+000C5"
+"angzarr;","U+0237C"
+"aogon;","U+00105"
+"aopf;","U+1D552"
+"ap;","U+02248"
+"apE;","U+02A70"
+"apacir;","U+02A6F"
+"ape;","U+0224A"
+"apid;","U+0224B"
+"apos;","U+00027"
+"approx;","U+02248"
+"approxeq;","U+0224A"
+"aring;","U+000E5"
+"aring","U+000E5"
+"ascr;","U+1D4B6"
+"ast;","U+0002A"
+"asymp;","U+02248"
+"asympeq;","U+0224D"
+"atilde;","U+000E3"
+"atilde","U+000E3"
+"auml;","U+000E4"
+"auml","U+000E4"
+"awconint;","U+02233"
+"awint;","U+02A11"
+"bNot;","U+02AED"
+"backcong;","U+0224C"
+"backepsilon;","U+003F6"
+"backprime;","U+02035"
+"backsim;","U+0223D"
+"backsimeq;","U+022CD"
+"barvee;","U+022BD"
+"barwed;","U+02305"
+"barwedge;","U+02305"
+"bbrk;","U+023B5"
+"bbrktbrk;","U+023B6"
+"bcong;","U+0224C"
+"bcy;","U+00431"
+"bdquo;","U+0201E"
+"becaus;","U+02235"
+"because;","U+02235"
+"bemptyv;","U+029B0"
+"bepsi;","U+003F6"
+"bernou;","U+0212C"
+"beta;","U+003B2"
+"beth;","U+02136"
+"between;","U+0226C"
+"bfr;","U+1D51F"
+"bigcap;","U+022C2"
+"bigcirc;","U+025EF"
+"bigcup;","U+022C3"
+"bigodot;","U+02A00"
+"bigoplus;","U+02A01"
+"bigotimes;","U+02A02"
+"bigsqcup;","U+02A06"
+"bigstar;","U+02605"
+"bigtriangledown;","U+025BD"
+"bigtriangleup;","U+025B3"
+"biguplus;","U+02A04"
+"bigvee;","U+022C1"
+"bigwedge;","U+022C0"
+"bkarow;","U+0290D"
+"blacklozenge;","U+029EB"
+"blacksquare;","U+025AA"
+"blacktriangle;","U+025B4"
+"blacktriangledown;","U+025BE"
+"blacktriangleleft;","U+025C2"
+"blacktriangleright;","U+025B8"
+"blank;","U+02423"
+"blk12;","U+02592"
+"blk14;","U+02591"
+"blk34;","U+02593"
+"block;","U+02588"
+"bnot;","U+02310"
+"bopf;","U+1D553"
+"bot;","U+022A5"
+"bottom;","U+022A5"
+"bowtie;","U+022C8"
+"boxDL;","U+02557"
+"boxDR;","U+02554"
+"boxDl;","U+02556"
+"boxDr;","U+02553"
+"boxH;","U+02550"
+"boxHD;","U+02566"
+"boxHU;","U+02569"
+"boxHd;","U+02564"
+"boxHu;","U+02567"
+"boxUL;","U+0255D"
+"boxUR;","U+0255A"
+"boxUl;","U+0255C"
+"boxUr;","U+02559"
+"boxV;","U+02551"
+"boxVH;","U+0256C"
+"boxVL;","U+02563"
+"boxVR;","U+02560"
+"boxVh;","U+0256B"
+"boxVl;","U+02562"
+"boxVr;","U+0255F"
+"boxbox;","U+029C9"
+"boxdL;","U+02555"
+"boxdR;","U+02552"
+"boxdl;","U+02510"
+"boxdr;","U+0250C"
+"boxh;","U+02500"
+"boxhD;","U+02565"
+"boxhU;","U+02568"
+"boxhd;","U+0252C"
+"boxhu;","U+02534"
+"boxminus;","U+0229F"
+"boxplus;","U+0229E"
+"boxtimes;","U+022A0"
+"boxuL;","U+0255B"
+"boxuR;","U+02558"
+"boxul;","U+02518"
+"boxur;","U+02514"
+"boxv;","U+02502"
+"boxvH;","U+0256A"
+"boxvL;","U+02561"
+"boxvR;","U+0255E"
+"boxvh;","U+0253C"
+"boxvl;","U+02524"
+"boxvr;","U+0251C"
+"bprime;","U+02035"
+"breve;","U+002D8"
+"brvbar;","U+000A6"
+"brvbar","U+000A6"
+"bscr;","U+1D4B7"
+"bsemi;","U+0204F"
+"bsim;","U+0223D"
+"bsime;","U+022CD"
+"bsol;","U+0005C"
+"bsolb;","U+029C5"
+"bsolhsub;","U+027C8"
+"bull;","U+02022"
+"bullet;","U+02022"
+"bump;","U+0224E"
+"bumpE;","U+02AAE"
+"bumpe;","U+0224F"
+"bumpeq;","U+0224F"
+"cacute;","U+00107"
+"cap;","U+02229"
+"capand;","U+02A44"
+"capbrcup;","U+02A49"
+"capcap;","U+02A4B"
+"capcup;","U+02A47"
+"capdot;","U+02A40"
+"caret;","U+02041"
+"caron;","U+002C7"
+"ccaps;","U+02A4D"
+"ccaron;","U+0010D"
+"ccedil;","U+000E7"
+"ccedil","U+000E7"
+"ccirc;","U+00109"
+"ccups;","U+02A4C"
+"ccupssm;","U+02A50"
+"cdot;","U+0010B"
+"cedil;","U+000B8"
+"cedil","U+000B8"
+"cemptyv;","U+029B2"
+"cent;","U+000A2"
+"cent","U+000A2"
+"centerdot;","U+000B7"
+"cfr;","U+1D520"
+"chcy;","U+00447"
+"check;","U+02713"
+"checkmark;","U+02713"
+"chi;","U+003C7"
+"cir;","U+025CB"
+"cirE;","U+029C3"
+"circ;","U+002C6"
+"circeq;","U+02257"
+"circlearrowleft;","U+021BA"
+"circlearrowright;","U+021BB"
+"circledR;","U+000AE"
+"circledS;","U+024C8"
+"circledast;","U+0229B"
+"circledcirc;","U+0229A"
+"circleddash;","U+0229D"
+"cire;","U+02257"
+"cirfnint;","U+02A10"
+"cirmid;","U+02AEF"
+"cirscir;","U+029C2"
+"clubs;","U+02663"
+"clubsuit;","U+02663"
+"colon;","U+0003A"
+"colone;","U+02254"
+"coloneq;","U+02254"
+"comma;","U+0002C"
+"commat;","U+00040"
+"comp;","U+02201"
+"compfn;","U+02218"
+"complement;","U+02201"
+"complexes;","U+02102"
+"cong;","U+02245"
+"congdot;","U+02A6D"
+"conint;","U+0222E"
+"copf;","U+1D554"
+"coprod;","U+02210"
+"copy;","U+000A9"
+"copy","U+000A9"
+"copysr;","U+02117"
+"crarr;","U+021B5"
+"cross;","U+02717"
+"cscr;","U+1D4B8"
+"csub;","U+02ACF"
+"csube;","U+02AD1"
+"csup;","U+02AD0"
+"csupe;","U+02AD2"
+"ctdot;","U+022EF"
+"cudarrl;","U+02938"
+"cudarrr;","U+02935"
+"cuepr;","U+022DE"
+"cuesc;","U+022DF"
+"cularr;","U+021B6"
+"cularrp;","U+0293D"
+"cup;","U+0222A"
+"cupbrcap;","U+02A48"
+"cupcap;","U+02A46"
+"cupcup;","U+02A4A"
+"cupdot;","U+0228D"
+"cupor;","U+02A45"
+"curarr;","U+021B7"
+"curarrm;","U+0293C"
+"curlyeqprec;","U+022DE"
+"curlyeqsucc;","U+022DF"
+"curlyvee;","U+022CE"
+"curlywedge;","U+022CF"
+"curren;","U+000A4"
+"curren","U+000A4"
+"curvearrowleft;","U+021B6"
+"curvearrowright;","U+021B7"
+"cuvee;","U+022CE"
+"cuwed;","U+022CF"
+"cwconint;","U+02232"
+"cwint;","U+02231"
+"cylcty;","U+0232D"
+"dArr;","U+021D3"
+"dHar;","U+02965"
+"dagger;","U+02020"
+"daleth;","U+02138"
+"darr;","U+02193"
+"dash;","U+02010"
+"dashv;","U+022A3"
+"dbkarow;","U+0290F"
+"dblac;","U+002DD"
+"dcaron;","U+0010F"
+"dcy;","U+00434"
+"dd;","U+02146"
+"ddagger;","U+02021"
+"ddarr;","U+021CA"
+"ddotseq;","U+02A77"
+"deg;","U+000B0"
+"deg","U+000B0"
+"delta;","U+003B4"
+"demptyv;","U+029B1"
+"dfisht;","U+0297F"
+"dfr;","U+1D521"
+"dharl;","U+021C3"
+"dharr;","U+021C2"
+"diam;","U+022C4"
+"diamond;","U+022C4"
+"diamondsuit;","U+02666"
+"diams;","U+02666"
+"die;","U+000A8"
+"digamma;","U+003DD"
+"disin;","U+022F2"
+"div;","U+000F7"
+"divide;","U+000F7"
+"divide","U+000F7"
+"divideontimes;","U+022C7"
+"divonx;","U+022C7"
+"djcy;","U+00452"
+"dlcorn;","U+0231E"
+"dlcrop;","U+0230D"
+"dollar;","U+00024"
+"dopf;","U+1D555"
+"dot;","U+002D9"
+"doteq;","U+02250"
+"doteqdot;","U+02251"
+"dotminus;","U+02238"
+"dotplus;","U+02214"
+"dotsquare;","U+022A1"
+"doublebarwedge;","U+02306"
+"downarrow;","U+02193"
+"downdownarrows;","U+021CA"
+"downharpoonleft;","U+021C3"
+"downharpoonright;","U+021C2"
+"drbkarow;","U+02910"
+"drcorn;","U+0231F"
+"drcrop;","U+0230C"
+"dscr;","U+1D4B9"
+"dscy;","U+00455"
+"dsol;","U+029F6"
+"dstrok;","U+00111"
+"dtdot;","U+022F1"
+"dtri;","U+025BF"
+"dtrif;","U+025BE"
+"duarr;","U+021F5"
+"duhar;","U+0296F"
+"dwangle;","U+029A6"
+"dzcy;","U+0045F"
+"dzigrarr;","U+027FF"
+"eDDot;","U+02A77"
+"eDot;","U+02251"
+"eacute;","U+000E9"
+"eacute","U+000E9"
+"easter;","U+02A6E"
+"ecaron;","U+0011B"
+"ecir;","U+02256"
+"ecirc;","U+000EA"
+"ecirc","U+000EA"
+"ecolon;","U+02255"
+"ecy;","U+0044D"
+"edot;","U+00117"
+"ee;","U+02147"
+"efDot;","U+02252"
+"efr;","U+1D522"
+"eg;","U+02A9A"
+"egrave;","U+000E8"
+"egrave","U+000E8"
+"egs;","U+02A96"
+"egsdot;","U+02A98"
+"el;","U+02A99"
+"elinters;","U+023E7"
+"ell;","U+02113"
+"els;","U+02A95"
+"elsdot;","U+02A97"
+"emacr;","U+00113"
+"empty;","U+02205"
+"emptyset;","U+02205"
+"emptyv;","U+02205"
+"emsp13;","U+02004"
+"emsp14;","U+02005"
+"emsp;","U+02003"
+"eng;","U+0014B"
+"ensp;","U+02002"
+"eogon;","U+00119"
+"eopf;","U+1D556"
+"epar;","U+022D5"
+"eparsl;","U+029E3"
+"eplus;","U+02A71"
+"epsi;","U+003B5"
+"epsilon;","U+003B5"
+"epsiv;","U+003F5"
+"eqcirc;","U+02256"
+"eqcolon;","U+02255"
+"eqsim;","U+02242"
+"eqslantgtr;","U+02A96"
+"eqslantless;","U+02A95"
+"equals;","U+0003D"
+"equest;","U+0225F"
+"equiv;","U+02261"
+"equivDD;","U+02A78"
+"eqvparsl;","U+029E5"
+"erDot;","U+02253"
+"erarr;","U+02971"
+"escr;","U+0212F"
+"esdot;","U+02250"
+"esim;","U+02242"
+"eta;","U+003B7"
+"eth;","U+000F0"
+"eth","U+000F0"
+"euml;","U+000EB"
+"euml","U+000EB"
+"euro;","U+020AC"
+"excl;","U+00021"
+"exist;","U+02203"
+"expectation;","U+02130"
+"exponentiale;","U+02147"
+"fallingdotseq;","U+02252"
+"fcy;","U+00444"
+"female;","U+02640"
+"ffilig;","U+0FB03"
+"fflig;","U+0FB00"
+"ffllig;","U+0FB04"
+"ffr;","U+1D523"
+"filig;","U+0FB01"
+"flat;","U+0266D"
+"fllig;","U+0FB02"
+"fltns;","U+025B1"
+"fnof;","U+00192"
+"fopf;","U+1D557"
+"forall;","U+02200"
+"fork;","U+022D4"
+"forkv;","U+02AD9"
+"fpartint;","U+02A0D"
+"frac12;","U+000BD"
+"frac12","U+000BD"
+"frac13;","U+02153"
+"frac14;","U+000BC"
+"frac14","U+000BC"
+"frac15;","U+02155"
+"frac16;","U+02159"
+"frac18;","U+0215B"
+"frac23;","U+02154"
+"frac25;","U+02156"
+"frac34;","U+000BE"
+"frac34","U+000BE"
+"frac35;","U+02157"
+"frac38;","U+0215C"
+"frac45;","U+02158"
+"frac56;","U+0215A"
+"frac58;","U+0215D"
+"frac78;","U+0215E"
+"frasl;","U+02044"
+"frown;","U+02322"
+"fscr;","U+1D4BB"
+"gE;","U+02267"
+"gEl;","U+02A8C"
+"gacute;","U+001F5"
+"gamma;","U+003B3"
+"gammad;","U+003DD"
+"gap;","U+02A86"
+"gbreve;","U+0011F"
+"gcirc;","U+0011D"
+"gcy;","U+00433"
+"gdot;","U+00121"
+"ge;","U+02265"
+"gel;","U+022DB"
+"geq;","U+02265"
+"geqq;","U+02267"
+"geqslant;","U+02A7E"
+"ges;","U+02A7E"
+"gescc;","U+02AA9"
+"gesdot;","U+02A80"
+"gesdoto;","U+02A82"
+"gesdotol;","U+02A84"
+"gesles;","U+02A94"
+"gfr;","U+1D524"
+"gg;","U+0226B"
+"ggg;","U+022D9"
+"gimel;","U+02137"
+"gjcy;","U+00453"
+"gl;","U+02277"
+"glE;","U+02A92"
+"gla;","U+02AA5"
+"glj;","U+02AA4"
+"gnE;","U+02269"
+"gnap;","U+02A8A"
+"gnapprox;","U+02A8A"
+"gne;","U+02A88"
+"gneq;","U+02A88"
+"gneqq;","U+02269"
+"gnsim;","U+022E7"
+"gopf;","U+1D558"
+"grave;","U+00060"
+"gscr;","U+0210A"
+"gsim;","U+02273"
+"gsime;","U+02A8E"
+"gsiml;","U+02A90"
+"gt;","U+0003E"
+"gt","U+0003E"
+"gtcc;","U+02AA7"
+"gtcir;","U+02A7A"
+"gtdot;","U+022D7"
+"gtlPar;","U+02995"
+"gtquest;","U+02A7C"
+"gtrapprox;","U+02A86"
+"gtrarr;","U+02978"
+"gtrdot;","U+022D7"
+"gtreqless;","U+022DB"
+"gtreqqless;","U+02A8C"
+"gtrless;","U+02277"
+"gtrsim;","U+02273"
+"hArr;","U+021D4"
+"hairsp;","U+0200A"
+"half;","U+000BD"
+"hamilt;","U+0210B"
+"hardcy;","U+0044A"
+"harr;","U+02194"
+"harrcir;","U+02948"
+"harrw;","U+021AD"
+"hbar;","U+0210F"
+"hcirc;","U+00125"
+"hearts;","U+02665"
+"heartsuit;","U+02665"
+"hellip;","U+02026"
+"hercon;","U+022B9"
+"hfr;","U+1D525"
+"hksearow;","U+02925"
+"hkswarow;","U+02926"
+"hoarr;","U+021FF"
+"homtht;","U+0223B"
+"hookleftarrow;","U+021A9"
+"hookrightarrow;","U+021AA"
+"hopf;","U+1D559"
+"horbar;","U+02015"
+"hscr;","U+1D4BD"
+"hslash;","U+0210F"
+"hstrok;","U+00127"
+"hybull;","U+02043"
+"hyphen;","U+02010"
+"iacute;","U+000ED"
+"iacute","U+000ED"
+"ic;","U+02063"
+"icirc;","U+000EE"
+"icirc","U+000EE"
+"icy;","U+00438"
+"iecy;","U+00435"
+"iexcl;","U+000A1"
+"iexcl","U+000A1"
+"iff;","U+021D4"
+"ifr;","U+1D526"
+"igrave;","U+000EC"
+"igrave","U+000EC"
+"ii;","U+02148"
+"iiiint;","U+02A0C"
+"iiint;","U+0222D"
+"iinfin;","U+029DC"
+"iiota;","U+02129"
+"ijlig;","U+00133"
+"imacr;","U+0012B"
+"image;","U+02111"
+"imagline;","U+02110"
+"imagpart;","U+02111"
+"imath;","U+00131"
+"imof;","U+022B7"
+"imped;","U+001B5"
+"in;","U+02208"
+"incare;","U+02105"
+"infin;","U+0221E"
+"infintie;","U+029DD"
+"inodot;","U+00131"
+"int;","U+0222B"
+"intcal;","U+022BA"
+"integers;","U+02124"
+"intercal;","U+022BA"
+"intlarhk;","U+02A17"
+"intprod;","U+02A3C"
+"iocy;","U+00451"
+"iogon;","U+0012F"
+"iopf;","U+1D55A"
+"iota;","U+003B9"
+"iprod;","U+02A3C"
+"iquest;","U+000BF"
+"iquest","U+000BF"
+"iscr;","U+1D4BE"
+"isin;","U+02208"
+"isinE;","U+022F9"
+"isindot;","U+022F5"
+"isins;","U+022F4"
+"isinsv;","U+022F3"
+"isinv;","U+02208"
+"it;","U+02062"
+"itilde;","U+00129"
+"iukcy;","U+00456"
+"iuml;","U+000EF"
+"iuml","U+000EF"
+"jcirc;","U+00135"
+"jcy;","U+00439"
+"jfr;","U+1D527"
+"jmath;","U+00237"
+"jopf;","U+1D55B"
+"jscr;","U+1D4BF"
+"jsercy;","U+00458"
+"jukcy;","U+00454"
+"kappa;","U+003BA"
+"kappav;","U+003F0"
+"kcedil;","U+00137"
+"kcy;","U+0043A"
+"kfr;","U+1D528"
+"kgreen;","U+00138"
+"khcy;","U+00445"
+"kjcy;","U+0045C"
+"kopf;","U+1D55C"
+"kscr;","U+1D4C0"
+"lAarr;","U+021DA"
+"lArr;","U+021D0"
+"lAtail;","U+0291B"
+"lBarr;","U+0290E"
+"lE;","U+02266"
+"lEg;","U+02A8B"
+"lHar;","U+02962"
+"lacute;","U+0013A"
+"laemptyv;","U+029B4"
+"lagran;","U+02112"
+"lambda;","U+003BB"
+"lang;","U+027E8"
+"langd;","U+02991"
+"langle;","U+027E8"
+"lap;","U+02A85"
+"laquo;","U+000AB"
+"laquo","U+000AB"
+"larr;","U+02190"
+"larrb;","U+021E4"
+"larrbfs;","U+0291F"
+"larrfs;","U+0291D"
+"larrhk;","U+021A9"
+"larrlp;","U+021AB"
+"larrpl;","U+02939"
+"larrsim;","U+02973"
+"larrtl;","U+021A2"
+"lat;","U+02AAB"
+"latail;","U+02919"
+"late;","U+02AAD"
+"lbarr;","U+0290C"
+"lbbrk;","U+02772"
+"lbrace;","U+0007B"
+"lbrack;","U+0005B"
+"lbrke;","U+0298B"
+"lbrksld;","U+0298F"
+"lbrkslu;","U+0298D"
+"lcaron;","U+0013E"
+"lcedil;","U+0013C"
+"lceil;","U+02308"
+"lcub;","U+0007B"
+"lcy;","U+0043B"
+"ldca;","U+02936"
+"ldquo;","U+0201C"
+"ldquor;","U+0201E"
+"ldrdhar;","U+02967"
+"ldrushar;","U+0294B"
+"ldsh;","U+021B2"
+"le;","U+02264"
+"leftarrow;","U+02190"
+"leftarrowtail;","U+021A2"
+"leftharpoondown;","U+021BD"
+"leftharpoonup;","U+021BC"
+"leftleftarrows;","U+021C7"
+"leftrightarrow;","U+02194"
+"leftrightarrows;","U+021C6"
+"leftrightharpoons;","U+021CB"
+"leftrightsquigarrow;","U+021AD"
+"leftthreetimes;","U+022CB"
+"leg;","U+022DA"
+"leq;","U+02264"
+"leqq;","U+02266"
+"leqslant;","U+02A7D"
+"les;","U+02A7D"
+"lescc;","U+02AA8"
+"lesdot;","U+02A7F"
+"lesdoto;","U+02A81"
+"lesdotor;","U+02A83"
+"lesges;","U+02A93"
+"lessapprox;","U+02A85"
+"lessdot;","U+022D6"
+"lesseqgtr;","U+022DA"
+"lesseqqgtr;","U+02A8B"
+"lessgtr;","U+02276"
+"lesssim;","U+02272"
+"lfisht;","U+0297C"
+"lfloor;","U+0230A"
+"lfr;","U+1D529"
+"lg;","U+02276"
+"lgE;","U+02A91"
+"lhard;","U+021BD"
+"lharu;","U+021BC"
+"lharul;","U+0296A"
+"lhblk;","U+02584"
+"ljcy;","U+00459"
+"ll;","U+0226A"
+"llarr;","U+021C7"
+"llcorner;","U+0231E"
+"llhard;","U+0296B"
+"lltri;","U+025FA"
+"lmidot;","U+00140"
+"lmoust;","U+023B0"
+"lmoustache;","U+023B0"
+"lnE;","U+02268"
+"lnap;","U+02A89"
+"lnapprox;","U+02A89"
+"lne;","U+02A87"
+"lneq;","U+02A87"
+"lneqq;","U+02268"
+"lnsim;","U+022E6"
+"loang;","U+027EC"
+"loarr;","U+021FD"
+"lobrk;","U+027E6"
+"longleftarrow;","U+027F5"
+"longleftrightarrow;","U+027F7"
+"longmapsto;","U+027FC"
+"longrightarrow;","U+027F6"
+"looparrowleft;","U+021AB"
+"looparrowright;","U+021AC"
+"lopar;","U+02985"
+"lopf;","U+1D55D"
+"loplus;","U+02A2D"
+"lotimes;","U+02A34"
+"lowast;","U+02217"
+"lowbar;","U+0005F"
+"loz;","U+025CA"
+"lozenge;","U+025CA"
+"lozf;","U+029EB"
+"lpar;","U+00028"
+"lparlt;","U+02993"
+"lrarr;","U+021C6"
+"lrcorner;","U+0231F"
+"lrhar;","U+021CB"
+"lrhard;","U+0296D"
+"lrm;","U+0200E"
+"lrtri;","U+022BF"
+"lsaquo;","U+02039"
+"lscr;","U+1D4C1"
+"lsh;","U+021B0"
+"lsim;","U+02272"
+"lsime;","U+02A8D"
+"lsimg;","U+02A8F"
+"lsqb;","U+0005B"
+"lsquo;","U+02018"
+"lsquor;","U+0201A"
+"lstrok;","U+00142"
+"lt;","U+0003C"
+"lt","U+0003C"
+"ltcc;","U+02AA6"
+"ltcir;","U+02A79"
+"ltdot;","U+022D6"
+"lthree;","U+022CB"
+"ltimes;","U+022C9"
+"ltlarr;","U+02976"
+"ltquest;","U+02A7B"
+"ltrPar;","U+02996"
+"ltri;","U+025C3"
+"ltrie;","U+022B4"
+"ltrif;","U+025C2"
+"lurdshar;","U+0294A"
+"luruhar;","U+02966"
+"mDDot;","U+0223A"
+"macr;","U+000AF"
+"macr","U+000AF"
+"male;","U+02642"
+"malt;","U+02720"
+"maltese;","U+02720"
+"map;","U+021A6"
+"mapsto;","U+021A6"
+"mapstodown;","U+021A7"
+"mapstoleft;","U+021A4"
+"mapstoup;","U+021A5"
+"marker;","U+025AE"
+"mcomma;","U+02A29"
+"mcy;","U+0043C"
+"mdash;","U+02014"
+"measuredangle;","U+02221"
+"mfr;","U+1D52A"
+"mho;","U+02127"
+"micro;","U+000B5"
+"micro","U+000B5"
+"mid;","U+02223"
+"midast;","U+0002A"
+"midcir;","U+02AF0"
+"middot;","U+000B7"
+"middot","U+000B7"
+"minus;","U+02212"
+"minusb;","U+0229F"
+"minusd;","U+02238"
+"minusdu;","U+02A2A"
+"mlcp;","U+02ADB"
+"mldr;","U+02026"
+"mnplus;","U+02213"
+"models;","U+022A7"
+"mopf;","U+1D55E"
+"mp;","U+02213"
+"mscr;","U+1D4C2"
+"mstpos;","U+0223E"
+"mu;","U+003BC"
+"multimap;","U+022B8"
+"mumap;","U+022B8"
+"nLeftarrow;","U+021CD"
+"nLeftrightarrow;","U+021CE"
+"nRightarrow;","U+021CF"
+"nVDash;","U+022AF"
+"nVdash;","U+022AE"
+"nabla;","U+02207"
+"nacute;","U+00144"
+"nap;","U+02249"
+"napos;","U+00149"
+"napprox;","U+02249"
+"natur;","U+0266E"
+"natural;","U+0266E"
+"naturals;","U+02115"
+"nbsp;","U+000A0"
+"nbsp","U+000A0"
+"ncap;","U+02A43"
+"ncaron;","U+00148"
+"ncedil;","U+00146"
+"ncong;","U+02247"
+"ncup;","U+02A42"
+"ncy;","U+0043D"
+"ndash;","U+02013"
+"ne;","U+02260"
+"neArr;","U+021D7"
+"nearhk;","U+02924"
+"nearr;","U+02197"
+"nearrow;","U+02197"
+"nequiv;","U+02262"
+"nesear;","U+02928"
+"nexist;","U+02204"
+"nexists;","U+02204"
+"nfr;","U+1D52B"
+"nge;","U+02271"
+"ngeq;","U+02271"
+"ngsim;","U+02275"
+"ngt;","U+0226F"
+"ngtr;","U+0226F"
+"nhArr;","U+021CE"
+"nharr;","U+021AE"
+"nhpar;","U+02AF2"
+"ni;","U+0220B"
+"nis;","U+022FC"
+"nisd;","U+022FA"
+"niv;","U+0220B"
+"njcy;","U+0045A"
+"nlArr;","U+021CD"
+"nlarr;","U+0219A"
+"nldr;","U+02025"
+"nle;","U+02270"
+"nleftarrow;","U+0219A"
+"nleftrightarrow;","U+021AE"
+"nleq;","U+02270"
+"nless;","U+0226E"
+"nlsim;","U+02274"
+"nlt;","U+0226E"
+"nltri;","U+022EA"
+"nltrie;","U+022EC"
+"nmid;","U+02224"
+"nopf;","U+1D55F"
+"not;","U+000AC"
+"not","U+000AC"
+"notin;","U+02209"
+"notinva;","U+02209"
+"notinvb;","U+022F7"
+"notinvc;","U+022F6"
+"notni;","U+0220C"
+"notniva;","U+0220C"
+"notnivb;","U+022FE"
+"notnivc;","U+022FD"
+"npar;","U+02226"
+"nparallel;","U+02226"
+"npolint;","U+02A14"
+"npr;","U+02280"
+"nprcue;","U+022E0"
+"nprec;","U+02280"
+"nrArr;","U+021CF"
+"nrarr;","U+0219B"
+"nrightarrow;","U+0219B"
+"nrtri;","U+022EB"
+"nrtrie;","U+022ED"
+"nsc;","U+02281"
+"nsccue;","U+022E1"
+"nscr;","U+1D4C3"
+"nshortmid;","U+02224"
+"nshortparallel;","U+02226"
+"nsim;","U+02241"
+"nsime;","U+02244"
+"nsimeq;","U+02244"
+"nsmid;","U+02224"
+"nspar;","U+02226"
+"nsqsube;","U+022E2"
+"nsqsupe;","U+022E3"
+"nsub;","U+02284"
+"nsube;","U+02288"
+"nsubseteq;","U+02288"
+"nsucc;","U+02281"
+"nsup;","U+02285"
+"nsupe;","U+02289"
+"nsupseteq;","U+02289"
+"ntgl;","U+02279"
+"ntilde;","U+000F1"
+"ntilde","U+000F1"
+"ntlg;","U+02278"
+"ntriangleleft;","U+022EA"
+"ntrianglelefteq;","U+022EC"
+"ntriangleright;","U+022EB"
+"ntrianglerighteq;","U+022ED"
+"nu;","U+003BD"
+"num;","U+00023"
+"numero;","U+02116"
+"numsp;","U+02007"
+"nvDash;","U+022AD"
+"nvHarr;","U+02904"
+"nvdash;","U+022AC"
+"nvinfin;","U+029DE"
+"nvlArr;","U+02902"
+"nvrArr;","U+02903"
+"nwArr;","U+021D6"
+"nwarhk;","U+02923"
+"nwarr;","U+02196"
+"nwarrow;","U+02196"
+"nwnear;","U+02927"
+"oS;","U+024C8"
+"oacute;","U+000F3"
+"oacute","U+000F3"
+"oast;","U+0229B"
+"ocir;","U+0229A"
+"ocirc;","U+000F4"
+"ocirc","U+000F4"
+"ocy;","U+0043E"
+"odash;","U+0229D"
+"odblac;","U+00151"
+"odiv;","U+02A38"
+"odot;","U+02299"
+"odsold;","U+029BC"
+"oelig;","U+00153"
+"ofcir;","U+029BF"
+"ofr;","U+1D52C"
+"ogon;","U+002DB"
+"ograve;","U+000F2"
+"ograve","U+000F2"
+"ogt;","U+029C1"
+"ohbar;","U+029B5"
+"ohm;","U+003A9"
+"oint;","U+0222E"
+"olarr;","U+021BA"
+"olcir;","U+029BE"
+"olcross;","U+029BB"
+"oline;","U+0203E"
+"olt;","U+029C0"
+"omacr;","U+0014D"
+"omega;","U+003C9"
+"omicron;","U+003BF"
+"omid;","U+029B6"
+"ominus;","U+02296"
+"oopf;","U+1D560"
+"opar;","U+029B7"
+"operp;","U+029B9"
+"oplus;","U+02295"
+"or;","U+02228"
+"orarr;","U+021BB"
+"ord;","U+02A5D"
+"order;","U+02134"
+"orderof;","U+02134"
+"ordf;","U+000AA"
+"ordf","U+000AA"
+"ordm;","U+000BA"
+"ordm","U+000BA"
+"origof;","U+022B6"
+"oror;","U+02A56"
+"orslope;","U+02A57"
+"orv;","U+02A5B"
+"oscr;","U+02134"
+"oslash;","U+000F8"
+"oslash","U+000F8"
+"osol;","U+02298"
+"otilde;","U+000F5"
+"otilde","U+000F5"
+"otimes;","U+02297"
+"otimesas;","U+02A36"
+"ouml;","U+000F6"
+"ouml","U+000F6"
+"ovbar;","U+0233D"
+"par;","U+02225"
+"para;","U+000B6"
+"para","U+000B6"
+"parallel;","U+02225"
+"parsim;","U+02AF3"
+"parsl;","U+02AFD"
+"part;","U+02202"
+"pcy;","U+0043F"
+"percnt;","U+00025"
+"period;","U+0002E"
+"permil;","U+02030"
+"perp;","U+022A5"
+"pertenk;","U+02031"
+"pfr;","U+1D52D"
+"phi;","U+003C6"
+"phiv;","U+003D5"
+"phmmat;","U+02133"
+"phone;","U+0260E"
+"pi;","U+003C0"
+"pitchfork;","U+022D4"
+"piv;","U+003D6"
+"planck;","U+0210F"
+"planckh;","U+0210E"
+"plankv;","U+0210F"
+"plus;","U+0002B"
+"plusacir;","U+02A23"
+"plusb;","U+0229E"
+"pluscir;","U+02A22"
+"plusdo;","U+02214"
+"plusdu;","U+02A25"
+"pluse;","U+02A72"
+"plusmn;","U+000B1"
+"plusmn","U+000B1"
+"plussim;","U+02A26"
+"plustwo;","U+02A27"
+"pm;","U+000B1"
+"pointint;","U+02A15"
+"popf;","U+1D561"
+"pound;","U+000A3"
+"pound","U+000A3"
+"pr;","U+0227A"
+"prE;","U+02AB3"
+"prap;","U+02AB7"
+"prcue;","U+0227C"
+"pre;","U+02AAF"
+"prec;","U+0227A"
+"precapprox;","U+02AB7"
+"preccurlyeq;","U+0227C"
+"preceq;","U+02AAF"
+"precnapprox;","U+02AB9"
+"precneqq;","U+02AB5"
+"precnsim;","U+022E8"
+"precsim;","U+0227E"
+"prime;","U+02032"
+"primes;","U+02119"
+"prnE;","U+02AB5"
+"prnap;","U+02AB9"
+"prnsim;","U+022E8"
+"prod;","U+0220F"
+"profalar;","U+0232E"
+"profline;","U+02312"
+"profsurf;","U+02313"
+"prop;","U+0221D"
+"propto;","U+0221D"
+"prsim;","U+0227E"
+"prurel;","U+022B0"
+"pscr;","U+1D4C5"
+"psi;","U+003C8"
+"puncsp;","U+02008"
+"qfr;","U+1D52E"
+"qint;","U+02A0C"
+"qopf;","U+1D562"
+"qprime;","U+02057"
+"qscr;","U+1D4C6"
+"quaternions;","U+0210D"
+"quatint;","U+02A16"
+"quest;","U+0003F"
+"questeq;","U+0225F"
+"quot;","U+00022"
+"quot","U+00022"
+"rAarr;","U+021DB"
+"rArr;","U+021D2"
+"rAtail;","U+0291C"
+"rBarr;","U+0290F"
+"rHar;","U+02964"
+"racute;","U+00155"
+"radic;","U+0221A"
+"raemptyv;","U+029B3"
+"rang;","U+027E9"
+"rangd;","U+02992"
+"range;","U+029A5"
+"rangle;","U+027E9"
+"raquo;","U+000BB"
+"raquo","U+000BB"
+"rarr;","U+02192"
+"rarrap;","U+02975"
+"rarrb;","U+021E5"
+"rarrbfs;","U+02920"
+"rarrc;","U+02933"
+"rarrfs;","U+0291E"
+"rarrhk;","U+021AA"
+"rarrlp;","U+021AC"
+"rarrpl;","U+02945"
+"rarrsim;","U+02974"
+"rarrtl;","U+021A3"
+"rarrw;","U+0219D"
+"ratail;","U+0291A"
+"ratio;","U+02236"
+"rationals;","U+0211A"
+"rbarr;","U+0290D"
+"rbbrk;","U+02773"
+"rbrace;","U+0007D"
+"rbrack;","U+0005D"
+"rbrke;","U+0298C"
+"rbrksld;","U+0298E"
+"rbrkslu;","U+02990"
+"rcaron;","U+00159"
+"rcedil;","U+00157"
+"rceil;","U+02309"
+"rcub;","U+0007D"
+"rcy;","U+00440"
+"rdca;","U+02937"
+"rdldhar;","U+02969"
+"rdquo;","U+0201D"
+"rdquor;","U+0201D"
+"rdsh;","U+021B3"
+"real;","U+0211C"
+"realine;","U+0211B"
+"realpart;","U+0211C"
+"reals;","U+0211D"
+"rect;","U+025AD"
+"reg;","U+000AE"
+"reg","U+000AE"
+"rfisht;","U+0297D"
+"rfloor;","U+0230B"
+"rfr;","U+1D52F"
+"rhard;","U+021C1"
+"rharu;","U+021C0"
+"rharul;","U+0296C"
+"rho;","U+003C1"
+"rhov;","U+003F1"
+"rightarrow;","U+02192"
+"rightarrowtail;","U+021A3"
+"rightharpoondown;","U+021C1"
+"rightharpoonup;","U+021C0"
+"rightleftarrows;","U+021C4"
+"rightleftharpoons;","U+021CC"
+"rightrightarrows;","U+021C9"
+"rightsquigarrow;","U+0219D"
+"rightthreetimes;","U+022CC"
+"ring;","U+002DA"
+"risingdotseq;","U+02253"
+"rlarr;","U+021C4"
+"rlhar;","U+021CC"
+"rlm;","U+0200F"
+"rmoust;","U+023B1"
+"rmoustache;","U+023B1"
+"rnmid;","U+02AEE"
+"roang;","U+027ED"
+"roarr;","U+021FE"
+"robrk;","U+027E7"
+"ropar;","U+02986"
+"ropf;","U+1D563"
+"roplus;","U+02A2E"
+"rotimes;","U+02A35"
+"rpar;","U+00029"
+"rpargt;","U+02994"
+"rppolint;","U+02A12"
+"rrarr;","U+021C9"
+"rsaquo;","U+0203A"
+"rscr;","U+1D4C7"
+"rsh;","U+021B1"
+"rsqb;","U+0005D"
+"rsquo;","U+02019"
+"rsquor;","U+02019"
+"rthree;","U+022CC"
+"rtimes;","U+022CA"
+"rtri;","U+025B9"
+"rtrie;","U+022B5"
+"rtrif;","U+025B8"
+"rtriltri;","U+029CE"
+"ruluhar;","U+02968"
+"rx;","U+0211E"
+"sacute;","U+0015B"
+"sbquo;","U+0201A"
+"sc;","U+0227B"
+"scE;","U+02AB4"
+"scap;","U+02AB8"
+"scaron;","U+00161"
+"sccue;","U+0227D"
+"sce;","U+02AB0"
+"scedil;","U+0015F"
+"scirc;","U+0015D"
+"scnE;","U+02AB6"
+"scnap;","U+02ABA"
+"scnsim;","U+022E9"
+"scpolint;","U+02A13"
+"scsim;","U+0227F"
+"scy;","U+00441"
+"sdot;","U+022C5"
+"sdotb;","U+022A1"
+"sdote;","U+02A66"
+"seArr;","U+021D8"
+"searhk;","U+02925"
+"searr;","U+02198"
+"searrow;","U+02198"
+"sect;","U+000A7"
+"sect","U+000A7"
+"semi;","U+0003B"
+"seswar;","U+02929"
+"setminus;","U+02216"
+"setmn;","U+02216"
+"sext;","U+02736"
+"sfr;","U+1D530"
+"sfrown;","U+02322"
+"sharp;","U+0266F"
+"shchcy;","U+00449"
+"shcy;","U+00448"
+"shortmid;","U+02223"
+"shortparallel;","U+02225"
+"shy;","U+000AD"
+"shy","U+000AD"
+"sigma;","U+003C3"
+"sigmaf;","U+003C2"
+"sigmav;","U+003C2"
+"sim;","U+0223C"
+"simdot;","U+02A6A"
+"sime;","U+02243"
+"simeq;","U+02243"
+"simg;","U+02A9E"
+"simgE;","U+02AA0"
+"siml;","U+02A9D"
+"simlE;","U+02A9F"
+"simne;","U+02246"
+"simplus;","U+02A24"
+"simrarr;","U+02972"
+"slarr;","U+02190"
+"smallsetminus;","U+02216"
+"smashp;","U+02A33"
+"smeparsl;","U+029E4"
+"smid;","U+02223"
+"smile;","U+02323"
+"smt;","U+02AAA"
+"smte;","U+02AAC"
+"softcy;","U+0044C"
+"sol;","U+0002F"
+"solb;","U+029C4"
+"solbar;","U+0233F"
+"sopf;","U+1D564"
+"spades;","U+02660"
+"spadesuit;","U+02660"
+"spar;","U+02225"
+"sqcap;","U+02293"
+"sqcup;","U+02294"
+"sqsub;","U+0228F"
+"sqsube;","U+02291"
+"sqsubset;","U+0228F"
+"sqsubseteq;","U+02291"
+"sqsup;","U+02290"
+"sqsupe;","U+02292"
+"sqsupset;","U+02290"
+"sqsupseteq;","U+02292"
+"squ;","U+025A1"
+"square;","U+025A1"
+"squarf;","U+025AA"
+"squf;","U+025AA"
+"srarr;","U+02192"
+"sscr;","U+1D4C8"
+"ssetmn;","U+02216"
+"ssmile;","U+02323"
+"sstarf;","U+022C6"
+"star;","U+02606"
+"starf;","U+02605"
+"straightepsilon;","U+003F5"
+"straightphi;","U+003D5"
+"strns;","U+000AF"
+"sub;","U+02282"
+"subE;","U+02AC5"
+"subdot;","U+02ABD"
+"sube;","U+02286"
+"subedot;","U+02AC3"
+"submult;","U+02AC1"
+"subnE;","U+02ACB"
+"subne;","U+0228A"
+"subplus;","U+02ABF"
+"subrarr;","U+02979"
+"subset;","U+02282"
+"subseteq;","U+02286"
+"subseteqq;","U+02AC5"
+"subsetneq;","U+0228A"
+"subsetneqq;","U+02ACB"
+"subsim;","U+02AC7"
+"subsub;","U+02AD5"
+"subsup;","U+02AD3"
+"succ;","U+0227B"
+"succapprox;","U+02AB8"
+"succcurlyeq;","U+0227D"
+"succeq;","U+02AB0"
+"succnapprox;","U+02ABA"
+"succneqq;","U+02AB6"
+"succnsim;","U+022E9"
+"succsim;","U+0227F"
+"sum;","U+02211"
+"sung;","U+0266A"
+"sup1;","U+000B9"
+"sup1","U+000B9"
+"sup2;","U+000B2"
+"sup2","U+000B2"
+"sup3;","U+000B3"
+"sup3","U+000B3"
+"sup;","U+02283"
+"supE;","U+02AC6"
+"supdot;","U+02ABE"
+"supdsub;","U+02AD8"
+"supe;","U+02287"
+"supedot;","U+02AC4"
+"suphsol;","U+027C9"
+"suphsub;","U+02AD7"
+"suplarr;","U+0297B"
+"supmult;","U+02AC2"
+"supnE;","U+02ACC"
+"supne;","U+0228B"
+"supplus;","U+02AC0"
+"supset;","U+02283"
+"supseteq;","U+02287"
+"supseteqq;","U+02AC6"
+"supsetneq;","U+0228B"
+"supsetneqq;","U+02ACC"
+"supsim;","U+02AC8"
+"supsub;","U+02AD4"
+"supsup;","U+02AD6"
+"swArr;","U+021D9"
+"swarhk;","U+02926"
+"swarr;","U+02199"
+"swarrow;","U+02199"
+"swnwar;","U+0292A"
+"szlig;","U+000DF"
+"szlig","U+000DF"
+"target;","U+02316"
+"tau;","U+003C4"
+"tbrk;","U+023B4"
+"tcaron;","U+00165"
+"tcedil;","U+00163"
+"tcy;","U+00442"
+"tdot;","U+020DB"
+"telrec;","U+02315"
+"tfr;","U+1D531"
+"there4;","U+02234"
+"therefore;","U+02234"
+"theta;","U+003B8"
+"thetasym;","U+003D1"
+"thetav;","U+003D1"
+"thickapprox;","U+02248"
+"thicksim;","U+0223C"
+"thinsp;","U+02009"
+"thkap;","U+02248"
+"thksim;","U+0223C"
+"thorn;","U+000FE"
+"thorn","U+000FE"
+"tilde;","U+002DC"
+"times;","U+000D7"
+"times","U+000D7"
+"timesb;","U+022A0"
+"timesbar;","U+02A31"
+"timesd;","U+02A30"
+"tint;","U+0222D"
+"toea;","U+02928"
+"top;","U+022A4"
+"topbot;","U+02336"
+"topcir;","U+02AF1"
+"topf;","U+1D565"
+"topfork;","U+02ADA"
+"tosa;","U+02929"
+"tprime;","U+02034"
+"trade;","U+02122"
+"triangle;","U+025B5"
+"triangledown;","U+025BF"
+"triangleleft;","U+025C3"
+"trianglelefteq;","U+022B4"
+"triangleq;","U+0225C"
+"triangleright;","U+025B9"
+"trianglerighteq;","U+022B5"
+"tridot;","U+025EC"
+"trie;","U+0225C"
+"triminus;","U+02A3A"
+"triplus;","U+02A39"
+"trisb;","U+029CD"
+"tritime;","U+02A3B"
+"trpezium;","U+023E2"
+"tscr;","U+1D4C9"
+"tscy;","U+00446"
+"tshcy;","U+0045B"
+"tstrok;","U+00167"
+"twixt;","U+0226C"
+"twoheadleftarrow;","U+0219E"
+"twoheadrightarrow;","U+021A0"
+"uArr;","U+021D1"
+"uHar;","U+02963"
+"uacute;","U+000FA"
+"uacute","U+000FA"
+"uarr;","U+02191"
+"ubrcy;","U+0045E"
+"ubreve;","U+0016D"
+"ucirc;","U+000FB"
+"ucirc","U+000FB"
+"ucy;","U+00443"
+"udarr;","U+021C5"
+"udblac;","U+00171"
+"udhar;","U+0296E"
+"ufisht;","U+0297E"
+"ufr;","U+1D532"
+"ugrave;","U+000F9"
+"ugrave","U+000F9"
+"uharl;","U+021BF"
+"uharr;","U+021BE"
+"uhblk;","U+02580"
+"ulcorn;","U+0231C"
+"ulcorner;","U+0231C"
+"ulcrop;","U+0230F"
+"ultri;","U+025F8"
+"umacr;","U+0016B"
+"uml;","U+000A8"
+"uml","U+000A8"
+"uogon;","U+00173"
+"uopf;","U+1D566"
+"uparrow;","U+02191"
+"updownarrow;","U+02195"
+"upharpoonleft;","U+021BF"
+"upharpoonright;","U+021BE"
+"uplus;","U+0228E"
+"upsi;","U+003C5"
+"upsih;","U+003D2"
+"upsilon;","U+003C5"
+"upuparrows;","U+021C8"
+"urcorn;","U+0231D"
+"urcorner;","U+0231D"
+"urcrop;","U+0230E"
+"uring;","U+0016F"
+"urtri;","U+025F9"
+"uscr;","U+1D4CA"
+"utdot;","U+022F0"
+"utilde;","U+00169"
+"utri;","U+025B5"
+"utrif;","U+025B4"
+"uuarr;","U+021C8"
+"uuml;","U+000FC"
+"uuml","U+000FC"
+"uwangle;","U+029A7"
+"vArr;","U+021D5"
+"vBar;","U+02AE8"
+"vBarv;","U+02AE9"
+"vDash;","U+022A8"
+"vangrt;","U+0299C"
+"varepsilon;","U+003F5"
+"varkappa;","U+003F0"
+"varnothing;","U+02205"
+"varphi;","U+003D5"
+"varpi;","U+003D6"
+"varpropto;","U+0221D"
+"varr;","U+02195"
+"varrho;","U+003F1"
+"varsigma;","U+003C2"
+"vartheta;","U+003D1"
+"vartriangleleft;","U+022B2"
+"vartriangleright;","U+022B3"
+"vcy;","U+00432"
+"vdash;","U+022A2"
+"vee;","U+02228"
+"veebar;","U+022BB"
+"veeeq;","U+0225A"
+"vellip;","U+022EE"
+"verbar;","U+0007C"
+"vert;","U+0007C"
+"vfr;","U+1D533"
+"vltri;","U+022B2"
+"vopf;","U+1D567"
+"vprop;","U+0221D"
+"vrtri;","U+022B3"
+"vscr;","U+1D4CB"
+"vzigzag;","U+0299A"
+"wcirc;","U+00175"
+"wedbar;","U+02A5F"
+"wedge;","U+02227"
+"wedgeq;","U+02259"
+"weierp;","U+02118"
+"wfr;","U+1D534"
+"wopf;","U+1D568"
+"wp;","U+02118"
+"wr;","U+02240"
+"wreath;","U+02240"
+"wscr;","U+1D4CC"
+"xcap;","U+022C2"
+"xcirc;","U+025EF"
+"xcup;","U+022C3"
+"xdtri;","U+025BD"
+"xfr;","U+1D535"
+"xhArr;","U+027FA"
+"xharr;","U+027F7"
+"xi;","U+003BE"
+"xlArr;","U+027F8"
+"xlarr;","U+027F5"
+"xmap;","U+027FC"
+"xnis;","U+022FB"
+"xodot;","U+02A00"
+"xopf;","U+1D569"
+"xoplus;","U+02A01"
+"xotime;","U+02A02"
+"xrArr;","U+027F9"
+"xrarr;","U+027F6"
+"xscr;","U+1D4CD"
+"xsqcup;","U+02A06"
+"xuplus;","U+02A04"
+"xutri;","U+025B3"
+"xvee;","U+022C1"
+"xwedge;","U+022C0"
+"yacute;","U+000FD"
+"yacute","U+000FD"
+"yacy;","U+0044F"
+"ycirc;","U+00177"
+"ycy;","U+0044B"
+"yen;","U+000A5"
+"yen","U+000A5"
+"yfr;","U+1D536"
+"yicy;","U+00457"
+"yopf;","U+1D56A"
+"yscr;","U+1D4CE"
+"yucy;","U+0044E"
+"yuml;","U+000FF"
+"yuml","U+000FF"
+"zacute;","U+0017A"
+"zcaron;","U+0017E"
+"zcy;","U+00437"
+"zdot;","U+0017C"
+"zeetrf;","U+02128"
+"zeta;","U+003B6"
+"zfr;","U+1D537"
+"zhcy;","U+00436"
+"zigrarr;","U+021DD"
+"zopf;","U+1D56B"
+"zscr;","U+1D4CF"
+"zwj;","U+0200D"
+"zwnj;","U+0200C"
+"acE;","U+0223E U+00333"
+"bne;","U+0003D U+020E5"
+"bnequiv;","U+02261 U+020E5"
+"caps;","U+02229 U+0FE00"
+"cups;","U+0222A U+0FE00"
+"fjlig;","U+00066 U+0006A"
+"gesl;","U+022DB U+0FE00"
+"gvertneqq;","U+02269 U+0FE00"
+"gvnE;","U+02269 U+0FE00"
+"lates;","U+02AAD U+0FE00"
+"lesg;","U+022DA U+0FE00"
+"lvertneqq;","U+02268 U+0FE00"
+"lvnE;","U+02268 U+0FE00"
+"nang;","U+02220 U+020D2"
+"napE;","U+02A70 U+00338"
+"napid;","U+0224B U+00338"
+"nbump;","U+0224E U+00338"
+"nbumpe;","U+0224F U+00338"
+"ncongdot;","U+02A6D U+00338"
+"nedot;","U+02250 U+00338"
+"nesim;","U+02242 U+00338"
+"ngE;","U+02267 U+00338"
+"ngeqq;","U+02267 U+00338"
+"ngeqslant;","U+02A7E U+00338"
+"nges;","U+02A7E U+00338"
+"nGg;","U+022D9 U+00338"
+"nGt;","U+0226B U+020D2"
+"nGtv;","U+0226B U+00338"
+"nlE;","U+02266 U+00338"
+"nleqq;","U+02266 U+00338"
+"nleqslant;","U+02A7D U+00338"
+"nles;","U+02A7D U+00338"
+"nLl;","U+022D8 U+00338"
+"nLt;","U+0226A U+020D2"
+"nLtv;","U+0226A U+00338"
+"NotEqualTilde;","U+02242 U+00338"
+"NotGreaterFullEqual;","U+02267 U+00338"
+"NotGreaterGreater;","U+0226B U+00338"
+"NotGreaterSlantEqual;","U+02A7E U+00338"
+"NotHumpDownHump;","U+0224E U+00338"
+"NotHumpEqual;","U+0224F U+00338"
+"notindot;","U+022F5 U+00338"
+"notinE;","U+022F9 U+00338"
+"NotLeftTriangleBar;","U+029CF U+00338"
+"NotLessLess;","U+0226A U+00338"
+"NotLessSlantEqual;","U+02A7D U+00338"
+"NotNestedGreaterGreater;","U+02AA2 U+00338"
+"NotNestedLessLess;","U+02AA1 U+00338"
+"NotPrecedesEqual;","U+02AAF U+00338"
+"NotRightTriangleBar;","U+029D0 U+00338"
+"NotSquareSubset;","U+0228F U+00338"
+"NotSquareSuperset;","U+02290 U+00338"
+"NotSubset;","U+02282 U+020D2"
+"NotSucceedsEqual;","U+02AB0 U+00338"
+"NotSucceedsTilde;","U+0227F U+00338"
+"NotSuperset;","U+02283 U+020D2"
+"nparsl;","U+02AFD U+020E5"
+"npart;","U+02202 U+00338"
+"npre;","U+02AAF U+00338"
+"npreceq;","U+02AAF U+00338"
+"nrarrc;","U+02933 U+00338"
+"nrarrw;","U+0219D U+00338"
+"nsce;","U+02AB0 U+00338"
+"nsubE;","U+02AC5 U+00338"
+"nsubset;","U+02282 U+020D2"
+"nsubseteqq;","U+02AC5 U+00338"
+"nsucceq;","U+02AB0 U+00338"
+"nsupE;","U+02AC6 U+00338"
+"nsupset;","U+02283 U+020D2"
+"nsupseteqq;","U+02AC6 U+00338"
+"nvap;","U+0224D U+020D2"
+"nvge;","U+02265 U+020D2"
+"nvgt;","U+0003E U+020D2"
+"nvle;","U+02264 U+020D2"
+"nvlt;","U+0003C U+020D2"
+"nvltrie;","U+022B4 U+020D2"
+"nvrtrie;","U+022B5 U+020D2"
+"nvsim;","U+0223C U+020D2"
+"race;","U+0223D U+00331"
+"smtes;","U+02AAC U+0FE00"
+"sqcaps;","U+02293 U+0FE00"
+"sqcups;","U+02294 U+0FE00"
+"ThickSpace;","U+0205F U+0200A"
+"varsubsetneq;","U+0228A U+0FE00"
+"varsubsetneqq;","U+02ACB U+0FE00"
+"varsupsetneq;","U+0228B U+0FE00"
+"varsupsetneqq;","U+02ACC U+0FE00"
+"vnsub;","U+02282 U+020D2"
+"vnsup;","U+02283 U+020D2"
+"vsubnE;","U+02ACB U+0FE00"
+"vsubne;","U+0228A U+0FE00"
+"vsupnE;","U+02ACC U+0FE00"
+"vsupne;","U+0228B U+0FE00"
diff --git a/Source/core/html/parser/HTMLEntityParser.cpp b/Source/core/html/parser/HTMLEntityParser.cpp
new file mode 100644
index 0000000..0282d6d
--- /dev/null
+++ b/Source/core/html/parser/HTMLEntityParser.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/
+ * 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. 
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLEntityParser.h"
+
+#include "core/html/parser/HTMLEntitySearch.h"
+#include "core/html/parser/HTMLEntityTable.h"
+#include "core/xml/parser/CharacterReferenceParserInlines.h"
+#include <wtf/text/StringBuilder.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+static const UChar windowsLatin1ExtensionArray[32] = {
+    0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, // 80-87
+    0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F, // 88-8F
+    0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, // 90-97
+    0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178, // 98-9F
+};
+
+static inline bool isAlphaNumeric(UChar cc)
+{
+    return (cc >= '0' && cc <= '9') || (cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z');
+}
+
+class HTMLEntityParser {
+public:
+    inline static UChar adjustEntity(UChar32 value)
+    {
+        if ((value & ~0x1F) != 0x0080)
+            return value;
+        return windowsLatin1ExtensionArray[value - 0x80];
+    }
+
+    inline static UChar32 legalEntityFor(UChar32 value)
+    {
+        // FIXME: A number of specific entity values generate parse errors.
+        if (!value || value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF))
+            return 0xFFFD;
+        if (U_IS_BMP(value))
+            return adjustEntity(value);
+        return value;
+    }
+
+    inline static bool acceptMalformed() { return true; }
+
+    inline static bool consumeNamedEntity(SegmentedString& source, StringBuilder& decodedEntity, bool& notEnoughCharacters, UChar additionalAllowedCharacter, UChar& cc)
+    {
+        StringBuilder consumedCharacters;
+        HTMLEntitySearch entitySearch;
+        while (!source.isEmpty()) {
+            cc = source.currentChar();
+            entitySearch.advance(cc);
+            if (!entitySearch.isEntityPrefix())
+                break;
+            consumedCharacters.append(cc);
+            source.advanceAndASSERT(cc);
+        }
+        notEnoughCharacters = source.isEmpty();
+        if (notEnoughCharacters) {
+            // We can't an entity because there might be a longer entity
+            // that we could match if we had more data.
+            unconsumeCharacters(source, consumedCharacters);
+            return false;
+        }
+        if (!entitySearch.mostRecentMatch()) {
+            unconsumeCharacters(source, consumedCharacters);
+            return false;
+        }
+        if (entitySearch.mostRecentMatch()->length != entitySearch.currentLength()) {
+            // We've consumed too many characters. We need to walk the
+            // source back to the point at which we had consumed an
+            // actual entity.
+            unconsumeCharacters(source, consumedCharacters);
+            consumedCharacters.clear();
+            const int length = entitySearch.mostRecentMatch()->length;
+            const UChar* reference = entitySearch.mostRecentMatch()->entity;
+            for (int i = 0; i < length; ++i) {
+                cc = source.currentChar();
+                ASSERT_UNUSED(reference, cc == *reference++);
+                consumedCharacters.append(cc);
+                source.advanceAndASSERT(cc);
+                ASSERT(!source.isEmpty());
+            }
+            cc = source.currentChar();
+        }
+        if (entitySearch.mostRecentMatch()->lastCharacter() == ';'
+            || !additionalAllowedCharacter
+            || !(isAlphaNumeric(cc) || cc == '=')) {
+            decodedEntity.append(entitySearch.mostRecentMatch()->firstValue);
+            if (entitySearch.mostRecentMatch()->secondValue)
+                decodedEntity.append(entitySearch.mostRecentMatch()->secondValue);
+            return true;
+        }
+        unconsumeCharacters(source, consumedCharacters);
+        return false;
+    }
+};
+
+bool consumeHTMLEntity(SegmentedString& source, StringBuilder& decodedEntity, bool& notEnoughCharacters, UChar additionalAllowedCharacter)
+{
+    return consumeCharacterReference<HTMLEntityParser>(source, decodedEntity, notEnoughCharacters, additionalAllowedCharacter);
+}
+
+static size_t appendUChar32ToUCharArray(UChar32 value, UChar* result)
+{
+    if (U_IS_BMP(value)) {
+        UChar character = static_cast<UChar>(value);
+        ASSERT(character == value);
+        result[0] = character;
+        return 1;
+    }
+
+    result[0] = U16_LEAD(value);
+    result[1] = U16_TRAIL(value);
+    return 2;
+}
+
+size_t decodeNamedEntityToUCharArray(const char* name, UChar result[4])
+{
+    HTMLEntitySearch search;
+    while (*name) {
+        search.advance(*name++);
+        if (!search.isEntityPrefix())
+            return 0;
+    }
+    search.advance(';');
+    if (!search.isEntityPrefix())
+        return 0;
+
+    size_t numberOfCodePoints = appendUChar32ToUCharArray(search.mostRecentMatch()->firstValue, result);
+    if (!search.mostRecentMatch()->secondValue)
+        return numberOfCodePoints;
+    return numberOfCodePoints + appendUChar32ToUCharArray(search.mostRecentMatch()->secondValue, result + numberOfCodePoints);
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/parser/HTMLEntityParser.h b/Source/core/html/parser/HTMLEntityParser.h
new file mode 100644
index 0000000..3b197a5
--- /dev/null
+++ b/Source/core/html/parser/HTMLEntityParser.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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 HTMLEntityParser_h
+#define HTMLEntityParser_h
+
+#include "core/platform/text/SegmentedString.h"
+
+namespace WebCore {
+
+bool consumeHTMLEntity(SegmentedString&, StringBuilder& decodedEntity, bool& notEnoughCharacters, UChar additionalAllowedCharacter = '\0');
+
+// Used by the XML parser.  Not suitable for use in HTML parsing.  Use consumeHTMLEntity instead.
+size_t decodeNamedEntityToUCharArray(const char*, UChar result[4]);
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLEntitySearch.cpp b/Source/core/html/parser/HTMLEntitySearch.cpp
new file mode 100644
index 0000000..9612db1
--- /dev/null
+++ b/Source/core/html/parser/HTMLEntitySearch.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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. 
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLEntitySearch.h"
+
+#include "core/html/parser/HTMLEntityTable.h"
+
+namespace WebCore {
+
+static const HTMLEntityTableEntry* halfway(const HTMLEntityTableEntry* left, const HTMLEntityTableEntry* right)
+{
+    return &left[(right - left) / 2];
+}
+
+HTMLEntitySearch::HTMLEntitySearch()
+    : m_currentLength(0)
+    , m_mostRecentMatch(0)
+    , m_first(HTMLEntityTable::firstEntry())
+    , m_last(HTMLEntityTable::lastEntry())
+{
+}
+
+HTMLEntitySearch::CompareResult HTMLEntitySearch::compare(const HTMLEntityTableEntry* entry, UChar nextCharacter) const
+{
+    if (entry->length < m_currentLength + 1)
+        return Before;
+    UChar entryNextCharacter = entry->entity[m_currentLength];
+    if (entryNextCharacter == nextCharacter)
+        return Prefix;
+    return entryNextCharacter < nextCharacter ? Before : After;
+}
+
+const HTMLEntityTableEntry* HTMLEntitySearch::findFirst(UChar nextCharacter) const
+{
+    const HTMLEntityTableEntry* left = m_first;
+    const HTMLEntityTableEntry* right = m_last;
+    if (left == right)
+        return left;
+    CompareResult result = compare(left, nextCharacter);
+    if (result == Prefix)
+        return left;
+    if (result == After)
+        return right;
+    while (left + 1 < right) {
+        const HTMLEntityTableEntry* probe = halfway(left, right);
+        result = compare(probe, nextCharacter);
+        if (result == Before)
+            left = probe;
+        else {
+            ASSERT(result == After || result == Prefix);
+            right = probe;
+        }
+    }
+    ASSERT(left + 1 == right);
+    return right;
+}
+
+const HTMLEntityTableEntry* HTMLEntitySearch::findLast(UChar nextCharacter) const
+{
+    const HTMLEntityTableEntry* left = m_first;
+    const HTMLEntityTableEntry* right = m_last;
+    if (left == right)
+        return right;
+    CompareResult result = compare(right, nextCharacter);
+    if (result == Prefix)
+        return right;
+    if (result == Before)
+        return left;
+    while (left + 1 < right) {
+        const HTMLEntityTableEntry* probe = halfway(left, right);
+        result = compare(probe, nextCharacter);
+        if (result == After)
+            right = probe;
+        else {
+            ASSERT(result == Before || result == Prefix);
+            left = probe;
+        }
+    }
+    ASSERT(left + 1 == right);
+    return left;
+}
+
+void HTMLEntitySearch::advance(UChar nextCharacter)
+{
+    ASSERT(isEntityPrefix());
+    if (!m_currentLength) {
+        m_first = HTMLEntityTable::firstEntryStartingWith(nextCharacter);
+        m_last = HTMLEntityTable::lastEntryStartingWith(nextCharacter);
+        if (!m_first || !m_last)
+            return fail();
+    } else {
+        m_first = findFirst(nextCharacter);
+        m_last = findLast(nextCharacter);
+        if (m_first == m_last && compare(m_first, nextCharacter) != Prefix)
+            return fail();
+    }
+    ++m_currentLength;
+    if (m_first->length != m_currentLength) {
+        return;
+    }
+    m_mostRecentMatch = m_first;
+}
+
+}
diff --git a/Source/core/html/parser/HTMLEntitySearch.h b/Source/core/html/parser/HTMLEntitySearch.h
new file mode 100644
index 0000000..0cb5920
--- /dev/null
+++ b/Source/core/html/parser/HTMLEntitySearch.h
@@ -0,0 +1,72 @@
+/*
+ * 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 HTMLEntitySearch_h
+#define HTMLEntitySearch_h
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+struct HTMLEntityTableEntry;
+
+class HTMLEntitySearch {
+public:
+    HTMLEntitySearch();
+
+    void advance(UChar);
+
+    bool isEntityPrefix() const { return !!m_first; }
+    int currentLength() const { return m_currentLength; }
+
+    const HTMLEntityTableEntry* mostRecentMatch() const { return m_mostRecentMatch; }
+
+private:
+    enum CompareResult {
+        Before,
+        Prefix,
+        After,
+    };
+
+    CompareResult compare(const HTMLEntityTableEntry*, UChar) const;
+    const HTMLEntityTableEntry* findFirst(UChar) const;
+    const HTMLEntityTableEntry* findLast(UChar) const;
+
+    void fail()
+    {
+        m_first = 0;
+        m_last = 0;
+    }
+
+    int m_currentLength;
+
+    const HTMLEntityTableEntry* m_mostRecentMatch;
+    const HTMLEntityTableEntry* m_first;
+    const HTMLEntityTableEntry* m_last;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLEntityTable.h b/Source/core/html/parser/HTMLEntityTable.h
new file mode 100644
index 0000000..5293f46
--- /dev/null
+++ b/Source/core/html/parser/HTMLEntityTable.h
@@ -0,0 +1,53 @@
+/*
+ * 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 HTMLEntityTable_h
+#define HTMLEntityTable_h
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+struct HTMLEntityTableEntry {
+    UChar lastCharacter() const { return entity[length - 1]; }
+
+    const UChar* entity;
+    int length;
+    UChar32 firstValue;
+    UChar32 secondValue;
+};
+
+class HTMLEntityTable {
+public:
+    static const HTMLEntityTableEntry* firstEntry();
+    static const HTMLEntityTableEntry* lastEntry();
+
+    static const HTMLEntityTableEntry* firstEntryStartingWith(UChar);
+    static const HTMLEntityTableEntry* lastEntryStartingWith(UChar);
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLFormattingElementList.cpp b/Source/core/html/parser/HTMLFormattingElementList.cpp
new file mode 100644
index 0000000..303d485
--- /dev/null
+++ b/Source/core/html/parser/HTMLFormattingElementList.cpp
@@ -0,0 +1,221 @@
+/*
+ * 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 GOOGLE 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 GOOGLE 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. 
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLFormattingElementList.h"
+
+#include "core/dom/Element.h"
+#include "core/platform/NotImplemented.h"
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+namespace WebCore {
+
+// Biblically, Noah's Ark only had room for two of each animal, but in the
+// Book of Hixie (aka http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#list-of-active-formatting-elements),
+// Noah's Ark of Formatting Elements can fit three of each element.
+static const size_t kNoahsArkCapacity = 3;
+
+HTMLFormattingElementList::HTMLFormattingElementList()
+{
+}
+
+HTMLFormattingElementList::~HTMLFormattingElementList()
+{
+}
+
+Element* HTMLFormattingElementList::closestElementInScopeWithName(const AtomicString& targetName)
+{
+    for (unsigned i = 1; i <= m_entries.size(); ++i) {
+        const Entry& entry = m_entries[m_entries.size() - i];
+        if (entry.isMarker())
+            return 0;
+        if (entry.stackItem()->matchesHTMLTag(targetName))
+            return entry.element();
+    }
+    return 0;
+}
+
+bool HTMLFormattingElementList::contains(Element* element)
+{
+    return !!find(element);
+}
+
+HTMLFormattingElementList::Entry* HTMLFormattingElementList::find(Element* element)
+{
+    size_t index = m_entries.reverseFind(element);
+    if (index != notFound) {
+        // This is somewhat of a hack, and is why this method can't be const.
+        return &m_entries[index];
+    }
+    return 0;
+}
+
+HTMLFormattingElementList::Bookmark HTMLFormattingElementList::bookmarkFor(Element* element)
+{
+    size_t index = m_entries.reverseFind(element);
+    ASSERT(index != notFound);
+    return Bookmark(&at(index));
+}
+
+void HTMLFormattingElementList::swapTo(Element* oldElement, PassRefPtr<HTMLStackItem> newItem, const Bookmark& bookmark)
+{
+    ASSERT(contains(oldElement));
+    ASSERT(!contains(newItem->element()));
+    if (!bookmark.hasBeenMoved()) {
+        ASSERT(bookmark.mark()->element() == oldElement);
+        bookmark.mark()->replaceElement(newItem);
+        return;
+    }
+    size_t index = bookmark.mark() - first();
+    ASSERT_WITH_SECURITY_IMPLICATION(index < size());
+    m_entries.insert(index + 1, newItem);
+    remove(oldElement);
+}
+
+void HTMLFormattingElementList::append(PassRefPtr<HTMLStackItem> item)
+{
+    ensureNoahsArkCondition(item.get());
+    m_entries.append(item);
+}
+
+void HTMLFormattingElementList::remove(Element* element)
+{
+    size_t index = m_entries.reverseFind(element);
+    if (index != notFound)
+        m_entries.remove(index);
+}
+
+void HTMLFormattingElementList::appendMarker()
+{
+    m_entries.append(Entry::MarkerEntry);
+}
+
+void HTMLFormattingElementList::clearToLastMarker()
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#clear-the-list-of-active-formatting-elements-up-to-the-last-marker
+    while (m_entries.size()) {
+        bool shouldStop = m_entries.last().isMarker();
+        m_entries.removeLast();
+        if (shouldStop)
+            break;
+    }
+}
+
+void HTMLFormattingElementList::tryToEnsureNoahsArkConditionQuickly(HTMLStackItem* newItem, Vector<HTMLStackItem*>& remainingCandidates)
+{
+    ASSERT(remainingCandidates.isEmpty());
+
+    if (m_entries.size() < kNoahsArkCapacity)
+        return;
+
+    // Use a vector with inline capacity to avoid a malloc in the common case
+    // of a quickly ensuring the condition.
+    Vector<HTMLStackItem*, 10> candidates;
+
+    size_t newItemAttributeCount = newItem->attributes().size();
+
+    for (size_t i = m_entries.size(); i; ) {
+        --i;
+        Entry& entry = m_entries[i];
+        if (entry.isMarker())
+            break;
+
+        // Quickly reject obviously non-matching candidates.
+        HTMLStackItem* candidate = entry.stackItem().get();
+        if (newItem->localName() != candidate->localName() || newItem->namespaceURI() != candidate->namespaceURI())
+            continue;
+        if (candidate->attributes().size() != newItemAttributeCount)
+            continue;
+
+        candidates.append(candidate);
+    }
+
+    if (candidates.size() < kNoahsArkCapacity)
+        return; // There's room for the new element in the ark. There's no need to copy out the remainingCandidates.
+
+    remainingCandidates.append(candidates);
+}
+
+void HTMLFormattingElementList::ensureNoahsArkCondition(HTMLStackItem* newItem)
+{
+    Vector<HTMLStackItem*> candidates;
+    tryToEnsureNoahsArkConditionQuickly(newItem, candidates);
+    if (candidates.isEmpty())
+        return;
+
+    // We pre-allocate and re-use this second vector to save one malloc per
+    // attribute that we verify.
+    Vector<HTMLStackItem*> remainingCandidates;
+    remainingCandidates.reserveInitialCapacity(candidates.size());
+
+    const Vector<Attribute>& attributes = newItem->attributes();
+    for (size_t i = 0; i < attributes.size(); ++i) {
+        const Attribute& attribute = attributes[i];
+
+        for (size_t j = 0; j < candidates.size(); ++j) {
+            HTMLStackItem* candidate = candidates[j];
+
+            // These properties should already have been checked by tryToEnsureNoahsArkConditionQuickly.
+            ASSERT(newItem->attributes().size() == candidate->attributes().size());
+            ASSERT(newItem->localName() == candidate->localName() && newItem->namespaceURI() == candidate->namespaceURI());
+
+            Attribute* candidateAttribute = candidate->getAttributeItem(attribute.name());
+            if (candidateAttribute && candidateAttribute->value() == attribute.value())
+                remainingCandidates.append(candidate);
+        }
+
+        if (remainingCandidates.size() < kNoahsArkCapacity)
+            return;
+
+        candidates.swap(remainingCandidates);
+        remainingCandidates.shrink(0);
+    }
+
+    // Inductively, we shouldn't spin this loop very many times. It's possible,
+    // however, that we wil spin the loop more than once because of how the
+    // formatting element list gets permuted.
+    for (size_t i = kNoahsArkCapacity - 1; i < candidates.size(); ++i)
+        remove(candidates[i]->element());
+}
+
+#ifndef NDEBUG
+
+void HTMLFormattingElementList::show()
+{
+    for (unsigned i = 1; i <= m_entries.size(); ++i) {
+        const Entry& entry = m_entries[m_entries.size() - i];
+        if (entry.isMarker())
+            fprintf(stderr, "marker\n");
+        else
+            entry.element()->showNode();
+    }
+}
+
+#endif
+
+}
diff --git a/Source/core/html/parser/HTMLFormattingElementList.h b/Source/core/html/parser/HTMLFormattingElementList.h
new file mode 100644
index 0000000..24ba01f
--- /dev/null
+++ b/Source/core/html/parser/HTMLFormattingElementList.h
@@ -0,0 +1,141 @@
+/*
+ * 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 GOOGLE 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 GOOGLE 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 HTMLFormattingElementList_h
+#define HTMLFormattingElementList_h
+
+#include "core/html/parser/HTMLStackItem.h"
+#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Element;
+
+// This may end up merged into HTMLElementStack.
+class HTMLFormattingElementList {
+    WTF_MAKE_NONCOPYABLE(HTMLFormattingElementList);
+public:
+    HTMLFormattingElementList();
+    ~HTMLFormattingElementList();
+
+    // Ideally Entry would be private, but HTMLTreeBuilder has to coordinate
+    // between the HTMLFormattingElementList and HTMLElementStack and needs
+    // access to Entry::isMarker() and Entry::replaceElement() to do so.
+    class Entry {
+    public:
+        // Inline because they're hot and Vector<T> uses them.
+        explicit Entry(PassRefPtr<HTMLStackItem> item)
+            : m_item(item)
+        {
+        }
+        enum MarkerEntryType { MarkerEntry };
+        Entry(MarkerEntryType)
+            : m_item(0)
+        {
+        }
+        ~Entry() {}
+
+        bool isMarker() const { return !m_item; }
+
+        PassRefPtr<HTMLStackItem> stackItem() const { return m_item; }
+        Element* element() const
+        {
+            // The fact that !m_item == isMarker() is an implementation detail
+            // callers should check isMarker() before calling element().
+            ASSERT(m_item);
+            return m_item->element();
+        }
+        void replaceElement(PassRefPtr<HTMLStackItem> item) { m_item = item; }
+
+        // Needed for use with Vector.  These are super-hot and must be inline.
+        bool operator==(Element* element) const { return !m_item ? !element : m_item->element() == element; }
+        bool operator!=(Element* element) const { return !m_item ? !!element : m_item->element() != element; }
+
+    private:
+        RefPtr<HTMLStackItem> m_item;
+    };
+
+    class Bookmark {
+    public:
+        Bookmark(Entry* entry)
+            : m_hasBeenMoved(false)
+            , m_mark(entry)
+        {
+        }
+
+        void moveToAfter(Entry* before)
+        {
+            m_hasBeenMoved = true;
+            m_mark = before;
+        }
+
+        bool hasBeenMoved() const { return m_hasBeenMoved; }
+        Entry* mark() const { return m_mark; }
+
+    private:
+        bool m_hasBeenMoved;
+        Entry* m_mark;
+    };
+
+    bool isEmpty() const { return !size(); }
+    size_t size() const { return m_entries.size(); }
+
+    Element* closestElementInScopeWithName(const AtomicString&);
+
+    Entry* find(Element*);
+    bool contains(Element*);
+    void append(PassRefPtr<HTMLStackItem>);
+    void remove(Element*);
+
+    Bookmark bookmarkFor(Element*);
+    void swapTo(Element* oldElement, PassRefPtr<HTMLStackItem> newItem, const Bookmark&);
+
+    void appendMarker();
+    // clearToLastMarker also clears the marker (per the HTML5 spec).
+    void clearToLastMarker();
+
+    const Entry& at(size_t i) const { return m_entries[i]; }
+    Entry& at(size_t i) { return m_entries[i]; }
+
+#ifndef NDEBUG
+    void show();
+#endif
+
+private:
+    Entry* first() { return &at(0); }
+
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#list-of-active-formatting-elements
+    // These functions enforce the "Noah's Ark" condition, which removes redundant mis-nested elements.
+    void tryToEnsureNoahsArkConditionQuickly(HTMLStackItem*, Vector<HTMLStackItem*>& remainingCandiates);
+    void ensureNoahsArkCondition(HTMLStackItem*);
+
+    Vector<Entry> m_entries;
+};
+
+}
+
+#endif // HTMLFormattingElementList_h
diff --git a/Source/core/html/parser/HTMLIdentifier.cpp b/Source/core/html/parser/HTMLIdentifier.cpp
new file mode 100644
index 0000000..41b8ee7
--- /dev/null
+++ b/Source/core/html/parser/HTMLIdentifier.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLIdentifier.h"
+
+#include "HTMLNames.h"
+#include <wtf/HashMap.h>
+#include <wtf/MainThread.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+typedef HashMap<unsigned, StringImpl*, AlreadyHashed> IdentifierTable;
+
+unsigned HTMLIdentifier::maxNameLength = 0;
+
+static IdentifierTable& identifierTable()
+{
+    DEFINE_STATIC_LOCAL(IdentifierTable, table, ());
+    ASSERT(isMainThread() || !table.isEmpty());
+    return table;
+}
+
+#ifndef NDEBUG
+bool HTMLIdentifier::isKnown(const StringImpl* string)
+{
+    const IdentifierTable& table = identifierTable();
+    return table.contains(string->hash());
+}
+#endif
+
+StringImpl* HTMLIdentifier::findIfKnown(const UChar* characters, unsigned length)
+{
+    // We don't need to try hashing if we know the string is too long.
+    if (length > maxNameLength)
+        return 0;
+    // computeHashAndMaskTop8Bits is the function StringImpl::hash() uses.
+    unsigned hash = StringHasher::computeHashAndMaskTop8Bits(characters, length);
+    const IdentifierTable& table = identifierTable();
+    ASSERT(!table.isEmpty());
+
+    IdentifierTable::const_iterator it = table.find(hash);
+    if (it == table.end())
+        return 0;
+    // It's possible to have hash collisions between arbitrary strings and
+    // known identifiers (e.g. "bvvfg" collides with "script").
+    // However ASSERTs in addNames() guard against there ever being collisions
+    // between known identifiers.
+    if (!equal(it->value, characters, length))
+        return 0;
+    return it->value;
+}
+
+const unsigned kHTMLNamesIndexOffset = 0;
+const unsigned kHTMLAttrsIndexOffset = 1000;
+COMPILE_ASSERT(kHTMLAttrsIndexOffset > HTMLTagsCount, kHTMLAttrsIndexOffset_should_be_larger_than_HTMLTagsCount);
+
+const String& HTMLIdentifier::asString() const
+{
+    ASSERT(isMainThread());
+    return m_string;
+}
+
+const StringImpl* HTMLIdentifier::asStringImpl() const
+{
+    return m_string.impl();
+}
+
+void HTMLIdentifier::addNames(QualifiedName** names, unsigned namesCount, unsigned indexOffset)
+{
+    IdentifierTable& table = identifierTable();
+    for (unsigned i = 0; i < namesCount; ++i) {
+        StringImpl* name = names[i]->localName().impl();
+        unsigned hash = name->hash();
+        IdentifierTable::AddResult addResult = table.add(hash, name);
+        maxNameLength = std::max(maxNameLength, name->length());
+        // Ensure we're using the same hashing algorithm to get and set.
+        ASSERT_UNUSED(addResult, !addResult.isNewEntry || HTMLIdentifier::findIfKnown(name->characters(), name->length()) == name);
+        // We expect some hash collisions, but only for identical strings.
+        // Since all of these names are AtomicStrings pointers should be equal.
+        // Note: If you hit this ASSERT, then we had a hash collision among
+        // HTMLNames strings, and we need to re-design how we use this hash!
+        ASSERT_UNUSED(addResult, !addResult.isNewEntry || name == addResult.iterator->value);
+    }
+}
+
+void HTMLIdentifier::init()
+{
+    ASSERT(isMainThread()); // Not technically necessary, but this is our current expected usage.
+    static bool isInitialized = false;
+    if (isInitialized)
+        return;
+    isInitialized = true;
+
+    // FIXME: We should atomize small whitespace (\n, \n\n, etc.)
+    addNames(getHTMLTags(), HTMLTagsCount, kHTMLNamesIndexOffset);
+    addNames(getHTMLAttrs(), HTMLAttrsCount, kHTMLAttrsIndexOffset);
+}
+
+}
diff --git a/Source/core/html/parser/HTMLIdentifier.h b/Source/core/html/parser/HTMLIdentifier.h
new file mode 100644
index 0000000..08eef85
--- /dev/null
+++ b/Source/core/html/parser/HTMLIdentifier.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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 HTMLIdentifier_h
+#define HTMLIdentifier_h
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class QualifiedName;
+
+enum CharacterWidth {
+    Likely8Bit,
+    Force8Bit,
+    Force16Bit
+};
+
+class HTMLIdentifier {
+public:
+    HTMLIdentifier() { }
+
+    template<size_t inlineCapacity>
+    HTMLIdentifier(const Vector<UChar, inlineCapacity>& vector, CharacterWidth width)
+        : m_string(findIfKnown(vector.data(), vector.size()))
+    {
+        if (m_string.impl())
+            return;
+        if (width == Likely8Bit)
+            m_string = StringImpl::create8BitIfPossible(vector);
+        else if (width == Force8Bit)
+            m_string = String::make8BitFrom16BitSource(vector);
+        else
+            m_string = String(vector);
+    }
+
+    // asString should only be used on the main thread.
+    const String& asString() const;
+    // asStringImpl() is safe to call from any thread.
+    const StringImpl* asStringImpl() const;
+
+    static void init();
+
+    bool isSafeToSendToAnotherThread() const { return m_string.isSafeToSendToAnotherThread(); }
+
+#ifndef NDEBUG
+    static bool isKnown(const StringImpl*);
+#endif
+
+private:
+    static unsigned maxNameLength;
+    static StringImpl* findIfKnown(const UChar* characters, unsigned length);
+    static void addNames(QualifiedName** names, unsigned namesCount, unsigned indexOffset);
+
+    String m_string;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLInputStream.h b/Source/core/html/parser/HTMLInputStream.h
new file mode 100644
index 0000000..c7acd97
--- /dev/null
+++ b/Source/core/html/parser/HTMLInputStream.h
@@ -0,0 +1,159 @@
+/*
+ * 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 HTMLInputStream_h
+#define HTMLInputStream_h
+
+#include "core/html/parser/InputStreamPreprocessor.h"
+#include "core/platform/text/SegmentedString.h"
+
+namespace WebCore {
+
+// The InputStream is made up of a sequence of SegmentedStrings:
+//
+// [--current--][--next--][--next--] ... [--next--]
+//            /\                         (also called m_last)
+//            L_ current insertion point
+//
+// The current segmented string is stored in InputStream.  Each of the
+// afterInsertionPoint buffers are stored in InsertionPointRecords on the
+// stack.
+//
+// We remove characters from the "current" string in the InputStream.
+// document.write() will add characters at the current insertion point,
+// which appends them to the "current" string.
+//
+// m_last is a pointer to the last of the afterInsertionPoint strings.
+// The network adds data at the end of the InputStream, which appends
+// them to the "last" string.
+class HTMLInputStream {
+    WTF_MAKE_NONCOPYABLE(HTMLInputStream);
+public:
+    HTMLInputStream()
+        : m_last(&m_first)
+    {
+    }
+
+    void appendToEnd(const SegmentedString& string)
+    {
+        m_last->append(string);
+    }
+
+    void insertAtCurrentInsertionPoint(const SegmentedString& string)
+    {
+        m_first.append(string);
+    }
+
+    bool hasInsertionPoint() const
+    {
+        return &m_first != m_last;
+    }
+
+    void markEndOfFile()
+    {
+        m_last->append(SegmentedString(String(&kEndOfFileMarker, 1)));
+        m_last->close();
+    }
+
+    void closeWithoutMarkingEndOfFile()
+    {
+        m_last->close();
+    }
+
+    bool haveSeenEndOfFile() const
+    {
+        return m_last->isClosed();
+    }
+
+    SegmentedString& current() { return m_first; }
+    const SegmentedString& current() const { return m_first; }
+
+    void splitInto(SegmentedString& next)
+    {
+        next = m_first;
+        m_first = SegmentedString();
+        if (m_last == &m_first) {
+            // We used to only have one SegmentedString in the InputStream
+            // but now we have two.  That means m_first is no longer also
+            // the m_last string, |next| is now the last one.
+            m_last = &next;
+        }
+    }
+
+    void mergeFrom(SegmentedString& next)
+    {
+        m_first.append(next);
+        if (m_last == &next) {
+            // The string |next| used to be the last SegmentedString in
+            // the InputStream.  Now that it's been merged into m_first,
+            // that makes m_first the last one.
+            m_last = &m_first;
+        }
+        if (next.isClosed()) {
+            // We also need to merge the "closed" state from next to
+            // m_first.  Arguably, this work could be done in append().
+            m_first.close();
+        }
+    }
+
+private:
+    SegmentedString m_first;
+    SegmentedString* m_last;
+};
+
+class InsertionPointRecord {
+    WTF_MAKE_NONCOPYABLE(InsertionPointRecord);
+public:
+    explicit InsertionPointRecord(HTMLInputStream& inputStream)
+        : m_inputStream(&inputStream)
+    {
+        m_line = m_inputStream->current().currentLine();
+        m_column = m_inputStream->current().currentColumn();
+        m_inputStream->splitInto(m_next);
+        // We 'fork' current position and use it for the generated script part.
+        // This is a bit weird, because generated part does not have positions within an HTML document.
+        m_inputStream->current().setCurrentPosition(m_line, m_column, 0);
+    }
+
+    ~InsertionPointRecord()
+    {
+        // Some inserted text may have remained in input stream. E.g. if script has written "&amp" or "<table",
+        // it stays in buffer because it cannot be properly tokenized before we see next part.
+        int unparsedRemainderLength = m_inputStream->current().length();
+        m_inputStream->mergeFrom(m_next);
+        // We restore position for the character that goes right after unparsed remainder.
+        m_inputStream->current().setCurrentPosition(m_line, m_column, unparsedRemainderLength);
+    }
+
+private:
+    HTMLInputStream* m_inputStream;
+    SegmentedString m_next;
+    OrdinalNumber m_line;
+    OrdinalNumber m_column;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLMetaCharsetParser.cpp b/Source/core/html/parser/HTMLMetaCharsetParser.cpp
new file mode 100644
index 0000000..b2b213a
--- /dev/null
+++ b/Source/core/html/parser/HTMLMetaCharsetParser.cpp
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLMetaCharsetParser.h"
+
+#include "HTMLNames.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/parser/HTMLParserOptions.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/platform/text/TextCodec.h"
+#include "core/platform/text/TextEncodingRegistry.h"
+#include <wtf/text/WTFString.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLMetaCharsetParser::HTMLMetaCharsetParser()
+    : m_tokenizer(HTMLTokenizer::create(HTMLParserOptions(0)))
+    , m_assumedCodec(newTextCodec(Latin1Encoding()))
+    , m_inHeadSection(true)
+    , m_doneChecking(false)
+{
+}
+
+HTMLMetaCharsetParser::~HTMLMetaCharsetParser()
+{
+}
+
+static const char charsetString[] = "charset";
+static const size_t charsetLength = sizeof("charset") - 1;
+
+String HTMLMetaCharsetParser::extractCharset(const String& value)
+{
+    size_t pos = 0;
+    unsigned length = value.length();
+
+    while (pos < length) {
+        pos = value.find(charsetString, pos, false);
+        if (pos == notFound)
+            break;
+
+        pos += charsetLength;
+
+        // Skip whitespace.
+        while (pos < length && value[pos] <= ' ')
+            ++pos;
+
+        if (value[pos] != '=')
+            continue;
+
+        ++pos;
+
+        while (pos < length && value[pos] <= ' ')
+            ++pos;
+
+        char quoteMark = 0;
+        if (pos < length && (value[pos] == '"' || value[pos] == '\'')) {
+            quoteMark = static_cast<char>(value[pos++]);
+            ASSERT(!(quoteMark & 0x80));
+        }
+            
+        if (pos == length)
+            break;
+
+        unsigned end = pos;
+        while (end < length && ((quoteMark && value[end] != quoteMark) || (!quoteMark && value[end] > ' ' && value[end] != '"' && value[end] != '\'' && value[end] != ';')))
+            ++end;
+
+        if (quoteMark && (end == length))
+            break; // Close quote not found.
+
+        return value.substring(pos, end - pos);
+    }
+
+    return "";
+}
+
+bool HTMLMetaCharsetParser::processMeta()
+{
+    const HTMLToken::AttributeList& tokenAttributes = m_token.attributes();
+    AttributeList attributes;
+    for (HTMLToken::AttributeList::const_iterator iter = tokenAttributes.begin(); iter != tokenAttributes.end(); ++iter) {
+        String attributeName = StringImpl::create8BitIfPossible(iter->name);
+        String attributeValue = StringImpl::create8BitIfPossible(iter->value);
+        attributes.append(std::make_pair(attributeName, attributeValue));
+    }
+
+    m_encoding = encodingFromMetaAttributes(attributes);
+    return m_encoding.isValid();
+}
+
+TextEncoding HTMLMetaCharsetParser::encodingFromMetaAttributes(const AttributeList& attributes)
+{
+    bool gotPragma = false;
+    Mode mode = None;
+    String charset;
+
+    for (AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) {
+        const AtomicString& attributeName = iter->first;
+        const String& attributeValue = iter->second;
+
+        if (attributeName == http_equivAttr) {
+            if (equalIgnoringCase(attributeValue, "content-type"))
+                gotPragma = true;
+        } else if (charset.isEmpty()) {
+            if (attributeName == charsetAttr) {
+                charset = attributeValue;
+                mode = Charset;
+            } else if (attributeName == contentAttr) {
+                charset = extractCharset(attributeValue);
+                if (charset.length())
+                    mode = Pragma;
+            }
+        }
+    }
+
+    if (mode == Charset || (mode == Pragma && gotPragma))
+        return TextEncoding(stripLeadingAndTrailingHTMLSpaces(charset));
+
+    return TextEncoding();
+}
+
+static const int bytesToCheckUnconditionally = 1024; // That many input bytes will be checked for meta charset even if <head> section is over.
+
+bool HTMLMetaCharsetParser::checkForMetaCharset(const char* data, size_t length)
+{
+    if (m_doneChecking)
+        return true;
+
+    ASSERT(!m_encoding.isValid());
+
+    // We still don't have an encoding, and are in the head.
+    // The following tags are allowed in <head>:
+    // SCRIPT|STYLE|META|LINK|OBJECT|TITLE|BASE
+
+    // We stop scanning when a tag that is not permitted in <head>
+    // is seen, rather when </head> is seen, because that more closely
+    // matches behavior in other browsers; more details in
+    // <http://bugs.webkit.org/show_bug.cgi?id=3590>.
+
+    // Additionally, we ignore things that looks like tags in <title>, <script>
+    // and <noscript>; see <http://bugs.webkit.org/show_bug.cgi?id=4560>,
+    // <http://bugs.webkit.org/show_bug.cgi?id=12165> and
+    // <http://bugs.webkit.org/show_bug.cgi?id=12389>.
+
+    // Since many sites have charset declarations after <body> or other tags
+    // that are disallowed in <head>, we don't bail out until we've checked at
+    // least bytesToCheckUnconditionally bytes of input.
+
+    m_input.append(SegmentedString(m_assumedCodec->decode(data, length)));
+
+    while (m_tokenizer->nextToken(m_input, m_token)) {
+        bool end = m_token.type() == HTMLToken::EndTag;
+        if (end || m_token.type() == HTMLToken::StartTag) {
+            AtomicString tagName(m_token.name());
+            if (!end) {
+                m_tokenizer->updateStateFor(tagName);
+                if (tagName == metaTag && processMeta()) {
+                    m_doneChecking = true;
+                    return true;
+                }
+            }
+
+            if (tagName != scriptTag && tagName != noscriptTag
+                && tagName != styleTag && tagName != linkTag
+                && tagName != metaTag && tagName != objectTag
+                && tagName != titleTag && tagName != baseTag
+                && (end || tagName != htmlTag) && (end || tagName != headTag)) {
+                m_inHeadSection = false;
+            }
+        }
+
+        if (!m_inHeadSection && m_input.numberOfCharactersConsumed() >= bytesToCheckUnconditionally) {
+            m_doneChecking = true;
+            return true;
+        }
+
+        m_token.clear();
+    }
+
+    return false;
+}
+
+}
diff --git a/Source/core/html/parser/HTMLMetaCharsetParser.h b/Source/core/html/parser/HTMLMetaCharsetParser.h
new file mode 100644
index 0000000..9787662
--- /dev/null
+++ b/Source/core/html/parser/HTMLMetaCharsetParser.h
@@ -0,0 +1,79 @@
+/*
+ * 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 HTMLMetaCharsetParser_h
+#define HTMLMetaCharsetParser_h
+
+#include "core/html/parser/HTMLToken.h"
+#include "core/platform/text/SegmentedString.h"
+#include "core/platform/text/TextEncoding.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class HTMLTokenizer;
+class TextCodec;
+
+class HTMLMetaCharsetParser {
+    WTF_MAKE_NONCOPYABLE(HTMLMetaCharsetParser); WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<HTMLMetaCharsetParser> create() { return adoptPtr(new HTMLMetaCharsetParser()); }
+
+    ~HTMLMetaCharsetParser();
+
+    // Returns true if done checking, regardless whether an encoding is found.
+    bool checkForMetaCharset(const char*, size_t);
+
+    const TextEncoding& encoding() { return m_encoding; }
+
+    typedef Vector<pair<String, String> > AttributeList;
+    // The returned encoding might not be valid.
+    static TextEncoding encodingFromMetaAttributes(const AttributeList&
+);
+
+private:
+    HTMLMetaCharsetParser();
+
+    bool processMeta();
+    static String extractCharset(const String&);
+
+    enum Mode {
+        None,
+        Charset,
+        Pragma,
+    };
+
+    OwnPtr<HTMLTokenizer> m_tokenizer;
+    OwnPtr<TextCodec> m_assumedCodec;
+    SegmentedString m_input;
+    HTMLToken m_token;
+    bool m_inHeadSection;
+
+    bool m_doneChecking;
+    TextEncoding m_encoding;
+};
+
+}
+#endif
diff --git a/Source/core/html/parser/HTMLParserIdioms.cpp b/Source/core/html/parser/HTMLParserIdioms.cpp
new file mode 100644
index 0000000..5ef401b
--- /dev/null
+++ b/Source/core/html/parser/HTMLParserIdioms.cpp
@@ -0,0 +1,300 @@
+/*
+ * 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 "core/html/parser/HTMLParserIdioms.h"
+
+#include <limits>
+#include "core/dom/QualifiedName.h"
+#include "core/html/parser/HTMLIdentifier.h"
+#include "core/platform/Decimal.h"
+#include <wtf/MathExtras.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+template <typename CharType>
+static String stripLeadingAndTrailingHTMLSpaces(String string, CharType characters, unsigned length)
+{
+    unsigned numLeadingSpaces = 0;
+    unsigned numTrailingSpaces = 0;
+
+    for (; numLeadingSpaces < length; ++numLeadingSpaces) {
+        if (isNotHTMLSpace(characters[numLeadingSpaces]))
+            break;
+    }
+
+    if (numLeadingSpaces == length)
+        return string.isNull() ? string : emptyAtom.string();
+
+    for (; numTrailingSpaces < length; ++numTrailingSpaces) {
+        if (isNotHTMLSpace(characters[length - numTrailingSpaces - 1]))
+            break;
+    }
+
+    ASSERT(numLeadingSpaces + numTrailingSpaces < length);
+
+    if (!(numLeadingSpaces | numTrailingSpaces))
+        return string;
+
+    return string.substring(numLeadingSpaces, length - (numLeadingSpaces + numTrailingSpaces));
+}
+
+String stripLeadingAndTrailingHTMLSpaces(const String& string)
+{
+    unsigned length = string.length();
+
+    if (!length)
+        return string.isNull() ? string : emptyAtom.string();
+
+    if (string.is8Bit())
+        return stripLeadingAndTrailingHTMLSpaces(string, string.characters8(), length);
+
+    return stripLeadingAndTrailingHTMLSpaces(string, string.characters(), length);
+}
+
+String serializeForNumberType(const Decimal& number)
+{
+    if (number.isZero()) {
+        // Decimal::toString appends exponent, e.g. "0e-18"
+        return number.isNegative() ? "-0" : "0";
+    }
+    return number.toString();
+}
+
+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.
+    return String::numberToStringECMAScript(number);
+}
+
+Decimal parseToDecimalForNumberType(const String& string, const Decimal& fallbackValue)
+{
+    // See HTML5 2.5.4.3 `Real numbers.' and parseToDoubleForNumberType
+
+    // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
+    const UChar firstCharacter = string[0];
+    if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter))
+        return fallbackValue;
+
+    const Decimal value = Decimal::fromString(string);
+    if (!value.isFinite())
+        return fallbackValue;
+
+    // Numbers are considered finite IEEE 754 single-precision floating point values.
+    // See HTML5 2.5.4.3 `Real numbers.'
+    // FIXME: We should use numeric_limits<double>::max for number input type.
+    const Decimal floatMax = Decimal::fromDouble(std::numeric_limits<float>::max());
+    if (value < -floatMax || value > floatMax)
+        return fallbackValue;
+
+    // We return +0 for -0 case.
+    return value.isZero() ? Decimal(0) : value;
+}
+
+Decimal parseToDecimalForNumberType(const String& string)
+{
+    return parseToDecimalForNumberType(string, Decimal::nan());
+}
+
+double parseToDoubleForNumberType(const String& string, double fallbackValue)
+{
+    // See HTML5 2.5.4.3 `Real numbers.'
+
+    // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
+    UChar firstCharacter = string[0];
+    if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter))
+        return fallbackValue;
+
+    bool valid = false;
+    double value = string.toDouble(&valid);
+    if (!valid)
+        return fallbackValue;
+
+    // NaN and infinity are considered valid by String::toDouble, but not valid here.
+    if (!std::isfinite(value))
+        return fallbackValue;
+
+    // Numbers are considered finite IEEE 754 single-precision floating point values.
+    // See HTML5 2.5.4.3 `Real numbers.'
+    if (-std::numeric_limits<float>::max() > value || value > std::numeric_limits<float>::max())
+        return fallbackValue;
+
+    // The following expression converts -0 to +0.
+    return value ? value : 0;
+}
+
+double parseToDoubleForNumberType(const String& string)
+{
+    return parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN());
+}
+
+template <typename CharacterType>
+static bool parseHTMLIntegerInternal(const CharacterType* position, const CharacterType* end, int& value)
+{
+    // 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
+    StringBuilder digits;
+    while (position < end) {
+        if (!isASCIIDigit(*position))
+            break;
+        digits.append(*position++);
+    }
+
+    // Step 9
+    bool ok;
+    if (digits.is8Bit())
+        value = sign * charactersToIntStrict(digits.characters8(), digits.length(), &ok);
+    else
+        value = sign * charactersToIntStrict(digits.characters16(), digits.length(), &ok);
+    return ok;
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
+bool parseHTMLInteger(const String& input, int& value)
+{
+    // Step 1
+    // Step 2
+    unsigned length = input.length();
+    if (length && input.is8Bit()) {
+        const LChar* start = input.characters8();
+        return parseHTMLIntegerInternal(start, start + length, value);
+    }
+
+    const UChar* start = input.characters();
+    return parseHTMLIntegerInternal(start, start + length, value);
+}
+
+template <typename CharacterType>
+static bool parseHTMLNonNegativeIntegerInternal(const CharacterType* position, const CharacterType* end, unsigned& value)
+{
+    // Step 3
+    while (position < end) {
+        if (!isHTMLSpace(*position))
+            break;
+        ++position;
+    }
+
+    // Step 4
+    if (position == end)
+        return false;
+    ASSERT(position < end);
+
+    // Step 5
+    if (*position == '+')
+        ++position;
+
+    // Step 6
+    if (position == end)
+        return false;
+    ASSERT(position < end);
+
+    // Step 7
+    if (!isASCIIDigit(*position))
+        return false;
+
+    // Step 8
+    StringBuilder digits;
+    while (position < end) {
+        if (!isASCIIDigit(*position))
+            break;
+        digits.append(*position++);
+    }
+
+    // Step 9
+    bool ok;
+    if (digits.is8Bit())
+        value = charactersToUIntStrict(digits.characters8(), digits.length(), &ok);
+    else
+        value = charactersToUIntStrict(digits.characters16(), digits.length(), &ok);
+    return ok;
+}
+
+
+// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
+bool parseHTMLNonNegativeInteger(const String& input, unsigned& value)
+{
+    // Step 1
+    // Step 2
+    unsigned length = input.length();
+    if (length && input.is8Bit()) {
+        const LChar* start = input.characters8();
+        return parseHTMLNonNegativeIntegerInternal(start, start + length, value);
+    }
+    
+    const UChar* start = input.characters();
+    return parseHTMLNonNegativeIntegerInternal(start, start + length, value);
+}
+
+static bool threadSafeEqual(const StringImpl* a, const StringImpl* b)
+{
+    if (a == b)
+        return true;
+    if (a->hash() != b->hash())
+        return false;
+    return equalNonNull(a, b);
+}
+
+bool threadSafeMatch(const QualifiedName& a, const QualifiedName& b)
+{
+    return threadSafeEqual(a.localName().impl(), b.localName().impl());
+}
+
+bool threadSafeMatch(const HTMLIdentifier& localName, const QualifiedName& qName)
+{
+    return threadSafeEqual(localName.asStringImpl(), qName.localName().impl());
+}
+
+}
diff --git a/Source/core/html/parser/HTMLParserIdioms.h b/Source/core/html/parser/HTMLParserIdioms.h
new file mode 100644
index 0000000..3c6903e
--- /dev/null
+++ b/Source/core/html/parser/HTMLParserIdioms.h
@@ -0,0 +1,108 @@
+/*
+ * 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 "core/dom/QualifiedName.h"
+#include "core/html/parser/HTMLIdentifier.h"
+#include <wtf/Forward.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+class Decimal;
+
+// Space characters as defined by the HTML specification.
+bool isHTMLSpace(UChar);
+bool isHTMLLineBreak(UChar);
+bool isNotHTMLSpace(UChar);
+
+// Strip leading and trailing whitespace as defined by the HTML specification. 
+String stripLeadingAndTrailingHTMLSpaces(const String&);
+template<size_t inlineCapacity>
+String stripLeadingAndTrailingHTMLSpaces(const Vector<UChar, inlineCapacity>& vector)
+{
+    return stripLeadingAndTrailingHTMLSpaces(StringImpl::create8BitIfPossible(vector));
+}
+
+// An implementation of the HTML specification's algorithm to convert a number to a string for number and range types.
+String serializeForNumberType(const Decimal&);
+String serializeForNumberType(double);
+
+// Convert the specified string to a decimal/double. If the conversion fails, the return value is fallback value or NaN if not specified.
+// 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.
+Decimal parseToDecimalForNumberType(const String&);
+Decimal parseToDecimalForNumberType(const String&, const Decimal& fallbackValue);
+double parseToDoubleForNumberType(const String&);
+double parseToDoubleForNumberType(const String&, double fallbackValue);
+
+// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
+bool parseHTMLInteger(const String&, int&);
+
+// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
+bool parseHTMLNonNegativeInteger(const String&, unsigned int&);
+
+// Inline implementations of some of the functions declared above.
+
+inline bool isHTMLSpace(UChar character)
+{
+    // Histogram from Apple's page load test combined with some ad hoc browsing some other test suites.
+    //
+    //     82%: 216330 non-space characters, all > U+0020
+    //     11%:  30017 plain space characters, U+0020
+    //      5%:  12099 newline characters, U+000A
+    //      2%:   5346 tab characters, U+0009
+    //
+    // No other characters seen. No U+000C or U+000D, and no other control characters.
+    // Accordingly, we check for non-spaces first, then space, then newline, then tab, then the other characters.
+
+    return character <= ' ' && (character == ' ' || character == '\n' || character == '\t' || character == '\r' || character == '\f');
+}
+
+inline bool isHTMLLineBreak(UChar character)
+{
+    return character <= '\r' && (character == '\n' || character == '\r');
+}
+
+inline bool isNotHTMLSpace(UChar character)
+{
+    return !isHTMLSpace(character);
+}
+
+bool threadSafeMatch(const QualifiedName&, const QualifiedName&);
+bool threadSafeMatch(const HTMLIdentifier&, const QualifiedName&);
+inline bool threadSafeHTMLNamesMatch(const HTMLIdentifier& tagName, const QualifiedName& qName)
+{
+    // When the QualifiedName is known to HTMLIdentifier,
+    // all we have to do is a pointer compare.
+    ASSERT(HTMLIdentifier::isKnown(qName.localName().impl()));
+    return tagName.asStringImpl() == qName.localName().impl();
+}
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLParserOptions.cpp b/Source/core/html/parser/HTMLParserOptions.cpp
new file mode 100644
index 0000000..bdb80a0
--- /dev/null
+++ b/Source/core/html/parser/HTMLParserOptions.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLParserOptions.h"
+
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/Document.h"
+#include "core/loader/FrameLoader.h"
+#include "core/page/Frame.h"
+#include "core/page/Settings.h"
+
+namespace WebCore {
+
+HTMLParserOptions::HTMLParserOptions(Document* document)
+{
+    Frame* frame = document ? document->frame() : 0;
+    scriptEnabled = frame && frame->script()->canExecuteScripts(NotAboutToExecuteScript);
+    pluginsEnabled = frame && frame->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin);
+
+    Settings* settings = document ? document->settings() : 0;
+    // We force the main-thread parser for about:blank, javascript: and data: urls for compatibility
+    // with historical synchronous loading/parsing behavior of those schemes.
+    useThreading = settings && settings->threadedHTMLParser() && !document->url().isBlankURL()
+        && (settings->useThreadedHTMLParserForDataURLs() || !document->url().protocolIsData());
+}
+
+}
diff --git a/Source/core/html/parser/HTMLParserOptions.h b/Source/core/html/parser/HTMLParserOptions.h
new file mode 100644
index 0000000..9a6f8e7
--- /dev/null
+++ b/Source/core/html/parser/HTMLParserOptions.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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 HTMLParserOptions_h
+#define HTMLParserOptions_h
+
+namespace WebCore {
+
+class Document;
+
+class HTMLParserOptions {
+public:
+    bool scriptEnabled;
+    bool pluginsEnabled;
+    bool useThreading;
+
+    explicit HTMLParserOptions(Document* = 0);
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLParserScheduler.cpp b/Source/core/html/parser/HTMLParserScheduler.cpp
new file mode 100644
index 0000000..19baf9c
--- /dev/null
+++ b/Source/core/html/parser/HTMLParserScheduler.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLParserScheduler.h"
+
+#include "core/dom/Document.h"
+#include "core/html/parser/HTMLDocumentParser.h"
+#include "core/page/FrameView.h"
+
+namespace WebCore {
+
+// parserChunkSize is used to define how many tokens the parser will
+// process before checking against parserTimeLimit and possibly yielding.
+// This is a performance optimization to prevent checking after every token.
+const int HTMLParserScheduler::parserChunkSize = 4096;
+
+// parserTimeLimit is the seconds the parser will run in one write() call
+// before yielding. Inline <script> execution can cause it to exceed the limit.
+// FIXME: We would like this value to be 0.2.
+const double HTMLParserScheduler::parserTimeLimit = 0.500;
+
+ActiveParserSession::ActiveParserSession(Document* document)
+    : m_document(document)
+{
+    if (!m_document)
+        return;
+    m_document->incrementActiveParserCount();
+}
+
+ActiveParserSession::~ActiveParserSession()
+{
+    if (!m_document)
+        return;
+    m_document->decrementActiveParserCount();
+}
+
+PumpSession::PumpSession(unsigned& nestingLevel, Document* document)
+    : NestingLevelIncrementer(nestingLevel)
+    , ActiveParserSession(document)
+    // Setting processedTokens to INT_MAX causes us to check for yields
+    // after any token during any parse where yielding is allowed.
+    // At that time we'll initialize startTime.
+    , processedTokens(INT_MAX)
+    , startTime(0)
+    , needsYield(false)
+    , didSeeScript(false)
+{
+}
+
+PumpSession::~PumpSession()
+{
+}
+
+HTMLParserScheduler::HTMLParserScheduler(HTMLDocumentParser* parser)
+    : m_parser(parser)
+    , m_continueNextChunkTimer(this, &HTMLParserScheduler::continueNextChunkTimerFired)
+    , m_isSuspendedWithActiveTimer(false)
+{
+}
+
+HTMLParserScheduler::~HTMLParserScheduler()
+{
+    m_continueNextChunkTimer.stop();
+}
+
+void HTMLParserScheduler::continueNextChunkTimerFired(Timer<HTMLParserScheduler>* timer)
+{
+    ASSERT_UNUSED(timer, timer == &m_continueNextChunkTimer);
+    // FIXME: The timer class should handle timer priorities instead of this code.
+    // If a layout is scheduled, wait again to let the layout timer run first.
+    if (m_parser->document()->isLayoutTimerActive()) {
+        m_continueNextChunkTimer.startOneShot(0);
+        return;
+    }
+    m_parser->resumeParsingAfterYield();
+}
+
+void HTMLParserScheduler::checkForYieldBeforeScript(PumpSession& session)
+{
+    // If we've never painted before and a layout is pending, yield prior to running
+    // scripts to give the page a chance to paint earlier.
+    Document* document = m_parser->document();
+    bool needsFirstPaint = document->view() && !document->view()->hasEverPainted();
+    if (needsFirstPaint && document->isLayoutTimerActive())
+        session.needsYield = true;
+    session.didSeeScript = true;
+}
+
+void HTMLParserScheduler::scheduleForResume()
+{
+    m_continueNextChunkTimer.startOneShot(0);
+}
+
+
+void HTMLParserScheduler::suspend()
+{
+    ASSERT(!m_isSuspendedWithActiveTimer);
+    if (!m_continueNextChunkTimer.isActive())
+        return;
+    m_isSuspendedWithActiveTimer = true;
+    m_continueNextChunkTimer.stop();
+}
+
+void HTMLParserScheduler::resume()
+{
+    ASSERT(!m_continueNextChunkTimer.isActive());
+    if (!m_isSuspendedWithActiveTimer)
+        return;
+    m_isSuspendedWithActiveTimer = false;
+    m_continueNextChunkTimer.startOneShot(0);
+}
+
+}
diff --git a/Source/core/html/parser/HTMLParserScheduler.h b/Source/core/html/parser/HTMLParserScheduler.h
new file mode 100644
index 0000000..722c284
--- /dev/null
+++ b/Source/core/html/parser/HTMLParserScheduler.h
@@ -0,0 +1,112 @@
+/*
+ * 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 HTMLParserScheduler_h
+#define HTMLParserScheduler_h
+
+#include <limits.h>
+#include "core/html/parser/NestingLevelIncrementer.h"
+#include "core/platform/Timer.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Document;
+class HTMLDocumentParser;
+
+class ActiveParserSession {
+public:
+    explicit ActiveParserSession(Document*);
+    ~ActiveParserSession();
+
+private:
+    RefPtr<Document> m_document;
+};
+
+class PumpSession : public NestingLevelIncrementer, public ActiveParserSession {
+public:
+    PumpSession(unsigned& nestingLevel, Document*);
+    ~PumpSession();
+
+    int processedTokens;
+    double startTime;
+    bool needsYield;
+    bool didSeeScript;
+};
+
+class HTMLParserScheduler {
+    WTF_MAKE_NONCOPYABLE(HTMLParserScheduler); WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<HTMLParserScheduler> create(HTMLDocumentParser* parser)
+    {
+        return adoptPtr(new HTMLParserScheduler(parser));
+    }
+    ~HTMLParserScheduler();
+
+    // Inline as this is called after every token in the parser.
+    void checkForYieldBeforeToken(PumpSession& session)
+    {
+        if (session.processedTokens > parserChunkSize || session.didSeeScript) {
+            // currentTime() can be expensive.  By delaying, we avoided calling
+            // currentTime() when constructing non-yielding PumpSessions.
+            if (!session.startTime)
+                session.startTime = currentTime();
+
+            session.processedTokens = 0;
+            session.didSeeScript = false;
+
+            double elapsedTime = currentTime() - session.startTime;
+            if (elapsedTime > parserTimeLimit)
+                session.needsYield = true;
+        }
+        ++session.processedTokens;
+    }
+    void checkForYieldBeforeScript(PumpSession&);
+
+    void scheduleForResume();
+    bool isScheduledForResume() const { return m_isSuspendedWithActiveTimer || m_continueNextChunkTimer.isActive(); }
+
+    void suspend();
+    void resume();
+
+private:
+    static const double parserTimeLimit;
+    static const int parserChunkSize;
+
+    HTMLParserScheduler(HTMLDocumentParser*);
+
+    void continueNextChunkTimerFired(Timer<HTMLParserScheduler>*);
+
+    HTMLDocumentParser* m_parser;
+
+    Timer<HTMLParserScheduler> m_continueNextChunkTimer;
+    bool m_isSuspendedWithActiveTimer;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLParserThread.cpp b/Source/core/html/parser/HTMLParserThread.cpp
new file mode 100644
index 0000000..f7d00be
--- /dev/null
+++ b/Source/core/html/parser/HTMLParserThread.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2013 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLParserThread.h"
+
+namespace WebCore {
+
+HTMLParserThread::HTMLParserThread()
+    : m_threadID(0)
+{
+}
+
+HTMLParserThread::~HTMLParserThread()
+{
+    ASSERT(m_queue.killed());
+}
+
+bool HTMLParserThread::start()
+{
+    MutexLocker lock(m_threadCreationMutex);
+    if (m_threadID)
+        return true;
+    m_threadID = createThread(HTMLParserThread::threadStart, this, "WebCore: HTMLParser");
+    return m_threadID;
+}
+
+void HTMLParserThread::stop()
+{
+    m_queue.kill();
+    waitForThreadCompletion(m_threadID);
+}
+
+HTMLParserThread* HTMLParserThread::shared()
+{
+    static HTMLParserThread* thread;
+    if (!thread) {
+        thread = HTMLParserThread::create().leakPtr();
+        thread->start();
+    }
+    return thread;
+}
+
+void HTMLParserThread::postTask(const Closure& function)
+{
+    m_queue.append(adoptPtr(new Closure(function)));
+}
+
+void HTMLParserThread::threadStart(void* arg)
+{
+    HTMLParserThread* thread = static_cast<HTMLParserThread*>(arg);
+    thread->runLoop();
+}
+
+void HTMLParserThread::runLoop()
+{
+    {
+        // Wait for HTMLParserThread::start() to complete to have m_threadID
+        // established before starting the main loop.
+        MutexLocker lock(m_threadCreationMutex);
+    }
+    while (OwnPtr<Closure> function = m_queue.waitForMessage())
+        (*function)();
+
+    // stop() will wait to join the thread, so we do not detach here.
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/parser/HTMLParserThread.h b/Source/core/html/parser/HTMLParserThread.h
new file mode 100644
index 0000000..543f2b3
--- /dev/null
+++ b/Source/core/html/parser/HTMLParserThread.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 HTMLParserThread_h
+#define HTMLParserThread_h
+
+#include <wtf/Functional.h>
+#include <wtf/MessageQueue.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+// FIXME:: Closure is the Chromium-name for Function<void()>, but we may want something else for WebCore.
+typedef Function<void()> Closure;
+
+class HTMLParserThread {
+public:
+    static PassOwnPtr<HTMLParserThread> create()
+    {
+        return adoptPtr(new HTMLParserThread());
+    }
+    ~HTMLParserThread();
+
+    static HTMLParserThread* shared();
+
+    bool start();
+    void stop();
+
+    void postTask(const Closure&);
+
+    ThreadIdentifier threadId() const { return m_threadID; }
+
+private:
+    HTMLParserThread();
+
+    static void threadStart(void*);
+    void runLoop();
+
+    Mutex m_threadCreationMutex;
+    MessageQueue<Closure> m_queue;
+    ThreadIdentifier m_threadID;
+};
+
+} // namespace WebCore
+
+#endif // HTMLParserThread_h
diff --git a/Source/core/html/parser/HTMLPreloadScanner.cpp b/Source/core/html/parser/HTMLPreloadScanner.cpp
new file mode 100644
index 0000000..48c777e
--- /dev/null
+++ b/Source/core/html/parser/HTMLPreloadScanner.cpp
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/
+ * 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. 
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLPreloadScanner.h"
+
+#include "HTMLNames.h"
+#include "core/html/InputTypeNames.h"
+#include "core/html/LinkRelAttribute.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/parser/HTMLParserOptions.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include <wtf/Functional.h>
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static bool match(const StringImpl* impl, const QualifiedName& qName)
+{
+    return impl == qName.localName().impl();
+}
+
+static bool match(const HTMLIdentifier& name, const QualifiedName& qName)
+{
+    return match(name.asStringImpl(), qName);
+}
+
+static bool match(const AtomicString& name, const QualifiedName& qName)
+{
+    ASSERT(isMainThread());
+    return qName.localName() == name;
+}
+
+static const StringImpl* tagImplFor(const HTMLToken::DataVector& data)
+{
+    AtomicString tagName(data);
+    const StringImpl* result = tagName.impl();
+    if (result->isStatic())
+        return result;
+    return 0;
+}
+
+static const StringImpl* tagImplFor(const HTMLIdentifier& tagName)
+{
+    const StringImpl* result = tagName.asStringImpl();
+    if (result->isStatic())
+        return result;
+    return 0;
+}
+
+static String initiatorFor(const StringImpl* tagImpl)
+{
+    ASSERT(tagImpl);
+    if (match(tagImpl, imgTag))
+        return imgTag.localName();
+    if (match(tagImpl, inputTag))
+        return inputTag.localName();
+    if (match(tagImpl, linkTag))
+        return linkTag.localName();
+    if (match(tagImpl, scriptTag))
+        return scriptTag.localName();
+    ASSERT_NOT_REACHED();
+    return "unknown";
+}
+
+class TokenPreloadScanner::StartTagScanner {
+public:
+    explicit StartTagScanner(const StringImpl* tagImpl)
+        : m_tagImpl(tagImpl)
+        , m_linkIsStyleSheet(false)
+        , m_inputIsImage(false)
+    {
+        if (!match(m_tagImpl, imgTag)
+            && !match(m_tagImpl, inputTag)
+            && !match(m_tagImpl, linkTag)
+            && !match(m_tagImpl, scriptTag))
+            m_tagImpl = 0;
+    }
+
+    void processAttributes(const HTMLToken::AttributeList& attributes)
+    {
+        ASSERT(isMainThread());
+        if (!m_tagImpl)
+            return;
+        for (HTMLToken::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) {
+            AtomicString attributeName(iter->name);
+            String attributeValue = StringImpl::create8BitIfPossible(iter->value);
+            processAttribute(attributeName, attributeValue);
+        }
+    }
+
+    void processAttributes(const Vector<CompactHTMLToken::Attribute>& attributes)
+    {
+        if (!m_tagImpl)
+            return;
+        for (Vector<CompactHTMLToken::Attribute>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
+            processAttribute(iter->name, iter->value);
+    }
+
+    PassOwnPtr<PreloadRequest> createPreloadRequest(const KURL& predictedBaseURL)
+    {
+        if (!shouldPreload())
+            return nullptr;
+
+        OwnPtr<PreloadRequest> request = PreloadRequest::create(initiatorFor(m_tagImpl), m_urlToLoad, predictedBaseURL, resourceType(), m_mediaAttribute);
+        request->setCrossOriginModeAllowsCookies(crossOriginModeAllowsCookies());
+        request->setCharset(charset());
+        return request.release();
+    }
+
+private:
+    template<typename NameType>
+    void processAttribute(const NameType& attributeName, const String& attributeValue)
+    {
+        if (match(attributeName, charsetAttr))
+            m_charset = attributeValue;
+
+        if (match(m_tagImpl, scriptTag) || match(m_tagImpl, imgTag)) {
+            if (match(attributeName, srcAttr))
+                setUrlToLoad(attributeValue);
+            else if (match(attributeName, crossoriginAttr) && !attributeValue.isNull())
+                m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeValue);
+        } else if (match(m_tagImpl, linkTag)) {
+            if (match(attributeName, hrefAttr))
+                setUrlToLoad(attributeValue);
+            else if (match(attributeName, relAttr))
+                m_linkIsStyleSheet = relAttributeIsStyleSheet(attributeValue);
+            else if (match(attributeName, mediaAttr))
+                m_mediaAttribute = attributeValue;
+        } else if (match(m_tagImpl, inputTag)) {
+            if (match(attributeName, srcAttr))
+                setUrlToLoad(attributeValue);
+            else if (match(attributeName, typeAttr))
+                m_inputIsImage = equalIgnoringCase(attributeValue, InputTypeNames::image());
+        }
+    }
+
+    static bool relAttributeIsStyleSheet(const String& attributeValue)
+    {
+        LinkRelAttribute rel(attributeValue);
+        return rel.isStyleSheet() && !rel.isAlternate() && rel.iconType() == InvalidIcon && !rel.isDNSPrefetch();
+    }
+
+    void setUrlToLoad(const String& attributeValue)
+    {
+        // We only respect the first src/href, per HTML5:
+        // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#attribute-name-state
+        if (!m_urlToLoad.isEmpty())
+            return;
+        m_urlToLoad = stripLeadingAndTrailingHTMLSpaces(attributeValue);
+    }
+
+    const String& charset() const
+    {
+        // FIXME: Its not clear that this if is needed, the loader probably ignores charset for image requests anyway.
+        if (match(m_tagImpl, imgTag))
+            return emptyString();
+        return m_charset;
+    }
+
+    CachedResource::Type resourceType() const
+    {
+        if (match(m_tagImpl, scriptTag))
+            return CachedResource::Script;
+        if (match(m_tagImpl, imgTag) || (match(m_tagImpl, inputTag) && m_inputIsImage))
+            return CachedResource::ImageResource;
+        if (match(m_tagImpl, linkTag) && m_linkIsStyleSheet)
+            return CachedResource::CSSStyleSheet;
+        ASSERT_NOT_REACHED();
+        return CachedResource::RawResource;
+    }
+
+    bool shouldPreload()
+    {
+        if (m_urlToLoad.isEmpty())
+            return false;
+        if (match(m_tagImpl, linkTag) && !m_linkIsStyleSheet)
+            return false;
+        if (match(m_tagImpl, inputTag) && !m_inputIsImage)
+            return false;
+        return true;
+    }
+
+    bool crossOriginModeAllowsCookies()
+    {
+        return m_crossOriginMode.isNull() || equalIgnoringCase(m_crossOriginMode, "use-credentials");
+    }
+
+    const StringImpl* m_tagImpl;
+    String m_urlToLoad;
+    String m_charset;
+    String m_crossOriginMode;
+    bool m_linkIsStyleSheet;
+    String m_mediaAttribute;
+    bool m_inputIsImage;
+};
+
+TokenPreloadScanner::TokenPreloadScanner(const KURL& documentURL)
+    : m_documentURL(documentURL)
+    , m_inStyle(false)
+    , m_templateCount(0)
+{
+}
+
+TokenPreloadScanner::~TokenPreloadScanner()
+{
+}
+
+TokenPreloadScannerCheckpoint TokenPreloadScanner::createCheckpoint()
+{
+    TokenPreloadScannerCheckpoint checkpoint = m_checkpoints.size();
+    m_checkpoints.append(Checkpoint(m_predictedBaseElementURL, m_inStyle, m_templateCount));
+    return checkpoint;
+}
+
+void TokenPreloadScanner::rewindTo(TokenPreloadScannerCheckpoint checkpointIndex)
+{
+    ASSERT(checkpointIndex < m_checkpoints.size()); // If this ASSERT fires, checkpointIndex is invalid.
+    const Checkpoint& checkpoint = m_checkpoints[checkpointIndex];
+    m_predictedBaseElementURL = checkpoint.predictedBaseElementURL;
+    m_inStyle = checkpoint.inStyle;
+    m_templateCount = checkpoint.templateCount;
+    m_cssScanner.reset();
+    m_checkpoints.clear();
+}
+
+void TokenPreloadScanner::scan(const HTMLToken& token, Vector<OwnPtr<PreloadRequest> >& requests)
+{
+    scanCommon(token, requests);
+}
+
+void TokenPreloadScanner::scan(const CompactHTMLToken& token, Vector<OwnPtr<PreloadRequest> >& requests)
+{
+    scanCommon(token, requests);
+}
+
+template<typename Token>
+void TokenPreloadScanner::scanCommon(const Token& token, Vector<OwnPtr<PreloadRequest> >& requests)
+{
+    switch (token.type()) {
+    case HTMLToken::Character: {
+        if (!m_inStyle)
+            return;
+        m_cssScanner.scan(token.data(), requests);
+        return;
+    }
+    case HTMLToken::EndTag: {
+        const StringImpl* tagImpl = tagImplFor(token.data());
+        if (match(tagImpl, templateTag)) {
+            if (m_templateCount)
+                --m_templateCount;
+            return;
+        }
+        if (match(tagImpl, styleTag)) {
+            if (m_inStyle)
+                m_cssScanner.reset();
+            m_inStyle = false;
+        }
+        return;
+    }
+    case HTMLToken::StartTag: {
+        if (m_templateCount)
+            return;
+        const StringImpl* tagImpl = tagImplFor(token.data());
+        if (match(tagImpl, templateTag)) {
+            ++m_templateCount;
+            return;
+        }
+        if (match(tagImpl, styleTag)) {
+            m_inStyle = true;
+            return;
+        }
+        if (match(tagImpl, baseTag)) {
+            // The first <base> element is the one that wins.
+            if (!m_predictedBaseElementURL.isEmpty())
+                return;
+            updatePredictedBaseURL(token);
+            return;
+        }
+
+        StartTagScanner scanner(tagImpl);
+        scanner.processAttributes(token.attributes());
+        OwnPtr<PreloadRequest> request = scanner.createPreloadRequest(m_predictedBaseElementURL);
+        if (request)
+            requests.append(request.release());
+        return;
+    }
+    default: {
+        return;
+    }
+    }
+}
+
+template<typename Token>
+void TokenPreloadScanner::updatePredictedBaseURL(const Token& token)
+{
+    ASSERT(m_predictedBaseElementURL.isEmpty());
+    if (const typename Token::Attribute* hrefAttribute = token.getAttributeItem(hrefAttr))
+        m_predictedBaseElementURL = KURL(m_documentURL, stripLeadingAndTrailingHTMLSpaces(hrefAttribute->value)).copy();
+}
+
+HTMLPreloadScanner::HTMLPreloadScanner(const HTMLParserOptions& options, const KURL& documentURL)
+    : m_scanner(documentURL)
+    , m_tokenizer(HTMLTokenizer::create(options))
+{
+}
+
+HTMLPreloadScanner::~HTMLPreloadScanner()
+{
+}
+
+void HTMLPreloadScanner::appendToEnd(const SegmentedString& source)
+{
+    m_source.append(source);
+}
+
+void HTMLPreloadScanner::scan(HTMLResourcePreloader* preloader, const KURL& startingBaseElementURL)
+{
+    ASSERT(isMainThread()); // HTMLTokenizer::updateStateFor only works on the main thread.
+
+    // When we start scanning, our best prediction of the baseElementURL is the real one!
+    if (!startingBaseElementURL.isEmpty())
+        m_scanner.setPredictedBaseElementURL(startingBaseElementURL);
+
+    PreloadRequestStream requests;
+
+    while (m_tokenizer->nextToken(m_source, m_token)) {
+        if (m_token.type() == HTMLToken::StartTag)
+            m_tokenizer->updateStateFor(AtomicString(m_token.name()));
+        m_scanner.scan(m_token, requests);
+        m_token.clear();
+    }
+
+    preloader->takeAndPreload(requests);
+}
+
+}
diff --git a/Source/core/html/parser/HTMLPreloadScanner.h b/Source/core/html/parser/HTMLPreloadScanner.h
new file mode 100644
index 0000000..5c2c4ad
--- /dev/null
+++ b/Source/core/html/parser/HTMLPreloadScanner.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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 HTMLPreloadScanner_h
+#define HTMLPreloadScanner_h
+
+#include "core/html/parser/CSSPreloadScanner.h"
+#include "core/html/parser/CompactHTMLToken.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/platform/text/SegmentedString.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+typedef size_t TokenPreloadScannerCheckpoint;
+
+class HTMLParserOptions;
+class HTMLTokenizer;
+class SegmentedString;
+
+class TokenPreloadScanner {
+    WTF_MAKE_NONCOPYABLE(TokenPreloadScanner); WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit TokenPreloadScanner(const KURL& documentURL);
+    ~TokenPreloadScanner();
+
+    void scan(const HTMLToken&, PreloadRequestStream& requests);
+    void scan(const CompactHTMLToken&, PreloadRequestStream& requests);
+
+    void setPredictedBaseElementURL(const KURL& url) { m_predictedBaseElementURL = url; }
+
+    // A TokenPreloadScannerCheckpoint is valid until the next call to rewindTo,
+    // at which point all outstanding checkpoints are invalidated.
+    TokenPreloadScannerCheckpoint createCheckpoint();
+    void rewindTo(TokenPreloadScannerCheckpoint);
+
+    bool isSafeToSendToAnotherThread()
+    {
+        return m_documentURL.isSafeToSendToAnotherThread()
+            && m_predictedBaseElementURL.isSafeToSendToAnotherThread();
+    }
+
+private:
+    class StartTagScanner;
+
+    template<typename Token>
+    inline void scanCommon(const Token&, PreloadRequestStream& requests);
+
+    template<typename Token>
+    void updatePredictedBaseURL(const Token&);
+
+    struct Checkpoint {
+        Checkpoint(const KURL& predictedBaseElementURL, bool inStyle, size_t templateCount)
+            : predictedBaseElementURL(predictedBaseElementURL)
+            , inStyle(inStyle)
+            , templateCount(templateCount)
+        {
+        }
+
+        KURL predictedBaseElementURL;
+        bool inStyle;
+        size_t templateCount;
+    };
+
+    CSSPreloadScanner m_cssScanner;
+    const KURL m_documentURL;
+    KURL m_predictedBaseElementURL;
+    bool m_inStyle;
+    size_t m_templateCount;
+
+    Vector<Checkpoint> m_checkpoints;
+};
+
+class HTMLPreloadScanner {
+    WTF_MAKE_NONCOPYABLE(HTMLPreloadScanner); WTF_MAKE_FAST_ALLOCATED;
+public:
+    HTMLPreloadScanner(const HTMLParserOptions&, const KURL& documentURL);
+    ~HTMLPreloadScanner();
+
+    void appendToEnd(const SegmentedString&);
+    void scan(HTMLResourcePreloader*, const KURL& documentBaseElementURL);
+
+private:
+    TokenPreloadScanner m_scanner;
+    SegmentedString m_source;
+    HTMLToken m_token;
+    OwnPtr<HTMLTokenizer> m_tokenizer;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLResourcePreloader.cpp b/Source/core/html/parser/HTMLResourcePreloader.cpp
new file mode 100644
index 0000000..7da5f44
--- /dev/null
+++ b/Source/core/html/parser/HTMLResourcePreloader.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 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. 
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLResourcePreloader.h"
+
+#include "core/dom/Document.h"
+#include "core/loader/cache/CachedResourceLoader.h"
+
+#include "core/css/MediaList.h"
+#include "core/css/MediaQueryEvaluator.h"
+#include "core/rendering/RenderObject.h"
+
+namespace WebCore {
+
+bool PreloadRequest::isSafeToSendToAnotherThread() const
+{
+    return m_initiator.isSafeToSendToAnotherThread()
+        && m_charset.isSafeToSendToAnotherThread()
+        && m_resourceURL.isSafeToSendToAnotherThread()
+        && m_mediaAttribute.isSafeToSendToAnotherThread()
+        && m_baseURL.isSafeToSendToAnotherThread();
+}
+
+KURL PreloadRequest::completeURL(Document* document)
+{
+    return document->completeURL(m_resourceURL, m_baseURL.isEmpty() ? document->url() : m_baseURL);
+}
+
+CachedResourceRequest PreloadRequest::resourceRequest(Document* document)
+{
+    ASSERT(isMainThread());
+    CachedResourceRequest request(ResourceRequest(completeURL(document)));
+    request.setInitiator(m_initiator);
+
+    // FIXME: It's possible CORS should work for other request types?
+    if (m_resourceType == CachedResource::Script)
+        request.mutableResourceRequest().setAllowCookies(m_crossOriginModeAllowsCookies);
+    return request;
+}
+
+void HTMLResourcePreloader::takeAndPreload(PreloadRequestStream& r)
+{
+    PreloadRequestStream requests;
+    requests.swap(r);
+
+    for (PreloadRequestStream::iterator it = requests.begin(); it != requests.end(); ++it)
+        preload(it->release());
+}
+
+static bool mediaAttributeMatches(Frame* frame, RenderStyle* renderStyle, const String& attributeValue)
+{
+    RefPtr<MediaQuerySet> mediaQueries = MediaQuerySet::createAllowingDescriptionSyntax(attributeValue);
+    MediaQueryEvaluator mediaQueryEvaluator("screen", frame, renderStyle);
+    return mediaQueryEvaluator.eval(mediaQueries.get());
+}
+
+void HTMLResourcePreloader::preload(PassOwnPtr<PreloadRequest> preload)
+{
+    ASSERT(m_document->frame());
+    ASSERT(m_document->renderer());
+    ASSERT(m_document->renderer()->style());
+    if (!preload->media().isEmpty() && !mediaAttributeMatches(m_document->frame(), m_document->renderer()->style(), preload->media()))
+        return;
+
+    CachedResourceRequest request = preload->resourceRequest(m_document);
+    m_document->cachedResourceLoader()->preload(preload->resourceType(), request, preload->charset());
+}
+
+
+}
diff --git a/Source/core/html/parser/HTMLResourcePreloader.h b/Source/core/html/parser/HTMLResourcePreloader.h
new file mode 100644
index 0000000..2fcf3f2
--- /dev/null
+++ b/Source/core/html/parser/HTMLResourcePreloader.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2013 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 HTMLResourcePreloader_h
+#define HTMLResourcePreloader_h
+
+#include "core/loader/cache/CachedResource.h"
+#include "core/loader/cache/CachedResourceRequest.h"
+
+namespace WebCore {
+
+class PreloadRequest {
+public:
+    static PassOwnPtr<PreloadRequest> create(const String& initiator, const String& resourceURL, const KURL& baseURL, CachedResource::Type resourceType, const String& mediaAttribute)
+    {
+        return adoptPtr(new PreloadRequest(initiator, resourceURL, baseURL, resourceType, mediaAttribute));
+    }
+
+    static PassOwnPtr<PreloadRequest> create(const String& initiator, const String& resourceURL, const KURL& baseURL, CachedResource::Type resourceType)
+    {
+        return adoptPtr(new PreloadRequest(initiator, resourceURL, baseURL, resourceType, ""));
+    }
+
+    bool isSafeToSendToAnotherThread() const;
+
+    CachedResourceRequest resourceRequest(Document*);
+
+    const String& charset() const { return m_charset; }
+    const String& media() const { return m_mediaAttribute; }
+    void setCharset(const String& charset) { m_charset = charset.isolatedCopy(); }
+    void setCrossOriginModeAllowsCookies(bool allowsCookies) { m_crossOriginModeAllowsCookies = allowsCookies; }
+    CachedResource::Type resourceType() const { return m_resourceType; }
+
+private:
+    PreloadRequest(const String& initiator, const String& resourceURL, const KURL& baseURL, CachedResource::Type resourceType, const String& mediaAttribute)
+        : m_initiator(initiator)
+        , m_resourceURL(resourceURL.isolatedCopy())
+        , m_baseURL(baseURL.copy())
+        , m_resourceType(resourceType)
+        , m_mediaAttribute(mediaAttribute.isolatedCopy())
+        , m_crossOriginModeAllowsCookies(false)
+    {
+    }
+
+    KURL completeURL(Document*);
+
+    String m_initiator;
+    String m_resourceURL;
+    KURL m_baseURL;
+    String m_charset;
+    CachedResource::Type m_resourceType;
+    String m_mediaAttribute;
+    bool m_crossOriginModeAllowsCookies;
+};
+
+typedef Vector<OwnPtr<PreloadRequest> > PreloadRequestStream;
+
+class HTMLResourcePreloader {
+    WTF_MAKE_NONCOPYABLE(HTMLResourcePreloader); WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit HTMLResourcePreloader(Document* document)
+        : m_document(document)
+        , m_weakFactory(this)
+    {
+    }
+
+    void takeAndPreload(PreloadRequestStream&);
+    void preload(PassOwnPtr<PreloadRequest>);
+
+    WeakPtr<HTMLResourcePreloader> createWeakPtr() { return m_weakFactory.createWeakPtr(); }
+
+private:
+    Document* m_document;
+    WeakPtrFactory<HTMLResourcePreloader> m_weakFactory;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLScriptRunner.cpp b/Source/core/html/parser/HTMLScriptRunner.cpp
new file mode 100644
index 0000000..93514ef
--- /dev/null
+++ b/Source/core/html/parser/HTMLScriptRunner.cpp
@@ -0,0 +1,326 @@
+/*
+ * 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. 
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLScriptRunner.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptSourceCode.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/CustomElementRegistry.h"
+#include "core/dom/Element.h"
+#include "core/dom/Event.h"
+#include "core/dom/IgnoreDestructiveWriteCountIncrementer.h"
+#include "core/dom/MutationObserver.h"
+#include "core/dom/ScriptElement.h"
+#include "core/html/parser/HTMLInputStream.h"
+#include "core/html/parser/HTMLScriptRunnerHost.h"
+#include "core/html/parser/NestingLevelIncrementer.h"
+#include "core/loader/cache/CachedResourceLoader.h"
+#include "core/loader/cache/CachedScript.h"
+#include "core/page/Frame.h"
+#include "core/platform/NotImplemented.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HTMLScriptRunner::HTMLScriptRunner(Document* document, HTMLScriptRunnerHost* host)
+    : m_document(document)
+    , m_host(host)
+    , m_scriptNestingLevel(0)
+    , m_hasScriptsWaitingForStylesheets(false)
+{
+    ASSERT(m_host);
+}
+
+HTMLScriptRunner::~HTMLScriptRunner()
+{
+    // FIXME: Should we be passed a "done loading/parsing" callback sooner than destruction?
+    if (m_parserBlockingScript.cachedScript() && m_parserBlockingScript.watchingForLoad())
+        stopWatchingForLoad(m_parserBlockingScript);
+
+    while (!m_scriptsToExecuteAfterParsing.isEmpty()) {
+        PendingScript pendingScript = m_scriptsToExecuteAfterParsing.takeFirst();
+        if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
+            stopWatchingForLoad(pendingScript);
+    }
+}
+
+void HTMLScriptRunner::detach()
+{
+    m_document = 0;
+}
+
+static KURL documentURLForScriptExecution(Document* document)
+{
+    if (!document || !document->frame())
+        return KURL();
+
+    // Use the URL of the currently active document for this frame.
+    return document->frame()->document()->url();
+}
+
+inline PassRefPtr<Event> createScriptLoadEvent()
+{
+    return Event::create(eventNames().loadEvent, false, false);
+}
+
+ScriptSourceCode HTMLScriptRunner::sourceFromPendingScript(const PendingScript& script, bool& errorOccurred) const
+{
+    if (script.cachedScript()) {
+        errorOccurred = script.cachedScript()->errorOccurred();
+        ASSERT(script.cachedScript()->isLoaded());
+        return ScriptSourceCode(script.cachedScript());
+    }
+    errorOccurred = false;
+    return ScriptSourceCode(script.element()->textContent(), documentURLForScriptExecution(m_document), script.startingPosition());
+}
+
+bool HTMLScriptRunner::isPendingScriptReady(const PendingScript& script)
+{
+    m_hasScriptsWaitingForStylesheets = !m_document->haveStylesheetsLoaded();
+    if (m_hasScriptsWaitingForStylesheets)
+        return false;
+    if (script.cachedScript() && !script.cachedScript()->isLoaded())
+        return false;
+    return true;
+}
+
+void HTMLScriptRunner::executeParsingBlockingScript()
+{
+    ASSERT(m_document);
+    ASSERT(!isExecutingScript());
+    ASSERT(m_document->haveStylesheetsLoaded());
+    ASSERT(isPendingScriptReady(m_parserBlockingScript));
+
+    InsertionPointRecord insertionPointRecord(m_host->inputStream());
+    executePendingScriptAndDispatchEvent(m_parserBlockingScript);
+}
+
+void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendingScript)
+{
+    bool errorOccurred = false;
+    ScriptSourceCode sourceCode = sourceFromPendingScript(pendingScript, errorOccurred);
+
+    // Stop watching loads before executeScript to prevent recursion if the script reloads itself.
+    if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
+        stopWatchingForLoad(pendingScript);
+
+    if (!isExecutingScript()) {
+        CustomElementRegistry::deliverAllLifecycleCallbacks();
+        MutationObserver::deliverAllMutations();
+    }
+
+    // Clear the pending script before possible rentrancy from executeScript()
+    RefPtr<Element> element = pendingScript.releaseElementAndClear();
+    if (ScriptElement* scriptElement = toScriptElementIfPossible(element.get())) {
+        NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
+        IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document);
+        if (errorOccurred)
+            scriptElement->dispatchErrorEvent();
+        else {
+            ASSERT(isExecutingScript());
+            scriptElement->executeScript(sourceCode);
+            element->dispatchEvent(createScriptLoadEvent());
+        }
+    }
+    ASSERT(!isExecutingScript());
+}
+
+void HTMLScriptRunner::watchForLoad(PendingScript& pendingScript)
+{
+    ASSERT(!pendingScript.watchingForLoad());
+    m_host->watchForLoad(pendingScript.cachedScript());
+    pendingScript.setWatchingForLoad(true);
+}
+
+void HTMLScriptRunner::stopWatchingForLoad(PendingScript& pendingScript)
+{
+    ASSERT(pendingScript.watchingForLoad());
+    m_host->stopWatchingForLoad(pendingScript.cachedScript());
+    pendingScript.setWatchingForLoad(false);
+}
+
+// This function should match 10.2.5.11 "An end tag whose tag name is 'script'"
+// Script handling lives outside the tree builder to keep the each class simple.
+void HTMLScriptRunner::execute(PassRefPtr<Element> scriptElement, const TextPosition& scriptStartPosition)
+{
+    ASSERT(scriptElement);
+    // FIXME: If scripting is disabled, always just return.
+
+    bool hadPreloadScanner = m_host->hasPreloadScanner();
+
+    // Try to execute the script given to us.
+    runScript(scriptElement.get(), scriptStartPosition);
+
+    if (hasParserBlockingScript()) {
+        if (isExecutingScript())
+            return; // Unwind to the outermost HTMLScriptRunner::execute before continuing parsing.
+        // If preload scanner got created, it is missing the source after the current insertion point. Append it and scan.
+        if (!hadPreloadScanner && m_host->hasPreloadScanner())
+            m_host->appendCurrentInputStreamToPreloadScannerAndScan();
+        executeParsingBlockingScripts();
+    }
+}
+
+bool HTMLScriptRunner::hasParserBlockingScript() const
+{
+    return !!m_parserBlockingScript.element();
+}
+
+void HTMLScriptRunner::executeParsingBlockingScripts()
+{
+    while (hasParserBlockingScript() && isPendingScriptReady(m_parserBlockingScript))
+        executeParsingBlockingScript();
+}
+
+void HTMLScriptRunner::executeScriptsWaitingForLoad(CachedResource* cachedScript)
+{
+    ASSERT(!isExecutingScript());
+    ASSERT(hasParserBlockingScript());
+    ASSERT_UNUSED(cachedScript, m_parserBlockingScript.cachedScript() == cachedScript);
+    ASSERT(m_parserBlockingScript.cachedScript()->isLoaded());
+    executeParsingBlockingScripts();
+}
+
+void HTMLScriptRunner::executeScriptsWaitingForStylesheets()
+{
+    ASSERT(m_document);
+    // Callers should check hasScriptsWaitingForStylesheets() before calling
+    // to prevent parser or script re-entry during </style> parsing.
+    ASSERT(hasScriptsWaitingForStylesheets());
+    ASSERT(!isExecutingScript());
+    ASSERT(m_document->haveStylesheetsLoaded());
+    executeParsingBlockingScripts();
+}
+
+bool HTMLScriptRunner::executeScriptsWaitingForParsing()
+{
+    while (!m_scriptsToExecuteAfterParsing.isEmpty()) {
+        ASSERT(!isExecutingScript());
+        ASSERT(!hasParserBlockingScript());
+        ASSERT(m_scriptsToExecuteAfterParsing.first().cachedScript());
+        if (!m_scriptsToExecuteAfterParsing.first().cachedScript()->isLoaded()) {
+            watchForLoad(m_scriptsToExecuteAfterParsing.first());
+            return false;
+        }
+        PendingScript first = m_scriptsToExecuteAfterParsing.takeFirst();
+        executePendingScriptAndDispatchEvent(first);
+        // FIXME: What is this m_document check for?
+        if (!m_document)
+            return false;
+    }
+    return true;
+}
+
+void HTMLScriptRunner::requestParsingBlockingScript(Element* element)
+{
+    if (!requestPendingScript(m_parserBlockingScript, element))
+        return;
+
+    ASSERT(m_parserBlockingScript.cachedScript());
+
+    // We only care about a load callback if cachedScript is not already
+    // in the cache. Callers will attempt to run the m_parserBlockingScript
+    // if possible before returning control to the parser.
+    if (!m_parserBlockingScript.cachedScript()->isLoaded())
+        watchForLoad(m_parserBlockingScript);
+}
+
+void HTMLScriptRunner::requestDeferredScript(Element* element)
+{
+    PendingScript pendingScript;
+    if (!requestPendingScript(pendingScript, element))
+        return;
+
+    ASSERT(pendingScript.cachedScript());
+    m_scriptsToExecuteAfterParsing.append(pendingScript);
+}
+
+bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const
+{
+    ASSERT(!pendingScript.element());
+    pendingScript.setElement(script);
+    // This should correctly return 0 for empty or invalid srcValues.
+    CachedScript* cachedScript = toScriptElementIfPossible(script)->cachedScript().get();
+    if (!cachedScript) {
+        notImplemented(); // Dispatch error event.
+        return false;
+    }
+    pendingScript.setCachedScript(cachedScript);
+    return true;
+}
+
+// This method is meant to match the HTML5 definition of "running a script"
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#running-a-script
+void HTMLScriptRunner::runScript(Element* script, const TextPosition& scriptStartPosition)
+{
+    ASSERT(m_document);
+    ASSERT(!hasParserBlockingScript());
+    {
+        ScriptElement* scriptElement = toScriptElementIfPossible(script);
+
+        // This contains both and ASSERTION and a null check since we should not
+        // be getting into the case of a null script element, but seem to be from
+        // time to time. The assertion is left in to help find those cases and
+        // is being tracked by <https://bugs.webkit.org/show_bug.cgi?id=60559>.
+        ASSERT(scriptElement);
+        if (!scriptElement)
+            return;
+
+        // FIXME: This may be too agressive as we always deliver mutations at
+        // every script element, even if it's not ready to execute yet. There's
+        // unfortuantely no obvious way to tell if prepareScript is going to
+        // execute the script from out here.
+        if (!isExecutingScript()) {
+            CustomElementRegistry::deliverAllLifecycleCallbacks();
+            MutationObserver::deliverAllMutations();
+        }
+
+        InsertionPointRecord insertionPointRecord(m_host->inputStream());
+        NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
+
+        scriptElement->prepareScript(scriptStartPosition);
+
+        if (!scriptElement->willBeParserExecuted())
+            return;
+
+        if (scriptElement->willExecuteWhenDocumentFinishedParsing())
+            requestDeferredScript(script);
+        else if (scriptElement->readyToBeParserExecuted()) {
+            if (m_scriptNestingLevel == 1) {
+                m_parserBlockingScript.setElement(script);
+                m_parserBlockingScript.setStartingPosition(scriptStartPosition);
+            } else {
+                ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition);
+                scriptElement->executeScript(sourceCode);
+            }
+        } else
+            requestParsingBlockingScript(script);
+    }
+}
+
+}
diff --git a/Source/core/html/parser/HTMLScriptRunner.h b/Source/core/html/parser/HTMLScriptRunner.h
new file mode 100644
index 0000000..0e52a70
--- /dev/null
+++ b/Source/core/html/parser/HTMLScriptRunner.h
@@ -0,0 +1,102 @@
+/*
+ * 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 HTMLScriptRunner_h
+#define HTMLScriptRunner_h
+
+#include "core/dom/PendingScript.h"
+#include <wtf/Deque.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/text/TextPosition.h>
+
+namespace WebCore {
+
+class CachedResource;
+class CachedScript;
+class Document;
+class Element;
+class Frame;
+class HTMLScriptRunnerHost;
+class ScriptSourceCode;
+
+class HTMLScriptRunner {
+    WTF_MAKE_NONCOPYABLE(HTMLScriptRunner); WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<HTMLScriptRunner> create(Document* document, HTMLScriptRunnerHost* host)
+    {
+        return adoptPtr(new HTMLScriptRunner(document, host));
+    }
+    ~HTMLScriptRunner();
+
+    void detach();
+
+    // Processes the passed in script and any pending scripts if possible.
+    void execute(PassRefPtr<Element> scriptToProcess, const TextPosition& scriptStartPosition);
+
+    void executeScriptsWaitingForLoad(CachedResource*);
+    bool hasScriptsWaitingForStylesheets() const { return m_hasScriptsWaitingForStylesheets; }
+    void executeScriptsWaitingForStylesheets();
+    bool executeScriptsWaitingForParsing();
+
+    bool hasParserBlockingScript() const;
+    bool isExecutingScript() const { return !!m_scriptNestingLevel; }
+
+private:
+    HTMLScriptRunner(Document*, HTMLScriptRunnerHost*);
+
+    Frame* frame() const;
+
+    void executeParsingBlockingScript();
+    void executePendingScriptAndDispatchEvent(PendingScript&);
+    void executeParsingBlockingScripts();
+
+    void requestParsingBlockingScript(Element*);
+    void requestDeferredScript(Element*);
+    bool requestPendingScript(PendingScript&, Element*) const;
+
+    void runScript(Element*, const TextPosition& scriptStartPosition);
+
+    // Helpers for dealing with HTMLScriptRunnerHost
+    void watchForLoad(PendingScript&);
+    void stopWatchingForLoad(PendingScript&);
+    bool isPendingScriptReady(const PendingScript&);
+    ScriptSourceCode sourceFromPendingScript(const PendingScript&, bool& errorOccurred) const;
+
+    Document* m_document;
+    HTMLScriptRunnerHost* m_host;
+    PendingScript m_parserBlockingScript;
+    Deque<PendingScript> m_scriptsToExecuteAfterParsing; // http://www.whatwg.org/specs/web-apps/current-work/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing
+    unsigned m_scriptNestingLevel;
+
+    // We only want stylesheet loads to trigger script execution if script
+    // execution is currently stopped due to stylesheet loads, otherwise we'd
+    // cause nested script execution when parsing <style> tags since </style>
+    // tags can cause Document to call executeScriptsWaitingForStylesheets.
+    bool m_hasScriptsWaitingForStylesheets;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLScriptRunnerHost.h b/Source/core/html/parser/HTMLScriptRunnerHost.h
new file mode 100644
index 0000000..1f22896
--- /dev/null
+++ b/Source/core/html/parser/HTMLScriptRunnerHost.h
@@ -0,0 +1,56 @@
+/*
+ * 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 HTMLScriptRunnerHost_h
+#define HTMLScriptRunnerHost_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class CachedResource;
+class Element;
+class HTMLInputStream;
+class ScriptSourceCode;
+
+class HTMLScriptRunnerHost {
+public:
+    virtual ~HTMLScriptRunnerHost() { }
+
+    // Implementors should call cachedResource->addClient() here or soon after.
+    virtual void watchForLoad(CachedResource*) = 0;
+    // Implementors must call cachedResource->removeClient() immediately.
+    virtual void stopWatchingForLoad(CachedResource*) = 0;
+
+    virtual HTMLInputStream& inputStream() = 0;
+
+    virtual bool hasPreloadScanner() const = 0;
+    virtual void appendCurrentInputStreamToPreloadScannerAndScan() = 0;
+    
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLSourceTracker.cpp b/Source/core/html/parser/HTMLSourceTracker.cpp
new file mode 100644
index 0000000..d2e6038
--- /dev/null
+++ b/Source/core/html/parser/HTMLSourceTracker.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 Adam Barth. 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLSourceTracker.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+HTMLSourceTracker::HTMLSourceTracker()
+{
+}
+
+void HTMLSourceTracker::start(SegmentedString& currentInput, HTMLTokenizer* tokenizer, HTMLToken& token)
+{
+    if (token.type() == HTMLToken::Uninitialized) {
+        m_previousSource.clear();
+        if (tokenizer->numberOfBufferedCharacters())
+            m_previousSource = tokenizer->bufferedCharacters();
+    } else
+        m_previousSource.append(m_currentSource);
+
+    m_currentSource = currentInput;
+    token.setBaseOffset(m_currentSource.numberOfCharactersConsumed() - m_previousSource.length());
+}
+
+void HTMLSourceTracker::end(SegmentedString& currentInput, HTMLTokenizer* tokenizer, HTMLToken& token)
+{
+    m_cachedSourceForToken = String();
+
+    // FIXME: This work should really be done by the HTMLTokenizer.
+    token.end(currentInput.numberOfCharactersConsumed() - tokenizer->numberOfBufferedCharacters());
+}
+
+String HTMLSourceTracker::sourceForToken(const HTMLToken& token)
+{
+    if (token.type() == HTMLToken::EndOfFile)
+        return String(); // Hides the null character we use to mark the end of file.
+
+    if (!m_cachedSourceForToken.isEmpty())
+        return m_cachedSourceForToken;
+
+    ASSERT(!token.startIndex());
+    size_t length = static_cast<size_t>(token.endIndex() - token.startIndex());
+
+    StringBuilder source;
+    source.reserveCapacity(length);
+
+    size_t i = 0;
+    for ( ; i < length && !m_previousSource.isEmpty(); ++i) {
+        source.append(m_previousSource.currentChar());
+        m_previousSource.advance();
+    }
+    for ( ; i < length; ++i) {
+        ASSERT(!m_currentSource.isEmpty());
+        source.append(m_currentSource.currentChar());
+        m_currentSource.advance();
+    }
+
+    m_cachedSourceForToken = source.toString();
+    return m_cachedSourceForToken;
+}
+
+}
diff --git a/Source/core/html/parser/HTMLSourceTracker.h b/Source/core/html/parser/HTMLSourceTracker.h
new file mode 100644
index 0000000..79b4aca
--- /dev/null
+++ b/Source/core/html/parser/HTMLSourceTracker.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Adam Barth. 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 HTMLSourceTracker_h
+#define HTMLSourceTracker_h
+
+#include "core/html/parser/HTMLToken.h"
+#include "core/platform/text/SegmentedString.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+class HTMLTokenizer;
+
+class HTMLSourceTracker {
+    WTF_MAKE_NONCOPYABLE(HTMLSourceTracker);
+public:
+    HTMLSourceTracker();
+
+    // FIXME: Once we move "end" into HTMLTokenizer, rename "start" to
+    // something that makes it obvious that this method can be called multiple
+    // times.
+    void start(SegmentedString&, HTMLTokenizer*, HTMLToken&);
+    void end(SegmentedString&, HTMLTokenizer*, HTMLToken&);
+
+    String sourceForToken(const HTMLToken&);
+
+private:
+    SegmentedString m_previousSource;
+    SegmentedString m_currentSource;
+
+    String m_cachedSourceForToken;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLStackItem.h b/Source/core/html/parser/HTMLStackItem.h
new file mode 100644
index 0000000..dd8eac6
--- /dev/null
+++ b/Source/core/html/parser/HTMLStackItem.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2012 Company 100, 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 GOOGLE 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 GOOGLE 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 HTMLStackItem_h
+#define HTMLStackItem_h
+
+#include "HTMLNames.h"
+#include "MathMLNames.h"
+#include "SVGNames.h"
+#include "core/dom/Element.h"
+#include "core/html/parser/AtomicHTMLToken.h"
+
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+class ContainerNode;
+
+class HTMLStackItem : public RefCounted<HTMLStackItem> {
+public:
+    enum ItemType {
+        ItemForContextElement,
+        ItemForDocumentFragmentNode
+    };
+
+    // Used by document fragment node and context element.
+    static PassRefPtr<HTMLStackItem> create(PassRefPtr<ContainerNode> node, ItemType type)
+    {
+        return adoptRef(new HTMLStackItem(node, type));
+    }
+
+    // Used by HTMLElementStack and HTMLFormattingElementList.
+    static PassRefPtr<HTMLStackItem> create(PassRefPtr<ContainerNode> node, AtomicHTMLToken* token, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI)
+    {
+        return adoptRef(new HTMLStackItem(node, token, namespaceURI));
+    }
+
+    Element* element() const { return toElement(m_node.get()); }
+    ContainerNode* node() const { return m_node.get(); }
+
+    bool isDocumentFragmentNode() const { return m_isDocumentFragmentNode; }
+    bool isElementNode() const { return !m_isDocumentFragmentNode; }
+
+    const AtomicString& namespaceURI() const { return m_namespaceURI; }
+    const AtomicString& localName() const { return m_tokenLocalName; }
+
+    const Vector<Attribute>& attributes() const { ASSERT(m_tokenLocalName); return m_tokenAttributes; }
+    Attribute* getAttributeItem(const QualifiedName& attributeName)
+    {
+        ASSERT(m_tokenLocalName);
+        return findAttributeInVector(m_tokenAttributes, attributeName);
+    }
+
+    bool hasLocalName(const AtomicString& name) const { return m_tokenLocalName == name; }
+    bool hasTagName(const QualifiedName& name) const { return m_tokenLocalName == name.localName() && m_namespaceURI == name.namespaceURI(); }
+
+    bool matchesHTMLTag(const AtomicString& name) const { return m_tokenLocalName == name && m_namespaceURI == HTMLNames::xhtmlNamespaceURI; }
+    bool matchesHTMLTag(const QualifiedName& name) const { return m_tokenLocalName == name && m_namespaceURI == HTMLNames::xhtmlNamespaceURI; }
+
+    bool causesFosterParenting()
+    {
+        return hasTagName(HTMLNames::tableTag)
+            || hasTagName(HTMLNames::tbodyTag)
+            || hasTagName(HTMLNames::tfootTag)
+            || hasTagName(HTMLNames::theadTag)
+            || hasTagName(HTMLNames::trTag);
+    }
+
+    bool isInHTMLNamespace() const
+    {
+        // A DocumentFragment takes the place of the document element when parsing
+        // fragments and should be considered in the HTML namespace.
+        return namespaceURI() == HTMLNames::xhtmlNamespaceURI
+            || isDocumentFragmentNode(); // FIXME: Does this also apply to ShadowRoot?
+    }
+
+    bool isNumberedHeaderElement() const
+    {
+        return hasTagName(HTMLNames::h1Tag)
+            || hasTagName(HTMLNames::h2Tag)
+            || hasTagName(HTMLNames::h3Tag)
+            || hasTagName(HTMLNames::h4Tag)
+            || hasTagName(HTMLNames::h5Tag)
+            || hasTagName(HTMLNames::h6Tag);
+    }
+
+    bool isTableBodyContextElement() const
+    {
+        return hasTagName(HTMLNames::tbodyTag)
+            || hasTagName(HTMLNames::tfootTag)
+            || hasTagName(HTMLNames::theadTag);
+    }
+
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#special
+    bool isSpecialNode() const
+    {
+        if (hasTagName(MathMLNames::miTag)
+            || hasTagName(MathMLNames::moTag)
+            || hasTagName(MathMLNames::mnTag)
+            || hasTagName(MathMLNames::msTag)
+            || hasTagName(MathMLNames::mtextTag)
+            || hasTagName(MathMLNames::annotation_xmlTag)
+            || hasTagName(SVGNames::foreignObjectTag)
+            || hasTagName(SVGNames::descTag)
+            || hasTagName(SVGNames::titleTag))
+            return true;
+        if (isDocumentFragmentNode())
+            return true;
+        if (!isInHTMLNamespace())
+            return false;
+        const AtomicString& tagName = localName();
+        return tagName == HTMLNames::addressTag
+            || tagName == HTMLNames::appletTag
+            || tagName == HTMLNames::areaTag
+            || tagName == HTMLNames::articleTag
+            || tagName == HTMLNames::asideTag
+            || tagName == HTMLNames::baseTag
+            || tagName == HTMLNames::basefontTag
+            || tagName == HTMLNames::bgsoundTag
+            || tagName == HTMLNames::blockquoteTag
+            || tagName == HTMLNames::bodyTag
+            || tagName == HTMLNames::brTag
+            || tagName == HTMLNames::buttonTag
+            || tagName == HTMLNames::captionTag
+            || tagName == HTMLNames::centerTag
+            || tagName == HTMLNames::colTag
+            || tagName == HTMLNames::colgroupTag
+            || tagName == HTMLNames::commandTag
+            || tagName == HTMLNames::ddTag
+            || tagName == HTMLNames::detailsTag
+            || tagName == HTMLNames::dirTag
+            || tagName == HTMLNames::divTag
+            || tagName == HTMLNames::dlTag
+            || tagName == HTMLNames::dtTag
+            || tagName == HTMLNames::embedTag
+            || tagName == HTMLNames::fieldsetTag
+            || tagName == HTMLNames::figcaptionTag
+            || tagName == HTMLNames::figureTag
+            || tagName == HTMLNames::footerTag
+            || tagName == HTMLNames::formTag
+            || tagName == HTMLNames::frameTag
+            || tagName == HTMLNames::framesetTag
+            || isNumberedHeaderElement()
+            || tagName == HTMLNames::headTag
+            || tagName == HTMLNames::headerTag
+            || tagName == HTMLNames::hgroupTag
+            || tagName == HTMLNames::hrTag
+            || tagName == HTMLNames::htmlTag
+            || tagName == HTMLNames::iframeTag
+            || tagName == HTMLNames::imgTag
+            || tagName == HTMLNames::inputTag
+            || tagName == HTMLNames::isindexTag
+            || tagName == HTMLNames::liTag
+            || tagName == HTMLNames::linkTag
+            || tagName == HTMLNames::listingTag
+            || tagName == HTMLNames::mainTag
+            || tagName == HTMLNames::marqueeTag
+            || tagName == HTMLNames::menuTag
+            || tagName == HTMLNames::metaTag
+            || tagName == HTMLNames::navTag
+            || tagName == HTMLNames::noembedTag
+            || tagName == HTMLNames::noframesTag
+            || tagName == HTMLNames::noscriptTag
+            || tagName == HTMLNames::objectTag
+            || tagName == HTMLNames::olTag
+            || tagName == HTMLNames::pTag
+            || tagName == HTMLNames::paramTag
+            || tagName == HTMLNames::plaintextTag
+            || tagName == HTMLNames::preTag
+            || tagName == HTMLNames::scriptTag
+            || tagName == HTMLNames::sectionTag
+            || tagName == HTMLNames::selectTag
+            || tagName == HTMLNames::styleTag
+            || tagName == HTMLNames::summaryTag
+            || tagName == HTMLNames::tableTag
+            || isTableBodyContextElement()
+            || tagName == HTMLNames::tdTag
+            || tagName == HTMLNames::templateTag
+            || tagName == HTMLNames::textareaTag
+            || tagName == HTMLNames::thTag
+            || tagName == HTMLNames::titleTag
+            || tagName == HTMLNames::trTag
+            || tagName == HTMLNames::ulTag
+            || tagName == HTMLNames::wbrTag
+            || tagName == HTMLNames::xmpTag;
+    }
+
+private:
+    HTMLStackItem(PassRefPtr<ContainerNode> node, ItemType type)
+        : m_node(node)
+    {
+        switch (type) {
+        case ItemForDocumentFragmentNode:
+            m_isDocumentFragmentNode = true;
+            break;
+        case ItemForContextElement:
+            m_tokenLocalName = m_node->localName();
+            m_namespaceURI = m_node->namespaceURI();
+            m_isDocumentFragmentNode = false;
+            break;
+        }
+    }
+
+    HTMLStackItem(PassRefPtr<ContainerNode> node, AtomicHTMLToken* token, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI)
+        : m_node(node)
+        , m_tokenLocalName(token->name())
+        , m_tokenAttributes(token->attributes())
+        , m_namespaceURI(namespaceURI)
+        , m_isDocumentFragmentNode(false)
+    {
+    }
+
+    RefPtr<ContainerNode> m_node;
+
+    AtomicString m_tokenLocalName;
+    Vector<Attribute> m_tokenAttributes;
+    AtomicString m_namespaceURI;
+    bool m_isDocumentFragmentNode;
+};
+
+} // namespace WebCore
+
+#endif // HTMLStackItem_h
diff --git a/Source/core/html/parser/HTMLToken.h b/Source/core/html/parser/HTMLToken.h
new file mode 100644
index 0000000..87732d3
--- /dev/null
+++ b/Source/core/html/parser/HTMLToken.h
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2013 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 HTMLToken_h
+#define HTMLToken_h
+
+#include "core/dom/Attribute.h"
+#include "core/html/parser/HTMLToken.h"
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class DoctypeData {
+    WTF_MAKE_NONCOPYABLE(DoctypeData);
+public:
+    DoctypeData()
+        : m_hasPublicIdentifier(false)
+        , m_hasSystemIdentifier(false)
+        , m_forceQuirks(false)
+    {
+    }
+
+    // FIXME: This should use String instead of Vector<UChar>.
+    bool m_hasPublicIdentifier;
+    bool m_hasSystemIdentifier;
+    WTF::Vector<UChar> m_publicIdentifier;
+    WTF::Vector<UChar> m_systemIdentifier;
+    bool m_forceQuirks;
+};
+
+static inline Attribute* findAttributeInVector(Vector<Attribute>& attributes, const QualifiedName& name)
+{
+    for (unsigned i = 0; i < attributes.size(); ++i) {
+        if (attributes.at(i).name().matches(name))
+            return &attributes.at(i);
+    }
+    return 0;
+}
+
+class HTMLToken {
+    WTF_MAKE_NONCOPYABLE(HTMLToken);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    enum Type {
+        Uninitialized,
+        DOCTYPE,
+        StartTag,
+        EndTag,
+        Comment,
+        Character,
+        EndOfFile,
+    };
+
+    class Attribute {
+    public:
+        class Range {
+        public:
+            int start;
+            int end;
+        };
+
+        Range nameRange;
+        Range valueRange;
+        Vector<UChar, 32> name;
+        Vector<UChar, 32> value;
+    };
+
+    typedef WTF::Vector<Attribute, 10> AttributeList;
+    typedef WTF::Vector<UChar, 1024> DataVector;
+
+    HTMLToken() { clear(); }
+
+    void clear()
+    {
+        m_type = Uninitialized;
+        m_range.start = 0;
+        m_range.end = 0;
+        m_baseOffset = 0;
+        m_data.clear();
+        m_orAllData = 0;
+    }
+
+    bool isUninitialized() { return m_type == Uninitialized; }
+    Type type() const { return m_type; }
+
+    void makeEndOfFile()
+    {
+        ASSERT(m_type == Uninitialized);
+        m_type = EndOfFile;
+    }
+
+    /* Range and offset methods exposed for HTMLSourceTracker and HTMLViewSourceParser */
+    int startIndex() const { return m_range.start; }
+    int endIndex() const { return m_range.end; }
+
+    void setBaseOffset(int offset)
+    {
+        m_baseOffset = offset;
+    }
+
+    void end(int endOffset)
+    {
+        m_range.end = endOffset - m_baseOffset;
+    }
+
+    const DataVector& data() const
+    {
+        ASSERT(m_type == Character || m_type == Comment || m_type == StartTag || m_type == EndTag);
+        return m_data;
+    }
+
+    bool isAll8BitData() const
+    {
+        return (m_orAllData <= 0xff);
+    }
+
+    const DataVector& name() const
+    {
+        ASSERT(m_type == StartTag || m_type == EndTag || m_type == DOCTYPE);
+        return m_data;
+    }
+
+    void appendToName(UChar character)
+    {
+        ASSERT(m_type == StartTag || m_type == EndTag || m_type == DOCTYPE);
+        ASSERT(character);
+        m_data.append(character);
+        m_orAllData |= character;
+    }
+
+    /* DOCTYPE Tokens */
+
+    bool forceQuirks() const
+    {
+        ASSERT(m_type == DOCTYPE);
+        return m_doctypeData->m_forceQuirks;
+    }
+
+    void setForceQuirks()
+    {
+        ASSERT(m_type == DOCTYPE);
+        m_doctypeData->m_forceQuirks = true;
+    }
+
+    void beginDOCTYPE()
+    {
+        ASSERT(m_type == Uninitialized);
+        m_type = DOCTYPE;
+        m_doctypeData = adoptPtr(new DoctypeData);
+    }
+
+    void beginDOCTYPE(UChar character)
+    {
+        ASSERT(character);
+        beginDOCTYPE();
+        m_data.append(character);
+        m_orAllData |= character;
+    }
+
+    // FIXME: Distinguish between a missing public identifer and an empty one.
+    const WTF::Vector<UChar>& publicIdentifier() const
+    {
+        ASSERT(m_type == DOCTYPE);
+        return m_doctypeData->m_publicIdentifier;
+    }
+
+    // FIXME: Distinguish between a missing system identifer and an empty one.
+    const WTF::Vector<UChar>& systemIdentifier() const
+    {
+        ASSERT(m_type == DOCTYPE);
+        return m_doctypeData->m_systemIdentifier;
+    }
+
+    void setPublicIdentifierToEmptyString()
+    {
+        ASSERT(m_type == DOCTYPE);
+        m_doctypeData->m_hasPublicIdentifier = true;
+        m_doctypeData->m_publicIdentifier.clear();
+    }
+
+    void setSystemIdentifierToEmptyString()
+    {
+        ASSERT(m_type == DOCTYPE);
+        m_doctypeData->m_hasSystemIdentifier = true;
+        m_doctypeData->m_systemIdentifier.clear();
+    }
+
+    void appendToPublicIdentifier(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == DOCTYPE);
+        ASSERT(m_doctypeData->m_hasPublicIdentifier);
+        m_doctypeData->m_publicIdentifier.append(character);
+    }
+
+    void appendToSystemIdentifier(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == DOCTYPE);
+        ASSERT(m_doctypeData->m_hasSystemIdentifier);
+        m_doctypeData->m_systemIdentifier.append(character);
+    }
+
+    PassOwnPtr<DoctypeData> releaseDoctypeData()
+    {
+        return m_doctypeData.release();
+    }
+
+    /* Start/End Tag Tokens */
+
+    bool selfClosing() const
+    {
+        ASSERT(m_type == StartTag || m_type == EndTag);
+        return m_selfClosing;
+    }
+
+    void setSelfClosing()
+    {
+        ASSERT(m_type == StartTag || m_type == EndTag);
+        m_selfClosing = true;
+    }
+
+    void beginStartTag(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == Uninitialized);
+        m_type = StartTag;
+        m_selfClosing = false;
+        m_currentAttribute = 0;
+        m_attributes.clear();
+
+        m_data.append(character);
+        m_orAllData |= character;
+    }
+
+    void beginEndTag(LChar character)
+    {
+        ASSERT(m_type == Uninitialized);
+        m_type = EndTag;
+        m_selfClosing = false;
+        m_currentAttribute = 0;
+        m_attributes.clear();
+
+        m_data.append(character);
+    }
+
+    void beginEndTag(const Vector<LChar, 32>& characters)
+    {
+        ASSERT(m_type == Uninitialized);
+        m_type = EndTag;
+        m_selfClosing = false;
+        m_currentAttribute = 0;
+        m_attributes.clear();
+
+        m_data.appendVector(characters);
+    }
+
+    void addNewAttribute()
+    {
+        ASSERT(m_type == StartTag || m_type == EndTag);
+        m_attributes.grow(m_attributes.size() + 1);
+        m_currentAttribute = &m_attributes.last();
+#ifndef NDEBUG
+        m_currentAttribute->nameRange.start = 0;
+        m_currentAttribute->nameRange.end = 0;
+        m_currentAttribute->valueRange.start = 0;
+        m_currentAttribute->valueRange.end = 0;
+#endif
+    }
+
+    void beginAttributeName(int offset)
+    {
+        m_currentAttribute->nameRange.start = offset - m_baseOffset;
+    }
+
+    void endAttributeName(int offset)
+    {
+        int index = offset - m_baseOffset;
+        m_currentAttribute->nameRange.end = index;
+        m_currentAttribute->valueRange.start = index;
+        m_currentAttribute->valueRange.end = index;
+    }
+
+    void beginAttributeValue(int offset)
+    {
+        m_currentAttribute->valueRange.start = offset - m_baseOffset;
+#ifndef NDEBUG
+        m_currentAttribute->valueRange.end = 0;
+#endif
+    }
+
+    void endAttributeValue(int offset)
+    {
+        m_currentAttribute->valueRange.end = offset - m_baseOffset;
+    }
+
+    void appendToAttributeName(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == StartTag || m_type == EndTag);
+        // FIXME: We should be able to add the following ASSERT once we fix
+        // https://bugs.webkit.org/show_bug.cgi?id=62971
+        //   ASSERT(m_currentAttribute->nameRange.start);
+        m_currentAttribute->name.append(character);
+    }
+
+    void appendToAttributeValue(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == StartTag || m_type == EndTag);
+        ASSERT(m_currentAttribute->valueRange.start);
+        m_currentAttribute->value.append(character);
+    }
+
+    void appendToAttributeValue(size_t i, const String& value)
+    {
+        ASSERT(!value.isEmpty());
+        ASSERT(m_type == StartTag || m_type == EndTag);
+        append(m_attributes[i].value, value);
+    }
+
+    const AttributeList& attributes() const
+    {
+        ASSERT(m_type == StartTag || m_type == EndTag);
+        return m_attributes;
+    }
+
+    const Attribute* getAttributeItem(const QualifiedName& name) const
+    {
+        for (unsigned i = 0; i < m_attributes.size(); ++i) {
+            if (AtomicString(m_attributes.at(i).name) == name.localName())
+                return &m_attributes.at(i);
+        }
+        return 0;
+    }
+
+    // Used by the XSSAuditor to nuke XSS-laden attributes.
+    void eraseValueOfAttribute(size_t i)
+    {
+        ASSERT(m_type == StartTag || m_type == EndTag);
+        m_attributes[i].value.clear();
+    }
+
+    /* Character Tokens */
+
+    // Starting a character token works slightly differently than starting
+    // other types of tokens because we want to save a per-character branch.
+    void ensureIsCharacterToken()
+    {
+        ASSERT(m_type == Uninitialized || m_type == Character);
+        m_type = Character;
+    }
+
+    const DataVector& characters() const
+    {
+        ASSERT(m_type == Character);
+        return m_data;
+    }
+
+    void appendToCharacter(char character)
+    {
+        ASSERT(m_type == Character);
+        m_data.append(character);
+    }
+
+    void appendToCharacter(UChar character)
+    {
+        ASSERT(m_type == Character);
+        m_data.append(character);
+        m_orAllData |= character;
+    }
+
+    void appendToCharacter(const Vector<LChar, 32>& characters)
+    {
+        ASSERT(m_type == Character);
+        m_data.appendVector(characters);
+    }
+
+    /* Comment Tokens */
+
+    const DataVector& comment() const
+    {
+        ASSERT(m_type == Comment);
+        return m_data;
+    }
+
+    void beginComment()
+    {
+        ASSERT(m_type == Uninitialized);
+        m_type = Comment;
+    }
+
+    void appendToComment(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == Comment);
+        m_data.append(character);
+        m_orAllData |= character;
+    }
+
+    void eraseCharacters()
+    {
+        ASSERT(m_type == Character);
+        m_data.clear();
+        m_orAllData = 0;
+    }
+
+private:
+    Type m_type;
+    Attribute::Range m_range; // Always starts at zero.
+    int m_baseOffset;
+    DataVector m_data;
+    UChar m_orAllData;
+
+    // For StartTag and EndTag
+    bool m_selfClosing;
+    AttributeList m_attributes;
+
+    // A pointer into m_attributes used during lexing.
+    Attribute* m_currentAttribute;
+
+    // For DOCTYPE
+    OwnPtr<DoctypeData> m_doctypeData;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLTokenizer.cpp b/Source/core/html/parser/HTMLTokenizer.cpp
new file mode 100644
index 0000000..5775af9
--- /dev/null
+++ b/Source/core/html/parser/HTMLTokenizer.cpp
@@ -0,0 +1,1651 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/
+ * 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. 
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLTokenizer.h"
+
+#include "HTMLNames.h"
+#include "core/html/parser/HTMLEntityParser.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/html/parser/HTMLTreeBuilder.h"
+#include "core/platform/NotImplemented.h"
+#include "core/xml/parser/MarkupTokenizerInlines.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/CString.h>
+#include <wtf/unicode/Unicode.h>
+#include <wtf/UnusedParam.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// This has to go in a .cpp file, as the linker doesn't like it being included more than once.
+// We don't have an HTMLToken.cpp though, so this is the next best place.
+QualifiedName AtomicHTMLToken::nameForAttribute(const HTMLToken::Attribute& attribute) const
+{
+    return QualifiedName(nullAtom, AtomicString(attribute.name), nullAtom);
+}
+
+bool AtomicHTMLToken::usesName() const
+{
+    return m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag || m_type == HTMLToken::DOCTYPE;
+}
+
+bool AtomicHTMLToken::usesAttributes() const
+{
+    return m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag;
+}
+
+static inline UChar toLowerCase(UChar cc)
+{
+    ASSERT(isASCIIUpper(cc));
+    const int lowerCaseOffset = 0x20;
+    return cc + lowerCaseOffset;
+}
+
+static inline bool vectorEqualsString(const Vector<LChar, 32>& vector, const String& string)
+{
+    if (vector.size() != string.length())
+        return false;
+
+    if (!string.length())
+        return true;
+
+    return equal(string.impl(), vector.data(), vector.size());
+}
+
+static inline bool isEndTagBufferingState(HTMLTokenizer::State state)
+{
+    switch (state) {
+    case HTMLTokenizer::RCDATAEndTagOpenState:
+    case HTMLTokenizer::RCDATAEndTagNameState:
+    case HTMLTokenizer::RAWTEXTEndTagOpenState:
+    case HTMLTokenizer::RAWTEXTEndTagNameState:
+    case HTMLTokenizer::ScriptDataEndTagOpenState:
+    case HTMLTokenizer::ScriptDataEndTagNameState:
+    case HTMLTokenizer::ScriptDataEscapedEndTagOpenState:
+    case HTMLTokenizer::ScriptDataEscapedEndTagNameState:
+        return true;
+    default:
+        return false;
+    }
+}
+
+#define HTML_BEGIN_STATE(stateName) BEGIN_STATE(HTMLTokenizer, stateName)
+#define HTML_RECONSUME_IN(stateName) RECONSUME_IN(HTMLTokenizer, stateName)
+#define HTML_ADVANCE_TO(stateName) ADVANCE_TO(HTMLTokenizer, stateName)
+#define HTML_SWITCH_TO(stateName) SWITCH_TO(HTMLTokenizer, stateName)
+
+HTMLTokenizer::HTMLTokenizer(const HTMLParserOptions& options)
+    : m_inputStreamPreprocessor(this)
+    , m_options(options)
+{
+    reset();
+}
+
+HTMLTokenizer::~HTMLTokenizer()
+{
+}
+
+void HTMLTokenizer::reset()
+{
+    m_state = HTMLTokenizer::DataState;
+    m_token = 0;
+    m_forceNullCharacterReplacement = false;
+    m_shouldAllowCDATA = false;
+    m_additionalAllowedCharacter = '\0';
+}
+
+bool HTMLTokenizer::canCreateCheckpoint() const
+{
+    if (!m_appropriateEndTagName.isEmpty())
+        return false;
+    if (!m_temporaryBuffer.isEmpty())
+        return false;
+    if (!m_bufferedEndTagName.isEmpty())
+        return false;
+    return true;
+}
+
+void HTMLTokenizer::createCheckpoint(Checkpoint& result) const
+{
+    ASSERT(canCreateCheckpoint());
+    result.options = m_options;
+    result.state = m_state;
+    result.additionalAllowedCharacter = m_additionalAllowedCharacter;
+    result.skipNextNewLine = m_inputStreamPreprocessor.skipNextNewLine();
+    result.shouldAllowCDATA = m_shouldAllowCDATA;
+}
+
+void HTMLTokenizer::restoreFromCheckpoint(const Checkpoint& checkpoint)
+{
+    m_token = 0;
+    m_options = checkpoint.options;
+    m_state = checkpoint.state;
+    m_additionalAllowedCharacter = checkpoint.additionalAllowedCharacter;
+    m_inputStreamPreprocessor.reset(checkpoint.skipNextNewLine);
+    m_shouldAllowCDATA = checkpoint.shouldAllowCDATA;
+}
+
+inline bool HTMLTokenizer::processEntity(SegmentedString& source)
+{
+    bool notEnoughCharacters = false;
+    StringBuilder decodedEntity;
+    bool success = consumeHTMLEntity(source, decodedEntity, notEnoughCharacters);
+    if (notEnoughCharacters)
+        return false;
+    if (!success) {
+        ASSERT(decodedEntity.isEmpty());
+        bufferCharacter('&');
+    } else {
+        for (unsigned i = 0; i < decodedEntity.length(); ++i)
+            bufferCharacter(decodedEntity[i]);
+    }
+    return true;
+}
+
+bool HTMLTokenizer::flushBufferedEndTag(SegmentedString& source)
+{
+    ASSERT(m_token->type() == HTMLToken::Character || m_token->type() == HTMLToken::Uninitialized);
+    source.advanceAndUpdateLineNumber();
+    if (m_token->type() == HTMLToken::Character)
+        return true;
+    m_token->beginEndTag(m_bufferedEndTagName);
+    m_bufferedEndTagName.clear();
+    m_appropriateEndTagName.clear();
+    m_temporaryBuffer.clear();
+    return false;
+}
+
+#define FLUSH_AND_ADVANCE_TO(stateName)                                    \
+    do {                                                                   \
+        m_state = HTMLTokenizer::stateName;                           \
+        if (flushBufferedEndTag(source))                                   \
+            return true;                                                   \
+        if (source.isEmpty()                                               \
+            || !m_inputStreamPreprocessor.peek(source))                    \
+            return haveBufferedCharacterToken();                           \
+        cc = m_inputStreamPreprocessor.nextInputCharacter();               \
+        goto stateName;                                                    \
+    } while (false)
+
+bool HTMLTokenizer::flushEmitAndResumeIn(SegmentedString& source, HTMLTokenizer::State state)
+{
+    m_state = state;
+    flushBufferedEndTag(source);
+    return true;
+}
+
+bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
+{
+    // If we have a token in progress, then we're supposed to be called back
+    // with the same token so we can finish it.
+    ASSERT(!m_token || m_token == &token || token.type() == HTMLToken::Uninitialized);
+    m_token = &token;
+
+    if (!m_bufferedEndTagName.isEmpty() && !isEndTagBufferingState(m_state)) {
+        // FIXME: This should call flushBufferedEndTag().
+        // We started an end tag during our last iteration.
+        m_token->beginEndTag(m_bufferedEndTagName);
+        m_bufferedEndTagName.clear();
+        m_appropriateEndTagName.clear();
+        m_temporaryBuffer.clear();
+        if (m_state == HTMLTokenizer::DataState) {
+            // We're back in the data state, so we must be done with the tag.
+            return true;
+        }
+    }
+
+    if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source))
+        return haveBufferedCharacterToken();
+    UChar cc = m_inputStreamPreprocessor.nextInputCharacter();
+
+    // Source: http://www.whatwg.org/specs/web-apps/current-work/#tokenisation0
+    switch (m_state) {
+    HTML_BEGIN_STATE(DataState) {
+        if (cc == '&')
+            HTML_ADVANCE_TO(CharacterReferenceInDataState);
+        else if (cc == '<') {
+            if (m_token->type() == HTMLToken::Character) {
+                // We have a bunch of character tokens queued up that we
+                // are emitting lazily here.
+                return true;
+            }
+            HTML_ADVANCE_TO(TagOpenState);
+        } else if (cc == kEndOfFileMarker)
+            return emitEndOfFile(source);
+        else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(DataState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CharacterReferenceInDataState) {
+        if (!processEntity(source))
+            return haveBufferedCharacterToken();
+        HTML_SWITCH_TO(DataState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(RCDATAState) {
+        if (cc == '&')
+            HTML_ADVANCE_TO(CharacterReferenceInRCDATAState);
+        else if (cc == '<')
+            HTML_ADVANCE_TO(RCDATALessThanSignState);
+        else if (cc == kEndOfFileMarker)
+            return emitEndOfFile(source);
+        else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(RCDATAState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CharacterReferenceInRCDATAState) {
+        if (!processEntity(source))
+            return haveBufferedCharacterToken();
+        HTML_SWITCH_TO(RCDATAState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(RAWTEXTState) {
+        if (cc == '<')
+            HTML_ADVANCE_TO(RAWTEXTLessThanSignState);
+        else if (cc == kEndOfFileMarker)
+            return emitEndOfFile(source);
+        else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(RAWTEXTState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataState) {
+        if (cc == '<')
+            HTML_ADVANCE_TO(ScriptDataLessThanSignState);
+        else if (cc == kEndOfFileMarker)
+            return emitEndOfFile(source);
+        else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(PLAINTEXTState) {
+        if (cc == kEndOfFileMarker)
+            return emitEndOfFile(source);
+        bufferCharacter(cc);
+        HTML_ADVANCE_TO(PLAINTEXTState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(TagOpenState) {
+        if (cc == '!')
+            HTML_ADVANCE_TO(MarkupDeclarationOpenState);
+        else if (cc == '/')
+            HTML_ADVANCE_TO(EndTagOpenState);
+        else if (isASCIIUpper(cc)) {
+            m_token->beginStartTag(toLowerCase(cc));
+            HTML_ADVANCE_TO(TagNameState);
+        } else if (isASCIILower(cc)) {
+            m_token->beginStartTag(cc);
+            HTML_ADVANCE_TO(TagNameState);
+        } else if (cc == '?') {
+            parseError();
+            // The spec consumes the current character before switching
+            // to the bogus comment state, but it's easier to implement
+            // if we reconsume the current character.
+            HTML_RECONSUME_IN(BogusCommentState);
+        } else {
+            parseError();
+            bufferCharacter('<');
+            HTML_RECONSUME_IN(DataState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(EndTagOpenState) {
+        if (isASCIIUpper(cc)) {
+            m_token->beginEndTag(static_cast<LChar>(toLowerCase(cc)));
+            m_appropriateEndTagName.clear();
+            HTML_ADVANCE_TO(TagNameState);
+        } else if (isASCIILower(cc)) {
+            m_token->beginEndTag(static_cast<LChar>(cc));
+            m_appropriateEndTagName.clear();
+            HTML_ADVANCE_TO(TagNameState);
+        } else if (cc == '>') {
+            parseError();
+            HTML_ADVANCE_TO(DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            bufferCharacter('<');
+            bufferCharacter('/');
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            parseError();
+            HTML_RECONSUME_IN(BogusCommentState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(TagNameState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeAttributeNameState);
+        else if (cc == '/')
+            HTML_ADVANCE_TO(SelfClosingStartTagState);
+        else if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (isASCIIUpper(cc)) {
+            m_token->appendToName(toLowerCase(cc));
+            HTML_ADVANCE_TO(TagNameState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            m_token->appendToName(cc);
+            HTML_ADVANCE_TO(TagNameState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(RCDATALessThanSignState) {
+        if (cc == '/') {
+            m_temporaryBuffer.clear();
+            ASSERT(m_bufferedEndTagName.isEmpty());
+            HTML_ADVANCE_TO(RCDATAEndTagOpenState);
+        } else {
+            bufferCharacter('<');
+            HTML_RECONSUME_IN(RCDATAState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(RCDATAEndTagOpenState) {
+        if (isASCIIUpper(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
+            HTML_ADVANCE_TO(RCDATAEndTagNameState);
+        } else if (isASCIILower(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(RCDATAEndTagNameState);
+        } else {
+            bufferCharacter('<');
+            bufferCharacter('/');
+            HTML_RECONSUME_IN(RCDATAState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(RCDATAEndTagNameState) {
+        if (isASCIIUpper(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
+            HTML_ADVANCE_TO(RCDATAEndTagNameState);
+        } else if (isASCIILower(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(RCDATAEndTagNameState);
+        } else {
+            if (isTokenizerWhitespace(cc)) {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
+                }
+            } else if (cc == '/') {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
+                }
+            } else if (cc == '>') {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
+                }
+            }
+            bufferCharacter('<');
+            bufferCharacter('/');
+            m_token->appendToCharacter(m_temporaryBuffer);
+            m_bufferedEndTagName.clear();
+            m_temporaryBuffer.clear();
+            HTML_RECONSUME_IN(RCDATAState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(RAWTEXTLessThanSignState) {
+        if (cc == '/') {
+            m_temporaryBuffer.clear();
+            ASSERT(m_bufferedEndTagName.isEmpty());
+            HTML_ADVANCE_TO(RAWTEXTEndTagOpenState);
+        } else {
+            bufferCharacter('<');
+            HTML_RECONSUME_IN(RAWTEXTState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(RAWTEXTEndTagOpenState) {
+        if (isASCIIUpper(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
+            HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
+        } else if (isASCIILower(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
+        } else {
+            bufferCharacter('<');
+            bufferCharacter('/');
+            HTML_RECONSUME_IN(RAWTEXTState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(RAWTEXTEndTagNameState) {
+        if (isASCIIUpper(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
+            HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
+        } else if (isASCIILower(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
+        } else {
+            if (isTokenizerWhitespace(cc)) {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
+                }
+            } else if (cc == '/') {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
+                }
+            } else if (cc == '>') {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
+                }
+            }
+            bufferCharacter('<');
+            bufferCharacter('/');
+            m_token->appendToCharacter(m_temporaryBuffer);
+            m_bufferedEndTagName.clear();
+            m_temporaryBuffer.clear();
+            HTML_RECONSUME_IN(RAWTEXTState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataLessThanSignState) {
+        if (cc == '/') {
+            m_temporaryBuffer.clear();
+            ASSERT(m_bufferedEndTagName.isEmpty());
+            HTML_ADVANCE_TO(ScriptDataEndTagOpenState);
+        } else if (cc == '!') {
+            bufferCharacter('<');
+            bufferCharacter('!');
+            HTML_ADVANCE_TO(ScriptDataEscapeStartState);
+        } else {
+            bufferCharacter('<');
+            HTML_RECONSUME_IN(ScriptDataState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEndTagOpenState) {
+        if (isASCIIUpper(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
+            HTML_ADVANCE_TO(ScriptDataEndTagNameState);
+        } else if (isASCIILower(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(ScriptDataEndTagNameState);
+        } else {
+            bufferCharacter('<');
+            bufferCharacter('/');
+            HTML_RECONSUME_IN(ScriptDataState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEndTagNameState) {
+        if (isASCIIUpper(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
+            HTML_ADVANCE_TO(ScriptDataEndTagNameState);
+        } else if (isASCIILower(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(ScriptDataEndTagNameState);
+        } else {
+            if (isTokenizerWhitespace(cc)) {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
+                }
+            } else if (cc == '/') {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
+                }
+            } else if (cc == '>') {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
+                }
+            }
+            bufferCharacter('<');
+            bufferCharacter('/');
+            m_token->appendToCharacter(m_temporaryBuffer);
+            m_bufferedEndTagName.clear();
+            m_temporaryBuffer.clear();
+            HTML_RECONSUME_IN(ScriptDataState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEscapeStartState) {
+        if (cc == '-') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataEscapeStartDashState);
+        } else
+            HTML_RECONSUME_IN(ScriptDataState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEscapeStartDashState) {
+        if (cc == '-') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataEscapedDashDashState);
+        } else
+            HTML_RECONSUME_IN(ScriptDataState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEscapedState) {
+        if (cc == '-') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataEscapedDashState);
+        } else if (cc == '<')
+            HTML_ADVANCE_TO(ScriptDataEscapedLessThanSignState);
+        else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataEscapedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEscapedDashState) {
+        if (cc == '-') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataEscapedDashDashState);
+        } else if (cc == '<')
+            HTML_ADVANCE_TO(ScriptDataEscapedLessThanSignState);
+        else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataEscapedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEscapedDashDashState) {
+        if (cc == '-') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataEscapedDashDashState);
+        } else if (cc == '<')
+            HTML_ADVANCE_TO(ScriptDataEscapedLessThanSignState);
+        else if (cc == '>') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataEscapedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEscapedLessThanSignState) {
+        if (cc == '/') {
+            m_temporaryBuffer.clear();
+            ASSERT(m_bufferedEndTagName.isEmpty());
+            HTML_ADVANCE_TO(ScriptDataEscapedEndTagOpenState);
+        } else if (isASCIIUpper(cc)) {
+            bufferCharacter('<');
+            bufferCharacter(cc);
+            m_temporaryBuffer.clear();
+            m_temporaryBuffer.append(toLowerCase(cc));
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
+        } else if (isASCIILower(cc)) {
+            bufferCharacter('<');
+            bufferCharacter(cc);
+            m_temporaryBuffer.clear();
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
+        } else {
+            bufferCharacter('<');
+            HTML_RECONSUME_IN(ScriptDataEscapedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEscapedEndTagOpenState) {
+        if (isASCIIUpper(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
+            HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
+        } else if (isASCIILower(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
+        } else {
+            bufferCharacter('<');
+            bufferCharacter('/');
+            HTML_RECONSUME_IN(ScriptDataEscapedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataEscapedEndTagNameState) {
+        if (isASCIIUpper(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
+            HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
+        } else if (isASCIILower(cc)) {
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            addToPossibleEndTag(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
+        } else {
+            if (isTokenizerWhitespace(cc)) {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
+                }
+            } else if (cc == '/') {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
+                }
+            } else if (cc == '>') {
+                if (isAppropriateEndTag()) {
+                    m_temporaryBuffer.append(static_cast<LChar>(cc));
+                    return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
+                }
+            }
+            bufferCharacter('<');
+            bufferCharacter('/');
+            m_token->appendToCharacter(m_temporaryBuffer);
+            m_bufferedEndTagName.clear();
+            m_temporaryBuffer.clear();
+            HTML_RECONSUME_IN(ScriptDataEscapedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataDoubleEscapeStartState) {
+        if (isTokenizerWhitespace(cc) || cc == '/' || cc == '>') {
+            bufferCharacter(cc);
+            if (temporaryBufferIs(scriptTag.localName()))
+                HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
+            else
+                HTML_ADVANCE_TO(ScriptDataEscapedState);
+        } else if (isASCIIUpper(cc)) {
+            bufferCharacter(cc);
+            m_temporaryBuffer.append(toLowerCase(cc));
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
+        } else if (isASCIILower(cc)) {
+            bufferCharacter(cc);
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
+        } else
+            HTML_RECONSUME_IN(ScriptDataEscapedState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataDoubleEscapedState) {
+        if (cc == '-') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapedDashState);
+        } else if (cc == '<') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapedLessThanSignState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataDoubleEscapedDashState) {
+        if (cc == '-') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapedDashDashState);
+        } else if (cc == '<') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapedLessThanSignState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataDoubleEscapedDashDashState) {
+        if (cc == '-') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapedDashDashState);
+        } else if (cc == '<') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapedLessThanSignState);
+        } else if (cc == '>') {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataDoubleEscapedLessThanSignState) {
+        if (cc == '/') {
+            bufferCharacter(cc);
+            m_temporaryBuffer.clear();
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
+        } else
+            HTML_RECONSUME_IN(ScriptDataDoubleEscapedState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ScriptDataDoubleEscapeEndState) {
+        if (isTokenizerWhitespace(cc) || cc == '/' || cc == '>') {
+            bufferCharacter(cc);
+            if (temporaryBufferIs(scriptTag.localName()))
+                HTML_ADVANCE_TO(ScriptDataEscapedState);
+            else
+                HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
+        } else if (isASCIIUpper(cc)) {
+            bufferCharacter(cc);
+            m_temporaryBuffer.append(toLowerCase(cc));
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
+        } else if (isASCIILower(cc)) {
+            bufferCharacter(cc);
+            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
+        } else
+            HTML_RECONSUME_IN(ScriptDataDoubleEscapedState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(BeforeAttributeNameState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeAttributeNameState);
+        else if (cc == '/')
+            HTML_ADVANCE_TO(SelfClosingStartTagState);
+        else if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (isASCIIUpper(cc)) {
+            m_token->addNewAttribute();
+            m_token->beginAttributeName(source.numberOfCharactersConsumed());
+            m_token->appendToAttributeName(toLowerCase(cc));
+            HTML_ADVANCE_TO(AttributeNameState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            if (cc == '"' || cc == '\'' || cc == '<' || cc == '=')
+                parseError();
+            m_token->addNewAttribute();
+            m_token->beginAttributeName(source.numberOfCharactersConsumed());
+            m_token->appendToAttributeName(cc);
+            HTML_ADVANCE_TO(AttributeNameState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AttributeNameState) {
+        if (isTokenizerWhitespace(cc)) {
+            m_token->endAttributeName(source.numberOfCharactersConsumed());
+            HTML_ADVANCE_TO(AfterAttributeNameState);
+        } else if (cc == '/') {
+            m_token->endAttributeName(source.numberOfCharactersConsumed());
+            HTML_ADVANCE_TO(SelfClosingStartTagState);
+        } else if (cc == '=') {
+            m_token->endAttributeName(source.numberOfCharactersConsumed());
+            HTML_ADVANCE_TO(BeforeAttributeValueState);
+        } else if (cc == '>') {
+            m_token->endAttributeName(source.numberOfCharactersConsumed());
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (isASCIIUpper(cc)) {
+            m_token->appendToAttributeName(toLowerCase(cc));
+            HTML_ADVANCE_TO(AttributeNameState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->endAttributeName(source.numberOfCharactersConsumed());
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            if (cc == '"' || cc == '\'' || cc == '<' || cc == '=')
+                parseError();
+            m_token->appendToAttributeName(cc);
+            HTML_ADVANCE_TO(AttributeNameState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AfterAttributeNameState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(AfterAttributeNameState);
+        else if (cc == '/')
+            HTML_ADVANCE_TO(SelfClosingStartTagState);
+        else if (cc == '=')
+            HTML_ADVANCE_TO(BeforeAttributeValueState);
+        else if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (isASCIIUpper(cc)) {
+            m_token->addNewAttribute();
+            m_token->beginAttributeName(source.numberOfCharactersConsumed());
+            m_token->appendToAttributeName(toLowerCase(cc));
+            HTML_ADVANCE_TO(AttributeNameState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            if (cc == '"' || cc == '\'' || cc == '<')
+                parseError();
+            m_token->addNewAttribute();
+            m_token->beginAttributeName(source.numberOfCharactersConsumed());
+            m_token->appendToAttributeName(cc);
+            HTML_ADVANCE_TO(AttributeNameState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(BeforeAttributeValueState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeAttributeValueState);
+        else if (cc == '"') {
+            m_token->beginAttributeValue(source.numberOfCharactersConsumed() + 1);
+            HTML_ADVANCE_TO(AttributeValueDoubleQuotedState);
+        } else if (cc == '&') {
+            m_token->beginAttributeValue(source.numberOfCharactersConsumed());
+            HTML_RECONSUME_IN(AttributeValueUnquotedState);
+        } else if (cc == '\'') {
+            m_token->beginAttributeValue(source.numberOfCharactersConsumed() + 1);
+            HTML_ADVANCE_TO(AttributeValueSingleQuotedState);
+        } else if (cc == '>') {
+            parseError();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            if (cc == '<' || cc == '=' || cc == '`')
+                parseError();
+            m_token->beginAttributeValue(source.numberOfCharactersConsumed());
+            m_token->appendToAttributeValue(cc);
+            HTML_ADVANCE_TO(AttributeValueUnquotedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AttributeValueDoubleQuotedState) {
+        if (cc == '"') {
+            m_token->endAttributeValue(source.numberOfCharactersConsumed());
+            HTML_ADVANCE_TO(AfterAttributeValueQuotedState);
+        } else if (cc == '&') {
+            m_additionalAllowedCharacter = '"';
+            HTML_ADVANCE_TO(CharacterReferenceInAttributeValueState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->endAttributeValue(source.numberOfCharactersConsumed());
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            m_token->appendToAttributeValue(cc);
+            HTML_ADVANCE_TO(AttributeValueDoubleQuotedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AttributeValueSingleQuotedState) {
+        if (cc == '\'') {
+            m_token->endAttributeValue(source.numberOfCharactersConsumed());
+            HTML_ADVANCE_TO(AfterAttributeValueQuotedState);
+        } else if (cc == '&') {
+            m_additionalAllowedCharacter = '\'';
+            HTML_ADVANCE_TO(CharacterReferenceInAttributeValueState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->endAttributeValue(source.numberOfCharactersConsumed());
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            m_token->appendToAttributeValue(cc);
+            HTML_ADVANCE_TO(AttributeValueSingleQuotedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AttributeValueUnquotedState) {
+        if (isTokenizerWhitespace(cc)) {
+            m_token->endAttributeValue(source.numberOfCharactersConsumed());
+            HTML_ADVANCE_TO(BeforeAttributeNameState);
+        } else if (cc == '&') {
+            m_additionalAllowedCharacter = '>';
+            HTML_ADVANCE_TO(CharacterReferenceInAttributeValueState);
+        } else if (cc == '>') {
+            m_token->endAttributeValue(source.numberOfCharactersConsumed());
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->endAttributeValue(source.numberOfCharactersConsumed());
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            if (cc == '"' || cc == '\'' || cc == '<' || cc == '=' || cc == '`')
+                parseError();
+            m_token->appendToAttributeValue(cc);
+            HTML_ADVANCE_TO(AttributeValueUnquotedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CharacterReferenceInAttributeValueState) {
+        bool notEnoughCharacters = false;
+        StringBuilder decodedEntity;
+        bool success = consumeHTMLEntity(source, decodedEntity, notEnoughCharacters, m_additionalAllowedCharacter);
+        if (notEnoughCharacters)
+            return haveBufferedCharacterToken();
+        if (!success) {
+            ASSERT(decodedEntity.isEmpty());
+            m_token->appendToAttributeValue('&');
+        } else {
+            for (unsigned i = 0; i < decodedEntity.length(); ++i)
+                m_token->appendToAttributeValue(decodedEntity[i]);
+        }
+        // We're supposed to switch back to the attribute value state that
+        // 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 == '"')
+            HTML_SWITCH_TO(AttributeValueDoubleQuotedState);
+        else if (m_additionalAllowedCharacter == '\'')
+            HTML_SWITCH_TO(AttributeValueSingleQuotedState);
+        else if (m_additionalAllowedCharacter == '>')
+            HTML_SWITCH_TO(AttributeValueUnquotedState);
+        else
+            ASSERT_NOT_REACHED();
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AfterAttributeValueQuotedState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeAttributeNameState);
+        else if (cc == '/')
+            HTML_ADVANCE_TO(SelfClosingStartTagState);
+        else if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            parseError();
+            HTML_RECONSUME_IN(BeforeAttributeNameState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(SelfClosingStartTagState) {
+        if (cc == '>') {
+            m_token->setSelfClosing();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            HTML_RECONSUME_IN(DataState);
+        } else {
+            parseError();
+            HTML_RECONSUME_IN(BeforeAttributeNameState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(BogusCommentState) {
+        m_token->beginComment();
+        HTML_RECONSUME_IN(ContinueBogusCommentState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(ContinueBogusCommentState) {
+        if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (cc == kEndOfFileMarker)
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        else {
+            m_token->appendToComment(cc);
+            HTML_ADVANCE_TO(ContinueBogusCommentState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(MarkupDeclarationOpenState) {
+        DEFINE_STATIC_LOCAL(String, dashDashString, (ASCIILiteral("--")));
+        DEFINE_STATIC_LOCAL(String, doctypeString, (ASCIILiteral("doctype")));
+        DEFINE_STATIC_LOCAL(String, cdataString, (ASCIILiteral("[CDATA[")));
+        if (cc == '-') {
+            SegmentedString::LookAheadResult result = source.lookAhead(dashDashString);
+            if (result == SegmentedString::DidMatch) {
+                source.advanceAndASSERT('-');
+                source.advanceAndASSERT('-');
+                m_token->beginComment();
+                HTML_SWITCH_TO(CommentStartState);
+            } else if (result == SegmentedString::NotEnoughCharacters)
+                return haveBufferedCharacterToken();
+        } else if (cc == 'D' || cc == 'd') {
+            SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(doctypeString);
+            if (result == SegmentedString::DidMatch) {
+                advanceStringAndASSERTIgnoringCase(source, "doctype");
+                HTML_SWITCH_TO(DOCTYPEState);
+            } else if (result == SegmentedString::NotEnoughCharacters)
+                return haveBufferedCharacterToken();
+        } else if (cc == '[' && shouldAllowCDATA()) {
+            SegmentedString::LookAheadResult result = source.lookAhead(cdataString);
+            if (result == SegmentedString::DidMatch) {
+                advanceStringAndASSERT(source, "[CDATA[");
+                HTML_SWITCH_TO(CDATASectionState);
+            } else if (result == SegmentedString::NotEnoughCharacters)
+                return haveBufferedCharacterToken();
+        }
+        parseError();
+        HTML_RECONSUME_IN(BogusCommentState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CommentStartState) {
+        if (cc == '-')
+            HTML_ADVANCE_TO(CommentStartDashState);
+        else if (cc == '>') {
+            parseError();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToComment(cc);
+            HTML_ADVANCE_TO(CommentState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CommentStartDashState) {
+        if (cc == '-')
+            HTML_ADVANCE_TO(CommentEndState);
+        else if (cc == '>') {
+            parseError();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToComment('-');
+            m_token->appendToComment(cc);
+            HTML_ADVANCE_TO(CommentState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CommentState) {
+        if (cc == '-')
+            HTML_ADVANCE_TO(CommentEndDashState);
+        else if (cc == kEndOfFileMarker) {
+            parseError();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToComment(cc);
+            HTML_ADVANCE_TO(CommentState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CommentEndDashState) {
+        if (cc == '-')
+            HTML_ADVANCE_TO(CommentEndState);
+        else if (cc == kEndOfFileMarker) {
+            parseError();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToComment('-');
+            m_token->appendToComment(cc);
+            HTML_ADVANCE_TO(CommentState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CommentEndState) {
+        if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (cc == '!') {
+            parseError();
+            HTML_ADVANCE_TO(CommentEndBangState);
+        } else if (cc == '-') {
+            parseError();
+            m_token->appendToComment('-');
+            HTML_ADVANCE_TO(CommentEndState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            parseError();
+            m_token->appendToComment('-');
+            m_token->appendToComment('-');
+            m_token->appendToComment(cc);
+            HTML_ADVANCE_TO(CommentState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CommentEndBangState) {
+        if (cc == '-') {
+            m_token->appendToComment('-');
+            m_token->appendToComment('-');
+            m_token->appendToComment('!');
+            HTML_ADVANCE_TO(CommentEndDashState);
+        } else if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (cc == kEndOfFileMarker) {
+            parseError();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToComment('-');
+            m_token->appendToComment('-');
+            m_token->appendToComment('!');
+            m_token->appendToComment(cc);
+            HTML_ADVANCE_TO(CommentState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(DOCTYPEState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeDOCTYPENameState);
+        else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->beginDOCTYPE();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            parseError();
+            HTML_RECONSUME_IN(BeforeDOCTYPENameState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(BeforeDOCTYPENameState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeDOCTYPENameState);
+        else if (isASCIIUpper(cc)) {
+            m_token->beginDOCTYPE(toLowerCase(cc));
+            HTML_ADVANCE_TO(DOCTYPENameState);
+        } else if (cc == '>') {
+            parseError();
+            m_token->beginDOCTYPE();
+            m_token->setForceQuirks();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->beginDOCTYPE();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->beginDOCTYPE(cc);
+            HTML_ADVANCE_TO(DOCTYPENameState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(DOCTYPENameState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(AfterDOCTYPENameState);
+        else if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (isASCIIUpper(cc)) {
+            m_token->appendToName(toLowerCase(cc));
+            HTML_ADVANCE_TO(DOCTYPENameState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToName(cc);
+            HTML_ADVANCE_TO(DOCTYPENameState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AfterDOCTYPENameState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(AfterDOCTYPENameState);
+        if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            DEFINE_STATIC_LOCAL(String, publicString, (ASCIILiteral("public")));
+            DEFINE_STATIC_LOCAL(String, systemString, (ASCIILiteral("system")));
+            if (cc == 'P' || cc == 'p') {
+                SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(publicString);
+                if (result == SegmentedString::DidMatch) {
+                    advanceStringAndASSERTIgnoringCase(source, "public");
+                    HTML_SWITCH_TO(AfterDOCTYPEPublicKeywordState);
+                } else if (result == SegmentedString::NotEnoughCharacters)
+                    return haveBufferedCharacterToken();
+            } else if (cc == 'S' || cc == 's') {
+                SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(systemString);
+                if (result == SegmentedString::DidMatch) {
+                    advanceStringAndASSERTIgnoringCase(source, "system");
+                    HTML_SWITCH_TO(AfterDOCTYPESystemKeywordState);
+                } else if (result == SegmentedString::NotEnoughCharacters)
+                    return haveBufferedCharacterToken();
+            }
+            parseError();
+            m_token->setForceQuirks();
+            HTML_ADVANCE_TO(BogusDOCTYPEState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AfterDOCTYPEPublicKeywordState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeDOCTYPEPublicIdentifierState);
+        else if (cc == '"') {
+            parseError();
+            m_token->setPublicIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
+        } else if (cc == '\'') {
+            parseError();
+            m_token->setPublicIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
+        } else if (cc == '>') {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            parseError();
+            m_token->setForceQuirks();
+            HTML_ADVANCE_TO(BogusDOCTYPEState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(BeforeDOCTYPEPublicIdentifierState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeDOCTYPEPublicIdentifierState);
+        else if (cc == '"') {
+            m_token->setPublicIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
+        } else if (cc == '\'') {
+            m_token->setPublicIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
+        } else if (cc == '>') {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            parseError();
+            m_token->setForceQuirks();
+            HTML_ADVANCE_TO(BogusDOCTYPEState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(DOCTYPEPublicIdentifierDoubleQuotedState) {
+        if (cc == '"')
+            HTML_ADVANCE_TO(AfterDOCTYPEPublicIdentifierState);
+        else if (cc == '>') {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToPublicIdentifier(cc);
+            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(DOCTYPEPublicIdentifierSingleQuotedState) {
+        if (cc == '\'')
+            HTML_ADVANCE_TO(AfterDOCTYPEPublicIdentifierState);
+        else if (cc == '>') {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToPublicIdentifier(cc);
+            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AfterDOCTYPEPublicIdentifierState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BetweenDOCTYPEPublicAndSystemIdentifiersState);
+        else if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (cc == '"') {
+            parseError();
+            m_token->setSystemIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+        } else if (cc == '\'') {
+            parseError();
+            m_token->setSystemIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            parseError();
+            m_token->setForceQuirks();
+            HTML_ADVANCE_TO(BogusDOCTYPEState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(BetweenDOCTYPEPublicAndSystemIdentifiersState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BetweenDOCTYPEPublicAndSystemIdentifiersState);
+        else if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (cc == '"') {
+            m_token->setSystemIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+        } else if (cc == '\'') {
+            m_token->setSystemIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            parseError();
+            m_token->setForceQuirks();
+            HTML_ADVANCE_TO(BogusDOCTYPEState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AfterDOCTYPESystemKeywordState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeDOCTYPESystemIdentifierState);
+        else if (cc == '"') {
+            parseError();
+            m_token->setSystemIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+        } else if (cc == '\'') {
+            parseError();
+            m_token->setSystemIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+        } else if (cc == '>') {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            parseError();
+            m_token->setForceQuirks();
+            HTML_ADVANCE_TO(BogusDOCTYPEState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(BeforeDOCTYPESystemIdentifierState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(BeforeDOCTYPESystemIdentifierState);
+        if (cc == '"') {
+            m_token->setSystemIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+        } else if (cc == '\'') {
+            m_token->setSystemIdentifierToEmptyString();
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+        } else if (cc == '>') {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            parseError();
+            m_token->setForceQuirks();
+            HTML_ADVANCE_TO(BogusDOCTYPEState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(DOCTYPESystemIdentifierDoubleQuotedState) {
+        if (cc == '"')
+            HTML_ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
+        else if (cc == '>') {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToSystemIdentifier(cc);
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(DOCTYPESystemIdentifierSingleQuotedState) {
+        if (cc == '\'')
+            HTML_ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
+        else if (cc == '>') {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        } else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            m_token->appendToSystemIdentifier(cc);
+            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(AfterDOCTYPESystemIdentifierState) {
+        if (isTokenizerWhitespace(cc))
+            HTML_ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
+        else if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (cc == kEndOfFileMarker) {
+            parseError();
+            m_token->setForceQuirks();
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        } else {
+            parseError();
+            HTML_ADVANCE_TO(BogusDOCTYPEState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(BogusDOCTYPEState) {
+        if (cc == '>')
+            return emitAndResumeIn(source, HTMLTokenizer::DataState);
+        else if (cc == kEndOfFileMarker)
+            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
+        HTML_ADVANCE_TO(BogusDOCTYPEState);
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CDATASectionState) {
+        if (cc == ']')
+            HTML_ADVANCE_TO(CDATASectionRightSquareBracketState);
+        else if (cc == kEndOfFileMarker)
+            HTML_RECONSUME_IN(DataState);
+        else {
+            bufferCharacter(cc);
+            HTML_ADVANCE_TO(CDATASectionState);
+        }
+    }
+    END_STATE()
+
+    HTML_BEGIN_STATE(CDATASectionRightSquareBracketState) {
+        if (cc == ']')
+            HTML_ADVANCE_TO(CDATASectionDoubleRightSquareBracketState);
+        else {
+            bufferCharacter(']');
+            HTML_RECONSUME_IN(CDATASectionState);
+        }
+    }
+
+    HTML_BEGIN_STATE(CDATASectionDoubleRightSquareBracketState) {
+        if (cc == '>')
+            HTML_ADVANCE_TO(DataState);
+        else {
+            bufferCharacter(']');
+            bufferCharacter(']');
+            HTML_RECONSUME_IN(CDATASectionState);
+        }
+    }
+    END_STATE()
+
+    }
+
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+String HTMLTokenizer::bufferedCharacters() const
+{
+    // FIXME: Add an assert about m_state.
+    StringBuilder characters;
+    characters.reserveCapacity(numberOfBufferedCharacters());
+    characters.append('<');
+    characters.append('/');
+    characters.append(m_temporaryBuffer.data(), m_temporaryBuffer.size());
+    return characters.toString();
+}
+
+void HTMLTokenizer::updateStateFor(const AtomicString& tagName)
+{
+    if (tagName == textareaTag || tagName == titleTag)
+        setState(HTMLTokenizer::RCDATAState);
+    else if (tagName == plaintextTag)
+        setState(HTMLTokenizer::PLAINTEXTState);
+    else if (tagName == scriptTag)
+        setState(HTMLTokenizer::ScriptDataState);
+    else if (tagName == styleTag
+        || tagName == iframeTag
+        || tagName == xmpTag
+        || (tagName == noembedTag && m_options.pluginsEnabled)
+        || tagName == noframesTag
+        || (tagName == noscriptTag && m_options.scriptEnabled))
+        setState(HTMLTokenizer::RAWTEXTState);
+}
+
+inline bool HTMLTokenizer::temporaryBufferIs(const String& expectedString)
+{
+    return vectorEqualsString(m_temporaryBuffer, expectedString);
+}
+
+inline void HTMLTokenizer::addToPossibleEndTag(LChar cc)
+{
+    ASSERT(isEndTagBufferingState(m_state));
+    m_bufferedEndTagName.append(cc);
+}
+
+inline bool HTMLTokenizer::isAppropriateEndTag()
+{
+    if (m_bufferedEndTagName.size() != m_appropriateEndTagName.size())
+        return false;
+
+    size_t numCharacters = m_bufferedEndTagName.size();
+
+    for (size_t i = 0; i < numCharacters; i++) {
+        if (m_bufferedEndTagName[i] != m_appropriateEndTagName[i])
+            return false;
+    }
+
+    return true;
+}
+
+inline void HTMLTokenizer::parseError()
+{
+    notImplemented();
+}
+
+}
diff --git a/Source/core/html/parser/HTMLTokenizer.h b/Source/core/html/parser/HTMLTokenizer.h
new file mode 100644
index 0000000..809d291
--- /dev/null
+++ b/Source/core/html/parser/HTMLTokenizer.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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 HTMLTokenizer_h
+#define HTMLTokenizer_h
+
+#include "core/html/parser/HTMLParserOptions.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/html/parser/InputStreamPreprocessor.h"
+#include "core/platform/text/SegmentedString.h"
+
+namespace WebCore {
+
+class HTMLTokenizer {
+    WTF_MAKE_NONCOPYABLE(HTMLTokenizer);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<HTMLTokenizer> create(const HTMLParserOptions& options) { return adoptPtr(new HTMLTokenizer(options)); }
+    ~HTMLTokenizer();
+
+    void reset();
+
+    enum State {
+        DataState,
+        CharacterReferenceInDataState,
+        RCDATAState,
+        CharacterReferenceInRCDATAState,
+        RAWTEXTState,
+        ScriptDataState,
+        PLAINTEXTState,
+        TagOpenState,
+        EndTagOpenState,
+        TagNameState,
+        RCDATALessThanSignState,
+        RCDATAEndTagOpenState,
+        RCDATAEndTagNameState,
+        RAWTEXTLessThanSignState,
+        RAWTEXTEndTagOpenState,
+        RAWTEXTEndTagNameState,
+        ScriptDataLessThanSignState,
+        ScriptDataEndTagOpenState,
+        ScriptDataEndTagNameState,
+        ScriptDataEscapeStartState,
+        ScriptDataEscapeStartDashState,
+        ScriptDataEscapedState,
+        ScriptDataEscapedDashState,
+        ScriptDataEscapedDashDashState,
+        ScriptDataEscapedLessThanSignState,
+        ScriptDataEscapedEndTagOpenState,
+        ScriptDataEscapedEndTagNameState,
+        ScriptDataDoubleEscapeStartState,
+        ScriptDataDoubleEscapedState,
+        ScriptDataDoubleEscapedDashState,
+        ScriptDataDoubleEscapedDashDashState,
+        ScriptDataDoubleEscapedLessThanSignState,
+        ScriptDataDoubleEscapeEndState,
+        BeforeAttributeNameState,
+        AttributeNameState,
+        AfterAttributeNameState,
+        BeforeAttributeValueState,
+        AttributeValueDoubleQuotedState,
+        AttributeValueSingleQuotedState,
+        AttributeValueUnquotedState,
+        CharacterReferenceInAttributeValueState,
+        AfterAttributeValueQuotedState,
+        SelfClosingStartTagState,
+        BogusCommentState,
+        // The ContinueBogusCommentState is not in the HTML5 spec, but we use
+        // it internally to keep track of whether we've started the bogus
+        // comment token yet.
+        ContinueBogusCommentState,
+        MarkupDeclarationOpenState,
+        CommentStartState,
+        CommentStartDashState,
+        CommentState,
+        CommentEndDashState,
+        CommentEndState,
+        CommentEndBangState,
+        DOCTYPEState,
+        BeforeDOCTYPENameState,
+        DOCTYPENameState,
+        AfterDOCTYPENameState,
+        AfterDOCTYPEPublicKeywordState,
+        BeforeDOCTYPEPublicIdentifierState,
+        DOCTYPEPublicIdentifierDoubleQuotedState,
+        DOCTYPEPublicIdentifierSingleQuotedState,
+        AfterDOCTYPEPublicIdentifierState,
+        BetweenDOCTYPEPublicAndSystemIdentifiersState,
+        AfterDOCTYPESystemKeywordState,
+        BeforeDOCTYPESystemIdentifierState,
+        DOCTYPESystemIdentifierDoubleQuotedState,
+        DOCTYPESystemIdentifierSingleQuotedState,
+        AfterDOCTYPESystemIdentifierState,
+        BogusDOCTYPEState,
+        CDATASectionState,
+        // These CDATA states are not in the HTML5 spec, but we use them internally.
+        CDATASectionRightSquareBracketState,
+        CDATASectionDoubleRightSquareBracketState,
+    };
+
+    struct Checkpoint {
+        HTMLParserOptions options;
+        State state;
+        UChar additionalAllowedCharacter;
+        bool skipNextNewLine;
+        bool forceNullCharacterReplacement;
+        bool shouldAllowCDATA;
+
+        Checkpoint()
+            : options(0)
+            , state()
+            , additionalAllowedCharacter('\0')
+            , skipNextNewLine(false)
+            , forceNullCharacterReplacement(false)
+            , shouldAllowCDATA(false)
+        {
+        }
+    };
+
+    bool canCreateCheckpoint() const;
+    void createCheckpoint(Checkpoint&) const;
+    void restoreFromCheckpoint(const Checkpoint&);
+
+    // 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&);
+
+    // Returns a copy of any characters buffered internally by the tokenizer.
+    // The tokenizer buffers characters when searching for the </script> token
+    // that terminates a script element.
+    String bufferedCharacters() const;
+
+    size_t numberOfBufferedCharacters() const
+    {
+        // Notice that we add 2 to the length of the m_temporaryBuffer to
+        // account for the "</" characters, which are effecitvely buffered in
+        // the tokenizer's state machine.
+        return m_temporaryBuffer.size() ? m_temporaryBuffer.size() + 2 : 0;
+    }
+
+    // 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);
+
+    bool forceNullCharacterReplacement() const { return m_forceNullCharacterReplacement; }
+    void setForceNullCharacterReplacement(bool value) { m_forceNullCharacterReplacement = value; }
+
+    bool shouldAllowCDATA() const { return m_shouldAllowCDATA; }
+    void setShouldAllowCDATA(bool value) { m_shouldAllowCDATA = value; }
+
+    State state() const { return m_state; }
+    void setState(State state) { m_state = state; }
+
+    inline bool shouldSkipNullCharacters() const
+    {
+        return !m_forceNullCharacterReplacement
+            && (m_state == HTMLTokenizer::DataState
+                || m_state == HTMLTokenizer::RCDATAState
+                || m_state == HTMLTokenizer::RAWTEXTState);
+    }
+
+private:
+    explicit HTMLTokenizer(const HTMLParserOptions&);
+
+    inline bool processEntity(SegmentedString&);
+
+    inline void parseError();
+
+    inline void bufferCharacter(UChar character)
+    {
+        ASSERT(character != kEndOfFileMarker);
+        m_token->ensureIsCharacterToken();
+        m_token->appendToCharacter(character);
+    }
+
+    inline bool emitAndResumeIn(SegmentedString& source, State state)
+    {
+        saveEndTagNameIfNeeded();
+        m_state = state;
+        source.advanceAndUpdateLineNumber();
+        return true;
+    }
+    
+    inline bool emitAndReconsumeIn(SegmentedString&, State state)
+    {
+        saveEndTagNameIfNeeded();
+        m_state = state;
+        return true;
+    }
+
+    inline bool emitEndOfFile(SegmentedString& source)
+    {
+        if (haveBufferedCharacterToken())
+            return true;
+        m_state = HTMLTokenizer::DataState;
+        source.advanceAndUpdateLineNumber();
+        m_token->clear();
+        m_token->makeEndOfFile();
+        return true;
+    }
+
+    inline bool flushEmitAndResumeIn(SegmentedString&, State);
+
+    // Return whether we need to emit a character token before dealing with
+    // the buffered end tag.
+    inline bool flushBufferedEndTag(SegmentedString&);
+    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
+    // functions help manage these state.
+    inline void addToPossibleEndTag(LChar cc);
+
+    inline void saveEndTagNameIfNeeded()
+    {
+        ASSERT(m_token->type() != HTMLToken::Uninitialized);
+        if (m_token->type() == HTMLToken::StartTag)
+            m_appropriateEndTagName = m_token->name();
+    }
+    inline bool isAppropriateEndTag();
+
+
+    inline bool haveBufferedCharacterToken()
+    {
+        return m_token->type() == HTMLToken::Character;
+    }
+
+    State m_state;
+    bool m_forceNullCharacterReplacement;
+    bool m_shouldAllowCDATA;
+
+    // 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;
+
+    // http://www.whatwg.org/specs/web-apps/current-work/#additional-allowed-character
+    UChar m_additionalAllowedCharacter;
+
+    // http://www.whatwg.org/specs/web-apps/current-work/#preprocessing-the-input-stream
+    InputStreamPreprocessor<HTMLTokenizer> m_inputStreamPreprocessor;
+
+    Vector<UChar, 32> m_appropriateEndTagName;
+
+    // http://www.whatwg.org/specs/web-apps/current-work/#temporary-buffer
+    Vector<LChar, 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 here so we remember it next time we re-enter the tokenizer.
+    Vector<LChar, 32> m_bufferedEndTagName;
+
+    HTMLParserOptions m_options;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLTreeBuilder.cpp b/Source/core/html/parser/HTMLTreeBuilder.cpp
new file mode 100644
index 0000000..0d67542
--- /dev/null
+++ b/Source/core/html/parser/HTMLTreeBuilder.cpp
@@ -0,0 +1,2837 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 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 GOOGLE 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 GOOGLE 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLTreeBuilder.h"
+
+#include "HTMLNames.h"
+#include "MathMLNames.h"
+#include "SVGNames.h"
+#include "XLinkNames.h"
+#include "XMLNSNames.h"
+#include "XMLNames.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLFormElement.h"
+#include "core/html/HTMLTemplateElement.h"
+#include "core/html/parser/AtomicHTMLToken.h"
+#include "core/html/parser/HTMLDocumentParser.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/parser/HTMLStackItem.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/NotImplemented.h"
+#include <wtf/MainThread.h>
+#include <wtf/unicode/CharacterNames.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+namespace {
+
+inline bool isHTMLSpaceOrReplacementCharacter(UChar character)
+{
+    return isHTMLSpace(character) || character == replacementCharacter;
+}
+
+}
+
+static TextPosition uninitializedPositionValue1()
+{
+    return TextPosition(OrdinalNumber::fromOneBasedInt(-1), OrdinalNumber::first());
+}
+
+static inline bool isAllWhitespace(const String& string)
+{
+    return string.isAllSpecialCharacters<isHTMLSpace>();
+}
+
+static inline bool isAllWhitespaceOrReplacementCharacters(const String& string)
+{
+    return string.isAllSpecialCharacters<isHTMLSpaceOrReplacementCharacter>();
+}
+
+static bool isNumberedHeaderTag(const AtomicString& tagName)
+{
+    return tagName == h1Tag
+        || tagName == h2Tag
+        || tagName == h3Tag
+        || tagName == h4Tag
+        || tagName == h5Tag
+        || tagName == h6Tag;
+}
+
+static bool isCaptionColOrColgroupTag(const AtomicString& tagName)
+{
+    return tagName == captionTag
+        || tagName == colTag
+        || tagName == colgroupTag;
+}
+
+static bool isTableCellContextTag(const AtomicString& tagName)
+{
+    return tagName == thTag || tagName == tdTag;
+}
+
+static bool isTableBodyContextTag(const AtomicString& tagName)
+{
+    return tagName == tbodyTag
+        || tagName == tfootTag
+        || tagName == theadTag;
+}
+
+static bool isNonAnchorNonNobrFormattingTag(const AtomicString& tagName)
+{
+    return tagName == bTag
+        || tagName == bigTag
+        || tagName == codeTag
+        || tagName == emTag
+        || tagName == fontTag
+        || tagName == iTag
+        || tagName == sTag
+        || tagName == smallTag
+        || tagName == strikeTag
+        || tagName == strongTag
+        || tagName == ttTag
+        || tagName == uTag;
+}
+
+static bool isNonAnchorFormattingTag(const AtomicString& tagName)
+{
+    return tagName == nobrTag
+        || isNonAnchorNonNobrFormattingTag(tagName);
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#formatting
+static bool isFormattingTag(const AtomicString& tagName)
+{
+    return tagName == aTag || isNonAnchorFormattingTag(tagName);
+}
+
+static HTMLFormElement* closestFormAncestor(Element* element)
+{
+    ASSERT(isMainThread());
+    while (element) {
+        if (element->hasTagName(formTag))
+            return static_cast<HTMLFormElement*>(element);
+        ContainerNode* parent = element->parentNode();
+        if (!parent || !parent->isElementNode())
+            return 0;
+        element = toElement(parent);
+    }
+    return 0;
+}
+
+class HTMLTreeBuilder::ExternalCharacterTokenBuffer {
+    WTF_MAKE_NONCOPYABLE(ExternalCharacterTokenBuffer);
+public:
+    explicit ExternalCharacterTokenBuffer(AtomicHTMLToken* token)
+        : m_current(token->characters())
+        , m_end(m_current + token->charactersLength())
+        , m_isAll8BitData(token->isAll8BitData())
+    {
+        ASSERT(!isEmpty());
+    }
+
+    explicit ExternalCharacterTokenBuffer(const String& string)
+        : m_current(string.characters())
+        , m_end(m_current + string.length())
+        , m_isAll8BitData(string.length() && string.is8Bit())
+    {
+        ASSERT(!isEmpty());
+    }
+
+    ~ExternalCharacterTokenBuffer()
+    {
+        ASSERT(isEmpty());
+    }
+
+    bool isEmpty() const { return m_current == m_end; }
+
+    bool isAll8BitData() const { return m_isAll8BitData; }
+
+    void skipAtMostOneLeadingNewline()
+    {
+        ASSERT(!isEmpty());
+        if (*m_current == '\n')
+            ++m_current;
+    }
+
+    void skipLeadingWhitespace()
+    {
+        skipLeading<isHTMLSpace>();
+    }
+
+    String takeLeadingWhitespace()
+    {
+        return takeLeading<isHTMLSpace>();
+    }
+
+    void skipLeadingNonWhitespace()
+    {
+        skipLeading<isNotHTMLSpace>();
+    }
+
+    String takeRemaining()
+    {
+        ASSERT(!isEmpty());
+        const UChar* start = m_current;
+        m_current = m_end;
+        size_t length = m_current - start;
+
+        if (isAll8BitData())
+            return String::make8BitFrom16BitSource(start, length);
+
+        return String(start, length);
+    }
+
+    void giveRemainingTo(StringBuilder& recipient)
+    {
+        recipient.append(m_current, m_end - m_current);
+        m_current = m_end;
+    }
+
+    String takeRemainingWhitespace()
+    {
+        ASSERT(!isEmpty());
+        Vector<UChar> whitespace;
+        do {
+            UChar cc = *m_current++;
+            if (isHTMLSpace(cc))
+                whitespace.append(cc);
+        } while (m_current < m_end);
+        // Returning the null string when there aren't any whitespace
+        // characters is slightly cleaner semantically because we don't want
+        // to insert a text node (as opposed to inserting an empty text node).
+        if (whitespace.isEmpty())
+            return String();
+        return String::adopt(whitespace);
+    }
+
+private:
+    template<bool characterPredicate(UChar)>
+    void skipLeading()
+    {
+        ASSERT(!isEmpty());
+        while (characterPredicate(*m_current)) {
+            if (++m_current == m_end)
+                return;
+        }
+    }
+
+    template<bool characterPredicate(UChar)>
+    String takeLeading()
+    {
+        ASSERT(!isEmpty());
+        const UChar* start = m_current;
+        skipLeading<characterPredicate>();
+        if (start == m_current)
+            return String();
+        if (isAll8BitData())
+            return String::make8BitFrom16BitSource(start, m_current - start);
+        return String(start, m_current - start);
+    }
+
+    const UChar* m_current;
+    const UChar* m_end;
+    bool m_isAll8BitData;
+};
+
+
+HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser, HTMLDocument* document, ParserContentPolicy parserContentPolicy, bool, const HTMLParserOptions& options)
+    : m_framesetOk(true)
+#ifndef NDEBUG
+    , m_isAttached(true)
+#endif
+    , m_tree(document, parserContentPolicy)
+    , m_insertionMode(InitialMode)
+    , m_originalInsertionMode(InitialMode)
+    , m_shouldSkipLeadingNewline(false)
+    , m_parser(parser)
+    , m_scriptToProcessStartPosition(uninitializedPositionValue1())
+    , m_options(options)
+{
+}
+
+// FIXME: Member variables should be grouped into self-initializing structs to
+// minimize code duplication between these constructors.
+HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser, DocumentFragment* fragment, Element* contextElement, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options)
+    : m_framesetOk(true)
+#ifndef NDEBUG
+    , m_isAttached(true)
+#endif
+    , m_fragmentContext(fragment, contextElement)
+    , m_tree(fragment, parserContentPolicy)
+    , m_insertionMode(InitialMode)
+    , m_originalInsertionMode(InitialMode)
+    , m_shouldSkipLeadingNewline(false)
+    , m_parser(parser)
+    , m_scriptToProcessStartPosition(uninitializedPositionValue1())
+    , m_options(options)
+{
+    ASSERT(isMainThread());
+    // FIXME: This assertion will become invalid if <http://webkit.org/b/60316> is fixed.
+    ASSERT(contextElement);
+    if (contextElement) {
+        // Steps 4.2-4.6 of the HTML5 Fragment Case parsing algorithm:
+        // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
+        // For efficiency, we skip step 4.2 ("Let root be a new html element with no attributes")
+        // and instead use the DocumentFragment as a root node.
+        m_tree.openElements()->pushRootNode(HTMLStackItem::create(fragment, HTMLStackItem::ItemForDocumentFragmentNode));
+
+        if (contextElement->hasTagName(templateTag))
+            m_templateInsertionModes.append(TemplateContentsMode);
+
+        resetInsertionModeAppropriately();
+        m_tree.setForm(closestFormAncestor(contextElement));
+    }
+}
+
+HTMLTreeBuilder::~HTMLTreeBuilder()
+{
+}
+
+void HTMLTreeBuilder::detach()
+{
+#ifndef NDEBUG
+    // This call makes little sense in fragment mode, but for consistency
+    // DocumentParser expects detach() to always be called before it's destroyed.
+    m_isAttached = false;
+#endif
+    // HTMLConstructionSite might be on the callstack when detach() is called
+    // otherwise we'd just call m_tree.clear() here instead.
+    m_tree.detach();
+}
+
+HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext()
+    : m_fragment(0)
+    , m_contextElement(0)
+{
+}
+
+HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment* fragment, Element* contextElement)
+    : m_fragment(fragment)
+    , m_contextElement(contextElement)
+{
+    ASSERT(!fragment->hasChildNodes());
+}
+
+HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext()
+{
+}
+
+PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition)
+{
+    ASSERT(m_scriptToProcess);
+    // Unpause ourselves, callers may pause us again when processing the script.
+    // The HTML5 spec is written as though scripts are executed inside the tree
+    // builder.  We pause the parser to exit the tree builder, and then resume
+    // before running scripts.
+    scriptStartPosition = m_scriptToProcessStartPosition;
+    m_scriptToProcessStartPosition = uninitializedPositionValue1();
+    return m_scriptToProcess.release();
+}
+
+void HTMLTreeBuilder::constructTree(AtomicHTMLToken* token)
+{
+    if (shouldProcessTokenInForeignContent(token))
+        processTokenInForeignContent(token);
+    else
+        processToken(token);
+
+    if (m_parser->tokenizer()) {
+        bool inForeignContent = !m_tree.isEmpty()
+            && !m_tree.currentStackItem()->isInHTMLNamespace()
+            && !HTMLElementStack::isHTMLIntegrationPoint(m_tree.currentStackItem())
+            && !HTMLElementStack::isMathMLTextIntegrationPoint(m_tree.currentStackItem());
+
+        m_parser->tokenizer()->setForceNullCharacterReplacement(m_insertionMode == TextMode || inForeignContent);
+        m_parser->tokenizer()->setShouldAllowCDATA(inForeignContent);
+    }
+
+    m_tree.executeQueuedTasks();
+    // We might be detached now.
+}
+
+void HTMLTreeBuilder::processToken(AtomicHTMLToken* token)
+{
+    switch (token->type()) {
+    case HTMLToken::Uninitialized:
+        ASSERT_NOT_REACHED();
+        break;
+    case HTMLToken::DOCTYPE:
+        m_shouldSkipLeadingNewline = false;
+        processDoctypeToken(token);
+        break;
+    case HTMLToken::StartTag:
+        m_shouldSkipLeadingNewline = false;
+        processStartTag(token);
+        break;
+    case HTMLToken::EndTag:
+        m_shouldSkipLeadingNewline = false;
+        processEndTag(token);
+        break;
+    case HTMLToken::Comment:
+        m_shouldSkipLeadingNewline = false;
+        processComment(token);
+        return;
+    case HTMLToken::Character:
+        processCharacter(token);
+        break;
+    case HTMLToken::EndOfFile:
+        m_shouldSkipLeadingNewline = false;
+        processEndOfFile(token);
+        break;
+    }
+}
+
+void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::DOCTYPE);
+    if (m_insertionMode == InitialMode) {
+        m_tree.insertDoctype(token);
+        setInsertionMode(BeforeHTMLMode);
+        return;
+    }
+    if (m_insertionMode == InTableTextMode) {
+        defaultForInTableText();
+        processDoctypeToken(token);
+        return;
+    }
+    parseError(token);
+}
+
+void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, const Vector<Attribute>& attributes)
+{
+    // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags.
+    AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), attributes);
+    processStartTag(&fakeToken);
+}
+
+void HTMLTreeBuilder::processFakeEndTag(const AtomicString& tagName)
+{
+    AtomicHTMLToken fakeToken(HTMLToken::EndTag, tagName);
+    processEndTag(&fakeToken);
+}
+
+void HTMLTreeBuilder::processFakeEndTag(const QualifiedName& tagName)
+{
+    // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags.
+    processFakeEndTag(tagName.localName());
+}
+
+void HTMLTreeBuilder::processFakeCharacters(const String& characters)
+{
+    ASSERT(!characters.isEmpty());
+    ExternalCharacterTokenBuffer buffer(characters);
+    processCharacterBuffer(buffer);
+}
+
+void HTMLTreeBuilder::processFakePEndTagIfPInButtonScope()
+{
+    if (!m_tree.openElements()->inButtonScope(pTag.localName()))
+        return;
+    AtomicHTMLToken endP(HTMLToken::EndTag, pTag.localName());
+    processEndTag(&endP);
+}
+
+Vector<Attribute> HTMLTreeBuilder::attributesForIsindexInput(AtomicHTMLToken* token)
+{
+    Vector<Attribute> attributes = token->attributes();
+    for (int i = attributes.size() - 1; i >= 0; --i) {
+        const QualifiedName& name = attributes.at(i).name();
+        if (name.matches(nameAttr) || name.matches(actionAttr) || name.matches(promptAttr))
+            attributes.remove(i);
+    }
+
+    attributes.append(Attribute(nameAttr, isindexTag.localName()));
+    return attributes;
+}
+
+void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    ASSERT(token->name() == isindexTag);
+    parseError(token);
+    if (m_tree.form())
+        return;
+    notImplemented(); // Acknowledge self-closing flag
+    processFakeStartTag(formTag);
+    Attribute* actionAttribute = token->getAttributeItem(actionAttr);
+    if (actionAttribute)
+        m_tree.form()->setAttribute(actionAttr, actionAttribute->value());
+    processFakeStartTag(hrTag);
+    processFakeStartTag(labelTag);
+    Attribute* promptAttribute = token->getAttributeItem(promptAttr);
+    if (promptAttribute)
+        processFakeCharacters(promptAttribute->value());
+    else
+        processFakeCharacters(searchableIndexIntroduction());
+    processFakeStartTag(inputTag, attributesForIsindexInput(token));
+    notImplemented(); // This second set of characters may be needed by non-english locales.
+    processFakeEndTag(labelTag);
+    processFakeStartTag(hrTag);
+    processFakeEndTag(formTag);
+}
+
+namespace {
+
+bool isLi(const HTMLStackItem* item)
+{
+    return item->hasTagName(liTag);
+}
+
+bool isDdOrDt(const HTMLStackItem* item)
+{
+    return item->hasTagName(ddTag)
+        || item->hasTagName(dtTag);
+}
+
+}
+
+template <bool shouldClose(const HTMLStackItem*)>
+void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken* token)
+{
+    m_framesetOk = false;
+    HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
+    while (1) {
+        RefPtr<HTMLStackItem> item = nodeRecord->stackItem();
+        if (shouldClose(item.get())) {
+            ASSERT(item->isElementNode());
+            processFakeEndTag(item->localName());
+            break;
+        }
+        if (item->isSpecialNode() && !item->hasTagName(addressTag) && !item->hasTagName(divTag) && !item->hasTagName(pTag))
+            break;
+        nodeRecord = nodeRecord->next();
+    }
+    processFakePEndTagIfPInButtonScope();
+    m_tree.insertHTMLElement(token);
+}
+
+typedef HashMap<AtomicString, QualifiedName> PrefixedNameToQualifiedNameMap;
+
+static void mapLoweredLocalNameToName(PrefixedNameToQualifiedNameMap* map, QualifiedName** names, size_t length)
+{
+    for (size_t i = 0; i < length; ++i) {
+        const QualifiedName& name = *names[i];
+        const AtomicString& localName = name.localName();
+        AtomicString loweredLocalName = localName.lower();
+        if (loweredLocalName != localName)
+            map->add(loweredLocalName, name);
+    }
+}
+
+static void adjustSVGTagNameCase(AtomicHTMLToken* token)
+{
+    static PrefixedNameToQualifiedNameMap* caseMap = 0;
+    if (!caseMap) {
+        caseMap = new PrefixedNameToQualifiedNameMap;
+        QualifiedName** svgTags = SVGNames::getSVGTags();
+        mapLoweredLocalNameToName(caseMap, svgTags, SVGNames::SVGTagsCount);
+    }
+
+    const QualifiedName& casedName = caseMap->get(token->name());
+    if (casedName.localName().isNull())
+        return;
+    token->setName(casedName.localName());
+}
+
+template<QualifiedName** getAttrs(), unsigned length>
+static void adjustAttributes(AtomicHTMLToken* token)
+{
+    static PrefixedNameToQualifiedNameMap* caseMap = 0;
+    if (!caseMap) {
+        caseMap = new PrefixedNameToQualifiedNameMap;
+        QualifiedName** attrs = getAttrs();
+        mapLoweredLocalNameToName(caseMap, attrs, length);
+    }
+
+    for (unsigned i = 0; i < token->attributes().size(); ++i) {
+        Attribute& tokenAttribute = token->attributes().at(i);
+        const QualifiedName& casedName = caseMap->get(tokenAttribute.localName());
+        if (!casedName.localName().isNull())
+            tokenAttribute.parserSetName(casedName);
+    }
+}
+
+static void adjustSVGAttributes(AtomicHTMLToken* token)
+{
+    adjustAttributes<SVGNames::getSVGAttrs, SVGNames::SVGAttrsCount>(token);
+}
+
+static void adjustMathMLAttributes(AtomicHTMLToken* token)
+{
+    adjustAttributes<MathMLNames::getMathMLAttrs, MathMLNames::MathMLAttrsCount>(token);
+}
+
+static void addNamesWithPrefix(PrefixedNameToQualifiedNameMap* map, const AtomicString& prefix, QualifiedName** names, size_t length)
+{
+    for (size_t i = 0; i < length; ++i) {
+        QualifiedName* name = names[i];
+        const AtomicString& localName = name->localName();
+        AtomicString prefixColonLocalName = prefix + ':' + localName;
+        QualifiedName nameWithPrefix(prefix, localName, name->namespaceURI());
+        map->add(prefixColonLocalName, nameWithPrefix);
+    }
+}
+
+static void adjustForeignAttributes(AtomicHTMLToken* token)
+{
+    static PrefixedNameToQualifiedNameMap* map = 0;
+    if (!map) {
+        map = new PrefixedNameToQualifiedNameMap;
+
+        QualifiedName** attrs = XLinkNames::getXLinkAttrs();
+        addNamesWithPrefix(map, xlinkAtom, attrs, XLinkNames::XLinkAttrsCount);
+
+        attrs = XMLNames::getXMLAttrs();
+        addNamesWithPrefix(map, xmlAtom, attrs, XMLNames::XMLAttrsCount);
+
+        map->add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr);
+        map->add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkAtom, XMLNSNames::xmlnsNamespaceURI));
+    }
+
+    for (unsigned i = 0; i < token->attributes().size(); ++i) {
+        Attribute& tokenAttribute = token->attributes().at(i);
+        const QualifiedName& name = map->get(tokenAttribute.localName());
+        if (!name.localName().isNull())
+            tokenAttribute.parserSetName(name);
+    }
+}
+
+void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    if (token->name() == htmlTag) {
+        processHtmlStartTagForInBody(token);
+        return;
+    }
+    if (token->name() == baseTag
+        || token->name() == basefontTag
+        || token->name() == bgsoundTag
+        || token->name() == commandTag
+        || token->name() == linkTag
+        || token->name() == metaTag
+        || token->name() == noframesTag
+        || token->name() == scriptTag
+        || token->name() == styleTag
+        || token->name() == titleTag) {
+        bool didProcess = processStartTagForInHead(token);
+        ASSERT_UNUSED(didProcess, didProcess);
+        return;
+    }
+    if (token->name() == bodyTag) {
+        parseError(token);
+        if (!m_tree.openElements()->secondElementIsHTMLBodyElement() || m_tree.openElements()->hasOnlyOneElement() || m_tree.openElements()->hasTemplateInHTMLScope()) {
+            ASSERT(isParsingFragmentOrTemplateContents());
+            return;
+        }
+        m_framesetOk = false;
+        m_tree.insertHTMLBodyStartTagInBody(token);
+        return;
+    }
+    if (token->name() == framesetTag) {
+        parseError(token);
+        if (!m_tree.openElements()->secondElementIsHTMLBodyElement() || m_tree.openElements()->hasOnlyOneElement()) {
+            ASSERT(isParsingFragmentOrTemplateContents());
+            return;
+        }
+        if (!m_framesetOk)
+            return;
+        m_tree.openElements()->bodyElement()->remove(ASSERT_NO_EXCEPTION);
+        m_tree.openElements()->popUntil(m_tree.openElements()->bodyElement());
+        m_tree.openElements()->popHTMLBodyElement();
+        ASSERT(m_tree.openElements()->top() == m_tree.openElements()->htmlElement());
+        m_tree.insertHTMLElement(token);
+        setInsertionMode(InFramesetMode);
+        return;
+    }
+    if (token->name() == addressTag
+        || token->name() == articleTag
+        || token->name() == asideTag
+        || token->name() == blockquoteTag
+        || token->name() == centerTag
+        || token->name() == detailsTag
+        || token->name() == dirTag
+        || token->name() == divTag
+        || token->name() == dlTag
+        || token->name() == fieldsetTag
+        || token->name() == figcaptionTag
+        || token->name() == figureTag
+        || token->name() == footerTag
+        || token->name() == headerTag
+        || token->name() == hgroupTag
+        || token->name() == mainTag
+        || token->name() == menuTag
+        || token->name() == navTag
+        || token->name() == olTag
+        || token->name() == pTag
+        || token->name() == sectionTag
+        || token->name() == summaryTag
+        || token->name() == ulTag) {
+        processFakePEndTagIfPInButtonScope();
+        m_tree.insertHTMLElement(token);
+        return;
+    }
+    if (isNumberedHeaderTag(token->name())) {
+        processFakePEndTagIfPInButtonScope();
+        if (m_tree.currentStackItem()->isNumberedHeaderElement()) {
+            parseError(token);
+            m_tree.openElements()->pop();
+        }
+        m_tree.insertHTMLElement(token);
+        return;
+    }
+    if (token->name() == preTag || token->name() == listingTag) {
+        processFakePEndTagIfPInButtonScope();
+        m_tree.insertHTMLElement(token);
+        m_shouldSkipLeadingNewline = true;
+        m_framesetOk = false;
+        return;
+    }
+    if (token->name() == formTag) {
+        if (m_tree.form()) {
+            parseError(token);
+            return;
+        }
+        processFakePEndTagIfPInButtonScope();
+        m_tree.insertHTMLFormElement(token);
+        return;
+    }
+    if (token->name() == liTag) {
+        processCloseWhenNestedTag<isLi>(token);
+        return;
+    }
+    if (token->name() == ddTag || token->name() == dtTag) {
+        processCloseWhenNestedTag<isDdOrDt>(token);
+        return;
+    }
+    if (token->name() == plaintextTag) {
+        processFakePEndTagIfPInButtonScope();
+        m_tree.insertHTMLElement(token);
+        if (m_parser->tokenizer())
+            m_parser->tokenizer()->setState(HTMLTokenizer::PLAINTEXTState);
+        return;
+    }
+    if (token->name() == buttonTag) {
+        if (m_tree.openElements()->inScope(buttonTag)) {
+            parseError(token);
+            processFakeEndTag(buttonTag);
+            processStartTag(token); // FIXME: Could we just fall through here?
+            return;
+        }
+        m_tree.reconstructTheActiveFormattingElements();
+        m_tree.insertHTMLElement(token);
+        m_framesetOk = false;
+        return;
+    }
+    if (token->name() == aTag) {
+        Element* activeATag = m_tree.activeFormattingElements()->closestElementInScopeWithName(aTag.localName());
+        if (activeATag) {
+            parseError(token);
+            processFakeEndTag(aTag);
+            m_tree.activeFormattingElements()->remove(activeATag);
+            if (m_tree.openElements()->contains(activeATag))
+                m_tree.openElements()->remove(activeATag);
+        }
+        m_tree.reconstructTheActiveFormattingElements();
+        m_tree.insertFormattingElement(token);
+        return;
+    }
+    if (isNonAnchorNonNobrFormattingTag(token->name())) {
+        m_tree.reconstructTheActiveFormattingElements();
+        m_tree.insertFormattingElement(token);
+        return;
+    }
+    if (token->name() == nobrTag) {
+        m_tree.reconstructTheActiveFormattingElements();
+        if (m_tree.openElements()->inScope(nobrTag)) {
+            parseError(token);
+            processFakeEndTag(nobrTag);
+            m_tree.reconstructTheActiveFormattingElements();
+        }
+        m_tree.insertFormattingElement(token);
+        return;
+    }
+    if (token->name() == appletTag
+        || token->name() == embedTag
+        || token->name() == objectTag) {
+        if (!pluginContentIsAllowed(m_tree.parserContentPolicy()))
+            return;
+    }
+    if (token->name() == appletTag
+        || token->name() == marqueeTag
+        || token->name() == objectTag) {
+        m_tree.reconstructTheActiveFormattingElements();
+        m_tree.insertHTMLElement(token);
+        m_tree.activeFormattingElements()->appendMarker();
+        m_framesetOk = false;
+        return;
+    }
+    if (token->name() == tableTag) {
+        if (!m_tree.inQuirksMode() && m_tree.openElements()->inButtonScope(pTag))
+            processFakeEndTag(pTag);
+        m_tree.insertHTMLElement(token);
+        m_framesetOk = false;
+        setInsertionMode(InTableMode);
+        return;
+    }
+    if (token->name() == imageTag) {
+        parseError(token);
+        // Apparently we're not supposed to ask.
+        token->setName(imgTag.localName());
+        // Note the fall through to the imgTag handling below!
+    }
+    if (token->name() == areaTag
+        || token->name() == brTag
+        || token->name() == embedTag
+        || token->name() == imgTag
+        || token->name() == keygenTag
+        || token->name() == wbrTag) {
+        m_tree.reconstructTheActiveFormattingElements();
+        m_tree.insertSelfClosingHTMLElement(token);
+        m_framesetOk = false;
+        return;
+    }
+    if (token->name() == inputTag) {
+        Attribute* typeAttribute = token->getAttributeItem(typeAttr);
+        m_tree.reconstructTheActiveFormattingElements();
+        m_tree.insertSelfClosingHTMLElement(token);
+        if (!typeAttribute || !equalIgnoringCase(typeAttribute->value(), "hidden"))
+            m_framesetOk = false;
+        return;
+    }
+    if (token->name() == paramTag
+        || token->name() == sourceTag
+        || token->name() == trackTag) {
+        m_tree.insertSelfClosingHTMLElement(token);
+        return;
+    }
+    if (token->name() == hrTag) {
+        processFakePEndTagIfPInButtonScope();
+        m_tree.insertSelfClosingHTMLElement(token);
+        m_framesetOk = false;
+        return;
+    }
+    if (token->name() == isindexTag) {
+        processIsindexStartTagForInBody(token);
+        return;
+    }
+    if (token->name() == textareaTag) {
+        m_tree.insertHTMLElement(token);
+        m_shouldSkipLeadingNewline = true;
+        if (m_parser->tokenizer())
+            m_parser->tokenizer()->setState(HTMLTokenizer::RCDATAState);
+        m_originalInsertionMode = m_insertionMode;
+        m_framesetOk = false;
+        setInsertionMode(TextMode);
+        return;
+    }
+    if (token->name() == xmpTag) {
+        processFakePEndTagIfPInButtonScope();
+        m_tree.reconstructTheActiveFormattingElements();
+        m_framesetOk = false;
+        processGenericRawTextStartTag(token);
+        return;
+    }
+    if (token->name() == iframeTag) {
+        m_framesetOk = false;
+        processGenericRawTextStartTag(token);
+        return;
+    }
+    if (token->name() == noembedTag && m_options.pluginsEnabled) {
+        processGenericRawTextStartTag(token);
+        return;
+    }
+    if (token->name() == noscriptTag && m_options.scriptEnabled) {
+        processGenericRawTextStartTag(token);
+        return;
+    }
+    if (token->name() == selectTag) {
+        m_tree.reconstructTheActiveFormattingElements();
+        m_tree.insertHTMLElement(token);
+        m_framesetOk = false;
+        if (m_insertionMode == InTableMode
+             || m_insertionMode == InCaptionMode
+             || m_insertionMode == InColumnGroupMode
+             || m_insertionMode == InTableBodyMode
+             || m_insertionMode == InRowMode
+             || m_insertionMode == InCellMode)
+            setInsertionMode(InSelectInTableMode);
+        else
+            setInsertionMode(InSelectMode);
+        return;
+    }
+    if (token->name() == optgroupTag || token->name() == optionTag) {
+        if (m_tree.currentStackItem()->hasTagName(optionTag)) {
+            AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
+            processEndTag(&endOption);
+        }
+        m_tree.reconstructTheActiveFormattingElements();
+        m_tree.insertHTMLElement(token);
+        return;
+    }
+    if (token->name() == rpTag || token->name() == rtTag) {
+        if (m_tree.openElements()->inScope(rubyTag.localName())) {
+            m_tree.generateImpliedEndTags();
+            if (!m_tree.currentStackItem()->hasTagName(rubyTag))
+                parseError(token);
+        }
+        m_tree.insertHTMLElement(token);
+        return;
+    }
+    if (token->name() == MathMLNames::mathTag.localName()) {
+        m_tree.reconstructTheActiveFormattingElements();
+        adjustMathMLAttributes(token);
+        adjustForeignAttributes(token);
+        m_tree.insertForeignElement(token, MathMLNames::mathmlNamespaceURI);
+        return;
+    }
+    if (token->name() == SVGNames::svgTag.localName()) {
+        m_tree.reconstructTheActiveFormattingElements();
+        adjustSVGAttributes(token);
+        adjustForeignAttributes(token);
+        m_tree.insertForeignElement(token, SVGNames::svgNamespaceURI);
+        return;
+    }
+    if (isCaptionColOrColgroupTag(token->name())
+        || token->name() == frameTag
+        || token->name() == headTag
+        || isTableBodyContextTag(token->name())
+        || isTableCellContextTag(token->name())
+        || token->name() == trTag) {
+        parseError(token);
+        return;
+    }
+    if (token->name() == templateTag) {
+        processTemplateStartTag(token);
+        return;
+    }
+    m_tree.reconstructTheActiveFormattingElements();
+    m_tree.insertHTMLElement(token);
+}
+
+void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken* token)
+{
+    m_tree.activeFormattingElements()->appendMarker();
+    m_tree.insertHTMLElement(token);
+    m_templateInsertionModes.append(TemplateContentsMode);
+    setInsertionMode(TemplateContentsMode);
+}
+
+bool HTMLTreeBuilder::processTemplateEndTag(AtomicHTMLToken* token)
+{
+    ASSERT(token->name() == templateTag.localName());
+    if (!m_tree.openElements()->hasTemplateInHTMLScope()) {
+        ASSERT(m_templateInsertionModes.isEmpty() || (m_templateInsertionModes.size() == 1 && m_fragmentContext.contextElement()->hasTagName(templateTag)));
+        parseError(token);
+        return false;
+    }
+    m_tree.generateImpliedEndTags();
+    if (!m_tree.currentStackItem()->hasTagName(templateTag))
+        parseError(token);
+    m_tree.openElements()->popUntilPopped(templateTag);
+    m_tree.activeFormattingElements()->clearToLastMarker();
+    m_templateInsertionModes.removeLast();
+    resetInsertionModeAppropriately();
+    return true;
+}
+
+bool HTMLTreeBuilder::processEndOfFileForInTemplateContents(AtomicHTMLToken* token)
+{
+    AtomicHTMLToken endTemplate(HTMLToken::EndTag, templateTag.localName());
+    if (!processTemplateEndTag(&endTemplate))
+        return false;
+
+    processEndOfFile(token);
+    return true;
+}
+
+bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup()
+{
+    if (m_tree.currentIsRootNode() || m_tree.currentNode()->hasTagName(templateTag)) {
+        ASSERT(isParsingFragmentOrTemplateContents());
+        // FIXME: parse error
+        return false;
+    }
+    m_tree.openElements()->pop();
+    setInsertionMode(InTableMode);
+    return true;
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#close-the-cell
+void HTMLTreeBuilder::closeTheCell()
+{
+    ASSERT(insertionMode() == InCellMode);
+    if (m_tree.openElements()->inTableScope(tdTag)) {
+        ASSERT(!m_tree.openElements()->inTableScope(thTag));
+        processFakeEndTag(tdTag);
+        return;
+    }
+    ASSERT(m_tree.openElements()->inTableScope(thTag));
+    processFakeEndTag(thTag);
+    ASSERT(insertionMode() == InRowMode);
+}
+
+void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    if (token->name() == captionTag) {
+        m_tree.openElements()->popUntilTableScopeMarker();
+        m_tree.activeFormattingElements()->appendMarker();
+        m_tree.insertHTMLElement(token);
+        setInsertionMode(InCaptionMode);
+        return;
+    }
+    if (token->name() == colgroupTag) {
+        m_tree.openElements()->popUntilTableScopeMarker();
+        m_tree.insertHTMLElement(token);
+        setInsertionMode(InColumnGroupMode);
+        return;
+    }
+    if (token->name() == colTag) {
+        processFakeStartTag(colgroupTag);
+        ASSERT(InColumnGroupMode);
+        processStartTag(token);
+        return;
+    }
+    if (isTableBodyContextTag(token->name())) {
+        m_tree.openElements()->popUntilTableScopeMarker();
+        m_tree.insertHTMLElement(token);
+        setInsertionMode(InTableBodyMode);
+        return;
+    }
+    if (isTableCellContextTag(token->name())
+        || token->name() == trTag) {
+        processFakeStartTag(tbodyTag);
+        ASSERT(insertionMode() == InTableBodyMode);
+        processStartTag(token);
+        return;
+    }
+    if (token->name() == tableTag) {
+        parseError(token);
+        if (!processTableEndTagForInTable()) {
+            ASSERT(isParsingFragmentOrTemplateContents());
+            return;
+        }
+        processStartTag(token);
+        return;
+    }
+    if (token->name() == styleTag || token->name() == scriptTag) {
+        processStartTagForInHead(token);
+        return;
+    }
+    if (token->name() == inputTag) {
+        Attribute* typeAttribute = token->getAttributeItem(typeAttr);
+        if (typeAttribute && equalIgnoringCase(typeAttribute->value(), "hidden")) {
+            parseError(token);
+            m_tree.insertSelfClosingHTMLElement(token);
+            return;
+        }
+        // Fall through to "anything else" case.
+    }
+    if (token->name() == formTag) {
+        parseError(token);
+        if (m_tree.form())
+            return;
+        m_tree.insertHTMLFormElement(token, true);
+        m_tree.openElements()->pop();
+        return;
+    }
+    if (token->name() == templateTag) {
+        processTemplateStartTag(token);
+        return;
+    }
+    parseError(token);
+    HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
+    processStartTagForInBody(token);
+}
+
+void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    switch (insertionMode()) {
+    case InitialMode:
+        ASSERT(insertionMode() == InitialMode);
+        defaultForInitial();
+        // Fall through.
+    case BeforeHTMLMode:
+        ASSERT(insertionMode() == BeforeHTMLMode);
+        if (token->name() == htmlTag) {
+            m_tree.insertHTMLHtmlStartTagBeforeHTML(token);
+            setInsertionMode(BeforeHeadMode);
+            return;
+        }
+        defaultForBeforeHTML();
+        // Fall through.
+    case BeforeHeadMode:
+        ASSERT(insertionMode() == BeforeHeadMode);
+        if (token->name() == htmlTag) {
+            processHtmlStartTagForInBody(token);
+            return;
+        }
+        if (token->name() == headTag) {
+            m_tree.insertHTMLHeadElement(token);
+            setInsertionMode(InHeadMode);
+            return;
+        }
+        defaultForBeforeHead();
+        // Fall through.
+    case InHeadMode:
+        ASSERT(insertionMode() == InHeadMode);
+        if (processStartTagForInHead(token))
+            return;
+        defaultForInHead();
+        // Fall through.
+    case AfterHeadMode:
+        ASSERT(insertionMode() == AfterHeadMode);
+        if (token->name() == htmlTag) {
+            processHtmlStartTagForInBody(token);
+            return;
+        }
+        if (token->name() == bodyTag) {
+            m_framesetOk = false;
+            m_tree.insertHTMLBodyElement(token);
+            setInsertionMode(InBodyMode);
+            return;
+        }
+        if (token->name() == framesetTag) {
+            m_tree.insertHTMLElement(token);
+            setInsertionMode(InFramesetMode);
+            return;
+        }
+        if (token->name() == baseTag
+            || token->name() == basefontTag
+            || token->name() == bgsoundTag
+            || token->name() == linkTag
+            || token->name() == metaTag
+            || token->name() == noframesTag
+            || token->name() == scriptTag
+            || token->name() == styleTag
+            || token->name() == titleTag) {
+            parseError(token);
+            ASSERT(m_tree.head());
+            m_tree.openElements()->pushHTMLHeadElement(m_tree.headStackItem());
+            processStartTagForInHead(token);
+            m_tree.openElements()->removeHTMLHeadElement(m_tree.head());
+            return;
+        }
+        if (token->name() == headTag) {
+            parseError(token);
+            return;
+        }
+        defaultForAfterHead();
+        // Fall through
+    case InBodyMode:
+        ASSERT(insertionMode() == InBodyMode);
+        processStartTagForInBody(token);
+        break;
+    case InTableMode:
+        ASSERT(insertionMode() == InTableMode);
+        processStartTagForInTable(token);
+        break;
+    case InCaptionMode:
+        ASSERT(insertionMode() == InCaptionMode);
+        if (isCaptionColOrColgroupTag(token->name())
+            || isTableBodyContextTag(token->name())
+            || isTableCellContextTag(token->name())
+            || token->name() == trTag) {
+            parseError(token);
+            if (!processCaptionEndTagForInCaption()) {
+                ASSERT(isParsingFragment());
+                return;
+            }
+            processStartTag(token);
+            return;
+        }
+        processStartTagForInBody(token);
+        break;
+    case InColumnGroupMode:
+        ASSERT(insertionMode() == InColumnGroupMode);
+        if (token->name() == htmlTag) {
+            processHtmlStartTagForInBody(token);
+            return;
+        }
+        if (token->name() == colTag) {
+            m_tree.insertSelfClosingHTMLElement(token);
+            return;
+        }
+        if (token->name() == templateTag) {
+            processTemplateStartTag(token);
+            return;
+        }
+        if (!processColgroupEndTagForInColumnGroup()) {
+            ASSERT(isParsingFragmentOrTemplateContents());
+            return;
+        }
+        processStartTag(token);
+        break;
+    case InTableBodyMode:
+        ASSERT(insertionMode() == InTableBodyMode);
+        if (token->name() == trTag) {
+            m_tree.openElements()->popUntilTableBodyScopeMarker(); // How is there ever anything to pop?
+            m_tree.insertHTMLElement(token);
+            setInsertionMode(InRowMode);
+            return;
+        }
+        if (isTableCellContextTag(token->name())) {
+            parseError(token);
+            processFakeStartTag(trTag);
+            ASSERT(insertionMode() == InRowMode);
+            processStartTag(token);
+            return;
+        }
+        if (isCaptionColOrColgroupTag(token->name()) || isTableBodyContextTag(token->name())) {
+            // FIXME: This is slow.
+            if (!m_tree.openElements()->inTableScope(tbodyTag) && !m_tree.openElements()->inTableScope(theadTag) && !m_tree.openElements()->inTableScope(tfootTag)) {
+                ASSERT(isParsingFragmentOrTemplateContents());
+                parseError(token);
+                return;
+            }
+            m_tree.openElements()->popUntilTableBodyScopeMarker();
+            ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName()));
+            processFakeEndTag(m_tree.currentStackItem()->localName());
+            processStartTag(token);
+            return;
+        }
+        processStartTagForInTable(token);
+        break;
+    case InRowMode:
+        ASSERT(insertionMode() == InRowMode);
+        if (isTableCellContextTag(token->name())) {
+            m_tree.openElements()->popUntilTableRowScopeMarker();
+            m_tree.insertHTMLElement(token);
+            setInsertionMode(InCellMode);
+            m_tree.activeFormattingElements()->appendMarker();
+            return;
+        }
+        if (token->name() == trTag
+            || isCaptionColOrColgroupTag(token->name())
+            || isTableBodyContextTag(token->name())) {
+            if (!processTrEndTagForInRow()) {
+                ASSERT(isParsingFragmentOrTemplateContents());
+                return;
+            }
+            ASSERT(insertionMode() == InTableBodyMode);
+            processStartTag(token);
+            return;
+        }
+        processStartTagForInTable(token);
+        break;
+    case InCellMode:
+        ASSERT(insertionMode() == InCellMode);
+        if (isCaptionColOrColgroupTag(token->name())
+            || isTableCellContextTag(token->name())
+            || token->name() == trTag
+            || isTableBodyContextTag(token->name())) {
+            // FIXME: This could be more efficient.
+            if (!m_tree.openElements()->inTableScope(tdTag) && !m_tree.openElements()->inTableScope(thTag)) {
+                ASSERT(isParsingFragment());
+                parseError(token);
+                return;
+            }
+            closeTheCell();
+            processStartTag(token);
+            return;
+        }
+        processStartTagForInBody(token);
+        break;
+    case AfterBodyMode:
+    case AfterAfterBodyMode:
+        ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
+        if (token->name() == htmlTag) {
+            processHtmlStartTagForInBody(token);
+            return;
+        }
+        setInsertionMode(InBodyMode);
+        processStartTag(token);
+        break;
+    case InHeadNoscriptMode:
+        ASSERT(insertionMode() == InHeadNoscriptMode);
+        if (token->name() == htmlTag) {
+            processHtmlStartTagForInBody(token);
+            return;
+        }
+        if (token->name() == basefontTag
+            || token->name() == bgsoundTag
+            || token->name() == linkTag
+            || token->name() == metaTag
+            || token->name() == noframesTag
+            || token->name() == styleTag) {
+            bool didProcess = processStartTagForInHead(token);
+            ASSERT_UNUSED(didProcess, didProcess);
+            return;
+        }
+        if (token->name() == htmlTag || token->name() == noscriptTag) {
+            parseError(token);
+            return;
+        }
+        defaultForInHeadNoscript();
+        processToken(token);
+        break;
+    case InFramesetMode:
+        ASSERT(insertionMode() == InFramesetMode);
+        if (token->name() == htmlTag) {
+            processHtmlStartTagForInBody(token);
+            return;
+        }
+        if (token->name() == framesetTag) {
+            m_tree.insertHTMLElement(token);
+            return;
+        }
+        if (token->name() == frameTag) {
+            m_tree.insertSelfClosingHTMLElement(token);
+            return;
+        }
+        if (token->name() == noframesTag) {
+            processStartTagForInHead(token);
+            return;
+        }
+        if (token->name() == templateTag) {
+            processTemplateStartTag(token);
+            return;
+        }
+        parseError(token);
+        break;
+    case AfterFramesetMode:
+    case AfterAfterFramesetMode:
+        ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
+        if (token->name() == htmlTag) {
+            processHtmlStartTagForInBody(token);
+            return;
+        }
+        if (token->name() == noframesTag) {
+            processStartTagForInHead(token);
+            return;
+        }
+        parseError(token);
+        break;
+    case InSelectInTableMode:
+        ASSERT(insertionMode() == InSelectInTableMode);
+        if (token->name() == captionTag
+            || token->name() == tableTag
+            || isTableBodyContextTag(token->name())
+            || token->name() == trTag
+            || isTableCellContextTag(token->name())) {
+            parseError(token);
+            AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
+            processEndTag(&endSelect);
+            processStartTag(token);
+            return;
+        }
+        // Fall through
+    case InSelectMode:
+        ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);
+        if (token->name() == htmlTag) {
+            processHtmlStartTagForInBody(token);
+            return;
+        }
+        if (token->name() == optionTag) {
+            if (m_tree.currentStackItem()->hasTagName(optionTag)) {
+                AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
+                processEndTag(&endOption);
+            }
+            m_tree.insertHTMLElement(token);
+            return;
+        }
+        if (token->name() == optgroupTag) {
+            if (m_tree.currentStackItem()->hasTagName(optionTag)) {
+                AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
+                processEndTag(&endOption);
+            }
+            if (m_tree.currentStackItem()->hasTagName(optgroupTag)) {
+                AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName());
+                processEndTag(&endOptgroup);
+            }
+            m_tree.insertHTMLElement(token);
+            return;
+        }
+        if (token->name() == selectTag) {
+            parseError(token);
+            AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
+            processEndTag(&endSelect);
+            return;
+        }
+        if (token->name() == inputTag
+            || token->name() == keygenTag
+            || token->name() == textareaTag) {
+            parseError(token);
+            if (!m_tree.openElements()->inSelectScope(selectTag)) {
+                ASSERT(isParsingFragment());
+                return;
+            }
+            AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
+            processEndTag(&endSelect);
+            processStartTag(token);
+            return;
+        }
+        if (token->name() == scriptTag) {
+            bool didProcess = processStartTagForInHead(token);
+            ASSERT_UNUSED(didProcess, didProcess);
+            return;
+        }
+        if (token->name() == templateTag) {
+            processTemplateStartTag(token);
+            return;
+        }
+        break;
+    case InTableTextMode:
+        defaultForInTableText();
+        processStartTag(token);
+        break;
+    case TextMode:
+        ASSERT_NOT_REACHED();
+        break;
+    case TemplateContentsMode:
+        if (token->name() == templateTag) {
+            processTemplateStartTag(token);
+            return;
+        }
+
+        if (token->name() == linkTag
+            || token->name() == scriptTag
+            || token->name() == styleTag
+            || token->name() == metaTag) {
+            processStartTagForInHead(token);
+            return;
+        }
+
+        InsertionMode insertionMode = TemplateContentsMode;
+        if (token->name() == frameTag)
+            insertionMode = InFramesetMode;
+        else if (token->name() == colTag)
+            insertionMode = InColumnGroupMode;
+        else if (isCaptionColOrColgroupTag(token->name()) || isTableBodyContextTag(token->name()))
+            insertionMode = InTableMode;
+        else if (token->name() == trTag)
+            insertionMode = InTableBodyMode;
+        else if (isTableCellContextTag(token->name()))
+            insertionMode = InRowMode;
+        else
+            insertionMode = InBodyMode;
+
+        ASSERT(insertionMode != TemplateContentsMode);
+        ASSERT(m_templateInsertionModes.last() == TemplateContentsMode);
+        m_templateInsertionModes.last() = insertionMode;
+        setInsertionMode(insertionMode);
+
+        processStartTag(token);
+        break;
+    }
+}
+
+void HTMLTreeBuilder::processHtmlStartTagForInBody(AtomicHTMLToken* token)
+{
+    parseError(token);
+    if (m_tree.openElements()->hasTemplateInHTMLScope()) {
+        ASSERT(isParsingTemplateContents());
+        return;
+    }
+    m_tree.insertHTMLHtmlStartTagInBody(token);
+}
+
+bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::EndTag);
+    ASSERT(token->name() == bodyTag);
+    if (!m_tree.openElements()->inScope(bodyTag.localName())) {
+        parseError(token);
+        return false;
+    }
+    notImplemented(); // Emit a more specific parse error based on stack contents.
+    setInsertionMode(AfterBodyMode);
+    return true;
+}
+
+void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::EndTag);
+    HTMLElementStack::ElementRecord* record = m_tree.openElements()->topRecord();
+    while (1) {
+        RefPtr<HTMLStackItem> item = record->stackItem();
+        if (item->matchesHTMLTag(token->name())) {
+            m_tree.generateImpliedEndTagsWithExclusion(token->name());
+            if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+                parseError(token);
+            m_tree.openElements()->popUntilPopped(item->element());
+            return;
+        }
+        if (item->isSpecialNode()) {
+            parseError(token);
+            return;
+        }
+        record = record->next();
+    }
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
+void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token)
+{
+    // The adoption agency algorithm is N^2. We limit the number of iterations
+    // to stop from hanging the whole browser. This limit is specified in the
+    // adoption agency algorithm: 
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#parsing-main-inbody
+    static const int outerIterationLimit = 8;
+    static const int innerIterationLimit = 3;
+
+    // 1, 2, 3 and 16 are covered by the for() loop.
+    for (int i = 0; i < outerIterationLimit; ++i) {
+        // 4.
+        Element* formattingElement = m_tree.activeFormattingElements()->closestElementInScopeWithName(token->name());
+        // 4.a
+        if (!formattingElement)
+            return processAnyOtherEndTagForInBody(token);
+        // 4.c
+        if ((m_tree.openElements()->contains(formattingElement)) && !m_tree.openElements()->inScope(formattingElement)) {
+            parseError(token);
+            notImplemented(); // Check the stack of open elements for a more specific parse error.
+            return;
+        }
+        // 4.b
+        HTMLElementStack::ElementRecord* formattingElementRecord = m_tree.openElements()->find(formattingElement);
+        if (!formattingElementRecord) {
+            parseError(token);
+            m_tree.activeFormattingElements()->remove(formattingElement);
+            return;
+        }
+        // 4.d
+        if (formattingElement != m_tree.currentElement())
+            parseError(token);
+        // 5.
+        HTMLElementStack::ElementRecord* furthestBlock = m_tree.openElements()->furthestBlockForFormattingElement(formattingElement);
+        // 6.
+        if (!furthestBlock) {
+            m_tree.openElements()->popUntilPopped(formattingElement);
+            m_tree.activeFormattingElements()->remove(formattingElement);
+            return;
+        }
+        // 7.
+        ASSERT(furthestBlock->isAbove(formattingElementRecord));
+        RefPtr<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem();
+        // 8.
+        HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement);
+        // 9.
+        HTMLElementStack::ElementRecord* node = furthestBlock;
+        HTMLElementStack::ElementRecord* nextNode = node->next();
+        HTMLElementStack::ElementRecord* lastNode = furthestBlock;
+        // 9.1, 9.2, 9.3 and 9.11 are covered by the for() loop.
+        for (int i = 0; i < innerIterationLimit; ++i) {
+            // 9.4
+            node = nextNode;
+            ASSERT(node);
+            nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 9.5.
+            // 9.5
+            if (!m_tree.activeFormattingElements()->contains(node->element())) {
+                m_tree.openElements()->remove(node->element());
+                node = 0;
+                continue;
+            }
+            // 9.6
+            if (node == formattingElementRecord)
+                break;
+            // 9.7
+            RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(node->stackItem().get());
+
+            HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements()->find(node->element());
+            nodeEntry->replaceElement(newItem);
+            node->replaceElement(newItem.release());
+
+            // 9.8
+            if (lastNode == furthestBlock)
+                bookmark.moveToAfter(nodeEntry);
+            // 9.9
+            if (ContainerNode* parent = lastNode->element()->parentNode())
+                parent->parserRemoveChild(lastNode->element());
+            node->element()->parserAppendChild(lastNode->element());
+            if (lastNode->element()->parentElement()->attached() && !lastNode->element()->attached())
+                lastNode->element()->lazyAttach();
+            // 9.10
+            lastNode = node;
+        }
+        // 10.
+        if (ContainerNode* parent = lastNode->element()->parentNode())
+            parent->parserRemoveChild(lastNode->element());
+        if (commonAncestor->causesFosterParenting())
+            m_tree.fosterParent(lastNode->element());
+        else {
+            if (commonAncestor->hasTagName(templateTag))
+                toHTMLTemplateElement(commonAncestor->node())->content()->parserAppendChild(lastNode->element());
+            else
+                commonAncestor->node()->parserAppendChild(lastNode->element());
+            ASSERT(lastNode->stackItem()->isElementNode());
+            ASSERT(lastNode->element()->parentNode());
+            if (lastNode->element()->parentNode()->attached() && !lastNode->element()->attached())
+                lastNode->element()->lazyAttach();
+        }
+        // 11.
+        RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem().get());
+        // 12.
+        newItem->element()->takeAllChildrenFrom(furthestBlock->element());
+        // 13.
+        Element* furthestBlockElement = furthestBlock->element();
+        // FIXME: All this creation / parserAppendChild / attach business should
+        //        be in HTMLConstructionSite. My guess is that steps 11--15
+        //        should all be in some HTMLConstructionSite function.
+        furthestBlockElement->parserAppendChild(newItem->element());
+        // FIXME: Why is this attach logic necessary? Style resolve should attach us if needed.
+        if (furthestBlockElement->attached() && !newItem->element()->attached()) {
+            // Notice that newItem->element() might already be attached if, for example, one of the reparented
+            // children is a style element, which attaches itself automatically.
+            newItem->element()->attach();
+        }
+        // 14.
+        m_tree.activeFormattingElements()->swapTo(formattingElement, newItem, bookmark);
+        // 15.
+        m_tree.openElements()->remove(formattingElement);
+        m_tree.openElements()->insertAbove(newItem, furthestBlock);
+    }
+}
+
+void HTMLTreeBuilder::resetInsertionModeAppropriately()
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#reset-the-insertion-mode-appropriately
+    bool last = false;
+    HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
+    while (1) {
+        RefPtr<HTMLStackItem> item = nodeRecord->stackItem();
+        if (item->node() == m_tree.openElements()->rootNode()) {
+            ASSERT(isParsingFragment());
+            last = true;
+            item = HTMLStackItem::create(m_fragmentContext.contextElement(), HTMLStackItem::ItemForContextElement);
+        }
+        if (item->hasTagName(templateTag))
+            return setInsertionMode(m_templateInsertionModes.last());
+        if (item->hasTagName(selectTag)) {
+            return setInsertionMode(InSelectMode);
+        }
+        if (item->hasTagName(tdTag) || item->hasTagName(thTag))
+            return setInsertionMode(InCellMode);
+        if (item->hasTagName(trTag))
+            return setInsertionMode(InRowMode);
+        if (item->hasTagName(tbodyTag) || item->hasTagName(theadTag) || item->hasTagName(tfootTag))
+            return setInsertionMode(InTableBodyMode);
+        if (item->hasTagName(captionTag))
+            return setInsertionMode(InCaptionMode);
+        if (item->hasTagName(colgroupTag)) {
+            return setInsertionMode(InColumnGroupMode);
+        }
+        if (item->hasTagName(tableTag))
+            return setInsertionMode(InTableMode);
+        if (item->hasTagName(headTag)) {
+            if (!m_fragmentContext.fragment() || m_fragmentContext.contextElement() != item->node())
+                return setInsertionMode(InHeadMode);
+            return setInsertionMode(InBodyMode);
+        }
+        if (item->hasTagName(bodyTag))
+            return setInsertionMode(InBodyMode);
+        if (item->hasTagName(framesetTag)) {
+            return setInsertionMode(InFramesetMode);
+        }
+        if (item->hasTagName(htmlTag)) {
+            ASSERT(isParsingFragment());
+            return setInsertionMode(BeforeHeadMode);
+        }
+        if (last) {
+            ASSERT(isParsingFragment());
+            return setInsertionMode(InBodyMode);
+        }
+        nodeRecord = nodeRecord->next();
+    }
+}
+
+void HTMLTreeBuilder::processEndTagForInTableBody(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::EndTag);
+    if (isTableBodyContextTag(token->name())) {
+        if (!m_tree.openElements()->inTableScope(token->name())) {
+            parseError(token);
+            return;
+        }
+        m_tree.openElements()->popUntilTableBodyScopeMarker();
+        m_tree.openElements()->pop();
+        setInsertionMode(InTableMode);
+        return;
+    }
+    if (token->name() == tableTag) {
+        // FIXME: This is slow.
+        if (!m_tree.openElements()->inTableScope(tbodyTag) && !m_tree.openElements()->inTableScope(theadTag) && !m_tree.openElements()->inTableScope(tfootTag)) {
+            ASSERT(isParsingFragmentOrTemplateContents());
+            parseError(token);
+            return;
+        }
+        m_tree.openElements()->popUntilTableBodyScopeMarker();
+        ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName()));
+        processFakeEndTag(m_tree.currentStackItem()->localName());
+        processEndTag(token);
+        return;
+    }
+    if (token->name() == bodyTag
+        || isCaptionColOrColgroupTag(token->name())
+        || token->name() == htmlTag
+        || isTableCellContextTag(token->name())
+        || token->name() == trTag) {
+        parseError(token);
+        return;
+    }
+    processEndTagForInTable(token);
+}
+
+void HTMLTreeBuilder::processEndTagForInRow(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::EndTag);
+    if (token->name() == trTag) {
+        processTrEndTagForInRow();
+        return;
+    }
+    if (token->name() == tableTag) {
+        if (!processTrEndTagForInRow()) {
+            ASSERT(isParsingFragmentOrTemplateContents());
+            return;
+        }
+        ASSERT(insertionMode() == InTableBodyMode);
+        processEndTag(token);
+        return;
+    }
+    if (isTableBodyContextTag(token->name())) {
+        if (!m_tree.openElements()->inTableScope(token->name())) {
+            parseError(token);
+            return;
+        }
+        processFakeEndTag(trTag);
+        ASSERT(insertionMode() == InTableBodyMode);
+        processEndTag(token);
+        return;
+    }
+    if (token->name() == bodyTag
+        || isCaptionColOrColgroupTag(token->name())
+        || token->name() == htmlTag
+        || isTableCellContextTag(token->name())) {
+        parseError(token);
+        return;
+    }
+    processEndTagForInTable(token);
+}
+
+void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::EndTag);
+    if (isTableCellContextTag(token->name())) {
+        if (!m_tree.openElements()->inTableScope(token->name())) {
+            parseError(token);
+            return;
+        }
+        m_tree.generateImpliedEndTags();
+        if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+            parseError(token);
+        m_tree.openElements()->popUntilPopped(token->name());
+        m_tree.activeFormattingElements()->clearToLastMarker();
+        setInsertionMode(InRowMode);
+        return;
+    }
+    if (token->name() == bodyTag
+        || isCaptionColOrColgroupTag(token->name())
+        || token->name() == htmlTag) {
+        parseError(token);
+        return;
+    }
+    if (token->name() == tableTag
+        || token->name() == trTag
+        || isTableBodyContextTag(token->name())) {
+        if (!m_tree.openElements()->inTableScope(token->name())) {
+            ASSERT(isTableBodyContextTag(token->name()) || m_tree.openElements()->inTableScope(templateTag) || isParsingFragment());
+            parseError(token);
+            return;
+        }
+        closeTheCell();
+        processEndTag(token);
+        return;
+    }
+    processEndTagForInBody(token);
+}
+
+void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::EndTag);
+    if (token->name() == bodyTag) {
+        processBodyEndTagForInBody(token);
+        return;
+    }
+    if (token->name() == htmlTag) {
+        AtomicHTMLToken endBody(HTMLToken::EndTag, bodyTag.localName());
+        if (processBodyEndTagForInBody(&endBody))
+            processEndTag(token);
+        return;
+    }
+    if (token->name() == addressTag
+        || token->name() == articleTag
+        || token->name() == asideTag
+        || token->name() == blockquoteTag
+        || token->name() == buttonTag
+        || token->name() == centerTag
+        || token->name() == detailsTag
+        || token->name() == dirTag
+        || token->name() == divTag
+        || token->name() == dlTag
+        || token->name() == fieldsetTag
+        || token->name() == figcaptionTag
+        || token->name() == figureTag
+        || token->name() == footerTag
+        || token->name() == headerTag
+        || token->name() == hgroupTag
+        || token->name() == listingTag
+        || token->name() == mainTag
+        || token->name() == menuTag
+        || token->name() == navTag
+        || token->name() == olTag
+        || token->name() == preTag
+        || token->name() == sectionTag
+        || token->name() == summaryTag
+        || token->name() == ulTag) {
+        if (!m_tree.openElements()->inScope(token->name())) {
+            parseError(token);
+            return;
+        }
+        m_tree.generateImpliedEndTags();
+        if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+            parseError(token);
+        m_tree.openElements()->popUntilPopped(token->name());
+        return;
+    }
+    if (token->name() == formTag) {
+        RefPtr<Element> node = m_tree.takeForm();
+        if (!node || !m_tree.openElements()->inScope(node.get())) {
+            parseError(token);
+            return;
+        }
+        m_tree.generateImpliedEndTags();
+        if (m_tree.currentElement() != node.get())
+            parseError(token);
+        m_tree.openElements()->remove(node.get());
+    }
+    if (token->name() == pTag) {
+        if (!m_tree.openElements()->inButtonScope(token->name())) {
+            parseError(token);
+            processFakeStartTag(pTag);
+            ASSERT(m_tree.openElements()->inScope(token->name()));
+            processEndTag(token);
+            return;
+        }
+        m_tree.generateImpliedEndTagsWithExclusion(token->name());
+        if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+            parseError(token);
+        m_tree.openElements()->popUntilPopped(token->name());
+        return;
+    }
+    if (token->name() == liTag) {
+        if (!m_tree.openElements()->inListItemScope(token->name())) {
+            parseError(token);
+            return;
+        }
+        m_tree.generateImpliedEndTagsWithExclusion(token->name());
+        if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+            parseError(token);
+        m_tree.openElements()->popUntilPopped(token->name());
+        return;
+    }
+    if (token->name() == ddTag
+        || token->name() == dtTag) {
+        if (!m_tree.openElements()->inScope(token->name())) {
+            parseError(token);
+            return;
+        }
+        m_tree.generateImpliedEndTagsWithExclusion(token->name());
+        if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+            parseError(token);
+        m_tree.openElements()->popUntilPopped(token->name());
+        return;
+    }
+    if (isNumberedHeaderTag(token->name())) {
+        if (!m_tree.openElements()->hasNumberedHeaderElementInScope()) {
+            parseError(token);
+            return;
+        }
+        m_tree.generateImpliedEndTags();
+        if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+            parseError(token);
+        m_tree.openElements()->popUntilNumberedHeaderElementPopped();
+        return;
+    }
+    if (isFormattingTag(token->name())) {
+        callTheAdoptionAgency(token);
+        return;
+    }
+    if (token->name() == appletTag
+        || token->name() == marqueeTag
+        || token->name() == objectTag) {
+        if (!m_tree.openElements()->inScope(token->name())) {
+            parseError(token);
+            return;
+        }
+        m_tree.generateImpliedEndTags();
+        if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+            parseError(token);
+        m_tree.openElements()->popUntilPopped(token->name());
+        m_tree.activeFormattingElements()->clearToLastMarker();
+        return;
+    }
+    if (token->name() == brTag) {
+        parseError(token);
+        processFakeStartTag(brTag);
+        return;
+    }
+    if (token->name() == templateTag) {
+        processTemplateEndTag(token);
+        return;
+    }
+    processAnyOtherEndTagForInBody(token);
+}
+
+bool HTMLTreeBuilder::processCaptionEndTagForInCaption()
+{
+    if (!m_tree.openElements()->inTableScope(captionTag.localName())) {
+        ASSERT(isParsingFragment());
+        // FIXME: parse error
+        return false;
+    }
+    m_tree.generateImpliedEndTags();
+    // FIXME: parse error if (!m_tree.currentStackItem()->hasTagName(captionTag))
+    m_tree.openElements()->popUntilPopped(captionTag.localName());
+    m_tree.activeFormattingElements()->clearToLastMarker();
+    setInsertionMode(InTableMode);
+    return true;
+}
+
+bool HTMLTreeBuilder::processTrEndTagForInRow()
+{
+    if (!m_tree.openElements()->inTableScope(trTag)) {
+        ASSERT(isParsingFragmentOrTemplateContents());
+        // FIXME: parse error
+        return false;
+    }
+    m_tree.openElements()->popUntilTableRowScopeMarker();
+    ASSERT(m_tree.currentStackItem()->hasTagName(trTag));
+    m_tree.openElements()->pop();
+    setInsertionMode(InTableBodyMode);
+    return true;
+}
+
+bool HTMLTreeBuilder::processTableEndTagForInTable()
+{
+    if (!m_tree.openElements()->inTableScope(tableTag)) {
+        ASSERT(isParsingFragmentOrTemplateContents());
+        // FIXME: parse error.
+        return false;
+    }
+    m_tree.openElements()->popUntilPopped(tableTag.localName());
+    resetInsertionModeAppropriately();
+    return true;
+}
+
+void HTMLTreeBuilder::processEndTagForInTable(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::EndTag);
+    if (token->name() == tableTag) {
+        processTableEndTagForInTable();
+        return;
+    }
+    if (token->name() == bodyTag
+        || isCaptionColOrColgroupTag(token->name())
+        || token->name() == htmlTag
+        || isTableBodyContextTag(token->name())
+        || isTableCellContextTag(token->name())
+        || token->name() == trTag) {
+        parseError(token);
+        return;
+    }
+    parseError(token);
+    // Is this redirection necessary here?
+    HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
+    processEndTagForInBody(token);
+}
+
+void HTMLTreeBuilder::processEndTag(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::EndTag);
+    switch (insertionMode()) {
+    case InitialMode:
+        ASSERT(insertionMode() == InitialMode);
+        defaultForInitial();
+        // Fall through.
+    case BeforeHTMLMode:
+        ASSERT(insertionMode() == BeforeHTMLMode);
+        if (token->name() != headTag && token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) {
+            parseError(token);
+            return;
+        }
+        defaultForBeforeHTML();
+        // Fall through.
+    case BeforeHeadMode:
+        ASSERT(insertionMode() == BeforeHeadMode);
+        if (token->name() != headTag && token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) {
+            parseError(token);
+            return;
+        }
+        defaultForBeforeHead();
+        // Fall through.
+    case InHeadMode:
+        ASSERT(insertionMode() == InHeadMode);
+        // FIXME: This case should be broken out into processEndTagForInHead,
+        // because other end tag cases now refer to it ("process the token for using the rules of the "in head" insertion mode").
+        // but because the logic falls through to AfterHeadMode, that gets a little messy.
+        if (token->name() == templateTag) {
+            processTemplateEndTag(token);
+            return;
+        }
+        if (token->name() == headTag) {
+            m_tree.openElements()->popHTMLHeadElement();
+            setInsertionMode(AfterHeadMode);
+            return;
+        }
+        if (token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) {
+            parseError(token);
+            return;
+        }
+        defaultForInHead();
+        // Fall through.
+    case AfterHeadMode:
+        ASSERT(insertionMode() == AfterHeadMode);
+        if (token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) {
+            parseError(token);
+            return;
+        }
+        defaultForAfterHead();
+        // Fall through
+    case InBodyMode:
+        ASSERT(insertionMode() == InBodyMode);
+        processEndTagForInBody(token);
+        break;
+    case InTableMode:
+        ASSERT(insertionMode() == InTableMode);
+        processEndTagForInTable(token);
+        break;
+    case InCaptionMode:
+        ASSERT(insertionMode() == InCaptionMode);
+        if (token->name() == captionTag) {
+            processCaptionEndTagForInCaption();
+            return;
+        }
+        if (token->name() == tableTag) {
+            parseError(token);
+            if (!processCaptionEndTagForInCaption()) {
+                ASSERT(isParsingFragment());
+                return;
+            }
+            processEndTag(token);
+            return;
+        }
+        if (token->name() == bodyTag
+            || token->name() == colTag
+            || token->name() == colgroupTag
+            || token->name() == htmlTag
+            || isTableBodyContextTag(token->name())
+            || isTableCellContextTag(token->name())
+            || token->name() == trTag) {
+            parseError(token);
+            return;
+        }
+        processEndTagForInBody(token);
+        break;
+    case InColumnGroupMode:
+        ASSERT(insertionMode() == InColumnGroupMode);
+        if (token->name() == colgroupTag) {
+            processColgroupEndTagForInColumnGroup();
+            return;
+        }
+        if (token->name() == colTag) {
+            parseError(token);
+            return;
+        }
+        if (token->name() == templateTag) {
+            processTemplateEndTag(token);
+            return;
+        }
+        if (!processColgroupEndTagForInColumnGroup()) {
+            ASSERT(isParsingFragmentOrTemplateContents());
+            return;
+        }
+        processEndTag(token);
+        break;
+    case InRowMode:
+        ASSERT(insertionMode() == InRowMode);
+        processEndTagForInRow(token);
+        break;
+    case InCellMode:
+        ASSERT(insertionMode() == InCellMode);
+        processEndTagForInCell(token);
+        break;
+    case InTableBodyMode:
+        ASSERT(insertionMode() == InTableBodyMode);
+        processEndTagForInTableBody(token);
+        break;
+    case AfterBodyMode:
+        ASSERT(insertionMode() == AfterBodyMode);
+        if (token->name() == htmlTag) {
+            if (isParsingFragment()) {
+                parseError(token);
+                return;
+            }
+            setInsertionMode(AfterAfterBodyMode);
+            return;
+        }
+        // Fall through.
+    case AfterAfterBodyMode:
+        ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
+        parseError(token);
+        setInsertionMode(InBodyMode);
+        processEndTag(token);
+        break;
+    case InHeadNoscriptMode:
+        ASSERT(insertionMode() == InHeadNoscriptMode);
+        if (token->name() == noscriptTag) {
+            ASSERT(m_tree.currentStackItem()->hasTagName(noscriptTag));
+            m_tree.openElements()->pop();
+            ASSERT(m_tree.currentStackItem()->hasTagName(headTag));
+            setInsertionMode(InHeadMode);
+            return;
+        }
+        if (token->name() != brTag) {
+            parseError(token);
+            return;
+        }
+        defaultForInHeadNoscript();
+        processToken(token);
+        break;
+    case TextMode:
+        if (token->name() == scriptTag) {
+            // Pause ourselves so that parsing stops until the script can be processed by the caller.
+            ASSERT(m_tree.currentStackItem()->hasTagName(scriptTag));
+            if (scriptingContentIsAllowed(m_tree.parserContentPolicy()))
+                m_scriptToProcess = m_tree.currentElement();
+            m_tree.openElements()->pop();
+            setInsertionMode(m_originalInsertionMode);
+
+            if (m_parser->tokenizer()) {
+                // We must set the tokenizer's state to
+                // DataState explicitly if the tokenizer didn't have a chance to.
+                ASSERT(m_parser->tokenizer()->state() == HTMLTokenizer::DataState || m_options.useThreading);
+                m_parser->tokenizer()->setState(HTMLTokenizer::DataState);
+            }
+            return;
+        }
+        m_tree.openElements()->pop();
+        setInsertionMode(m_originalInsertionMode);
+        break;
+    case InFramesetMode:
+        ASSERT(insertionMode() == InFramesetMode);
+        if (token->name() == framesetTag) {
+            bool ignoreFramesetForFragmentParsing  = m_tree.currentIsRootNode();
+            ignoreFramesetForFragmentParsing = ignoreFramesetForFragmentParsing || m_tree.openElements()->hasTemplateInHTMLScope();
+            if (ignoreFramesetForFragmentParsing) {
+                ASSERT(isParsingFragmentOrTemplateContents());
+                parseError(token);
+                return;
+            }
+            m_tree.openElements()->pop();
+            if (!isParsingFragment() && !m_tree.currentStackItem()->hasTagName(framesetTag))
+                setInsertionMode(AfterFramesetMode);
+            return;
+        }
+        if (token->name() == templateTag) {
+            processTemplateEndTag(token);
+            return;
+        }
+        break;
+    case AfterFramesetMode:
+        ASSERT(insertionMode() == AfterFramesetMode);
+        if (token->name() == htmlTag) {
+            setInsertionMode(AfterAfterFramesetMode);
+            return;
+        }
+        // Fall through.
+    case AfterAfterFramesetMode:
+        ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
+        parseError(token);
+        break;
+    case InSelectInTableMode:
+        ASSERT(insertionMode() == InSelectInTableMode);
+        if (token->name() == captionTag
+            || token->name() == tableTag
+            || isTableBodyContextTag(token->name())
+            || token->name() == trTag
+            || isTableCellContextTag(token->name())) {
+            parseError(token);
+            if (m_tree.openElements()->inTableScope(token->name())) {
+                AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
+                processEndTag(&endSelect);
+                processEndTag(token);
+            }
+            return;
+        }
+        // Fall through.
+    case InSelectMode:
+        ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);
+        if (token->name() == optgroupTag) {
+            if (m_tree.currentStackItem()->hasTagName(optionTag) && m_tree.oneBelowTop() && m_tree.oneBelowTop()->hasTagName(optgroupTag))
+                processFakeEndTag(optionTag);
+            if (m_tree.currentStackItem()->hasTagName(optgroupTag)) {
+                m_tree.openElements()->pop();
+                return;
+            }
+            parseError(token);
+            return;
+        }
+        if (token->name() == optionTag) {
+            if (m_tree.currentStackItem()->hasTagName(optionTag)) {
+                m_tree.openElements()->pop();
+                return;
+            }
+            parseError(token);
+            return;
+        }
+        if (token->name() == selectTag) {
+            if (!m_tree.openElements()->inSelectScope(token->name())) {
+                ASSERT(isParsingFragment());
+                parseError(token);
+                return;
+            }
+            m_tree.openElements()->popUntilPopped(selectTag.localName());
+            resetInsertionModeAppropriately();
+            return;
+        }
+        if (token->name() == templateTag) {
+            processTemplateEndTag(token);
+            return;
+        }
+        break;
+    case InTableTextMode:
+        defaultForInTableText();
+        processEndTag(token);
+        break;
+    case TemplateContentsMode:
+        if (token->name() == templateTag) {
+            processTemplateEndTag(token);
+            return;
+        }
+        break;
+    }
+}
+
+void HTMLTreeBuilder::processComment(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::Comment);
+    if (m_insertionMode == InitialMode
+        || m_insertionMode == BeforeHTMLMode
+        || m_insertionMode == AfterAfterBodyMode
+        || m_insertionMode == AfterAfterFramesetMode) {
+        m_tree.insertCommentOnDocument(token);
+        return;
+    }
+    if (m_insertionMode == AfterBodyMode) {
+        m_tree.insertCommentOnHTMLHtmlElement(token);
+        return;
+    }
+    if (m_insertionMode == InTableTextMode) {
+        defaultForInTableText();
+        processComment(token);
+        return;
+    }
+    m_tree.insertComment(token);
+}
+
+void HTMLTreeBuilder::processCharacter(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::Character);
+    ExternalCharacterTokenBuffer buffer(token);
+    processCharacterBuffer(buffer);
+}
+
+void HTMLTreeBuilder::processCharacterBuffer(ExternalCharacterTokenBuffer& buffer)
+{
+ReprocessBuffer:
+    // 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
+    // "authoring convenience" so folks can write:
+    //
+    // <pre>
+    // lorem ipsum
+    // lorem ipsum
+    // </pre>
+    //
+    // without getting an extra newline at the start of their <pre> element.
+    if (m_shouldSkipLeadingNewline) {
+        m_shouldSkipLeadingNewline = false;
+        buffer.skipAtMostOneLeadingNewline();
+        if (buffer.isEmpty())
+            return;
+    }
+
+    switch (insertionMode()) {
+    case InitialMode: {
+        ASSERT(insertionMode() == InitialMode);
+        buffer.skipLeadingWhitespace();
+        if (buffer.isEmpty())
+            return;
+        defaultForInitial();
+        // Fall through.
+    }
+    case BeforeHTMLMode: {
+        ASSERT(insertionMode() == BeforeHTMLMode);
+        buffer.skipLeadingWhitespace();
+        if (buffer.isEmpty())
+            return;
+        defaultForBeforeHTML();
+        // Fall through.
+    }
+    case BeforeHeadMode: {
+        ASSERT(insertionMode() == BeforeHeadMode);
+        buffer.skipLeadingWhitespace();
+        if (buffer.isEmpty())
+            return;
+        defaultForBeforeHead();
+        // Fall through.
+    }
+    case InHeadMode: {
+        ASSERT(insertionMode() == InHeadMode);
+        String leadingWhitespace = buffer.takeLeadingWhitespace();
+        if (!leadingWhitespace.isEmpty())
+            m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+        if (buffer.isEmpty())
+            return;
+        defaultForInHead();
+        // Fall through.
+    }
+    case AfterHeadMode: {
+        ASSERT(insertionMode() == AfterHeadMode);
+        String leadingWhitespace = buffer.takeLeadingWhitespace();
+        if (!leadingWhitespace.isEmpty())
+            m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+        if (buffer.isEmpty())
+            return;
+        defaultForAfterHead();
+        // Fall through.
+    }
+    case InBodyMode:
+    case InCaptionMode:
+    case TemplateContentsMode:
+    case InCellMode: {
+        ASSERT(insertionMode() == InBodyMode || insertionMode() == InCaptionMode || insertionMode() == InCellMode || insertionMode() == TemplateContentsMode);
+        processCharacterBufferForInBody(buffer);
+        break;
+    }
+    case InTableMode:
+    case InTableBodyMode:
+    case InRowMode: {
+        ASSERT(insertionMode() == InTableMode || insertionMode() == InTableBodyMode || insertionMode() == InRowMode);
+        ASSERT(m_pendingTableCharacters.isEmpty());
+        if (m_tree.currentStackItem()->isElementNode()
+            && (m_tree.currentStackItem()->hasTagName(HTMLNames::tableTag)
+                || m_tree.currentStackItem()->hasTagName(HTMLNames::tbodyTag)
+                || m_tree.currentStackItem()->hasTagName(HTMLNames::tfootTag)
+                || m_tree.currentStackItem()->hasTagName(HTMLNames::theadTag)
+                || m_tree.currentStackItem()->hasTagName(HTMLNames::trTag))) {
+            m_originalInsertionMode = m_insertionMode;
+            setInsertionMode(InTableTextMode);
+            // Note that we fall through to the InTableTextMode case below.
+        } else {
+            HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
+            processCharacterBufferForInBody(buffer);
+            break;
+        }
+        // Fall through.
+    }
+    case InTableTextMode: {
+        buffer.giveRemainingTo(m_pendingTableCharacters);
+        break;
+    }
+    case InColumnGroupMode: {
+        ASSERT(insertionMode() == InColumnGroupMode);
+        String leadingWhitespace = buffer.takeLeadingWhitespace();
+        if (!leadingWhitespace.isEmpty())
+            m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+        if (buffer.isEmpty())
+            return;
+        if (!processColgroupEndTagForInColumnGroup()) {
+            ASSERT(isParsingFragmentOrTemplateContents());
+            // The spec tells us to drop these characters on the floor.
+            buffer.skipLeadingNonWhitespace();
+            if (buffer.isEmpty())
+                return;
+        }
+        goto ReprocessBuffer;
+    }
+    case AfterBodyMode:
+    case AfterAfterBodyMode: {
+        ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
+        // FIXME: parse error
+        setInsertionMode(InBodyMode);
+        goto ReprocessBuffer;
+        break;
+    }
+    case TextMode: {
+        ASSERT(insertionMode() == TextMode);
+        m_tree.insertTextNode(buffer.takeRemaining());
+        break;
+    }
+    case InHeadNoscriptMode: {
+        ASSERT(insertionMode() == InHeadNoscriptMode);
+        String leadingWhitespace = buffer.takeLeadingWhitespace();
+        if (!leadingWhitespace.isEmpty())
+            m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+        if (buffer.isEmpty())
+            return;
+        defaultForInHeadNoscript();
+        goto ReprocessBuffer;
+        break;
+    }
+    case InFramesetMode:
+    case AfterFramesetMode: {
+        ASSERT(insertionMode() == InFramesetMode || insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
+        String leadingWhitespace = buffer.takeRemainingWhitespace();
+        if (!leadingWhitespace.isEmpty())
+            m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+        // FIXME: We should generate a parse error if we skipped over any
+        // non-whitespace characters.
+        break;
+    }
+    case InSelectInTableMode:
+    case InSelectMode: {
+        ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);
+        m_tree.insertTextNode(buffer.takeRemaining());
+        break;
+    }
+    case AfterAfterFramesetMode: {
+        String leadingWhitespace = buffer.takeRemainingWhitespace();
+        if (!leadingWhitespace.isEmpty()) {
+            m_tree.reconstructTheActiveFormattingElements();
+            m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
+        }
+        // FIXME: We should generate a parse error if we skipped over any
+        // non-whitespace characters.
+        break;
+    }
+    }
+}
+
+void HTMLTreeBuilder::processCharacterBufferForInBody(ExternalCharacterTokenBuffer& buffer)
+{
+    m_tree.reconstructTheActiveFormattingElements();
+    String characters = buffer.takeRemaining();
+    m_tree.insertTextNode(characters);
+    if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters))
+        m_framesetOk = false;
+}
+
+void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::EndOfFile);
+    switch (insertionMode()) {
+    case InitialMode:
+        ASSERT(insertionMode() == InitialMode);
+        defaultForInitial();
+        // Fall through.
+    case BeforeHTMLMode:
+        ASSERT(insertionMode() == BeforeHTMLMode);
+        defaultForBeforeHTML();
+        // Fall through.
+    case BeforeHeadMode:
+        ASSERT(insertionMode() == BeforeHeadMode);
+        defaultForBeforeHead();
+        // Fall through.
+    case InHeadMode:
+        ASSERT(insertionMode() == InHeadMode);
+        defaultForInHead();
+        // Fall through.
+    case AfterHeadMode:
+        ASSERT(insertionMode() == AfterHeadMode);
+        defaultForAfterHead();
+        // Fall through
+    case InBodyMode:
+    case InCellMode:
+    case InCaptionMode:
+    case InRowMode:
+        ASSERT(insertionMode() == InBodyMode || insertionMode() == InCellMode || insertionMode() == InCaptionMode || insertionMode() == InRowMode || insertionMode() == TemplateContentsMode);
+        notImplemented(); // Emit parse error based on what elements are still open.
+        if (!m_templateInsertionModes.isEmpty() && processEndOfFileForInTemplateContents(token))
+            return;
+        break;
+    case AfterBodyMode:
+    case AfterAfterBodyMode:
+        ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
+        break;
+    case InHeadNoscriptMode:
+        ASSERT(insertionMode() == InHeadNoscriptMode);
+        defaultForInHeadNoscript();
+        processEndOfFile(token);
+        return;
+    case AfterFramesetMode:
+    case AfterAfterFramesetMode:
+        ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
+        break;
+    case InColumnGroupMode:
+        if (m_tree.currentIsRootNode()) {
+            ASSERT(isParsingFragment());
+            return; // FIXME: Should we break here instead of returning?
+        }
+        ASSERT(m_tree.currentNode()->hasTagName(colgroupTag) || m_tree.currentNode()->hasTagName(templateTag));
+        processColgroupEndTagForInColumnGroup();
+        // Fall through
+    case InFramesetMode:
+    case InTableMode:
+    case InTableBodyMode:
+    case InSelectInTableMode:
+    case InSelectMode:
+        ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode || insertionMode() == InTableMode || insertionMode() == InFramesetMode || insertionMode() == InTableBodyMode || insertionMode() == InColumnGroupMode);
+        if (m_tree.currentNode() != m_tree.openElements()->rootNode())
+            parseError(token);
+        if (!m_templateInsertionModes.isEmpty() && processEndOfFileForInTemplateContents(token))
+            return;
+        break;
+    case InTableTextMode:
+        defaultForInTableText();
+        processEndOfFile(token);
+        return;
+    case TextMode:
+        parseError(token);
+        if (m_tree.currentStackItem()->hasTagName(scriptTag))
+            notImplemented(); // mark the script element as "already started".
+        m_tree.openElements()->pop();
+        ASSERT(m_originalInsertionMode != TextMode);
+        setInsertionMode(m_originalInsertionMode);
+        processEndOfFile(token);
+        return;
+    case TemplateContentsMode:
+        if (processEndOfFileForInTemplateContents(token))
+            return;
+        break;
+    }
+    ASSERT(m_tree.currentNode());
+    m_tree.openElements()->popAll();
+}
+
+void HTMLTreeBuilder::defaultForInitial()
+{
+    notImplemented();
+    m_tree.setDefaultCompatibilityMode();
+    // FIXME: parse error
+    setInsertionMode(BeforeHTMLMode);
+}
+
+void HTMLTreeBuilder::defaultForBeforeHTML()
+{
+    AtomicHTMLToken startHTML(HTMLToken::StartTag, htmlTag.localName());
+    m_tree.insertHTMLHtmlStartTagBeforeHTML(&startHTML);
+    setInsertionMode(BeforeHeadMode);
+}
+
+void HTMLTreeBuilder::defaultForBeforeHead()
+{
+    AtomicHTMLToken startHead(HTMLToken::StartTag, headTag.localName());
+    processStartTag(&startHead);
+}
+
+void HTMLTreeBuilder::defaultForInHead()
+{
+    AtomicHTMLToken endHead(HTMLToken::EndTag, headTag.localName());
+    processEndTag(&endHead);
+}
+
+void HTMLTreeBuilder::defaultForInHeadNoscript()
+{
+    AtomicHTMLToken endNoscript(HTMLToken::EndTag, noscriptTag.localName());
+    processEndTag(&endNoscript);
+}
+
+void HTMLTreeBuilder::defaultForAfterHead()
+{
+    AtomicHTMLToken startBody(HTMLToken::StartTag, bodyTag.localName());
+    processStartTag(&startBody);
+    m_framesetOk = true;
+}
+
+void HTMLTreeBuilder::defaultForInTableText()
+{
+    String characters = m_pendingTableCharacters.toString();
+    m_pendingTableCharacters.clear();
+    if (!isAllWhitespace(characters)) {
+        // FIXME: parse error
+        HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
+        m_tree.reconstructTheActiveFormattingElements();
+        m_tree.insertTextNode(characters, NotAllWhitespace);
+        m_framesetOk = false;
+        setInsertionMode(m_originalInsertionMode);
+        return;
+    }
+    m_tree.insertTextNode(characters);
+    setInsertionMode(m_originalInsertionMode);
+}
+
+bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    if (token->name() == htmlTag) {
+        processHtmlStartTagForInBody(token);
+        return true;
+    }
+    if (token->name() == baseTag
+        || token->name() == basefontTag
+        || token->name() == bgsoundTag
+        || token->name() == commandTag
+        || token->name() == linkTag
+        || token->name() == metaTag) {
+        m_tree.insertSelfClosingHTMLElement(token);
+        // Note: The custom processing for the <meta> tag is done in HTMLMetaElement::process().
+        return true;
+    }
+    if (token->name() == titleTag) {
+        processGenericRCDATAStartTag(token);
+        return true;
+    }
+    if (token->name() == noscriptTag) {
+        if (m_options.scriptEnabled) {
+            processGenericRawTextStartTag(token);
+            return true;
+        }
+        m_tree.insertHTMLElement(token);
+        setInsertionMode(InHeadNoscriptMode);
+        return true;
+    }
+    if (token->name() == noframesTag || token->name() == styleTag) {
+        processGenericRawTextStartTag(token);
+        return true;
+    }
+    if (token->name() == scriptTag) {
+        processScriptStartTag(token);
+        return true;
+    }
+    if (token->name() == templateTag) {
+        processTemplateStartTag(token);
+        return true;
+    }
+    if (token->name() == headTag) {
+        parseError(token);
+        return true;
+    }
+    return false;
+}
+
+void HTMLTreeBuilder::processGenericRCDATAStartTag(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    m_tree.insertHTMLElement(token);
+    if (m_parser->tokenizer())
+        m_parser->tokenizer()->setState(HTMLTokenizer::RCDATAState);
+    m_originalInsertionMode = m_insertionMode;
+    setInsertionMode(TextMode);
+}
+
+void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    m_tree.insertHTMLElement(token);
+    if (m_parser->tokenizer())
+        m_parser->tokenizer()->setState(HTMLTokenizer::RAWTEXTState);
+    m_originalInsertionMode = m_insertionMode;
+    setInsertionMode(TextMode);
+}
+
+void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken* token)
+{
+    ASSERT(token->type() == HTMLToken::StartTag);
+    m_tree.insertScriptElement(token);
+    if (m_parser->tokenizer())
+        m_parser->tokenizer()->setState(HTMLTokenizer::ScriptDataState);
+    m_originalInsertionMode = m_insertionMode;
+
+    TextPosition position = m_parser->textPosition();
+
+    m_scriptToProcessStartPosition = position;
+
+    setInsertionMode(TextMode);
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#tree-construction
+bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken* token)
+{
+    if (m_tree.isEmpty())
+        return false;
+    HTMLStackItem* item = m_tree.currentStackItem();
+    if (item->isInHTMLNamespace())
+        return false;
+    if (HTMLElementStack::isMathMLTextIntegrationPoint(item)) {
+        if (token->type() == HTMLToken::StartTag
+            && token->name() != MathMLNames::mglyphTag
+            && token->name() != MathMLNames::malignmarkTag)
+            return false;
+        if (token->type() == HTMLToken::Character)
+            return false;
+    }
+    if (item->hasTagName(MathMLNames::annotation_xmlTag)
+        && token->type() == HTMLToken::StartTag
+        && token->name() == SVGNames::svgTag)
+        return false;
+    if (HTMLElementStack::isHTMLIntegrationPoint(item)) {
+        if (token->type() == HTMLToken::StartTag)
+            return false;
+        if (token->type() == HTMLToken::Character)
+            return false;
+    }
+    if (token->type() == HTMLToken::EndOfFile)
+        return false;
+    return true;
+}
+
+void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token)
+{
+    switch (token->type()) {
+    case HTMLToken::Uninitialized:
+        ASSERT_NOT_REACHED();
+        break;
+    case HTMLToken::DOCTYPE:
+        parseError(token);
+        break;
+    case HTMLToken::StartTag: {
+        if (token->name() == bTag
+            || token->name() == bigTag
+            || token->name() == blockquoteTag
+            || token->name() == bodyTag
+            || token->name() == brTag
+            || token->name() == centerTag
+            || token->name() == codeTag
+            || token->name() == ddTag
+            || token->name() == divTag
+            || token->name() == dlTag
+            || token->name() == dtTag
+            || token->name() == emTag
+            || token->name() == embedTag
+            || isNumberedHeaderTag(token->name())
+            || token->name() == headTag
+            || token->name() == hrTag
+            || token->name() == iTag
+            || token->name() == imgTag
+            || token->name() == liTag
+            || token->name() == listingTag
+            || token->name() == menuTag
+            || token->name() == metaTag
+            || token->name() == nobrTag
+            || token->name() == olTag
+            || token->name() == pTag
+            || token->name() == preTag
+            || token->name() == rubyTag
+            || token->name() == sTag
+            || token->name() == smallTag
+            || token->name() == spanTag
+            || token->name() == strongTag
+            || token->name() == strikeTag
+            || token->name() == subTag
+            || token->name() == supTag
+            || token->name() == tableTag
+            || token->name() == ttTag
+            || token->name() == uTag
+            || token->name() == ulTag
+            || token->name() == varTag
+            || (token->name() == fontTag && (token->getAttributeItem(colorAttr) || token->getAttributeItem(faceAttr) || token->getAttributeItem(sizeAttr)))) {
+            parseError(token);
+            m_tree.openElements()->popUntilForeignContentScopeMarker();
+            processStartTag(token);
+            return;
+        }
+        const AtomicString& currentNamespace = m_tree.currentStackItem()->namespaceURI();
+        if (currentNamespace == MathMLNames::mathmlNamespaceURI)
+            adjustMathMLAttributes(token);
+        if (currentNamespace == SVGNames::svgNamespaceURI) {
+            adjustSVGTagNameCase(token);
+            adjustSVGAttributes(token);
+        }
+        adjustForeignAttributes(token);
+        m_tree.insertForeignElement(token, currentNamespace);
+        break;
+    }
+    case HTMLToken::EndTag: {
+        if (m_tree.currentStackItem()->namespaceURI() == SVGNames::svgNamespaceURI)
+            adjustSVGTagNameCase(token);
+
+        if (token->name() == SVGNames::scriptTag && m_tree.currentStackItem()->hasTagName(SVGNames::scriptTag)) {
+            if (scriptingContentIsAllowed(m_tree.parserContentPolicy()))
+                m_scriptToProcess = m_tree.currentElement();
+            m_tree.openElements()->pop();
+            return;
+        }
+        if (!m_tree.currentStackItem()->isInHTMLNamespace()) {
+            // FIXME: This code just wants an Element* iterator, instead of an ElementRecord*
+            HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
+            if (!nodeRecord->stackItem()->hasLocalName(token->name()))
+                parseError(token);
+            while (1) {
+                if (nodeRecord->stackItem()->hasLocalName(token->name())) {
+                    m_tree.openElements()->popUntilPopped(nodeRecord->element());
+                    return;
+                }
+                nodeRecord = nodeRecord->next();
+
+                if (nodeRecord->stackItem()->isInHTMLNamespace())
+                    break;
+            }
+        }
+        // Otherwise, process the token according to the rules given in the section corresponding to the current insertion mode in HTML content.
+        processEndTag(token);
+        break;
+    }
+    case HTMLToken::Comment:
+        m_tree.insertComment(token);
+        return;
+    case HTMLToken::Character: {
+        String characters = String(token->characters(), token->charactersLength());
+        m_tree.insertTextNode(characters);
+        if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters))
+            m_framesetOk = false;
+        break;
+    }
+    case HTMLToken::EndOfFile:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+void HTMLTreeBuilder::finished()
+{
+    if (isParsingFragment())
+        return;
+
+    ASSERT(m_templateInsertionModes.isEmpty());
+    ASSERT(m_isAttached);
+    // Warning, this may detach the parser. Do not do anything else after this.
+    m_tree.finishedParsing();
+}
+
+void HTMLTreeBuilder::parseError(AtomicHTMLToken*)
+{
+}
+
+}
diff --git a/Source/core/html/parser/HTMLTreeBuilder.h b/Source/core/html/parser/HTMLTreeBuilder.h
new file mode 100644
index 0000000..61138ac
--- /dev/null
+++ b/Source/core/html/parser/HTMLTreeBuilder.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 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 GOOGLE 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 GOOGLE 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 HTMLTreeBuilder_h
+#define HTMLTreeBuilder_h
+
+#include "core/dom/FragmentScriptingPermission.h"
+#include "core/html/parser/HTMLConstructionSite.h"
+#include "core/html/parser/HTMLElementStack.h"
+#include "core/html/parser/HTMLFormattingElementList.h"
+#include "core/html/parser/HTMLParserOptions.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/TextPosition.h>
+#include <wtf/unicode/Unicode.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class AtomicHTMLToken;
+class Document;
+class DocumentFragment;
+class Element;
+class Frame;
+class HTMLToken;
+class HTMLDocument;
+class Node;
+class HTMLDocumentParser;
+
+class HTMLTreeBuilder {
+    WTF_MAKE_NONCOPYABLE(HTMLTreeBuilder); WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<HTMLTreeBuilder> create(HTMLDocumentParser* parser, HTMLDocument* document, ParserContentPolicy parserContentPolicy, bool reportErrors, const HTMLParserOptions& options)
+    {
+        return adoptPtr(new HTMLTreeBuilder(parser, document, parserContentPolicy, reportErrors, options));
+    }
+    static PassOwnPtr<HTMLTreeBuilder> create(HTMLDocumentParser* parser, DocumentFragment* fragment, Element* contextElement, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options)
+    {
+        return adoptPtr(new HTMLTreeBuilder(parser, fragment, contextElement, parserContentPolicy, options));
+    }
+    ~HTMLTreeBuilder();
+
+    const HTMLElementStack* openElements() const { return m_tree.openElements(); }
+
+    bool isParsingFragment() const { return !!m_fragmentContext.fragment(); }
+    bool isParsingTemplateContents() const { return m_tree.openElements()->hasTemplateInHTMLScope(); }
+    bool isParsingFragmentOrTemplateContents() const { return isParsingFragment() || isParsingTemplateContents(); }
+
+    void detach();
+
+    void constructTree(AtomicHTMLToken*);
+
+    bool hasParserBlockingScript() const { return !!m_scriptToProcess; }
+    // Must be called to take the parser-blocking script before calling the parser again.
+    PassRefPtr<Element> takeScriptToProcess(TextPosition& scriptStartPosition);
+
+    // Done, close any open tags, etc.
+    void finished();
+
+    void setShouldSkipLeadingNewline(bool shouldSkip) { m_shouldSkipLeadingNewline = shouldSkip; }
+
+private:
+    class ExternalCharacterTokenBuffer;
+    // Represents HTML5 "insertion mode"
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#insertion-mode
+    enum InsertionMode {
+        InitialMode,
+        BeforeHTMLMode,
+        BeforeHeadMode,
+        InHeadMode,
+        InHeadNoscriptMode,
+        AfterHeadMode,
+        TemplateContentsMode,
+        InBodyMode,
+        TextMode,
+        InTableMode,
+        InTableTextMode,
+        InCaptionMode,
+        InColumnGroupMode,
+        InTableBodyMode,
+        InRowMode,
+        InCellMode,
+        InSelectMode,
+        InSelectInTableMode,
+        AfterBodyMode,
+        InFramesetMode,
+        AfterFramesetMode,
+        AfterAfterBodyMode,
+        AfterAfterFramesetMode,
+    };
+
+    HTMLTreeBuilder(HTMLDocumentParser*, HTMLDocument*, ParserContentPolicy, bool reportErrors, const HTMLParserOptions&);
+    HTMLTreeBuilder(HTMLDocumentParser*, DocumentFragment*, Element* contextElement, ParserContentPolicy, const HTMLParserOptions&);
+
+    void processToken(AtomicHTMLToken*);
+
+    void processDoctypeToken(AtomicHTMLToken*);
+    void processStartTag(AtomicHTMLToken*);
+    void processEndTag(AtomicHTMLToken*);
+    void processComment(AtomicHTMLToken*);
+    void processCharacter(AtomicHTMLToken*);
+    void processEndOfFile(AtomicHTMLToken*);
+
+    bool processStartTagForInHead(AtomicHTMLToken*);
+    void processStartTagForInBody(AtomicHTMLToken*);
+    void processStartTagForInTable(AtomicHTMLToken*);
+    void processEndTagForInBody(AtomicHTMLToken*);
+    void processEndTagForInTable(AtomicHTMLToken*);
+    void processEndTagForInTableBody(AtomicHTMLToken*);
+    void processEndTagForInRow(AtomicHTMLToken*);
+    void processEndTagForInCell(AtomicHTMLToken*);
+
+    void processIsindexStartTagForInBody(AtomicHTMLToken*);
+    void processHtmlStartTagForInBody(AtomicHTMLToken*);
+    bool processBodyEndTagForInBody(AtomicHTMLToken*);
+    bool processTableEndTagForInTable();
+    bool processCaptionEndTagForInCaption();
+    bool processColgroupEndTagForInColumnGroup();
+    bool processTrEndTagForInRow();
+    // FIXME: This function should be inlined into its one call site or it
+    // needs to assert which tokens it can be called with.
+    void processAnyOtherEndTagForInBody(AtomicHTMLToken*);
+
+    void processCharacterBuffer(ExternalCharacterTokenBuffer&);
+    inline void processCharacterBufferForInBody(ExternalCharacterTokenBuffer&);
+
+    void processFakeStartTag(const QualifiedName&, const Vector<Attribute>& attributes = Vector<Attribute>());
+    void processFakeEndTag(const QualifiedName&);
+    void processFakeEndTag(const AtomicString&);
+    void processFakeCharacters(const String&);
+    void processFakePEndTagIfPInButtonScope();
+
+    void processGenericRCDATAStartTag(AtomicHTMLToken*);
+    void processGenericRawTextStartTag(AtomicHTMLToken*);
+    void processScriptStartTag(AtomicHTMLToken*);
+
+    // Default processing for the different insertion modes.
+    void defaultForInitial();
+    void defaultForBeforeHTML();
+    void defaultForBeforeHead();
+    void defaultForInHead();
+    void defaultForInHeadNoscript();
+    void defaultForAfterHead();
+    void defaultForInTableText();
+
+    inline bool shouldProcessTokenInForeignContent(AtomicHTMLToken*);
+    void processTokenInForeignContent(AtomicHTMLToken*);
+
+    Vector<Attribute> attributesForIsindexInput(AtomicHTMLToken*);
+
+    void callTheAdoptionAgency(AtomicHTMLToken*);
+
+    void closeTheCell();
+
+    template <bool shouldClose(const HTMLStackItem*)>
+    void processCloseWhenNestedTag(AtomicHTMLToken*);
+
+    void parseError(AtomicHTMLToken*);
+
+    InsertionMode insertionMode() const { return m_insertionMode; }
+    void setInsertionMode(InsertionMode mode) { m_insertionMode = mode; }
+
+    void resetInsertionModeAppropriately();
+
+    void processTemplateStartTag(AtomicHTMLToken*);
+    bool processTemplateEndTag(AtomicHTMLToken*);
+    bool processEndOfFileForInTemplateContents(AtomicHTMLToken*);
+
+    class FragmentParsingContext {
+        WTF_MAKE_NONCOPYABLE(FragmentParsingContext);
+    public:
+        FragmentParsingContext();
+        FragmentParsingContext(DocumentFragment*, Element* contextElement);
+        ~FragmentParsingContext();
+
+        DocumentFragment* fragment() const { return m_fragment; }
+        Element* contextElement() const { ASSERT(m_fragment); return m_contextElement; }
+
+    private:
+        DocumentFragment* m_fragment;
+        Element* m_contextElement;
+    };
+
+    bool m_framesetOk;
+#ifndef NDEBUG
+    bool m_isAttached;
+#endif
+    FragmentParsingContext m_fragmentContext;
+    HTMLConstructionSite m_tree;
+
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#insertion-mode
+    InsertionMode m_insertionMode;
+
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#original-insertion-mode
+    InsertionMode m_originalInsertionMode;
+
+    Vector<InsertionMode> m_templateInsertionModes;
+
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#pending-table-character-tokens
+    StringBuilder m_pendingTableCharacters;
+
+    bool m_shouldSkipLeadingNewline;
+
+    // We access parser because HTML5 spec requires that we be able to change the state of the tokenizer
+    // from within parser actions. We also need it to track the current position.
+    HTMLDocumentParser* m_parser;
+
+    RefPtr<Element> m_scriptToProcess; // <script> tag which needs processing before resuming the parser.
+    TextPosition m_scriptToProcessStartPosition; // Starting line number of the script tag needing processing.
+
+    HTMLParserOptions m_options;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp b/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp
new file mode 100644
index 0000000..77d53e9
--- /dev/null
+++ b/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLTreeBuilderSimulator.h"
+
+#include "HTMLNames.h"
+#include "MathMLNames.h"
+#include "SVGNames.h"
+#include "core/html/parser/HTMLDocumentParser.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/html/parser/HTMLTreeBuilder.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static bool tokenExitsForeignContent(const CompactHTMLToken& token)
+{
+    // FIXME: This is copied from HTMLTreeBuilder::processTokenInForeignContent and changed to use threadSafeHTMLNamesMatch.
+    const HTMLIdentifier& tagName = token.data();
+    return threadSafeHTMLNamesMatch(tagName, bTag)
+        || threadSafeHTMLNamesMatch(tagName, bigTag)
+        || threadSafeHTMLNamesMatch(tagName, blockquoteTag)
+        || threadSafeHTMLNamesMatch(tagName, bodyTag)
+        || threadSafeHTMLNamesMatch(tagName, brTag)
+        || threadSafeHTMLNamesMatch(tagName, centerTag)
+        || threadSafeHTMLNamesMatch(tagName, codeTag)
+        || threadSafeHTMLNamesMatch(tagName, ddTag)
+        || threadSafeHTMLNamesMatch(tagName, divTag)
+        || threadSafeHTMLNamesMatch(tagName, dlTag)
+        || threadSafeHTMLNamesMatch(tagName, dtTag)
+        || threadSafeHTMLNamesMatch(tagName, emTag)
+        || threadSafeHTMLNamesMatch(tagName, embedTag)
+        || threadSafeHTMLNamesMatch(tagName, h1Tag)
+        || threadSafeHTMLNamesMatch(tagName, h2Tag)
+        || threadSafeHTMLNamesMatch(tagName, h3Tag)
+        || threadSafeHTMLNamesMatch(tagName, h4Tag)
+        || threadSafeHTMLNamesMatch(tagName, h5Tag)
+        || threadSafeHTMLNamesMatch(tagName, h6Tag)
+        || threadSafeHTMLNamesMatch(tagName, headTag)
+        || threadSafeHTMLNamesMatch(tagName, hrTag)
+        || threadSafeHTMLNamesMatch(tagName, iTag)
+        || threadSafeHTMLNamesMatch(tagName, imgTag)
+        || threadSafeHTMLNamesMatch(tagName, liTag)
+        || threadSafeHTMLNamesMatch(tagName, listingTag)
+        || threadSafeHTMLNamesMatch(tagName, menuTag)
+        || threadSafeHTMLNamesMatch(tagName, metaTag)
+        || threadSafeHTMLNamesMatch(tagName, nobrTag)
+        || threadSafeHTMLNamesMatch(tagName, olTag)
+        || threadSafeHTMLNamesMatch(tagName, pTag)
+        || threadSafeHTMLNamesMatch(tagName, preTag)
+        || threadSafeHTMLNamesMatch(tagName, rubyTag)
+        || threadSafeHTMLNamesMatch(tagName, sTag)
+        || threadSafeHTMLNamesMatch(tagName, smallTag)
+        || threadSafeHTMLNamesMatch(tagName, spanTag)
+        || threadSafeHTMLNamesMatch(tagName, strongTag)
+        || threadSafeHTMLNamesMatch(tagName, strikeTag)
+        || threadSafeHTMLNamesMatch(tagName, subTag)
+        || threadSafeHTMLNamesMatch(tagName, supTag)
+        || threadSafeHTMLNamesMatch(tagName, tableTag)
+        || threadSafeHTMLNamesMatch(tagName, ttTag)
+        || threadSafeHTMLNamesMatch(tagName, uTag)
+        || threadSafeHTMLNamesMatch(tagName, ulTag)
+        || threadSafeHTMLNamesMatch(tagName, varTag)
+        || (threadSafeHTMLNamesMatch(tagName, fontTag) && (token.getAttributeItem(colorAttr) || token.getAttributeItem(faceAttr) || token.getAttributeItem(sizeAttr)));
+}
+
+static bool tokenExitsSVG(const CompactHTMLToken& token)
+{
+    // FIXME: It's very fragile that we special case foreignObject here to be case-insensitive.
+    return equalIgnoringCaseNonNull(token.data().asStringImpl(), SVGNames::foreignObjectTag.localName().impl());
+}
+
+static bool tokenExitsMath(const CompactHTMLToken& token)
+{
+    // FIXME: This is copied from HTMLElementStack::isMathMLTextIntegrationPoint and changed to use threadSafeMatch.
+    const HTMLIdentifier& tagName = token.data();
+    return threadSafeMatch(tagName, MathMLNames::miTag)
+        || threadSafeMatch(tagName, MathMLNames::moTag)
+        || threadSafeMatch(tagName, MathMLNames::mnTag)
+        || threadSafeMatch(tagName, MathMLNames::msTag)
+        || threadSafeMatch(tagName, MathMLNames::mtextTag);
+}
+
+HTMLTreeBuilderSimulator::HTMLTreeBuilderSimulator(const HTMLParserOptions& options)
+    : m_options(options)
+{
+    m_namespaceStack.append(HTML);
+}
+
+HTMLTreeBuilderSimulator::State HTMLTreeBuilderSimulator::stateFor(HTMLTreeBuilder* treeBuilder)
+{
+    ASSERT(isMainThread());
+    State namespaceStack;
+    for (HTMLElementStack::ElementRecord* record = treeBuilder->openElements()->topRecord(); record; record = record->next()) {
+        Namespace currentNamespace = HTML;
+        if (record->namespaceURI() == SVGNames::svgNamespaceURI)
+            currentNamespace = SVG;
+        else if (record->namespaceURI() == MathMLNames::mathmlNamespaceURI)
+            currentNamespace = MathML;
+
+        if (namespaceStack.isEmpty() || namespaceStack.last() != currentNamespace)
+            namespaceStack.append(currentNamespace);
+    }
+    namespaceStack.reverse();
+    return namespaceStack;
+}
+
+bool HTMLTreeBuilderSimulator::simulate(const CompactHTMLToken& token, HTMLTokenizer* tokenizer)
+{
+    if (token.type() == HTMLToken::StartTag) {
+        const HTMLIdentifier& tagName = token.data();
+        if (threadSafeMatch(tagName, SVGNames::svgTag))
+            m_namespaceStack.append(SVG);
+        if (threadSafeMatch(tagName, MathMLNames::mathTag))
+            m_namespaceStack.append(MathML);
+        if (inForeignContent() && tokenExitsForeignContent(token))
+            m_namespaceStack.removeLast();
+        if ((m_namespaceStack.last() == SVG && tokenExitsSVG(token))
+            || (m_namespaceStack.last() == MathML && tokenExitsMath(token)))
+            m_namespaceStack.append(HTML);
+        if (!inForeignContent()) {
+            // FIXME: This is just a copy of Tokenizer::updateStateFor which uses threadSafeMatches.
+            if (threadSafeHTMLNamesMatch(tagName, textareaTag) || threadSafeHTMLNamesMatch(tagName, titleTag))
+                tokenizer->setState(HTMLTokenizer::RCDATAState);
+            else if (threadSafeHTMLNamesMatch(tagName, plaintextTag))
+                tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
+            else if (threadSafeHTMLNamesMatch(tagName, scriptTag))
+                tokenizer->setState(HTMLTokenizer::ScriptDataState);
+            else if (threadSafeHTMLNamesMatch(tagName, styleTag)
+                || threadSafeHTMLNamesMatch(tagName, iframeTag)
+                || threadSafeHTMLNamesMatch(tagName, xmpTag)
+                || (threadSafeHTMLNamesMatch(tagName, noembedTag) && m_options.pluginsEnabled)
+                || threadSafeHTMLNamesMatch(tagName, noframesTag)
+                || (threadSafeHTMLNamesMatch(tagName, noscriptTag) && m_options.scriptEnabled))
+                tokenizer->setState(HTMLTokenizer::RAWTEXTState);
+        }
+    }
+
+    if (token.type() == HTMLToken::EndTag) {
+        const HTMLIdentifier& tagName = token.data();
+        if ((m_namespaceStack.last() == SVG && threadSafeMatch(tagName, SVGNames::svgTag))
+            || (m_namespaceStack.last() == MathML && threadSafeMatch(tagName, MathMLNames::mathTag))
+            || (m_namespaceStack.contains(SVG) && m_namespaceStack.last() == HTML && tokenExitsSVG(token))
+            || (m_namespaceStack.contains(MathML) && m_namespaceStack.last() == HTML && tokenExitsMath(token)))
+            m_namespaceStack.removeLast();
+        if (threadSafeHTMLNamesMatch(tagName, scriptTag)) {
+            if (!inForeignContent())
+                tokenizer->setState(HTMLTokenizer::DataState);
+            return false;
+        }
+    }
+
+    // FIXME: Also setForceNullCharacterReplacement when in text mode.
+    tokenizer->setForceNullCharacterReplacement(inForeignContent());
+    tokenizer->setShouldAllowCDATA(inForeignContent());
+    return true;
+}
+
+}
diff --git a/Source/core/html/parser/HTMLTreeBuilderSimulator.h b/Source/core/html/parser/HTMLTreeBuilderSimulator.h
new file mode 100644
index 0000000..4b73eb5
--- /dev/null
+++ b/Source/core/html/parser/HTMLTreeBuilderSimulator.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 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 GOOGLE 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 GOOGLE 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 HTMLTreeBuilderSimulator_h
+#define HTMLTreeBuilderSimulator_h
+
+#include "core/html/parser/HTMLParserOptions.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class CompactHTMLToken;
+class HTMLTokenizer;
+class HTMLTreeBuilder;
+
+class HTMLTreeBuilderSimulator {
+    WTF_MAKE_FAST_ALLOCATED;
+private:
+    enum Namespace {
+        HTML,
+        SVG,
+        MathML
+    };
+
+public:
+    typedef Vector<Namespace, 1> State;
+
+    explicit HTMLTreeBuilderSimulator(const HTMLParserOptions&);
+
+    static State stateFor(HTMLTreeBuilder*);
+
+    const State& state() const { return m_namespaceStack; }
+    void setState(const State& state) { m_namespaceStack = state; }
+
+    bool simulate(const CompactHTMLToken&, HTMLTokenizer*);
+
+private:
+    explicit HTMLTreeBuilderSimulator(HTMLTreeBuilder*);
+
+    bool inForeignContent() const { return m_namespaceStack.last() != HTML; }
+
+    HTMLParserOptions m_options;
+    State m_namespaceStack;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/HTMLViewSourceParser.cpp b/Source/core/html/parser/HTMLViewSourceParser.cpp
new file mode 100644
index 0000000..698bd0d
--- /dev/null
+++ b/Source/core/html/parser/HTMLViewSourceParser.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/HTMLViewSourceParser.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLViewSourceDocument.h"
+#include "core/html/parser/HTMLDocumentParser.h"
+#include "core/html/parser/HTMLParserOptions.h"
+
+namespace WebCore {
+
+HTMLViewSourceParser::HTMLViewSourceParser(HTMLViewSourceDocument* document)
+    : DecodedDataDocumentParser(document)
+    , m_tokenizer(HTMLTokenizer::create(HTMLParserOptions(document)))
+{
+}
+
+HTMLViewSourceParser::~HTMLViewSourceParser()
+{
+}
+
+void HTMLViewSourceParser::insert(const SegmentedString&)
+{
+    ASSERT_NOT_REACHED();
+}
+
+void HTMLViewSourceParser::pumpTokenizer()
+{
+    while (true) {
+        m_sourceTracker.start(m_input.current(), m_tokenizer.get(), m_token);
+        if (!m_tokenizer->nextToken(m_input.current(), m_token))
+            break;
+        m_sourceTracker.end(m_input.current(), m_tokenizer.get(), m_token);
+
+        document()->addSource(sourceForToken(), m_token);
+        updateTokenizerState();
+        m_token.clear();
+    }
+}
+
+void HTMLViewSourceParser::append(PassRefPtr<StringImpl> input)
+{
+    m_input.appendToEnd(String(input));
+    pumpTokenizer();
+}
+
+String HTMLViewSourceParser::sourceForToken()
+{
+    return m_sourceTracker.sourceForToken(m_token);
+}
+
+void HTMLViewSourceParser::updateTokenizerState()
+{
+    // FIXME: The tokenizer should do this work for us.
+    if (m_token.type() != HTMLToken::StartTag)
+        return;
+    m_tokenizer->updateStateFor(AtomicString(m_token.name()));
+}
+
+void HTMLViewSourceParser::finish()
+{
+    if (!m_input.haveSeenEndOfFile())
+        m_input.markEndOfFile();
+    pumpTokenizer();
+    document()->finishedParsing();
+}
+
+}
diff --git a/Source/core/html/parser/HTMLViewSourceParser.h b/Source/core/html/parser/HTMLViewSourceParser.h
new file mode 100644
index 0000000..958a811
--- /dev/null
+++ b/Source/core/html/parser/HTMLViewSourceParser.h
@@ -0,0 +1,79 @@
+/*
+ * 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 HTMLViewSourceParser_h
+#define HTMLViewSourceParser_h
+
+#include "core/dom/DecodedDataDocumentParser.h"
+#include "core/html/HTMLViewSourceDocument.h"
+#include "core/html/parser/HTMLInputStream.h"
+#include "core/html/parser/HTMLSourceTracker.h"
+#include "core/html/parser/HTMLToken.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class HTMLTokenizer;
+class HTMLScriptRunner;
+class HTMLTreeBuilder;
+class HTMLPreloadScanner;
+class ScriptController;
+class ScriptSourceCode;
+
+class HTMLViewSourceParser :  public DecodedDataDocumentParser {
+public:
+    static PassRefPtr<HTMLViewSourceParser> create(HTMLViewSourceDocument* document)
+    {
+        return adoptRef(new HTMLViewSourceParser(document));
+    }
+    virtual ~HTMLViewSourceParser();
+
+protected:
+    explicit HTMLViewSourceParser(HTMLViewSourceDocument*);
+
+    HTMLTokenizer* tokenizer() const { return m_tokenizer.get(); }
+
+private:
+    // DocumentParser
+    virtual void insert(const SegmentedString&);
+    virtual void append(PassRefPtr<StringImpl>);
+    virtual void finish();
+
+    HTMLViewSourceDocument* document() const { return static_cast<HTMLViewSourceDocument*>(DecodedDataDocumentParser::document()); }
+
+    void pumpTokenizer();
+    String sourceForToken();
+    void updateTokenizerState();
+
+    HTMLInputStream m_input;
+    HTMLToken m_token;
+    HTMLSourceTracker m_sourceTracker;
+    OwnPtr<HTMLTokenizer> m_tokenizer;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/InputStreamPreprocessor.h b/Source/core/html/parser/InputStreamPreprocessor.h
new file mode 100644
index 0000000..0d6ee30
--- /dev/null
+++ b/Source/core/html/parser/InputStreamPreprocessor.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/
+ * Copyright (C) 2013 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 InputStreamPreprocessor_h
+#define InputStreamPreprocessor_h
+
+#include "core/platform/text/SegmentedString.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+const UChar kEndOfFileMarker = 0;
+
+// http://www.whatwg.org/specs/web-apps/current-work/#preprocessing-the-input-stream
+template <typename Tokenizer>
+class InputStreamPreprocessor {
+    WTF_MAKE_NONCOPYABLE(InputStreamPreprocessor);
+public:
+    InputStreamPreprocessor(Tokenizer* tokenizer)
+        : m_tokenizer(tokenizer)
+    {
+        reset();
+    }
+
+    ALWAYS_INLINE UChar nextInputCharacter() const { return m_nextInputCharacter; }
+
+    // Returns whether we succeeded in peeking at the next character.
+    // The only way we can fail to peek is if there are no more
+    // characters in |source| (after collapsing \r\n, etc).
+    ALWAYS_INLINE bool peek(SegmentedString& source)
+    {
+    PeekAgain:
+        m_nextInputCharacter = source.currentChar();
+
+        // 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.
+        static const UChar specialCharacterMask = '\n' | '\r' | '\0';
+        if (m_nextInputCharacter & ~specialCharacterMask) {
+            m_skipNextNewLine = false;
+            return true;
+        }
+
+        if (m_nextInputCharacter == '\n' && m_skipNextNewLine) {
+            m_skipNextNewLine = false;
+            source.advancePastNewlineAndUpdateLineNumber();
+            if (source.isEmpty())
+                return false;
+            m_nextInputCharacter = source.currentChar();
+        }
+        if (m_nextInputCharacter == '\r') {
+            m_nextInputCharacter = '\n';
+            m_skipNextNewLine = true;
+        } else {
+            m_skipNextNewLine = false;
+            // FIXME: The spec indicates that the surrogate pair range as well as
+            // a number of specific character values are parse errors and should be replaced
+            // by the replacement character. We suspect this is a problem with the spec as doing
+            // that filtering breaks surrogate pair handling and causes us not to match Minefield.
+            if (m_nextInputCharacter == '\0' && !shouldTreatNullAsEndOfFileMarker(source)) {
+                if (m_tokenizer->shouldSkipNullCharacters()) {
+                    source.advancePastNonNewline();
+                    if (source.isEmpty())
+                        return false;
+                    goto PeekAgain;
+                }
+                m_nextInputCharacter = 0xFFFD;
+            }
+        }
+        return true;
+    }
+
+    // Returns whether there are more characters in |source| after advancing.
+    ALWAYS_INLINE bool advance(SegmentedString& source)
+    {
+        source.advanceAndUpdateLineNumber();
+        if (source.isEmpty())
+            return false;
+        return peek(source);
+    }
+
+    bool skipNextNewLine() const { return m_skipNextNewLine; }
+
+    void reset(bool skipNextNewLine = false)
+    {
+        m_nextInputCharacter = '\0';
+        m_skipNextNewLine = skipNextNewLine;
+    }
+
+private:
+    bool shouldTreatNullAsEndOfFileMarker(SegmentedString& source) const
+    {
+        return source.isClosed() && source.length() == 1;
+    }
+
+    Tokenizer* m_tokenizer;
+
+    // http://www.whatwg.org/specs/web-apps/current-work/#next-input-character
+    UChar m_nextInputCharacter;
+    bool m_skipNextNewLine;
+};
+
+}
+
+#endif // InputStreamPreprocessor_h
+
diff --git a/Source/core/html/parser/NestingLevelIncrementer.h b/Source/core/html/parser/NestingLevelIncrementer.h
new file mode 100644
index 0000000..bf08425
--- /dev/null
+++ b/Source/core/html/parser/NestingLevelIncrementer.h
@@ -0,0 +1,53 @@
+/*
+ * 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
+
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class NestingLevelIncrementer {
+    WTF_MAKE_NONCOPYABLE(NestingLevelIncrementer);
+public:
+    explicit NestingLevelIncrementer(unsigned& nestingLevel)
+        : m_nestingLevel(&nestingLevel)
+    {
+        ++(*m_nestingLevel);
+    }
+            
+    ~NestingLevelIncrementer()
+    {
+        --(*m_nestingLevel);
+    }
+            
+private:
+    unsigned* m_nestingLevel;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/TextDocumentParser.cpp b/Source/core/html/parser/TextDocumentParser.cpp
new file mode 100644
index 0000000..e90a624
--- /dev/null
+++ b/Source/core/html/parser/TextDocumentParser.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 "core/html/parser/TextDocumentParser.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/html/parser/HTMLTreeBuilder.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+TextDocumentParser::TextDocumentParser(HTMLDocument* document)
+    : HTMLDocumentParser(document, false)
+    , m_haveInsertedFakePreElement(false)
+{
+}
+
+TextDocumentParser::~TextDocumentParser()
+{
+}
+
+void TextDocumentParser::append(PassRefPtr<StringImpl> text)
+{
+    if (!m_haveInsertedFakePreElement)
+        insertFakePreElement();
+    HTMLDocumentParser::append(text);
+}
+
+void TextDocumentParser::insertFakePreElement()
+{
+    // In principle, we should create a specialized tree builder for
+    // TextDocuments, but instead we re-use the existing HTMLTreeBuilder.
+    // We create a fake token and give it to the tree builder rather than
+    // sending fake bytes through the front-end of the parser to avoid
+    // distrubing the line/column number calculations.
+    Vector<Attribute> attributes;
+    attributes.append(Attribute(styleAttr, "word-wrap: break-word; white-space: pre-wrap;"));
+    AtomicHTMLToken fakePre(HTMLToken::StartTag, preTag.localName(), attributes);
+    treeBuilder()->constructTree(&fakePre);
+
+    // Normally we would skip the first \n after a <pre> element, but we don't
+    // want to skip the first \n for text documents!
+    treeBuilder()->setShouldSkipLeadingNewline(false);
+
+    // Although Text Documents expose a "pre" element in their DOM, they
+    // act like a <plaintext> tag, so we have to force plaintext mode.
+    forcePlaintextForTextDocument();
+
+    m_haveInsertedFakePreElement = true;
+}
+
+}
diff --git a/Source/core/html/parser/TextDocumentParser.h b/Source/core/html/parser/TextDocumentParser.h
new file mode 100644
index 0000000..6b5bb9e
--- /dev/null
+++ b/Source/core/html/parser/TextDocumentParser.h
@@ -0,0 +1,52 @@
+/*
+ * 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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 TextDocumentParser_h
+#define TextDocumentParser_h
+
+#include "core/html/parser/HTMLDocumentParser.h"
+
+namespace WebCore {
+
+class TextDocumentParser : public HTMLDocumentParser {
+public:
+    static PassRefPtr<TextDocumentParser> create(HTMLDocument* document)
+    {
+        return adoptRef(new TextDocumentParser(document));
+    }
+    virtual ~TextDocumentParser();
+
+private:
+    explicit TextDocumentParser(HTMLDocument*);
+
+    virtual void append(PassRefPtr<StringImpl>);
+    void insertFakePreElement();
+
+    bool m_haveInsertedFakePreElement;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/TextViewSourceParser.cpp b/Source/core/html/parser/TextViewSourceParser.cpp
new file mode 100644
index 0000000..38c10c2
--- /dev/null
+++ b/Source/core/html/parser/TextViewSourceParser.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/TextViewSourceParser.h"
+
+#include "core/html/parser/HTMLTokenizer.h"
+
+namespace WebCore {
+
+TextViewSourceParser::TextViewSourceParser(HTMLViewSourceDocument* document)
+    : HTMLViewSourceParser(document)
+{
+    tokenizer()->setState(HTMLTokenizer::PLAINTEXTState);
+}
+
+TextViewSourceParser::~TextViewSourceParser()
+{
+}
+
+}
diff --git a/Source/core/html/parser/TextViewSourceParser.h b/Source/core/html/parser/TextViewSourceParser.h
new file mode 100644
index 0000000..1cfcd40
--- /dev/null
+++ b/Source/core/html/parser/TextViewSourceParser.h
@@ -0,0 +1,47 @@
+/*
+ * 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 TextViewSourceParser_h
+#define TextViewSourceParser_h
+
+#include "core/html/parser/HTMLViewSourceParser.h"
+
+namespace WebCore {
+
+class TextViewSourceParser :  public HTMLViewSourceParser {
+public:
+    static PassRefPtr<TextViewSourceParser> create(HTMLViewSourceDocument* document)
+    {
+        return adoptRef(new TextViewSourceParser(document));
+    }
+    virtual ~TextViewSourceParser();
+
+private:
+    explicit TextViewSourceParser(HTMLViewSourceDocument*);
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/XSSAuditor.cpp b/Source/core/html/parser/XSSAuditor.cpp
new file mode 100644
index 0000000..b24ff03
--- /dev/null
+++ b/Source/core/html/parser/XSSAuditor.cpp
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2011 Adam Barth. All Rights Reserved.
+ * Copyright (C) 2011 Daniel Bates (dbates@intudata.com).
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/XSSAuditor.h"
+
+#include "HTMLNames.h"
+#include "XLinkNames.h"
+#include "core/dom/Document.h"
+#include "core/html/FormDataList.h"
+#include "core/html/HTMLParamElement.h"
+#include "core/html/parser/HTMLDocumentParser.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/parser/HTMLTokenizer.h"
+#include "core/html/parser/XSSAuditorDelegate.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/loader/PingLoader.h"
+#include "core/loader/TextResourceDecoder.h"
+#include "core/page/Console.h"
+#include "core/page/ContentSecurityPolicy.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/page/Settings.h"
+#include "core/platform/KURL.h"
+#include "core/platform/network/FormData.h"
+#include "core/platform/text/DecodeEscapeSequences.h"
+#include "core/platform/text/TextEncoding.h"
+
+#if ENABLE(SVG)
+#include "SVGNames.h"
+#endif
+
+#include <wtf/Functional.h>
+#include <wtf/MainThread.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static bool isNonCanonicalCharacter(UChar c)
+{
+    // We remove all non-ASCII characters, including non-printable ASCII characters.
+    //
+    // Note, we don't remove backslashes like PHP stripslashes(), which among other things converts "\\0" to the \0 character.
+    // Instead, we remove backslashes and zeros (since the string "\\0" =(remove backslashes)=> "0"). However, this has the
+    // adverse effect that we remove any legitimate zeros from a string.
+    //
+    // For instance: new String("http://localhost:8000") => new String("http://localhost:8").
+    return (c == '\\' || c == '0' || c == '\0' || c >= 127);
+}
+
+static String canonicalize(const String& string)
+{
+    return string.removeCharacters(&isNonCanonicalCharacter);
+}
+
+static bool isRequiredForInjection(UChar c)
+{
+    return (c == '\'' || c == '"' || c == '<' || c == '>');
+}
+
+static bool isTerminatingCharacter(UChar c)
+{
+    return (c == '&' || c == '/' || c == '"' || c == '\'' || c == '<' || c == '>' || c == ',');
+}
+
+static bool isHTMLQuote(UChar c)
+{
+    return (c == '"' || c == '\'');
+}
+
+static bool isJSNewline(UChar c)
+{
+    // Per ecma-262 section 7.3 Line Terminators.
+    return (c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029);
+}
+
+static bool startsHTMLCommentAt(const String& string, size_t start)
+{
+    return (start + 3 < string.length() && string[start] == '<' && string[start+1] == '!' && string[start+2] == '-' && string[start+3] == '-');
+}
+
+static bool startsSingleLineCommentAt(const String& string, size_t start)
+{
+    return (start + 1 < string.length() && string[start] == '/' && string[start+1] == '/');
+}
+
+static bool startsMultiLineCommentAt(const String& string, size_t start)
+{
+    return (start + 1 < string.length() && string[start] == '/' && string[start+1] == '*');
+}
+
+// If other files need this, we should move this to core/html/parser/HTMLParserIdioms.h
+template<size_t inlineCapacity>
+bool threadSafeMatch(const Vector<UChar, inlineCapacity>& vector, const QualifiedName& qname)
+{
+    return equalIgnoringNullity(vector, qname.localName().impl());
+}
+
+static bool hasName(const HTMLToken& token, const QualifiedName& name)
+{
+    return threadSafeMatch(token.name(), name);
+}
+
+static bool findAttributeWithName(const HTMLToken& token, const QualifiedName& name, size_t& indexOfMatchingAttribute)
+{
+    // Notice that we're careful not to ref the StringImpl here because we might be on a background thread.
+    const String& attrName = name.namespaceURI() == XLinkNames::xlinkNamespaceURI ? "xlink:" + name.localName().string() : name.localName().string();
+
+    for (size_t i = 0; i < token.attributes().size(); ++i) {
+        if (equalIgnoringNullity(token.attributes().at(i).name, attrName)) {
+            indexOfMatchingAttribute = i;
+            return true;
+        }
+    }
+    return false;
+}
+
+static bool isNameOfInlineEventHandler(const Vector<UChar, 32>& name)
+{
+    const size_t lengthOfShortestInlineEventHandlerName = 5; // To wit: oncut.
+    if (name.size() < lengthOfShortestInlineEventHandlerName)
+        return false;
+    return name[0] == 'o' && name[1] == 'n';
+}
+
+static bool isDangerousHTTPEquiv(const String& value)
+{
+    String equiv = value.stripWhiteSpace();
+    return equalIgnoringCase(equiv, "refresh") || equalIgnoringCase(equiv, "set-cookie");
+}
+
+static inline String decode16BitUnicodeEscapeSequences(const String& string)
+{
+    // Note, the encoding is ignored since each %u-escape sequence represents a UTF-16 code unit.
+    return decodeEscapeSequences<Unicode16BitEscapeSequence>(string, UTF8Encoding());
+}
+
+static inline String decodeStandardURLEscapeSequences(const String& string, const TextEncoding& encoding)
+{
+    // We use decodeEscapeSequences() instead of decodeURLEscapeSequences() (declared in core/platform/KURL.h) to
+    // avoid platform-specific URL decoding differences (e.g. KURLGoogle).
+    return decodeEscapeSequences<URLEscapeSequence>(string, encoding);
+}
+
+static String fullyDecodeString(const String& string, const TextEncoding& encoding)
+{
+    size_t oldWorkingStringLength;
+    String workingString = string;
+    do {
+        oldWorkingStringLength = workingString.length();
+        workingString = decode16BitUnicodeEscapeSequences(decodeStandardURLEscapeSequences(workingString, encoding));
+    } while (workingString.length() < oldWorkingStringLength);
+    workingString.replace('+', ' ');
+    workingString = canonicalize(workingString);
+    return workingString;
+}
+
+static ContentSecurityPolicy::ReflectedXSSDisposition combineXSSProtectionHeaderAndCSP(ContentSecurityPolicy::ReflectedXSSDisposition xssProtection, ContentSecurityPolicy::ReflectedXSSDisposition reflectedXSS)
+{
+    ContentSecurityPolicy::ReflectedXSSDisposition result = std::max(xssProtection, reflectedXSS);
+
+    if (result == ContentSecurityPolicy::ReflectedXSSInvalid || result == ContentSecurityPolicy::FilterReflectedXSS || result == ContentSecurityPolicy::ReflectedXSSUnset)
+        return ContentSecurityPolicy::FilterReflectedXSS;
+
+    return result;
+}
+
+static bool isSemicolonSeparatedAttribute(const HTMLToken::Attribute& attribute)
+{
+#if ENABLE(SVG)
+    return threadSafeMatch(attribute.name, SVGNames::valuesAttr);
+#else
+    return false;
+#endif
+}
+
+static bool semicolonSeparatedValueContainsJavaScriptURL(const String& value)
+{
+    Vector<String> valueList;
+    value.split(';', valueList);
+    for (size_t i = 0; i < valueList.size(); ++i) {
+        if (protocolIsJavaScript(valueList[i]))
+            return true;
+    }
+    return false;
+}
+
+XSSAuditor::XSSAuditor()
+    : m_isEnabled(false)
+    , m_xssProtection(ContentSecurityPolicy::FilterReflectedXSS)
+    , m_didSendValidCSPHeader(false)
+    , m_didSendValidXSSProtectionHeader(false)
+    , m_state(Uninitialized)
+    , m_scriptTagNestingLevel(0)
+    , m_encoding(UTF8Encoding())
+{
+    // Although tempting to call init() at this point, the various objects
+    // we want to reference might not all have been constructed yet.
+}
+
+void XSSAuditor::initForFragment()
+{
+    ASSERT(isMainThread());
+    ASSERT(m_state == Uninitialized);
+    m_state = Initialized;
+    // When parsing a fragment, we don't enable the XSS auditor because it's
+    // too much overhead.
+    ASSERT(!m_isEnabled);
+}
+
+void XSSAuditor::init(Document* document, XSSAuditorDelegate* auditorDelegate)
+{
+    const size_t miniumLengthForSuffixTree = 512; // FIXME: Tune this parameter.
+    const int suffixTreeDepth = 5;
+
+    ASSERT(isMainThread());
+    if (m_state == Initialized)
+        return;
+    ASSERT(m_state == Uninitialized);
+    m_state = Initialized;
+
+    if (Frame* frame = document->frame())
+        if (Settings* settings = frame->settings())
+            m_isEnabled = settings->xssAuditorEnabled();
+
+    if (!m_isEnabled)
+        return;
+
+    m_documentURL = document->url().copy();
+
+    // In theory, the Document could have detached from the Frame after the
+    // XSSAuditor was constructed.
+    if (!document->frame()) {
+        m_isEnabled = false;
+        return;
+    }
+
+    if (m_documentURL.isEmpty()) {
+        // The URL can be empty when opening a new browser window or calling window.open("").
+        m_isEnabled = false;
+        return;
+    }
+
+    if (m_documentURL.protocolIsData()) {
+        m_isEnabled = false;
+        return;
+    }
+
+    if (document->decoder())
+        m_encoding = document->decoder()->encoding();
+
+    m_decodedURL = fullyDecodeString(m_documentURL.string(), m_encoding);
+    if (m_decodedURL.find(isRequiredForInjection) == notFound)
+        m_decodedURL = String();
+
+    String httpBodyAsString;
+    if (DocumentLoader* documentLoader = document->frame()->loader()->documentLoader()) {
+        DEFINE_STATIC_LOCAL(String, XSSProtectionHeader, (ASCIILiteral("X-XSS-Protection")));
+        String headerValue = documentLoader->response().httpHeaderField(XSSProtectionHeader);
+        String errorDetails;
+        unsigned errorPosition = 0;
+        String reportURL;
+        KURL xssProtectionReportURL;
+
+        // Process the X-XSS-Protection header, then mix in the CSP header's value.
+        ContentSecurityPolicy::ReflectedXSSDisposition xssProtectionHeader = parseXSSProtectionHeader(headerValue, errorDetails, errorPosition, reportURL);
+        m_didSendValidXSSProtectionHeader = xssProtectionHeader != ContentSecurityPolicy::ReflectedXSSUnset && xssProtectionHeader != ContentSecurityPolicy::ReflectedXSSInvalid;
+        if ((xssProtectionHeader == ContentSecurityPolicy::FilterReflectedXSS || xssProtectionHeader == ContentSecurityPolicy::BlockReflectedXSS) && !reportURL.isEmpty()) {
+            xssProtectionReportURL = document->completeURL(reportURL);
+            if (MixedContentChecker::isMixedContent(document->securityOrigin(), xssProtectionReportURL)) {
+                errorDetails = "insecure reporting URL for secure page";
+                xssProtectionHeader = ContentSecurityPolicy::ReflectedXSSInvalid;
+                xssProtectionReportURL = KURL();
+            }
+        }
+        if (xssProtectionHeader == ContentSecurityPolicy::ReflectedXSSInvalid)
+            document->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Error parsing header X-XSS-Protection: " + headerValue + ": "  + errorDetails + " at character position " + String::format("%u", errorPosition) + ". The default protections will be applied.");
+
+        ContentSecurityPolicy::ReflectedXSSDisposition cspHeader = document->contentSecurityPolicy()->reflectedXSSDisposition();
+        m_didSendValidCSPHeader = cspHeader != ContentSecurityPolicy::ReflectedXSSUnset && cspHeader != ContentSecurityPolicy::ReflectedXSSInvalid;
+
+        m_xssProtection = combineXSSProtectionHeaderAndCSP(xssProtectionHeader, cspHeader);
+        // FIXME: Combine the two report URLs in some reasonable way.
+        if (auditorDelegate)
+            auditorDelegate->setReportURL(xssProtectionReportURL.copy());
+        FormData* httpBody = documentLoader->originalRequest().httpBody();
+        if (httpBody && !httpBody->isEmpty()) {
+            httpBodyAsString = httpBody->flattenToString();
+            if (!httpBodyAsString.isEmpty()) {
+                m_decodedHTTPBody = fullyDecodeString(httpBodyAsString, m_encoding);
+                if (m_decodedHTTPBody.find(isRequiredForInjection) == notFound)
+                    m_decodedHTTPBody = String();
+                if (m_decodedHTTPBody.length() >= miniumLengthForSuffixTree)
+                    m_decodedHTTPBodySuffixTree = adoptPtr(new SuffixTree<ASCIICodebook>(m_decodedHTTPBody, suffixTreeDepth));
+            }
+        }
+    }
+
+    if (m_decodedURL.isEmpty() && m_decodedHTTPBody.isEmpty()) {
+        m_isEnabled = false;
+        return;
+    }
+}
+
+PassOwnPtr<XSSInfo> XSSAuditor::filterToken(const FilterTokenRequest& request)
+{
+    ASSERT(m_state == Initialized);
+    if (!m_isEnabled || m_xssProtection == ContentSecurityPolicy::AllowReflectedXSS)
+        return nullptr;
+
+    bool didBlockScript = false;
+    if (request.token.type() == HTMLToken::StartTag)
+        didBlockScript = filterStartToken(request);
+    else if (m_scriptTagNestingLevel) {
+        if (request.token.type() == HTMLToken::Character)
+            didBlockScript = filterCharacterToken(request);
+        else if (request.token.type() == HTMLToken::EndTag)
+            filterEndToken(request);
+    }
+
+    if (didBlockScript) {
+        bool didBlockEntirePage = (m_xssProtection == ContentSecurityPolicy::BlockReflectedXSS);
+        OwnPtr<XSSInfo> xssInfo = XSSInfo::create(didBlockEntirePage, m_didSendValidXSSProtectionHeader, m_didSendValidCSPHeader);
+        return xssInfo.release();
+    }
+    return nullptr;
+}
+
+bool XSSAuditor::filterStartToken(const FilterTokenRequest& request)
+{
+    bool didBlockScript = eraseDangerousAttributesIfInjected(request);
+
+    if (hasName(request.token, scriptTag)) {
+        didBlockScript |= filterScriptToken(request);
+        ASSERT(request.shouldAllowCDATA || !m_scriptTagNestingLevel);
+        m_scriptTagNestingLevel++;
+    } else if (hasName(request.token, objectTag))
+        didBlockScript |= filterObjectToken(request);
+    else if (hasName(request.token, paramTag))
+        didBlockScript |= filterParamToken(request);
+    else if (hasName(request.token, embedTag))
+        didBlockScript |= filterEmbedToken(request);
+    else if (hasName(request.token, appletTag))
+        didBlockScript |= filterAppletToken(request);
+    else if (hasName(request.token, iframeTag))
+        didBlockScript |= filterIframeToken(request);
+    else if (hasName(request.token, metaTag))
+        didBlockScript |= filterMetaToken(request);
+    else if (hasName(request.token, baseTag))
+        didBlockScript |= filterBaseToken(request);
+    else if (hasName(request.token, formTag))
+        didBlockScript |= filterFormToken(request);
+    else if (hasName(request.token, inputTag))
+        didBlockScript |= filterInputToken(request);
+    else if (hasName(request.token, buttonTag))
+        didBlockScript |= filterButtonToken(request);
+
+    return didBlockScript;
+}
+
+void XSSAuditor::filterEndToken(const FilterTokenRequest& request)
+{
+    ASSERT(m_scriptTagNestingLevel);
+    if (hasName(request.token, scriptTag)) {
+        m_scriptTagNestingLevel--;
+        ASSERT(request.shouldAllowCDATA || !m_scriptTagNestingLevel);
+    }
+}
+
+bool XSSAuditor::filterCharacterToken(const FilterTokenRequest& request)
+{
+    ASSERT(m_scriptTagNestingLevel);
+    if (isContainedInRequest(m_cachedDecodedSnippet) && isContainedInRequest(decodedSnippetForJavaScript(request))) {
+        request.token.eraseCharacters();
+        request.token.appendToCharacter(' '); // Technically, character tokens can't be empty.
+        return true;
+    }
+    return false;
+}
+
+bool XSSAuditor::filterScriptToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, scriptTag));
+
+    m_cachedDecodedSnippet = decodedSnippetForName(request);
+
+    bool didBlockScript = false;
+    if (isContainedInRequest(decodedSnippetForName(request))) {
+        didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), SrcLikeAttribute);
+        didBlockScript |= eraseAttributeIfInjected(request, XLinkNames::hrefAttr, blankURL().string(), SrcLikeAttribute);
+    }
+
+    return didBlockScript;
+}
+
+bool XSSAuditor::filterObjectToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, objectTag));
+
+    bool didBlockScript = false;
+    if (isContainedInRequest(decodedSnippetForName(request))) {
+        didBlockScript |= eraseAttributeIfInjected(request, dataAttr, blankURL().string(), SrcLikeAttribute);
+        didBlockScript |= eraseAttributeIfInjected(request, typeAttr);
+        didBlockScript |= eraseAttributeIfInjected(request, classidAttr);
+    }
+    return didBlockScript;
+}
+
+bool XSSAuditor::filterParamToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, paramTag));
+
+    size_t indexOfNameAttribute;
+    if (!findAttributeWithName(request.token, nameAttr, indexOfNameAttribute))
+        return false;
+
+    const HTMLToken::Attribute& nameAttribute = request.token.attributes().at(indexOfNameAttribute);
+    if (!HTMLParamElement::isURLParameter(String(nameAttribute.value)))
+        return false;
+
+    return eraseAttributeIfInjected(request, valueAttr, blankURL().string(), SrcLikeAttribute);
+}
+
+bool XSSAuditor::filterEmbedToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, embedTag));
+
+    bool didBlockScript = false;
+    if (isContainedInRequest(decodedSnippetForName(request))) {
+        didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), SrcLikeAttribute);
+        didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), SrcLikeAttribute);
+        didBlockScript |= eraseAttributeIfInjected(request, typeAttr);
+    }
+    return didBlockScript;
+}
+
+bool XSSAuditor::filterAppletToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, appletTag));
+
+    bool didBlockScript = false;
+    if (isContainedInRequest(decodedSnippetForName(request))) {
+        didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), SrcLikeAttribute);
+        didBlockScript |= eraseAttributeIfInjected(request, objectAttr);
+    }
+    return didBlockScript;
+}
+
+bool XSSAuditor::filterIframeToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, iframeTag));
+
+    bool didBlockScript = false;
+    if (isContainedInRequest(decodedSnippetForName(request))) {
+        didBlockScript |= eraseAttributeIfInjected(request, srcAttr, String(), SrcLikeAttribute);
+        didBlockScript |= eraseAttributeIfInjected(request, srcdocAttr, String(), ScriptLikeAttribute);
+    }
+    return didBlockScript;
+}
+
+bool XSSAuditor::filterMetaToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, metaTag));
+
+    return eraseAttributeIfInjected(request, http_equivAttr);
+}
+
+bool XSSAuditor::filterBaseToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, baseTag));
+
+    return eraseAttributeIfInjected(request, hrefAttr);
+}
+
+bool XSSAuditor::filterFormToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, formTag));
+
+    return eraseAttributeIfInjected(request, actionAttr, blankURL().string());
+}
+
+bool XSSAuditor::filterInputToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, inputTag));
+
+    return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), SrcLikeAttribute);
+}
+
+bool XSSAuditor::filterButtonToken(const FilterTokenRequest& request)
+{
+    ASSERT(request.token.type() == HTMLToken::StartTag);
+    ASSERT(hasName(request.token, buttonTag));
+
+    return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), SrcLikeAttribute);
+}
+
+bool XSSAuditor::eraseDangerousAttributesIfInjected(const FilterTokenRequest& request)
+{
+    DEFINE_STATIC_LOCAL(String, safeJavaScriptURL, (ASCIILiteral("javascript:void(0)")));
+
+    bool didBlockScript = false;
+    for (size_t i = 0; i < request.token.attributes().size(); ++i) {
+        const HTMLToken::Attribute& attribute = request.token.attributes().at(i);
+        bool isInlineEventHandler = isNameOfInlineEventHandler(attribute.name);
+        // FIXME: It would be better if we didn't create a new String for every attribute in the document.
+        String strippedValue = stripLeadingAndTrailingHTMLSpaces(String(attribute.value));
+        bool valueContainsJavaScriptURL = (!isInlineEventHandler && protocolIsJavaScript(strippedValue)) || (isSemicolonSeparatedAttribute(attribute) && semicolonSeparatedValueContainsJavaScriptURL(strippedValue));
+        if (!isInlineEventHandler && !valueContainsJavaScriptURL)
+            continue;
+        if (!isContainedInRequest(decodedSnippetForAttribute(request, attribute, ScriptLikeAttribute)))
+            continue;
+        request.token.eraseValueOfAttribute(i);
+        if (valueContainsJavaScriptURL)
+            request.token.appendToAttributeValue(i, safeJavaScriptURL);
+        didBlockScript = true;
+    }
+    return didBlockScript;
+}
+
+bool XSSAuditor::eraseAttributeIfInjected(const FilterTokenRequest& request, const QualifiedName& attributeName, const String& replacementValue, AttributeKind treatment)
+{
+    size_t indexOfAttribute = 0;
+    if (findAttributeWithName(request.token, attributeName, indexOfAttribute)) {
+        const HTMLToken::Attribute& attribute = request.token.attributes().at(indexOfAttribute);
+        if (isContainedInRequest(decodedSnippetForAttribute(request, attribute, treatment))) {
+            if (threadSafeMatch(attributeName, srcAttr) && isLikelySafeResource(String(attribute.value)))
+                return false;
+            if (threadSafeMatch(attributeName, http_equivAttr) && !isDangerousHTTPEquiv(String(attribute.value)))
+                return false;
+            request.token.eraseValueOfAttribute(indexOfAttribute);
+            if (!replacementValue.isEmpty())
+                request.token.appendToAttributeValue(indexOfAttribute, replacementValue);
+            return true;
+        }
+    }
+    return false;
+}
+
+String XSSAuditor::decodedSnippetForName(const FilterTokenRequest& request)
+{
+    // Grab a fixed number of characters equal to the length of the token's name plus one (to account for the "<").
+    return fullyDecodeString(request.sourceTracker.sourceForToken(request.token), m_encoding).substring(0, request.token.name().size() + 1);
+}
+
+String XSSAuditor::decodedSnippetForAttribute(const FilterTokenRequest& request, const HTMLToken::Attribute& attribute, AttributeKind treatment)
+{
+    // The range doesn't inlcude the character which terminates the value. So,
+    // for an input of |name="value"|, the snippet is |name="value|. For an
+    // unquoted input of |name=value |, the snippet is |name=value|.
+    // FIXME: We should grab one character before the name also.
+    int start = attribute.nameRange.start - request.token.startIndex();
+    int end = attribute.valueRange.end - request.token.startIndex();
+    String decodedSnippet = fullyDecodeString(request.sourceTracker.sourceForToken(request.token).substring(start, end - start), m_encoding);
+    decodedSnippet.truncate(kMaximumFragmentLengthTarget);
+    if (treatment == SrcLikeAttribute) {
+        int slashCount = 0;
+        bool commaSeen = false;
+        // In HTTP URLs, characters following the first ?, #, or third slash may come from 
+        // the page itself and can be merely ignored by an attacker's server when a remote
+        // script or script-like resource is requested. In DATA URLS, the payload starts at
+        // the first comma, and the the first /*, //, or <!-- may introduce a comment. Characters
+        // following this may come from the page itself and may be ignored when the script is
+        // executed. For simplicity, we don't differentiate based on URL scheme, and stop at
+        // the first # or ?, the third slash, or the first slash or < once a comma is seen.
+        for (size_t currentLength = 0; currentLength < decodedSnippet.length(); ++currentLength) {
+            UChar currentChar = decodedSnippet[currentLength];
+            if (currentChar == '?'
+                || currentChar == '#'
+                || ((currentChar == '/' || currentChar == '\\') && (commaSeen || ++slashCount > 2))
+                || (currentChar == '<' && commaSeen)) {
+                decodedSnippet.truncate(currentLength);
+                break;
+            }
+            if (currentChar == ',')
+                commaSeen = true;
+        }
+    } else if (treatment == ScriptLikeAttribute) {
+        // Beware of trailing characters which came from the page itself, not the 
+        // injected vector. Excluding the terminating character covers common cases
+        // where the page immediately ends the attribute, but doesn't cover more
+        // complex cases where there is other page data following the injection. 
+        // Generally, these won't parse as javascript, so the injected vector
+        // typically excludes them from consideration via a single-line comment or
+        // by enclosing them in a string literal terminated later by the page's own
+        // closing punctuation. Since the snippet has not been parsed, the vector
+        // may also try to introduce these via entities. As a result, we'd like to
+        // stop before the first "//", the first <!--, the first entity, or the first
+        // quote not immediately following the first equals sign (taking whitespace
+        // into consideration). To keep things simpler, we don't try to distinguish
+        // between entity-introducing amperands vs. other uses, nor do we bother to
+        // check for a second slash for a comment, nor do we bother to check for
+        // !-- following a less-than sign. We stop instead on any ampersand
+        // slash, or less-than sign.
+        size_t position = 0;
+        if ((position = decodedSnippet.find("=")) != notFound
+            && (position = decodedSnippet.find(isNotHTMLSpace, position + 1)) != notFound
+            && (position = decodedSnippet.find(isTerminatingCharacter, isHTMLQuote(decodedSnippet[position]) ? position + 1 : position)) != notFound) {
+            decodedSnippet.truncate(position);
+        }
+    }
+    return decodedSnippet;
+}
+
+String XSSAuditor::decodedSnippetForJavaScript(const FilterTokenRequest& request)
+{
+    String string = request.sourceTracker.sourceForToken(request.token);
+    size_t startPosition = 0;
+    size_t endPosition = string.length();
+    size_t foundPosition = notFound;
+
+    // Skip over initial comments to find start of code.
+    while (startPosition < endPosition) {
+        while (startPosition < endPosition && isHTMLSpace(string[startPosition]))
+            startPosition++;
+
+        // Under SVG/XML rules, only HTML comment syntax matters and the parser returns
+        // these as a separate comment tokens. Having consumed whitespace, we need not look
+        // further for these.
+        if (request.shouldAllowCDATA)
+            break;
+
+        // Under HTML rules, both the HTML and JS comment synatx matters, and the HTML
+        // comment ends at the end of the line, not with -->.
+        if (startsHTMLCommentAt(string, startPosition) || startsSingleLineCommentAt(string, startPosition)) {
+            while (startPosition < endPosition && !isJSNewline(string[startPosition]))
+                startPosition++;
+        } else if (startsMultiLineCommentAt(string, startPosition)) {
+            if (startPosition + 2 < endPosition && (foundPosition = string.find("*/", startPosition + 2)) != notFound)
+                startPosition = foundPosition + 2;
+            else
+                startPosition = endPosition;
+        } else
+            break;
+    }
+
+    String result;
+    while (startPosition < endPosition && !result.length()) {
+        // Stop at next comment (using the same rules as above for SVG/XML vs HTML), when we 
+        // encounter a comma, or when we  exceed the maximum length target. The comma rule
+        // covers a common parameter concatenation case performed by some webservers.
+        // After hitting the length target, we can only stop at a point where we know we are
+        // not in the middle of a %-escape sequence. For the sake of simplicity, approximate
+        // not stopping inside a (possibly multiply encoded) %-esacpe sequence by breaking on
+        // whitespace only. We should have enough text in these cases to avoid false positives.
+        for (foundPosition = startPosition; foundPosition < endPosition; foundPosition++) {
+            if (!request.shouldAllowCDATA) {
+                if (startsSingleLineCommentAt(string, foundPosition) || startsMultiLineCommentAt(string, foundPosition)) {
+                    foundPosition += 2;
+                    break;
+                }
+                if (startsHTMLCommentAt(string, foundPosition)) {
+                    foundPosition += 4;
+                    break;
+                }
+            }
+            if (string[foundPosition] == ',' || (foundPosition > startPosition + kMaximumFragmentLengthTarget && isHTMLSpace(string[foundPosition]))) {
+                break;
+            }
+        }
+
+        result = fullyDecodeString(string.substring(startPosition, foundPosition - startPosition), m_encoding);
+        startPosition = foundPosition + 1;
+    }
+    return result;
+}
+
+bool XSSAuditor::isContainedInRequest(const String& decodedSnippet)
+{
+    if (decodedSnippet.isEmpty())
+        return false;
+    if (m_decodedURL.find(decodedSnippet, 0, false) != notFound)
+        return true;
+    if (m_decodedHTTPBodySuffixTree && !m_decodedHTTPBodySuffixTree->mightContain(decodedSnippet))
+        return false;
+    return m_decodedHTTPBody.find(decodedSnippet, 0, false) != notFound;
+}
+
+bool XSSAuditor::isLikelySafeResource(const String& url)
+{
+    // Give empty URLs and about:blank a pass. Making a resourceURL from an
+    // empty string below will likely later fail the "no query args test" as
+    // it inherits the document's query args.
+    if (url.isEmpty() || url == blankURL().string())
+        return true;
+
+    // If the resource is loaded from the same host as the enclosing page, it's
+    // probably not an XSS attack, so we reduce false positives by allowing the
+    // request, ignoring scheme and port considerations. If the resource has a
+    // query string, we're more suspicious, however, because that's pretty rare
+    // and the attacker might be able to trick a server-side script into doing
+    // something dangerous with the query string.  
+    if (m_documentURL.host().isEmpty())
+        return false;
+
+    KURL resourceURL(m_documentURL, url);
+    return (m_documentURL.host() == resourceURL.host() && resourceURL.query().isEmpty());
+}
+
+bool XSSAuditor::isSafeToSendToAnotherThread() const
+{
+    return m_documentURL.isSafeToSendToAnotherThread()
+        && m_decodedURL.isSafeToSendToAnotherThread()
+        && m_decodedHTTPBody.isSafeToSendToAnotherThread()
+        && m_cachedDecodedSnippet.isSafeToSendToAnotherThread();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/parser/XSSAuditor.h b/Source/core/html/parser/XSSAuditor.h
new file mode 100644
index 0000000..8ff7131
--- /dev/null
+++ b/Source/core/html/parser/XSSAuditor.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2011 Adam Barth. 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 XSSAuditor_h
+#define XSSAuditor_h
+
+#include "core/html/parser/HTMLToken.h"
+#include "core/platform/KURL.h"
+#include "core/platform/network/HTTPParsers.h"
+#include "core/platform/text/SuffixTree.h"
+#include "core/platform/text/TextEncoding.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class Document;
+class HTMLDocumentParser;
+class HTMLSourceTracker;
+class XSSInfo;
+class XSSAuditorDelegate;
+
+struct FilterTokenRequest {
+    FilterTokenRequest(HTMLToken& token, HTMLSourceTracker& sourceTracker, bool shouldAllowCDATA)
+        : token(token)
+        , sourceTracker(sourceTracker)
+        , shouldAllowCDATA(shouldAllowCDATA)
+    { }
+
+    HTMLToken& token;
+    HTMLSourceTracker& sourceTracker;
+    bool shouldAllowCDATA;
+};
+
+class XSSAuditor {
+    WTF_MAKE_NONCOPYABLE(XSSAuditor);
+public:
+    XSSAuditor();
+
+    void init(Document*, XSSAuditorDelegate*);
+    void initForFragment();
+
+    PassOwnPtr<XSSInfo> filterToken(const FilterTokenRequest&);
+    bool isSafeToSendToAnotherThread() const;
+
+private:
+    static const size_t kMaximumFragmentLengthTarget = 100;
+
+    enum State {
+        Uninitialized,
+        Initialized
+    };
+
+    enum AttributeKind {
+        NormalAttribute,
+        SrcLikeAttribute,
+        ScriptLikeAttribute
+    };
+
+    bool filterStartToken(const FilterTokenRequest&);
+    void filterEndToken(const FilterTokenRequest&);
+    bool filterCharacterToken(const FilterTokenRequest&);
+    bool filterScriptToken(const FilterTokenRequest&);
+    bool filterObjectToken(const FilterTokenRequest&);
+    bool filterParamToken(const FilterTokenRequest&);
+    bool filterEmbedToken(const FilterTokenRequest&);
+    bool filterAppletToken(const FilterTokenRequest&);
+    bool filterIframeToken(const FilterTokenRequest&);
+    bool filterMetaToken(const FilterTokenRequest&);
+    bool filterBaseToken(const FilterTokenRequest&);
+    bool filterFormToken(const FilterTokenRequest&);
+    bool filterInputToken(const FilterTokenRequest&);
+    bool filterButtonToken(const FilterTokenRequest&);
+
+    bool eraseDangerousAttributesIfInjected(const FilterTokenRequest&);
+    bool eraseAttributeIfInjected(const FilterTokenRequest&, const QualifiedName&, const String& replacementValue = String(), AttributeKind treatment = NormalAttribute);
+
+    String decodedSnippetForToken(const HTMLToken&);
+    String decodedSnippetForName(const FilterTokenRequest&);
+    String decodedSnippetForAttribute(const FilterTokenRequest&, const HTMLToken::Attribute&, AttributeKind treatment = NormalAttribute);
+    String decodedSnippetForJavaScript(const FilterTokenRequest&);
+
+    bool isContainedInRequest(const String&);
+    bool isLikelySafeResource(const String& url);
+
+    KURL m_documentURL;
+    bool m_isEnabled;
+
+    ContentSecurityPolicy::ReflectedXSSDisposition m_xssProtection;
+    bool m_didSendValidCSPHeader;
+    bool m_didSendValidXSSProtectionHeader;
+
+    String m_decodedURL;
+    String m_decodedHTTPBody;
+    OwnPtr<SuffixTree<ASCIICodebook> > m_decodedHTTPBodySuffixTree;
+
+    State m_state;
+    String m_cachedDecodedSnippet;
+    unsigned m_scriptTagNestingLevel;
+    TextEncoding m_encoding;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/parser/XSSAuditorDelegate.cpp b/Source/core/html/parser/XSSAuditorDelegate.cpp
new file mode 100644
index 0000000..42db2f8
--- /dev/null
+++ b/Source/core/html/parser/XSSAuditorDelegate.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include "config.h"
+#include "core/html/parser/XSSAuditorDelegate.h"
+
+#include "core/dom/Document.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/loader/PingLoader.h"
+#include "core/page/Console.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/platform/network/FormData.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+XSSAuditorDelegate::XSSAuditorDelegate(Document* document)
+    : m_document(document)
+    , m_didSendNotifications(false)
+{
+    ASSERT(isMainThread());
+    ASSERT(m_document);
+}
+
+static inline String buildConsoleError(const XSSInfo& xssInfo, const String& url)
+{
+    StringBuilder message;
+    message.append("The XSS Auditor ");
+    message.append(xssInfo.m_didBlockEntirePage ? "blocked access to" : "refused to execute a script in");
+    message.append(" '");
+    message.append(url);
+    message.append("' because ");
+    message.append(xssInfo.m_didBlockEntirePage ? "the source code of a script" : "its source code");
+    message.append(" was found within the request.");
+
+    if (xssInfo.m_didSendCSPHeader)
+        message.append(" The server sent a 'Content-Security-Policy' header requesting this behavior.");
+    else if (xssInfo.m_didSendXSSProtectionHeader)
+        message.append(" The server sent an 'X-XSS-Protection' header requesting this behavior.");
+    else
+        message.append(" The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.");
+
+    return message.toString();
+}
+
+PassRefPtr<FormData> XSSAuditorDelegate::generateViolationReport()
+{
+    ASSERT(isMainThread());
+
+    FrameLoader* frameLoader = m_document->frame()->loader();
+    String httpBody;
+    if (frameLoader->documentLoader()) {
+        if (FormData* formData = frameLoader->documentLoader()->originalRequest().httpBody())
+            httpBody = formData->flattenToString();
+    }
+
+    RefPtr<InspectorObject> reportDetails = InspectorObject::create();
+    reportDetails->setString("request-url", m_document->url().string());
+    reportDetails->setString("request-body", httpBody);
+
+    RefPtr<InspectorObject> reportObject = InspectorObject::create();
+    reportObject->setObject("xss-report", reportDetails.release());
+
+    return FormData::create(reportObject->toJSONString().utf8().data());
+}
+
+void XSSAuditorDelegate::didBlockScript(const XSSInfo& xssInfo)
+{
+    ASSERT(isMainThread());
+
+    m_document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, buildConsoleError(xssInfo, m_document->url().string()));
+
+    // stopAllLoaders can detach the Frame, so protect it.
+    RefPtr<Frame> protect(m_document->frame());
+    FrameLoader* frameLoader = m_document->frame()->loader();
+    if (xssInfo.m_didBlockEntirePage)
+        frameLoader->stopAllLoaders();
+
+    if (!m_didSendNotifications) {
+        m_didSendNotifications = true;
+
+        frameLoader->client()->didDetectXSS(m_document->url(), xssInfo.m_didBlockEntirePage);
+
+        if (!m_reportURL.isEmpty())
+            PingLoader::sendViolationReport(m_document->frame(), m_reportURL, generateViolationReport());
+    }
+
+    if (xssInfo.m_didBlockEntirePage)
+        m_document->frame()->navigationScheduler()->scheduleLocationChange(m_document->securityOrigin(), SecurityOrigin::urlWithUniqueSecurityOrigin(), String());
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/parser/XSSAuditorDelegate.h b/Source/core/html/parser/XSSAuditorDelegate.h
new file mode 100644
index 0000000..8d4779c
--- /dev/null
+++ b/Source/core/html/parser/XSSAuditorDelegate.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 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 XSSAuditorDelegate_h
+#define XSSAuditorDelegate_h
+
+#include "core/platform/KURL.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/TextPosition.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Document;
+class FormData;
+
+class XSSInfo {
+public:
+    static PassOwnPtr<XSSInfo> create(bool didBlockEntirePage, bool didSendXSSProtectionHeader, bool didSendCSPHeader)
+    {
+        return adoptPtr(new XSSInfo(didBlockEntirePage, didSendXSSProtectionHeader, didSendCSPHeader));
+    }
+
+    bool m_didBlockEntirePage;
+    bool m_didSendXSSProtectionHeader;
+    bool m_didSendCSPHeader;
+    TextPosition m_textPosition;
+
+private:
+    XSSInfo(bool didBlockEntirePage, bool didSendXSSProtectionHeader, bool didSendCSPHeader)
+        : m_didBlockEntirePage(didBlockEntirePage)
+        , m_didSendXSSProtectionHeader(didSendXSSProtectionHeader)
+        , m_didSendCSPHeader(didSendCSPHeader)
+    { }
+};
+
+class XSSAuditorDelegate {
+    WTF_MAKE_NONCOPYABLE(XSSAuditorDelegate);
+public:
+    explicit XSSAuditorDelegate(Document*);
+
+    void didBlockScript(const XSSInfo&);
+    void setReportURL(const KURL& url) { m_reportURL = url; }
+
+private:
+    PassRefPtr<FormData> generateViolationReport();
+
+    Document* m_document;
+    bool m_didSendNotifications;
+    KURL m_reportURL;
+};
+
+typedef Vector<OwnPtr<XSSInfo> > XSSInfoStream;
+
+}
+
+#endif
diff --git a/Source/core/html/parser/create-html-entity-table b/Source/core/html/parser/create-html-entity-table
new file mode 100755
index 0000000..8c408fe
--- /dev/null
+++ b/Source/core/html/parser/create-html-entity-table
@@ -0,0 +1,185 @@
+#!/usr/bin/env python
+# 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:
+# 
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import csv
+import os.path
+import string
+import sys
+
+ENTITY = 0
+VALUE = 1
+
+def convert_entity_to_cpp_name(entity):
+    postfix = "EntityName"
+    if entity[-1] == ";":
+        return "%sSemicolon%s" % (entity[:-1], postfix)
+    return "%s%s" % (entity, postfix)
+
+
+def convert_entity_to_uchar_array(entity):
+    return "{'%s'}" % "', '".join(entity)
+
+
+def convert_value_to_int(value):
+    if not value:
+        return "0";
+    assert(value[0] == "U")
+    assert(value[1] == "+")
+    return "0x" + value[2:]
+
+
+def offset_table_entry(offset):
+    return "    &staticEntityTable[%s]," % offset
+
+
+program_name = os.path.basename(__file__)
+if len(sys.argv) < 4 or sys.argv[1] != "-o":
+    # Python 3, change to: print("Usage: %s -o OUTPUT_FILE INPUT_FILE" % program_name, file=sys.stderr)
+    sys.stderr.write("Usage: %s -o OUTPUT_FILE INPUT_FILE\n" % program_name)
+    exit(1)
+
+output_path = sys.argv[2]
+input_path = sys.argv[3]
+
+html_entity_names_file = open(input_path)
+entries = list(csv.reader(html_entity_names_file))
+html_entity_names_file.close()
+
+entries.sort(key = lambda entry: entry[ENTITY])
+entity_count = len(entries)
+
+output_file = open(output_path, "w")
+
+output_file.write("""/*
+ * 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. 
+ */
+
+// THIS FILE IS GENERATED BY WebCore/html/parser/create-html-entity-table
+// DO NOT EDIT (unless you are a ninja)!
+
+#include "config.h"
+#include "core/html/parser/HTMLEntityTable.h"
+
+namespace WebCore {
+
+namespace {
+""")
+
+for entry in entries:
+    output_file.write("static const UChar %s[] = %s;\n" % (
+        convert_entity_to_cpp_name(entry[ENTITY]),
+        convert_entity_to_uchar_array(entry[ENTITY])))
+
+output_file.write("""
+static const HTMLEntityTableEntry staticEntityTable[%s] = {\n""" % entity_count)
+
+index = {}
+offset = 0
+for entry in entries:
+    letter = entry[ENTITY][0]
+    if letter not in index:
+        index[letter] = offset
+    values = entry[VALUE].split(' ')
+    assert len(values) <= 2, values
+    output_file.write('    { %s, %s, %s, %s },\n' % (
+        convert_entity_to_cpp_name(entry[ENTITY]),
+        len(entry[ENTITY]),
+        convert_value_to_int(values[0]),
+        convert_value_to_int(values[1] if len(values) >= 2 else "")))
+    offset += 1
+
+output_file.write("""};
+
+""")
+
+output_file.write("static const HTMLEntityTableEntry* uppercaseOffset[] = {\n")
+for letter in string.ascii_uppercase:
+    output_file.write("%s\n" % offset_table_entry(index[letter]))
+output_file.write("%s\n" % offset_table_entry(index['a']))
+output_file.write("""};
+
+static const HTMLEntityTableEntry* lowercaseOffset[] = {\n""")
+for letter in string.ascii_lowercase:
+    output_file.write("%s\n" % offset_table_entry(index[letter]))
+output_file.write("%s\n" % offset_table_entry(entity_count))
+output_file.write("""};
+
+}
+
+const HTMLEntityTableEntry* HTMLEntityTable::firstEntryStartingWith(UChar c)
+{
+    if (c >= 'A' && c <= 'Z')
+        return uppercaseOffset[c - 'A'];
+    if (c >= 'a' && c <= 'z')
+        return lowercaseOffset[c - 'a'];
+    return 0;
+}
+
+const HTMLEntityTableEntry* HTMLEntityTable::lastEntryStartingWith(UChar c)
+{
+    if (c >= 'A' && c <= 'Z')
+        return uppercaseOffset[c - 'A' + 1] - 1;
+    if (c >= 'a' && c <= 'z')
+        return lowercaseOffset[c - 'a' + 1] - 1;
+    return 0;
+}
+
+const HTMLEntityTableEntry* HTMLEntityTable::firstEntry()
+{
+    return &staticEntityTable[0];
+}
+
+const HTMLEntityTableEntry* HTMLEntityTable::lastEntry()
+{
+    return &staticEntityTable[%s - 1];
+}
+
+}
+""" % entity_count)
diff --git a/Source/core/html/shadow/ClearButtonElement.cpp b/Source/core/html/shadow/ClearButtonElement.cpp
new file mode 100644
index 0000000..3558ace
--- /dev/null
+++ b/Source/core/html/shadow/ClearButtonElement.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2013 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. 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 "core/html/shadow/ClearButtonElement.h"
+
+#include "core/dom/MouseEvent.h"
+#include "core/page/EventHandler.h"
+#include "core/page/Frame.h"
+#include "core/rendering/RenderView.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline ClearButtonElement::ClearButtonElement(Document* document, ClearButtonOwner& clearButtonOwner)
+    : HTMLDivElement(divTag, document)
+    , m_clearButtonOwner(&clearButtonOwner)
+    , m_capturing(false)
+{
+    setPseudo(AtomicString("-webkit-clear-button", AtomicString::ConstructFromLiteral));
+}
+
+PassRefPtr<ClearButtonElement> ClearButtonElement::create(Document* document, ClearButtonOwner& clearButtonOwner)
+{
+    return adoptRef(new ClearButtonElement(document, clearButtonOwner));
+}
+
+void ClearButtonElement::detach()
+{
+    if (m_capturing) {
+        if (Frame* frame = document()->frame())
+            frame->eventHandler()->setCapturingMouseEventsNode(0);
+    }
+    HTMLDivElement::detach();
+}
+
+void ClearButtonElement::releaseCapture()
+{
+    if (!m_capturing)
+        return;
+
+    if (Frame* frame = document()->frame()) {
+        frame->eventHandler()->setCapturingMouseEventsNode(0);
+        m_capturing = false;
+    }
+}
+
+void ClearButtonElement::defaultEventHandler(Event* event)
+{
+    if (!m_clearButtonOwner) {
+        if (!event->defaultHandled())
+            HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    if (!m_clearButtonOwner->shouldClearButtonRespondToMouseEvents()) {
+        if (!event->defaultHandled())
+            HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+        if (renderer() && renderer()->visibleToHitTesting()) {
+            if (Frame* frame = document()->frame()) {
+                frame->eventHandler()->setCapturingMouseEventsNode(this);
+                m_capturing = true;
+            }
+        }
+        m_clearButtonOwner->focusAndSelectClearButtonOwner();
+        event->setDefaultHandled();
+    }
+    if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+        if (m_capturing) {
+            if (Frame* frame = document()->frame()) {
+                frame->eventHandler()->setCapturingMouseEventsNode(0);
+                m_capturing = false;
+            }
+            if (hovered()) {
+                m_clearButtonOwner->clearValue();
+                event->setDefaultHandled();
+            }
+        }
+    }
+
+    if (!event->defaultHandled())
+        HTMLDivElement::defaultEventHandler(event);
+}
+
+}
diff --git a/Source/core/html/shadow/ClearButtonElement.h b/Source/core/html/shadow/ClearButtonElement.h
new file mode 100644
index 0000000..bb5439b
--- /dev/null
+++ b/Source/core/html/shadow/ClearButtonElement.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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. 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 ClearButtonElement_h
+#define ClearButtonElement_h
+
+#include "core/html/HTMLDivElement.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class ClearButtonElement FINAL : public HTMLDivElement {
+public:
+    class ClearButtonOwner {
+    public:
+        virtual ~ClearButtonOwner() { }
+        virtual void focusAndSelectClearButtonOwner() = 0;
+        virtual bool shouldClearButtonRespondToMouseEvents() = 0;
+        virtual void clearValue() = 0;
+    };
+
+    static PassRefPtr<ClearButtonElement> create(Document*, ClearButtonOwner&);
+    void releaseCapture();
+    void removeClearButtonOwner() { m_clearButtonOwner = 0; }
+
+private:
+    ClearButtonElement(Document*, ClearButtonOwner&);
+    virtual void detach();
+    virtual bool isMouseFocusable() const { return false; }
+    virtual void defaultEventHandler(Event*);
+
+    ClearButtonOwner* m_clearButtonOwner;
+    bool m_capturing;
+};
+
+} // namespace
+
+#endif // ClearButtonElement_h
diff --git a/Source/core/html/shadow/ContentDistributor.cpp b/Source/core/html/shadow/ContentDistributor.cpp
new file mode 100644
index 0000000..9f30ad6
--- /dev/null
+++ b/Source/core/html/shadow/ContentDistributor.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/ContentDistributor.h"
+
+#include "core/dom/ElementShadow.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/shadow/ContentSelectorQuery.h"
+#include "core/html/shadow/HTMLContentElement.h"
+#include "core/html/shadow/HTMLShadowElement.h"
+
+
+namespace WebCore {
+
+void ContentDistribution::swap(ContentDistribution& other)
+{
+    m_nodes.swap(other.m_nodes);
+    m_indices.swap(other.m_indices);
+}
+
+void ContentDistribution::append(PassRefPtr<Node> node)
+{
+    size_t size = m_nodes.size();
+    m_indices.set(node.get(), size);
+    m_nodes.append(node);
+}
+
+size_t ContentDistribution::find(const Node* node) const
+{
+    HashMap<const Node*, size_t>::const_iterator it = m_indices.find(node);
+    if (it == m_indices.end())
+        return notFound;
+
+    return it.get()->value;
+}
+
+Node* ContentDistribution::nextTo(const Node* node) const
+{
+    size_t index = find(node);
+    if (index == notFound || index + 1 == size())
+        return 0;
+    return at(index + 1).get();
+}
+
+Node* ContentDistribution::previousTo(const Node* node) const
+{
+    size_t index = find(node);
+    if (index == notFound || !index)
+        return 0;
+    return at(index - 1).get();
+}
+
+
+ScopeContentDistribution::ScopeContentDistribution()
+    : m_insertionPointAssignedTo(0)
+    , m_numberOfShadowElementChildren(0)
+    , m_numberOfContentElementChildren(0)
+    , m_numberOfElementShadowChildren(0)
+    , m_insertionPointListIsValid(false)
+{
+}
+
+void ScopeContentDistribution::invalidateInsertionPointList()
+{
+    m_insertionPointListIsValid = false;
+    m_insertionPointList.clear();
+}
+
+const Vector<RefPtr<InsertionPoint> >& ScopeContentDistribution::ensureInsertionPointList(ShadowRoot* shadowRoot)
+{
+    if (m_insertionPointListIsValid)
+        return m_insertionPointList;
+
+    m_insertionPointListIsValid = true;
+    ASSERT(m_insertionPointList.isEmpty());
+
+    if (!hasInsertionPoint(shadowRoot))
+        return m_insertionPointList;
+
+    for (Element* element = ElementTraversal::firstWithin(shadowRoot); element; element = ElementTraversal::next(element, shadowRoot)) {
+        if (element->isInsertionPoint())
+            m_insertionPointList.append(toInsertionPoint(element));
+    }
+
+    return m_insertionPointList;
+}
+
+void ScopeContentDistribution::registerInsertionPoint(InsertionPoint* point)
+{
+    switch (point->insertionPointType()) {
+    case InsertionPoint::ShadowInsertionPoint:
+        ++m_numberOfShadowElementChildren;
+        break;
+    case InsertionPoint::ContentInsertionPoint:
+        ++m_numberOfContentElementChildren;
+        break;
+    }
+
+    invalidateInsertionPointList();
+}
+
+void ScopeContentDistribution::unregisterInsertionPoint(InsertionPoint* point)
+{
+    switch (point->insertionPointType()) {
+    case InsertionPoint::ShadowInsertionPoint:
+        ASSERT(m_numberOfShadowElementChildren > 0);
+        --m_numberOfShadowElementChildren;
+        break;
+    case InsertionPoint::ContentInsertionPoint:
+        ASSERT(m_numberOfContentElementChildren > 0);
+        --m_numberOfContentElementChildren;
+        break;
+    }
+
+    invalidateInsertionPointList();
+}
+
+bool ScopeContentDistribution::hasShadowElement(const ShadowRoot* holder)
+{
+    if (!holder->scopeDistribution())
+        return false;
+
+    return holder->scopeDistribution()->hasShadowElementChildren();
+}
+
+bool ScopeContentDistribution::hasContentElement(const ShadowRoot* holder)
+{
+    if (!holder->scopeDistribution())
+        return false;
+
+    return holder->scopeDistribution()->hasContentElementChildren();
+}
+
+unsigned ScopeContentDistribution::countElementShadow(const ShadowRoot* holder)
+{
+    if (!holder->scopeDistribution())
+        return 0;
+
+    return holder->scopeDistribution()->numberOfElementShadowChildren();
+}
+
+bool ScopeContentDistribution::hasInsertionPoint(const ShadowRoot* holder)
+{
+    return hasShadowElement(holder) || hasContentElement(holder);
+}
+
+InsertionPoint* ScopeContentDistribution::assignedTo(const ShadowRoot* holder)
+{
+    if (!holder->scopeDistribution())
+        return 0;
+
+    return holder->scopeDistribution()->insertionPointAssignedTo();
+}
+
+ContentDistributor::ContentDistributor()
+    : m_needsSelectFeatureSet(false)
+    , m_validity(Undetermined)
+{
+}
+
+ContentDistributor::~ContentDistributor()
+{
+}
+
+InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const
+{
+    return m_nodeToInsertionPoint.get(key).get();
+}
+
+void ContentDistributor::populate(Node* node, ContentDistribution& pool)
+{
+    if (!isActiveInsertionPoint(node)) {
+        pool.append(node);
+        return;
+    }
+
+    InsertionPoint* insertionPoint = toInsertionPoint(node);
+    if (insertionPoint->hasDistribution()) {
+        for (size_t i = 0; i < insertionPoint->size(); ++i)
+            populate(insertionPoint->at(i), pool);
+    } else {
+        for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling())
+            pool.append(fallbackNode);
+    }
+}
+
+void ContentDistributor::distribute(Element* host)
+{
+    ASSERT(needsDistribution());
+    ASSERT(m_nodeToInsertionPoint.isEmpty());
+    ASSERT(!host->containingShadowRoot() || host->containingShadowRoot()->owner()->distributor().isValid());
+
+    m_validity = Valid;
+
+    ContentDistribution pool;
+    for (Node* node = host->firstChild(); node; node = node->nextSibling())
+        populate(node, pool);
+
+    Vector<bool> distributed(pool.size());
+    distributed.fill(false);
+
+    Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints;
+    for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+        HTMLShadowElement* firstActiveShadowInsertionPoint = 0;
+
+        if (ScopeContentDistribution* scope = root->scopeDistribution()) {
+            const Vector<RefPtr<InsertionPoint> >& insertionPoints = scope->ensureInsertionPointList(root);
+            for (size_t i = 0; i < insertionPoints.size(); ++i) {
+                InsertionPoint* point = insertionPoints[i].get();
+                if (!point->isActive())
+                    continue;
+
+                if (isHTMLShadowElement(point)) {
+                    if (!firstActiveShadowInsertionPoint)
+                        firstActiveShadowInsertionPoint = toHTMLShadowElement(point);
+                } else {
+                    distributeSelectionsTo(point, pool, distributed);
+                    if (ElementShadow* shadow = point->parentNode()->isElementNode() ? toElement(point->parentNode())->shadow() : 0)
+                        shadow->invalidateDistribution();
+                }
+            }
+        }
+
+        if (firstActiveShadowInsertionPoint)
+            activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint);
+    }
+
+    for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) {
+        HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1];
+        ShadowRoot* root = shadowElement->containingShadowRoot();
+        ASSERT(root);
+        if (root->olderShadowRoot()) {
+            distributeNodeChildrenTo(shadowElement, root->olderShadowRoot());
+            root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPointAssignedTo(shadowElement);
+        } else {
+            distributeSelectionsTo(shadowElement, pool, distributed);
+            if (ElementShadow* shadow = shadowElement->parentNode()->isElementNode() ? toElement(shadowElement->parentNode())->shadow() : 0)
+                shadow->invalidateDistribution();
+        }
+    }
+}
+
+bool ContentDistributor::invalidate(Element* host)
+{
+    ASSERT(needsInvalidation());
+    bool needsReattach = (m_validity == Undetermined) || !m_nodeToInsertionPoint.isEmpty();
+
+    for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+        if (ScopeContentDistribution* scope = root->scopeDistribution()) {
+            scope->setInsertionPointAssignedTo(0);
+            const Vector<RefPtr<InsertionPoint> >& insertionPoints = scope->ensureInsertionPointList(root);
+            for (size_t i = 0; i < insertionPoints.size(); ++i) {
+                needsReattach = needsReattach || true;
+                insertionPoints[i]->clearDistribution();
+
+                // After insertionPoint's distribution is invalidated, its reprojection should also be invalidated.
+                if (!insertionPoints[i]->isActive())
+                    continue;
+
+                if (Element* parent = insertionPoints[i]->parentElement()) {
+                    if (ElementShadow* shadow = parent->shadow())
+                        shadow->invalidateDistribution();
+                }
+            }
+        }
+    }
+
+    m_validity = Invalidating;
+    m_nodeToInsertionPoint.clear();
+    return needsReattach;
+}
+
+void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, const ContentDistribution& pool, Vector<bool>& distributed)
+{
+    ContentDistribution distribution;
+    ContentSelectorQuery query(insertionPoint);
+
+    for (size_t i = 0; i < pool.size(); ++i) {
+        if (distributed[i])
+            continue;
+
+        if (!query.matches(pool.nodes(), i))
+            continue;
+
+        Node* child = pool.at(i).get();
+        distribution.append(child);
+        m_nodeToInsertionPoint.add(child, insertionPoint);
+        distributed[i] = true;
+    }
+
+    insertionPoint->setDistribution(distribution);
+}
+
+void ContentDistributor::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
+{
+    ContentDistribution distribution;
+    for (Node* node = containerNode->firstChild(); node; node = node->nextSibling()) {
+        if (isActiveInsertionPoint(node)) {
+            InsertionPoint* innerInsertionPoint = toInsertionPoint(node);
+            if (innerInsertionPoint->hasDistribution()) {
+                for (size_t i = 0; i < innerInsertionPoint->size(); ++i) {
+                    distribution.append(innerInsertionPoint->at(i));
+                    if (!m_nodeToInsertionPoint.contains(innerInsertionPoint->at(i)))
+                        m_nodeToInsertionPoint.add(innerInsertionPoint->at(i), insertionPoint);
+                }
+            } else {
+                for (Node* child = innerInsertionPoint->firstChild(); child; child = child->nextSibling()) {
+                    distribution.append(child);
+                    m_nodeToInsertionPoint.add(child, insertionPoint);
+                }
+            }
+        } else {
+            distribution.append(node);
+            if (!m_nodeToInsertionPoint.contains(node))
+                m_nodeToInsertionPoint.add(node, insertionPoint);
+        }
+    }
+
+    insertionPoint->setDistribution(distribution);
+}
+
+void ContentDistributor::ensureDistribution(ShadowRoot* shadowRoot)
+{
+    ASSERT(shadowRoot);
+
+    Vector<ElementShadow*, 8> elementShadows;
+    for (Element* current = shadowRoot->host(); current; current = current->shadowHost()) {
+        ElementShadow* elementShadow = current->shadow();
+        if (!elementShadow->distributor().needsDistribution())
+            break;
+
+        elementShadows.append(elementShadow);
+    }
+
+    for (size_t i = elementShadows.size(); i > 0; --i)
+        elementShadows[i - 1]->distributor().distribute(elementShadows[i - 1]->host());
+}
+
+
+void ContentDistributor::invalidateDistribution(Element* host)
+{
+    bool didNeedInvalidation = needsInvalidation();
+    bool needsReattach = didNeedInvalidation ? invalidate(host) : false;
+
+    if (needsReattach && host->attached()) {
+        for (Node* n = host->firstChild(); n; n = n->nextSibling())
+            n->lazyReattach();
+        host->setNeedsStyleRecalc();
+    }
+
+    if (didNeedInvalidation) {
+        ASSERT(m_validity == Invalidating);
+        m_validity = Invalidated;
+    }
+}
+
+const SelectRuleFeatureSet& ContentDistributor::ensureSelectFeatureSet(ElementShadow* shadow)
+{
+    if (!m_needsSelectFeatureSet)
+        return m_selectFeatures;
+
+    m_selectFeatures.clear();
+    for (ShadowRoot* root = shadow->oldestShadowRoot(); root; root = root->youngerShadowRoot())
+        collectSelectFeatureSetFrom(root);
+    m_needsSelectFeatureSet = false;
+    return m_selectFeatures;
+}
+
+void ContentDistributor::collectSelectFeatureSetFrom(ShadowRoot* root)
+{
+    if (ScopeContentDistribution::hasElementShadow(root)) {
+        for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(element)) {
+            if (ElementShadow* elementShadow = element->shadow())
+                m_selectFeatures.add(elementShadow->distributor().ensureSelectFeatureSet(elementShadow));
+        }
+    }
+
+    if (ScopeContentDistribution::hasContentElement(root)) {
+        for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(element)) {
+            if (!isHTMLContentElement(element))
+                continue;
+            const CSSSelectorList& list = toHTMLContentElement(element)->selectorList();
+            for (const CSSSelector* selector = list.first(); selector; selector = CSSSelectorList::next(selector)) {
+                for (const CSSSelector* component = selector; component; component = component->tagHistory())
+                    m_selectFeatures.collectFeaturesFromSelector(component);
+            }
+        }
+    }
+}
+
+void ContentDistributor::didAffectSelector(Element* host, AffectedSelectorMask mask)
+{
+    if (ensureSelectFeatureSet(host->shadow()).hasSelectorFor(mask))
+        invalidateDistribution(host);
+}
+
+void ContentDistributor::willAffectSelector(Element* host)
+{
+    for (ElementShadow* shadow = host->shadow(); shadow; shadow = shadow->containingShadow()) {
+        if (shadow->distributor().needsSelectFeatureSet())
+            break;
+        shadow->distributor().setNeedsSelectFeatureSet();
+    }
+
+    invalidateDistribution(host);
+}
+
+void ContentDistributor::didShadowBoundaryChange(Element* host)
+{
+    setValidity(Undetermined);
+    invalidateDistribution(host);
+}
+
+}
diff --git a/Source/core/html/shadow/ContentDistributor.h b/Source/core/html/shadow/ContentDistributor.h
new file mode 100644
index 0000000..1d3e657
--- /dev/null
+++ b/Source/core/html/shadow/ContentDistributor.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 ContentDistributor_h
+#define ContentDistributor_h
+
+#include "core/html/shadow/SelectRuleFeatureSet.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ContainerNode;
+class Element;
+class InsertionPoint;
+class Node;
+class ShadowRoot;
+
+class ContentDistribution {
+public:
+    PassRefPtr<Node> first() const { return m_nodes.first(); }
+    PassRefPtr<Node> last() const { return m_nodes.last(); }
+    PassRefPtr<Node> at(size_t index) const { return m_nodes.at(index); }
+
+    size_t size() const { return m_nodes.size(); }
+    bool isEmpty() const { return m_nodes.isEmpty(); }
+
+    void append(PassRefPtr<Node>);
+    void clear() { m_nodes.clear(); m_indices.clear(); }
+
+    bool contains(const Node* node) const { return m_indices.contains(node); }
+    size_t find(const Node*) const;
+    Node* nextTo(const Node*) const;
+    Node* previousTo(const Node*) const;
+
+    void swap(ContentDistribution& other);
+
+    const Vector<RefPtr<Node> >& nodes() const { return m_nodes; }
+
+private:
+    Vector<RefPtr<Node> > m_nodes;
+    HashMap<const Node*, size_t> m_indices;
+};
+
+class ScopeContentDistribution {
+public:
+    ScopeContentDistribution();
+
+    InsertionPoint* insertionPointAssignedTo() const { return m_insertionPointAssignedTo; }
+    void setInsertionPointAssignedTo(InsertionPoint* insertionPoint) { m_insertionPointAssignedTo = insertionPoint; }
+
+    void registerInsertionPoint(InsertionPoint*);
+    void unregisterInsertionPoint(InsertionPoint*);
+    bool hasShadowElementChildren() const { return m_numberOfShadowElementChildren > 0; }
+    bool hasContentElementChildren() const { return m_numberOfContentElementChildren > 0; }
+
+    void registerElementShadow() { ++m_numberOfElementShadowChildren; }
+    void unregisterElementShadow() { ASSERT(m_numberOfElementShadowChildren > 0); --m_numberOfElementShadowChildren; }
+    unsigned numberOfElementShadowChildren() const { return m_numberOfElementShadowChildren; }
+    bool hasElementShadowChildren() const { return m_numberOfElementShadowChildren > 0; }
+
+    void invalidateInsertionPointList();
+    const Vector<RefPtr<InsertionPoint> >& ensureInsertionPointList(ShadowRoot*);
+
+    bool isUsedForRendering() const;
+
+    static bool hasShadowElement(const ShadowRoot*);
+    static bool hasContentElement(const ShadowRoot*);
+    static bool hasInsertionPoint(const ShadowRoot*);
+    static bool hasElementShadow(const ShadowRoot* holder) { return countElementShadow(holder); }
+    static unsigned countElementShadow(const ShadowRoot*);
+    static InsertionPoint* assignedTo(const ShadowRoot*);
+
+private:
+    InsertionPoint* m_insertionPointAssignedTo;
+    unsigned m_numberOfShadowElementChildren;
+    unsigned m_numberOfContentElementChildren;
+    unsigned m_numberOfElementShadowChildren;
+    bool m_insertionPointListIsValid;
+    Vector<RefPtr<InsertionPoint> > m_insertionPointList;
+};
+
+class ContentDistributor {
+    WTF_MAKE_NONCOPYABLE(ContentDistributor);
+public:
+    enum Validity {
+        Valid = 0,
+        Invalidated = 1,
+        Invalidating = 2,
+        Undetermined = 3
+    };
+
+    ContentDistributor();
+    ~ContentDistributor();
+
+    InsertionPoint* findInsertionPointFor(const Node* key) const;
+    const SelectRuleFeatureSet& ensureSelectFeatureSet(ElementShadow*);
+
+    void distributeSelectionsTo(InsertionPoint*, const ContentDistribution& pool, Vector<bool>& distributed);
+    void distributeNodeChildrenTo(InsertionPoint*, ContainerNode*);
+
+    void invalidateDistribution(Element* host);
+    void didShadowBoundaryChange(Element* host);
+    void didAffectSelector(Element* host, AffectedSelectorMask);
+    void willAffectSelector(Element* host);
+
+    static void ensureDistribution(ShadowRoot*);
+
+private:
+    void distribute(Element* host);
+    bool invalidate(Element* host);
+    void populate(Node*, ContentDistribution&);
+
+    void collectSelectFeatureSetFrom(ShadowRoot*);
+    bool needsSelectFeatureSet() const { return m_needsSelectFeatureSet; }
+    void setNeedsSelectFeatureSet() { m_needsSelectFeatureSet = true; }
+
+    void setValidity(Validity validity) { m_validity = validity; }
+    bool isValid() const { return m_validity == Valid; }
+    bool needsDistribution() const;
+    bool needsInvalidation() const { return m_validity != Invalidated; }
+
+    HashMap<const Node*, RefPtr<InsertionPoint> > m_nodeToInsertionPoint;
+    SelectRuleFeatureSet m_selectFeatures;
+    bool m_needsSelectFeatureSet : 1;
+    unsigned m_validity : 2;
+};
+
+inline bool ContentDistributor::needsDistribution() const
+{
+    // During the invalidation, re-distribution should be supressed.
+    return m_validity != Valid && m_validity != Invalidating;
+}
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/ContentSelectorQuery.cpp b/Source/core/html/shadow/ContentSelectorQuery.cpp
new file mode 100644
index 0000000..418e159
--- /dev/null
+++ b/Source/core/html/shadow/ContentSelectorQuery.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/ContentSelectorQuery.h"
+
+#include "core/css/CSSSelectorList.h"
+#include "core/css/SelectorChecker.h"
+#include "core/css/SiblingTraversalStrategies.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/shadow/InsertionPoint.h"
+
+namespace WebCore {
+
+bool ContentSelectorDataList::checkContentSelector(const CSSSelector* selector, const Vector<RefPtr<Node> >& siblings, int nth)
+{
+    Element* element = toElement(siblings[nth].get());
+    SelectorChecker selectorChecker(element->document(), SelectorChecker::CollectingRules);
+    SelectorChecker::SelectorCheckingContext context(selector, element, SelectorChecker::VisitedMatchEnabled);
+    ShadowDOMSiblingTraversalStrategy strategy(siblings, nth);
+    PseudoId ignoreDynamicPseudo = NOPSEUDO;
+    return selectorChecker.match(context, ignoreDynamicPseudo, strategy) == SelectorChecker::SelectorMatches;
+}
+
+void ContentSelectorDataList::initialize(const CSSSelectorList& selectors)
+{
+    for (const CSSSelector* selector = selectors.first(); selector; selector = CSSSelectorList::next(selector))
+        m_selectors.append(selector);
+}
+
+bool ContentSelectorDataList::matches(const Vector<RefPtr<Node> >& siblings, int nth) const
+{
+    unsigned selectorCount = m_selectors.size();
+    for (unsigned i = 0; i < selectorCount; ++i) {
+        if (checkContentSelector(m_selectors[i], siblings, nth))
+            return true;
+    }
+    return false;
+}
+
+ContentSelectorQuery::ContentSelectorQuery(InsertionPoint* insertionPoint)
+    : m_insertionPoint(insertionPoint)
+{
+    m_selectors.initialize(insertionPoint->selectorList());
+}
+
+bool ContentSelectorQuery::matches(const Vector<RefPtr<Node> >& siblings, int nth) const
+{
+    Node* node = siblings[nth].get();
+    ASSERT(node);
+
+    switch (m_insertionPoint->matchTypeFor(node)) {
+    case InsertionPoint::AlwaysMatches:
+        return true;
+    case InsertionPoint::NeverMatches:
+        return false;
+    case InsertionPoint::HasToMatchSelector:
+        return node->isElementNode() && m_selectors.matches(siblings, nth);
+    default:
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+}
+
+}
diff --git a/Source/core/html/shadow/ContentSelectorQuery.h b/Source/core/html/shadow/ContentSelectorQuery.h
new file mode 100644
index 0000000..b86098d
--- /dev/null
+++ b/Source/core/html/shadow/ContentSelectorQuery.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 ContentSelectorQuery_h
+#define ContentSelectorQuery_h
+
+#include "core/css/CSSSelectorList.h"
+#include "core/css/SelectorChecker.h"
+#include "core/dom/SelectorQuery.h"
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Document;
+class Node;
+class InsertionPoint;
+
+class ContentSelectorDataList {
+public:
+    void initialize(const CSSSelectorList&);
+    bool matches(const Vector<RefPtr<Node> >& siblings, int nthNode) const;
+
+private:
+    static bool checkContentSelector(const CSSSelector*, const Vector<RefPtr<Node> >& siblings, int nthNode);
+
+    Vector<const CSSSelector*> m_selectors;
+};
+
+class ContentSelectorQuery {
+    WTF_MAKE_NONCOPYABLE(ContentSelectorQuery);
+public:
+    explicit ContentSelectorQuery(InsertionPoint*);
+
+    bool matches(const Vector<RefPtr<Node> >& siblings, int nthNode) const;
+
+private:
+    InsertionPoint* m_insertionPoint;
+    ContentSelectorDataList m_selectors;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/DateTimeEditElement.cpp b/Source/core/html/shadow/DateTimeEditElement.cpp
new file mode 100644
index 0000000..1e323a1
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeEditElement.cpp
@@ -0,0 +1,798 @@
+/*
+ * Copyright (C) 2012 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. 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"
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/shadow/DateTimeEditElement.h"
+
+#include "HTMLNames.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/Text.h"
+#include "core/html/DateTimeFieldsState.h"
+#include "core/html/shadow/DateTimeFieldElements.h"
+#include "core/html/shadow/DateTimeSymbolicFieldElement.h"
+#include "core/page/EventHandler.h"
+#include "core/platform/DateComponents.h"
+#include "core/platform/graphics/FontCache.h"
+#include "core/platform/text/DateTimeFormat.h"
+#include "core/platform/text/PlatformLocale.h"
+#include "core/rendering/style/RenderStyle.h"
+#include <wtf/DateMath.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace WTF::Unicode;
+
+class DateTimeEditBuilder : private DateTimeFormat::TokenHandler {
+    WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder);
+
+public:
+    // The argument objects must be alive until this object dies.
+    DateTimeEditBuilder(DateTimeEditElement&, const DateTimeEditElement::LayoutParameters&, const DateComponents&);
+
+    bool build(const String&);
+
+private:
+    bool needMillisecondField() const;
+    bool shouldAMPMFieldDisabled() const;
+    bool shouldDayOfMonthFieldDisabled() const;
+    bool shouldHourFieldDisabled() const;
+    bool shouldMillisecondFieldDisabled() const;
+    bool shouldMinuteFieldDisabled() const;
+    bool shouldSecondFieldDisabled() const;
+    bool shouldYearFieldDisabled() const;
+    inline const StepRange& stepRange() const { return m_parameters.stepRange; }
+    DateTimeNumericFieldElement::Step createStep(double msPerFieldUnit, double msPerFieldSize) const;
+
+    // DateTimeFormat::TokenHandler functions.
+    virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL;
+    virtual void visitLiteral(const String&) OVERRIDE FINAL;
+
+    DateTimeEditElement& m_editElement;
+    const DateComponents m_dateValue;
+    const DateTimeEditElement::LayoutParameters& m_parameters;
+    DateTimeNumericFieldElement::Range m_dayRange;
+    DateTimeNumericFieldElement::Range m_hour23Range;
+    DateTimeNumericFieldElement::Range m_minuteRange;
+    DateTimeNumericFieldElement::Range m_secondRange;
+    DateTimeNumericFieldElement::Range m_millisecondRange;
+};
+
+DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& dateValue)
+    : m_editElement(elemnt)
+    , m_dateValue(dateValue)
+    , m_parameters(layoutParameters)
+    , m_dayRange(1, 31)
+    , m_hour23Range(0, 23)
+    , m_minuteRange(0, 59)
+    , m_secondRange(0, 59)
+    , m_millisecondRange(0, 999)
+{
+    if (m_dateValue.type() == DateComponents::Date
+        || m_dateValue.type() == DateComponents::DateTimeLocal
+        || m_dateValue.type() == DateComponents::DateTime) {
+        if (m_parameters.minimum.type() != DateComponents::Invalid
+            && m_parameters.maximum.type() != DateComponents::Invalid
+            && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
+            && m_parameters.minimum.month() == m_parameters.maximum.month()
+            && m_parameters.minimum.monthDay() <= m_parameters.maximum.monthDay()) {
+            m_dayRange.minimum = m_parameters.minimum.monthDay();
+            m_dayRange.maximum = m_parameters.maximum.monthDay();
+        }
+    }
+
+    if (m_dateValue.type() == DateComponents::Time || m_dayRange.isSingleton()) {
+        if (m_parameters.minimum.type() != DateComponents::Invalid
+            && m_parameters.maximum.type() != DateComponents::Invalid
+            && m_parameters.minimum.hour() <= m_parameters.maximum.hour()) {
+            m_hour23Range.minimum = m_parameters.minimum.hour();
+            m_hour23Range.maximum = m_parameters.maximum.hour();
+        }
+    }
+
+    if (m_hour23Range.isSingleton() && m_parameters.minimum.minute() <= m_parameters.maximum.minute()) {
+        m_minuteRange.minimum = m_parameters.minimum.minute();
+        m_minuteRange.maximum = m_parameters.maximum.minute();
+    }
+    if (m_minuteRange.isSingleton() && m_parameters.minimum.second() <= m_parameters.maximum.second()) {
+        m_secondRange.minimum = m_parameters.minimum.second();
+        m_secondRange.maximum = m_parameters.maximum.second();
+    }
+    if (m_secondRange.isSingleton() && m_parameters.minimum.millisecond() <= m_parameters.maximum.millisecond()) {
+        m_millisecondRange.minimum = m_parameters.minimum.millisecond();
+        m_millisecondRange.maximum = m_parameters.maximum.millisecond();
+    }
+}
+
+bool DateTimeEditBuilder::build(const String& formatString)
+{
+    m_editElement.resetFields();
+    return DateTimeFormat::parse(formatString, *this);
+}
+
+bool DateTimeEditBuilder::needMillisecondField() const
+{
+    return m_dateValue.millisecond()
+        || !stepRange().minimum().remainder(static_cast<int>(msPerSecond)).isZero()
+        || !stepRange().step().remainder(static_cast<int>(msPerSecond)).isZero();
+}
+
+void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int count)
+{
+    const int countForAbbreviatedMonth = 3;
+    const int countForFullMonth = 4;
+    const int countForNarrowMonth = 5;
+    Document* const document = m_editElement.document();
+
+    switch (fieldType) {
+    case DateTimeFormat::FieldTypeDayOfMonth: {
+        RefPtr<DateTimeFieldElement> field = DateTimeDayFieldElement::create(document, m_editElement, m_parameters.placeholderForDay, m_dayRange);
+        m_editElement.addField(field);
+        if (shouldDayOfMonthFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeHour11: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12);
+        RefPtr<DateTimeFieldElement> field = DateTimeHour11FieldElement::create(document, m_editElement, m_hour23Range, step);
+        m_editElement.addField(field);
+        if (shouldHourFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeHour12: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12);
+        RefPtr<DateTimeFieldElement> field = DateTimeHour12FieldElement::create(document, m_editElement, m_hour23Range, step);
+        m_editElement.addField(field);
+        if (shouldHourFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeHour23: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay);
+        RefPtr<DateTimeFieldElement> field = DateTimeHour23FieldElement::create(document, m_editElement, m_hour23Range, step);
+        m_editElement.addField(field);
+        if (shouldHourFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeHour24: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay);
+        RefPtr<DateTimeFieldElement> field = DateTimeHour24FieldElement::create(document, m_editElement, m_hour23Range, step);
+        m_editElement.addField(field);
+        if (shouldHourFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeMinute: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerMinute, msPerHour);
+        RefPtr<DateTimeNumericFieldElement> field = DateTimeMinuteFieldElement::create(document, m_editElement, m_minuteRange, step);
+        m_editElement.addField(field);
+        if (shouldMinuteFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeMonth: // Fallthrough.
+    case DateTimeFormat::FieldTypeMonthStandAlone: {
+        int minMonth = 0, maxMonth = 11;
+        if (m_parameters.minimum.type() != DateComponents::Invalid
+            && m_parameters.maximum.type() != DateComponents::Invalid
+            && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
+            && m_parameters.minimum.month() <= m_parameters.maximum.month()) {
+            minMonth = m_parameters.minimum.month();
+            maxMonth = m_parameters.maximum.month();
+        }
+        RefPtr<DateTimeFieldElement> field;
+        switch (count) {
+        case countForNarrowMonth: // Fallthrough.
+        case countForAbbreviatedMonth:
+            field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.shortMonthLabels() : m_parameters.locale.shortStandAloneMonthLabels(), minMonth, maxMonth);
+            break;
+        case countForFullMonth:
+            field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.monthLabels() : m_parameters.locale.standAloneMonthLabels(), minMonth, maxMonth);
+            break;
+        default:
+            field = DateTimeMonthFieldElement::create(document, m_editElement, m_parameters.placeholderForMonth, DateTimeNumericFieldElement::Range(minMonth + 1, maxMonth + 1));
+            break;
+        }
+        m_editElement.addField(field);
+        if (minMonth == maxMonth && minMonth == m_dateValue.month() && m_dateValue.type() != DateComponents::Month) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypePeriod: {
+        RefPtr<DateTimeFieldElement> field = DateTimeAMPMFieldElement::create(document, m_editElement, m_parameters.locale.timeAMPMLabels());
+        m_editElement.addField(field);
+        if (shouldAMPMFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeSecond: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerSecond, msPerMinute);
+        RefPtr<DateTimeNumericFieldElement> field = DateTimeSecondFieldElement::create(document, m_editElement, m_secondRange, step);
+        m_editElement.addField(field);
+        if (shouldSecondFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+
+        if (needMillisecondField()) {
+            visitLiteral(m_parameters.locale.localizedDecimalSeparator());
+            visitField(DateTimeFormat::FieldTypeFractionalSecond, 3);
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeFractionalSecond: {
+        DateTimeNumericFieldElement::Step step = createStep(1, msPerSecond);
+        RefPtr<DateTimeNumericFieldElement> field = DateTimeMillisecondFieldElement::create(document, m_editElement, m_millisecondRange, step);
+        m_editElement.addField(field);
+        if (shouldMillisecondFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeWeekOfYear: {
+        DateTimeNumericFieldElement::Range range(DateComponents::minimumWeekNumber, DateComponents::maximumWeekNumber);
+        if (m_parameters.minimum.type() != DateComponents::Invalid
+            && m_parameters.maximum.type() != DateComponents::Invalid
+            && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
+            && m_parameters.minimum.week() <= m_parameters.maximum.week()) {
+            range.minimum = m_parameters.minimum.week();
+            range.maximum = m_parameters.maximum.week();
+        }
+        m_editElement.addField(DateTimeWeekFieldElement::create(document, m_editElement, range));
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeYear: {
+        DateTimeYearFieldElement::Parameters yearParams;
+        if (m_parameters.minimum.type() == DateComponents::Invalid) {
+            yearParams.minimumYear = DateComponents::minimumYear();
+            yearParams.minIsSpecified = false;
+        } else {
+            yearParams.minimumYear = m_parameters.minimum.fullYear();
+            yearParams.minIsSpecified = true;
+        }
+        if (m_parameters.maximum.type() == DateComponents::Invalid) {
+            yearParams.maximumYear = DateComponents::maximumYear();
+            yearParams.maxIsSpecified = false;
+        } else {
+            yearParams.maximumYear = m_parameters.maximum.fullYear();
+            yearParams.maxIsSpecified = true;
+        }
+        if (yearParams.minimumYear > yearParams.maximumYear) {
+            std::swap(yearParams.minimumYear, yearParams.maximumYear);
+            std::swap(yearParams.minIsSpecified, yearParams.maxIsSpecified);
+        }
+        yearParams.placeholder = m_parameters.placeholderForYear;
+        RefPtr<DateTimeFieldElement> field = DateTimeYearFieldElement::create(document, m_editElement, yearParams);
+        m_editElement.addField(field);
+        if (shouldYearFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    default:
+        return;
+    }
+}
+
+bool DateTimeEditBuilder::shouldAMPMFieldDisabled() const
+{
+    return shouldHourFieldDisabled()
+        || (m_hour23Range.minimum < 12 && m_hour23Range.maximum < 12 && m_dateValue.hour() < 12)
+        || (m_hour23Range.minimum >= 12 && m_hour23Range.maximum >= 12 && m_dateValue.hour() >= 12);
+}
+
+bool DateTimeEditBuilder::shouldDayOfMonthFieldDisabled() const
+{
+    return m_dayRange.isSingleton() && m_dayRange.minimum == m_dateValue.monthDay() && m_dateValue.type() != DateComponents::Date;
+}
+
+bool DateTimeEditBuilder::shouldHourFieldDisabled() const
+{
+    if (m_hour23Range.isSingleton() && m_hour23Range.minimum == m_dateValue.hour()
+        && !(shouldMinuteFieldDisabled() && shouldSecondFieldDisabled() && shouldMillisecondFieldDisabled()))
+        return true;
+
+    if (m_dateValue.type() == DateComponents::Time)
+        return false;
+    ASSERT(m_dateValue.type() == DateComponents::DateTimeLocal || m_dateValue.type() == DateComponents::DateTime);
+
+    if (shouldDayOfMonthFieldDisabled()) {
+        ASSERT(m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear());
+        ASSERT(m_parameters.minimum.month() == m_parameters.maximum.month());
+        return false;
+    }
+
+    const Decimal decimalMsPerDay(static_cast<int>(msPerDay));
+    Decimal hourPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerDay) / static_cast<int>(msPerHour)).floor();
+    return hourPartOfMinimum == m_dateValue.hour() && stepRange().step().remainder(decimalMsPerDay).isZero();
+}
+
+bool DateTimeEditBuilder::shouldMillisecondFieldDisabled() const
+{
+    if (m_millisecondRange.isSingleton() && m_millisecondRange.minimum == m_dateValue.millisecond())
+        return true;
+
+    const Decimal decimalMsPerSecond(static_cast<int>(msPerSecond));
+    return stepRange().minimum().abs().remainder(decimalMsPerSecond) == m_dateValue.millisecond() && stepRange().step().remainder(decimalMsPerSecond).isZero();
+}
+
+bool DateTimeEditBuilder::shouldMinuteFieldDisabled() const
+{
+    if (m_minuteRange.isSingleton() && m_minuteRange.minimum == m_dateValue.minute())
+        return true;
+
+    const Decimal decimalMsPerHour(static_cast<int>(msPerHour));
+    Decimal minutePartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerHour) / static_cast<int>(msPerMinute)).floor();
+    return minutePartOfMinimum == m_dateValue.minute() && stepRange().step().remainder(decimalMsPerHour).isZero();
+}
+
+bool DateTimeEditBuilder::shouldSecondFieldDisabled() const
+{
+    if (m_secondRange.isSingleton() && m_secondRange.minimum == m_dateValue.second())
+        return true;
+
+    const Decimal decimalMsPerMinute(static_cast<int>(msPerMinute));
+    Decimal secondPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerMinute) / static_cast<int>(msPerSecond)).floor();
+    return secondPartOfMinimum == m_dateValue.second() && stepRange().step().remainder(decimalMsPerMinute).isZero();
+}
+
+bool DateTimeEditBuilder::shouldYearFieldDisabled() const
+{
+    return m_parameters.minimum.type() != DateComponents::Invalid
+        && m_parameters.maximum.type() != DateComponents::Invalid
+        && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
+        && m_parameters.minimum.fullYear() == m_dateValue.fullYear();
+}
+
+void DateTimeEditBuilder::visitLiteral(const String& text)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, textPseudoId, ("-webkit-datetime-edit-text", AtomicString::ConstructFromLiteral));
+    ASSERT(text.length());
+    RefPtr<HTMLDivElement> element = HTMLDivElement::create(m_editElement.document());
+    element->setPseudo(textPseudoId);
+    if (m_parameters.locale.isRTL() && text.length()) {
+        Direction dir = direction(text[0]);
+        if (dir == SegmentSeparator || dir == WhiteSpaceNeutral || dir == OtherNeutral)
+            element->appendChild(Text::create(m_editElement.document(), String(&rightToLeftMark, 1)));
+    }
+    element->appendChild(Text::create(m_editElement.document(), text));
+    m_editElement.fieldsWrapperElement()->appendChild(element);
+}
+
+DateTimeNumericFieldElement::Step DateTimeEditBuilder::createStep(double msPerFieldUnit, double msPerFieldSize) const
+{
+    const Decimal msPerFieldUnitDecimal(static_cast<int>(msPerFieldUnit));
+    const Decimal msPerFieldSizeDecimal(static_cast<int>(msPerFieldSize));
+    Decimal stepMilliseconds = stepRange().step();
+    ASSERT(!msPerFieldUnitDecimal.isZero());
+    ASSERT(!msPerFieldSizeDecimal.isZero());
+    ASSERT(!stepMilliseconds.isZero());
+
+    DateTimeNumericFieldElement::Step step(1, 0);
+
+    if (stepMilliseconds.remainder(msPerFieldSizeDecimal).isZero())
+        stepMilliseconds = msPerFieldSizeDecimal;
+
+    if (msPerFieldSizeDecimal.remainder(stepMilliseconds).isZero() && stepMilliseconds.remainder(msPerFieldUnitDecimal).isZero()) {
+        step.step = static_cast<int>((stepMilliseconds / msPerFieldUnitDecimal).toDouble());
+        step.stepBase = static_cast<int>((stepRange().stepBase() / msPerFieldUnitDecimal).floor().remainder(msPerFieldSizeDecimal / msPerFieldUnitDecimal).toDouble());
+    }
+    return step;
+}
+
+// ----------------------------
+
+DateTimeEditElement::EditControlOwner::~EditControlOwner()
+{
+}
+
+DateTimeEditElement::DateTimeEditElement(Document* document, EditControlOwner& editControlOwner)
+    : HTMLDivElement(divTag, document)
+    , m_editControlOwner(&editControlOwner)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, dateTimeEditPseudoId, ("-webkit-datetime-edit", AtomicString::ConstructFromLiteral));
+    setPseudo(dateTimeEditPseudoId);
+    setHasCustomStyleCallbacks();
+}
+
+DateTimeEditElement::~DateTimeEditElement()
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->removeEventHandler();
+}
+
+inline Element* DateTimeEditElement::fieldsWrapperElement() const
+{
+    ASSERT(firstChild());
+    return toElement(firstChild());
+}
+
+void DateTimeEditElement::addField(PassRefPtr<DateTimeFieldElement> field)
+{
+    if (m_fields.size() == m_fields.capacity())
+        return;
+    m_fields.append(field.get());
+    fieldsWrapperElement()->appendChild(field);
+}
+
+bool DateTimeEditElement::anyEditableFieldsHaveValues() const
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
+        if (!m_fields[fieldIndex]->isDisabled() && m_fields[fieldIndex]->hasValue())
+            return true;
+    }
+    return false;
+}
+
+void DateTimeEditElement::blurByOwner()
+{
+    if (DateTimeFieldElement* field = focusedField())
+        field->blur();
+}
+
+PassRefPtr<DateTimeEditElement> DateTimeEditElement::create(Document* document, EditControlOwner& editControlOwner)
+{
+    RefPtr<DateTimeEditElement> container = adoptRef(new DateTimeEditElement(document, editControlOwner));
+    return container.release();
+}
+
+PassRefPtr<RenderStyle> DateTimeEditElement::customStyleForRenderer()
+{
+    // FIXME: This is a kind of layout. We might want to introduce new renderer.
+    FontCachePurgePreventer fontCachePurgePreventer;
+    RefPtr<RenderStyle> originalStyle = document()->styleResolver()->styleForElement(this);
+    RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
+    float width = 0;
+    for (Node* child = fieldsWrapperElement()->firstChild(); child; child = child->nextSibling()) {
+        if (!child->isElementNode())
+            continue;
+        Element* childElement = toElement(child);
+        if (childElement->isDateTimeFieldElement()) {
+            // We need to pass the Font of this element because child elements
+            // can't resolve inherited style at this timing.
+            width += static_cast<DateTimeFieldElement*>(childElement)->maximumWidth(style->font());
+        } else {
+            // ::-webkit-datetime-edit-text case. It has no
+            // border/padding/margin in html.css.
+            width += style->font().width(childElement->textContent());
+        }
+    }
+    style->setWidth(Length(ceilf(width), Fixed));
+    return style.release();
+}
+
+void DateTimeEditElement::didBlurFromField()
+{
+    if (m_editControlOwner)
+        m_editControlOwner->didBlurFromControl();
+}
+
+void DateTimeEditElement::didFocusOnField()
+{
+    if (m_editControlOwner)
+        m_editControlOwner->didFocusOnControl();
+}
+
+void DateTimeEditElement::disabledStateChanged()
+{
+    updateUIState();
+}
+
+DateTimeFieldElement* DateTimeEditElement::fieldAt(size_t fieldIndex) const
+{
+    return fieldIndex < m_fields.size() ? m_fields[fieldIndex] : 0;
+}
+
+size_t DateTimeEditElement::fieldIndexOf(const DateTimeFieldElement& field) const
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
+        if (m_fields[fieldIndex] == &field)
+            return fieldIndex;
+    }
+    return invalidFieldIndex;
+}
+
+void DateTimeEditElement::focusIfNoFocus()
+{
+    if (focusedFieldIndex() != invalidFieldIndex)
+        return;
+    focusOnNextFocusableField(0);
+}
+
+void DateTimeEditElement::focusByOwner(Node* oldFocusedNode)
+{
+    if (oldFocusedNode && oldFocusedNode->isElementNode() && toElement(oldFocusedNode)->isDateTimeFieldElement()) {
+        DateTimeFieldElement* oldFocusedField = static_cast<DateTimeFieldElement*>(oldFocusedNode);
+        size_t index = fieldIndexOf(*oldFocusedField);
+        if (index != invalidFieldIndex && oldFocusedField->isFocusable()) {
+            oldFocusedField->focus();
+            return;
+        }
+    }
+    focusOnNextFocusableField(0);
+}
+
+DateTimeFieldElement* DateTimeEditElement::focusedField() const
+{
+    return fieldAt(focusedFieldIndex());
+}
+
+size_t DateTimeEditElement::focusedFieldIndex() const
+{
+    Node* const focusedFieldNode = document()->focusedNode();
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
+        if (m_fields[fieldIndex] == focusedFieldNode)
+            return fieldIndex;
+    }
+    return invalidFieldIndex;
+}
+
+void DateTimeEditElement::fieldValueChanged()
+{
+    if (m_editControlOwner)
+        m_editControlOwner->editControlValueChanged();
+}
+
+bool DateTimeEditElement::focusOnNextFocusableField(size_t startIndex)
+{
+    for (size_t fieldIndex = startIndex; fieldIndex < m_fields.size(); ++fieldIndex) {
+        if (m_fields[fieldIndex]->isFocusable()) {
+            m_fields[fieldIndex]->focus();
+            return true;
+        }
+    }
+    return false;
+}
+
+bool DateTimeEditElement::focusOnNextField(const DateTimeFieldElement& field)
+{
+    const size_t startFieldIndex = fieldIndexOf(field);
+    if (startFieldIndex == invalidFieldIndex)
+        return false;
+    return focusOnNextFocusableField(startFieldIndex + 1);
+}
+
+bool DateTimeEditElement::focusOnPreviousField(const DateTimeFieldElement& field)
+{
+    const size_t startFieldIndex = fieldIndexOf(field);
+    if (startFieldIndex == invalidFieldIndex)
+        return false;
+    size_t fieldIndex = startFieldIndex;
+    while (fieldIndex > 0) {
+        --fieldIndex;
+        if (m_fields[fieldIndex]->isFocusable()) {
+            m_fields[fieldIndex]->focus();
+            return true;
+        }
+    }
+    return false;
+}
+
+bool DateTimeEditElement::isDisabled() const
+{
+    return m_editControlOwner && m_editControlOwner->isEditControlOwnerDisabled();
+}
+
+bool DateTimeEditElement::isFieldOwnerDisabled() const
+{
+    return isDisabled();
+}
+
+bool DateTimeEditElement::isFieldOwnerReadOnly() const
+{
+    return isReadOnly();
+}
+
+bool DateTimeEditElement::isReadOnly() const
+{
+    return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly();
+}
+
+void DateTimeEditElement::layout(const LayoutParameters& layoutParameters, const DateComponents& dateValue)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, fieldsWrapperPseudoId, ("-webkit-datetime-edit-fields-wrapper", AtomicString::ConstructFromLiteral));
+    if (!firstChild()) {
+        RefPtr<HTMLDivElement> element = HTMLDivElement::create(document());
+        element->setPseudo(fieldsWrapperPseudoId);
+        appendChild(element.get());
+    }
+    Element* fieldsWrapper = fieldsWrapperElement();
+
+    size_t focusedFieldIndex = this->focusedFieldIndex();
+    DateTimeFieldElement* const focusedField = fieldAt(focusedFieldIndex);
+    const AtomicString focusedFieldId = focusedField ? focusedField->shadowPseudoId() : nullAtom;
+
+    DateTimeEditBuilder builder(*this, layoutParameters, dateValue);
+    Node* lastChildToBeRemoved = fieldsWrapper->lastChild();
+    if (!builder.build(layoutParameters.dateTimeFormat) || m_fields.isEmpty()) {
+        lastChildToBeRemoved = fieldsWrapper->lastChild();
+        builder.build(layoutParameters.fallbackDateTimeFormat);
+    }
+
+    if (focusedFieldIndex != invalidFieldIndex) {
+        for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
+            if (m_fields[fieldIndex]->shadowPseudoId() == focusedFieldId) {
+                focusedFieldIndex = fieldIndex;
+                break;
+            }
+        }
+        if (DateTimeFieldElement* field = fieldAt(std::min(focusedFieldIndex, m_fields.size() - 1)))
+            field->focus();
+    }
+
+    if (lastChildToBeRemoved) {
+        for (Node* childNode = fieldsWrapper->firstChild(); childNode; childNode = fieldsWrapper->firstChild()) {
+            fieldsWrapper->removeChild(childNode);
+            if (childNode == lastChildToBeRemoved)
+                break;
+        }
+        setNeedsStyleRecalc();
+    }
+}
+
+AtomicString DateTimeEditElement::localeIdentifier() const
+{
+    return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom;
+}
+
+void DateTimeEditElement::readOnlyStateChanged()
+{
+    updateUIState();
+}
+
+void DateTimeEditElement::resetFields()
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->removeEventHandler();
+    m_fields.shrink(0);
+}
+
+void DateTimeEditElement::defaultEventHandler(Event* event)
+{
+    // In case of control owner forward event to control, e.g. DOM
+    // dispatchEvent method.
+    if (DateTimeFieldElement* field = focusedField()) {
+        field->defaultEventHandler(event);
+        if (event->defaultHandled())
+            return;
+    }
+
+    HTMLDivElement::defaultEventHandler(event);
+}
+
+void DateTimeEditElement::setValueAsDate(const LayoutParameters& layoutParameters, const DateComponents& date)
+{
+    layout(layoutParameters, date);
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->setValueAsDate(date);
+}
+
+void DateTimeEditElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->setValueAsDateTimeFieldsState(dateTimeFieldsState);
+}
+
+void DateTimeEditElement::setEmptyValue(const LayoutParameters& layoutParameters, const DateComponents& dateForReadOnlyField)
+{
+    layout(layoutParameters, dateForReadOnlyField);
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->setEmptyValue(DateTimeFieldElement::DispatchNoEvent);
+}
+
+bool DateTimeEditElement::hasFocusedField()
+{
+    return focusedFieldIndex() != invalidFieldIndex;
+}
+
+void DateTimeEditElement::setOnlyYearMonthDay(const DateComponents& date)
+{
+    ASSERT(date.type() == DateComponents::Date);
+
+    if (!m_editControlOwner)
+        return;
+
+    DateTimeFieldsState dateTimeFieldsState = valueAsDateTimeFieldsState();
+    dateTimeFieldsState.setYear(date.fullYear());
+    dateTimeFieldsState.setMonth(date.month() + 1);
+    dateTimeFieldsState.setDayOfMonth(date.monthDay());
+    setValueAsDateTimeFieldsState(dateTimeFieldsState);
+    m_editControlOwner->editControlValueChanged();
+}
+
+void DateTimeEditElement::stepDown()
+{
+    if (DateTimeFieldElement* const field = focusedField())
+        field->stepDown();
+}
+
+void DateTimeEditElement::stepUp()
+{
+    if (DateTimeFieldElement* const field = focusedField())
+        field->stepUp();
+}
+
+void DateTimeEditElement::updateUIState()
+{
+    if (isDisabled()) {
+        if (DateTimeFieldElement* field = focusedField())
+            field->blur();
+    }
+}
+
+String DateTimeEditElement::value() const
+{
+    if (!m_editControlOwner)
+        return emptyString();
+    return m_editControlOwner->formatDateTimeFieldsState(valueAsDateTimeFieldsState());
+}
+
+DateTimeFieldsState DateTimeEditElement::valueAsDateTimeFieldsState() const
+{
+    DateTimeFieldsState dateTimeFieldsState;
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->populateDateTimeFieldsState(dateTimeFieldsState);
+    return dateTimeFieldsState;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/shadow/DateTimeEditElement.h b/Source/core/html/shadow/DateTimeEditElement.h
new file mode 100644
index 0000000..5e45f90
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeEditElement.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2012 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. 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 DateTimeEditElement_h
+#define DateTimeEditElement_h
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/StepRange.h"
+#include "core/html/shadow/DateTimeFieldElement.h"
+#include "core/platform/DateComponents.h"
+
+namespace WebCore {
+
+class DateTimeFieldsState;
+class KeyboardEvent;
+class Locale;
+class MouseEvent;
+class StepRange;
+
+// DateTimeEditElement class contains numberic field and symbolc field for
+// representing date and time, such as
+//  - Year, Month, Day Of Month
+//  - Hour, Minute, Second, Millisecond, AM/PM
+class DateTimeEditElement FINAL : public HTMLDivElement, public DateTimeFieldElement::FieldOwner {
+    WTF_MAKE_NONCOPYABLE(DateTimeEditElement);
+
+public:
+    // EditControlOwner implementer must call removeEditControlOwner when
+    // it doesn't handle event, e.g. at destruction.
+    class EditControlOwner {
+    public:
+        virtual ~EditControlOwner();
+        virtual void didBlurFromControl() = 0;
+        virtual void didFocusOnControl() = 0;
+        virtual void editControlValueChanged() = 0;
+        virtual String formatDateTimeFieldsState(const DateTimeFieldsState&) const = 0;
+        virtual bool isEditControlOwnerDisabled() const = 0;
+        virtual bool isEditControlOwnerReadOnly() const = 0;
+        virtual AtomicString localeIdentifier() const = 0;
+    };
+
+    struct LayoutParameters {
+        String dateTimeFormat;
+        String fallbackDateTimeFormat;
+        Locale& locale;
+        const StepRange stepRange;
+        DateComponents minimum;
+        DateComponents maximum;
+        String placeholderForDay;
+        String placeholderForMonth;
+        String placeholderForYear;
+
+        LayoutParameters(Locale& locale, const StepRange& stepRange)
+            : locale(locale)
+            , stepRange(stepRange)
+        {
+        }
+    };
+
+    static PassRefPtr<DateTimeEditElement> create(Document*, EditControlOwner&);
+
+    virtual ~DateTimeEditElement();
+    void addField(PassRefPtr<DateTimeFieldElement>);
+    bool anyEditableFieldsHaveValues() const;
+    void blurByOwner();
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+    void disabledStateChanged();
+    Element* fieldsWrapperElement() const;
+    void focusIfNoFocus();
+    // If oldFocusedNode is one of sub-fields, focus on it. Otherwise focus on
+    // the first sub-field.
+    void focusByOwner(Node* oldFocusedNode = 0);
+    bool hasFocusedField();
+    void readOnlyStateChanged();
+    void removeEditControlOwner() { m_editControlOwner = 0; }
+    void resetFields();
+    void setEmptyValue(const LayoutParameters&, const DateComponents& dateForReadOnlyField);
+    void setValueAsDate(const LayoutParameters&, const DateComponents&);
+    void setValueAsDateTimeFieldsState(const DateTimeFieldsState&);
+    void setOnlyYearMonthDay(const DateComponents&);
+    void stepDown();
+    void stepUp();
+    String value() const;
+    DateTimeFieldsState valueAsDateTimeFieldsState() const;
+
+private:
+    static const size_t invalidFieldIndex = static_cast<size_t>(-1);
+
+    // Datetime can be represent at most five fields, such as
+    //  1. year
+    //  2. month
+    //  3. day-of-month
+    //  4. hour
+    //  5. minute
+    //  6. second
+    //  7. millisecond
+    //  8. AM/PM
+    static const int maximumNumberOfFields = 8;
+
+    DateTimeEditElement(Document*, EditControlOwner&);
+
+    DateTimeFieldElement* fieldAt(size_t) const;
+    size_t fieldIndexOf(const DateTimeFieldElement&) const;
+    DateTimeFieldElement* focusedField() const;
+    size_t focusedFieldIndex() const;
+    bool focusOnNextFocusableField(size_t startIndex);
+    bool isDisabled() const;
+    bool isReadOnly() const;
+    void layout(const LayoutParameters&, const DateComponents&);
+    void updateUIState();
+
+    // Element function.
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+
+    // DateTimeFieldElement::FieldOwner functions.
+    virtual void didBlurFromField() OVERRIDE FINAL;
+    virtual void didFocusOnField() OVERRIDE FINAL;
+    virtual void fieldValueChanged() OVERRIDE FINAL;
+    virtual bool focusOnNextField(const DateTimeFieldElement&) OVERRIDE FINAL;
+    virtual bool focusOnPreviousField(const DateTimeFieldElement&) OVERRIDE FINAL;
+    virtual bool isFieldOwnerDisabled() const OVERRIDE FINAL;
+    virtual bool isFieldOwnerReadOnly() const OVERRIDE FINAL;
+    virtual AtomicString localeIdentifier() const OVERRIDE FINAL;
+
+    Vector<DateTimeFieldElement*, maximumNumberOfFields> m_fields;
+    EditControlOwner* m_editControlOwner;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/shadow/DateTimeFieldElement.cpp b/Source/core/html/shadow/DateTimeFieldElement.cpp
new file mode 100644
index 0000000..46e0868
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeFieldElement.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2012 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. 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"
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/shadow/DateTimeFieldElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/Text.h"
+#include "core/platform/DateComponents.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/text/PlatformLocale.h"
+#include "core/rendering/RenderObject.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+DateTimeFieldElement::FieldOwner::~FieldOwner()
+{
+}
+
+DateTimeFieldElement::DateTimeFieldElement(Document* document, FieldOwner& fieldOwner)
+    : HTMLSpanElement(spanTag, document)
+    , m_fieldOwner(&fieldOwner)
+{
+    // On accessibility, DateTimeFieldElement acts like spin button.
+    setAttribute(roleAttr, "spinbutton");
+    setAttribute(aria_valuetextAttr, AXDateTimeFieldEmptyValueText());
+}
+
+void DateTimeFieldElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().blurEvent)
+        didBlur();
+
+    if (event->type() == eventNames().focusEvent)
+        didFocus();
+
+    if (event->isKeyboardEvent()) {
+        KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event);
+        if (!isDisabled() && !isFieldOwnerDisabled() && !isFieldOwnerReadOnly()) {
+            handleKeyboardEvent(keyboardEvent);
+            if (keyboardEvent->defaultHandled())
+                return;
+        }
+        defaultKeyboardEventHandler(keyboardEvent);
+        if (keyboardEvent->defaultHandled())
+            return;
+    }
+
+    HTMLElement::defaultEventHandler(event);
+}
+
+void DateTimeFieldElement::defaultKeyboardEventHandler(KeyboardEvent* keyboardEvent)
+{
+    if (keyboardEvent->type() != eventNames().keydownEvent)
+        return;
+
+    if (isDisabled() || isFieldOwnerDisabled())
+        return;
+
+    const String& keyIdentifier = keyboardEvent->keyIdentifier();
+
+    if (keyIdentifier == "Left") {
+        if (!m_fieldOwner)
+            return;
+        // FIXME: We'd like to use FocusController::advanceFocus(FocusDirectionLeft, ...)
+        // but it doesn't work for shadow nodes. webkit.org/b/104650
+        if (!localeForOwner().isRTL() && m_fieldOwner->focusOnPreviousField(*this))
+            keyboardEvent->setDefaultHandled();
+        return;
+    }
+
+    if (keyIdentifier == "Right") {
+        if (!m_fieldOwner)
+            return;
+        // FIXME: We'd like to use FocusController::advanceFocus(FocusDirectionRight, ...)
+        // but it doesn't work for shadow nodes. webkit.org/b/104650
+        if (!localeForOwner().isRTL() && m_fieldOwner->focusOnNextField(*this))
+            keyboardEvent->setDefaultHandled();
+        return;
+    }
+
+    if (isFieldOwnerReadOnly())
+        return;
+
+    if (keyIdentifier == "Down") {
+        if (keyboardEvent->getModifierState("Alt"))
+            return;
+        keyboardEvent->setDefaultHandled();
+        stepDown();
+        return;
+    }
+
+    if (keyIdentifier == "Up") {
+        keyboardEvent->setDefaultHandled();
+        stepUp();
+        return;
+    }
+
+    if (keyIdentifier == "U+0008" || keyIdentifier == "U+007F") {
+        keyboardEvent->setDefaultHandled();
+        setEmptyValue(DispatchEvent);
+        return;
+    }
+}
+
+void DateTimeFieldElement::didBlur()
+{
+    if (m_fieldOwner)
+        m_fieldOwner->didBlurFromField();
+}
+
+void DateTimeFieldElement::didFocus()
+{
+    if (m_fieldOwner)
+        m_fieldOwner->didFocusOnField();
+}
+
+void DateTimeFieldElement::focusOnNextField()
+{
+    if (!m_fieldOwner)
+        return;
+    m_fieldOwner->focusOnNextField(*this);
+}
+
+void DateTimeFieldElement::initialize(const AtomicString& pseudo, const String& axHelpText, int axMinimum, int axMaximum)
+{
+    setAttribute(aria_helpAttr, axHelpText);
+    setAttribute(aria_valueminAttr, String::number(axMinimum));
+    setAttribute(aria_valuemaxAttr, String::number(axMaximum));
+    setPseudo(pseudo);
+    appendChild(Text::create(document(), visibleValue()));
+}
+
+bool DateTimeFieldElement::isDateTimeFieldElement() const
+{
+    return true;
+}
+
+bool DateTimeFieldElement::isFieldOwnerDisabled() const
+{
+    return m_fieldOwner && m_fieldOwner->isFieldOwnerDisabled();
+}
+
+bool DateTimeFieldElement::isFieldOwnerReadOnly() const
+{
+    return m_fieldOwner && m_fieldOwner->isFieldOwnerReadOnly();
+}
+
+bool DateTimeFieldElement::isFocusable() const
+{
+    if (isDisabled())
+        return false;
+    if (isFieldOwnerDisabled())
+        return false;
+    return HTMLElement::isFocusable();
+}
+
+bool DateTimeFieldElement::isDisabled() const
+{
+    return fastHasAttribute(disabledAttr);
+}
+
+Locale& DateTimeFieldElement::localeForOwner() const
+{
+    return document()->getCachedLocale(localeIdentifier());
+}
+
+AtomicString DateTimeFieldElement::localeIdentifier() const
+{
+    return m_fieldOwner ? m_fieldOwner->localeIdentifier() : nullAtom;
+}
+
+float DateTimeFieldElement::maximumWidth(const Font&)
+{
+    const float paddingLeftAndRight = 2; // This should match to html.css.
+    return paddingLeftAndRight;
+}
+
+void DateTimeFieldElement::setDisabled()
+{
+    // Set HTML attribute disabled to change apperance.
+    setBooleanAttribute(disabledAttr, true);
+    setNeedsStyleRecalc();
+}
+
+bool DateTimeFieldElement::supportsFocus() const
+{
+    return true;
+}
+
+void DateTimeFieldElement::updateVisibleValue(EventBehavior eventBehavior)
+{
+    Text* const textNode = toText(firstChild());
+    const String newVisibleValue = visibleValue();
+    ASSERT(newVisibleValue.length() > 0);
+
+    if (textNode->wholeText() == newVisibleValue)
+        return;
+
+    textNode->replaceWholeText(newVisibleValue, ASSERT_NO_EXCEPTION);
+    if (hasValue()) {
+        setAttribute(aria_valuetextAttr, newVisibleValue);
+        setAttribute(aria_valuenowAttr, String::number(valueForARIAValueNow()));
+    } else {
+        setAttribute(aria_valuetextAttr, AXDateTimeFieldEmptyValueText());
+        removeAttribute(aria_valuenowAttr);
+    }
+
+    if (eventBehavior == DispatchEvent && m_fieldOwner)
+        m_fieldOwner->fieldValueChanged();
+}
+
+int DateTimeFieldElement::valueForARIAValueNow() const
+{
+    return valueAsInteger();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/shadow/DateTimeFieldElement.h b/Source/core/html/shadow/DateTimeFieldElement.h
new file mode 100644
index 0000000..0b0118d
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeFieldElement.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 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. 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 DateTimeFieldElement_h
+#define DateTimeFieldElement_h
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLSpanElement.h"
+
+namespace WebCore {
+
+class DateComponents;
+class DateTimeFieldsState;
+class Font;
+
+// DateTimeFieldElement is base class of date time field element.
+class DateTimeFieldElement : public HTMLSpanElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeFieldElement);
+
+public:
+    enum EventBehavior {
+        DispatchNoEvent,
+        DispatchEvent,
+    };
+
+    // FieldOwner implementer must call removeEventHandler when
+    // it doesn't handle event, e.g. at destruction.
+    class FieldOwner {
+    public:
+        virtual ~FieldOwner();
+        virtual void didBlurFromField() = 0;
+        virtual void didFocusOnField() = 0;
+        virtual void fieldValueChanged() = 0;
+        virtual bool focusOnNextField(const DateTimeFieldElement&) = 0;
+        virtual bool focusOnPreviousField(const DateTimeFieldElement&) = 0;
+        virtual bool isFieldOwnerDisabled() const = 0;
+        virtual bool isFieldOwnerReadOnly() const = 0;
+        virtual AtomicString localeIdentifier() const = 0;
+    };
+
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+    virtual bool hasValue() const = 0;
+    bool isDisabled() const;
+    virtual bool isFocusable() const OVERRIDE FINAL;
+    virtual float maximumWidth(const Font&);
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) = 0;
+    void removeEventHandler() { m_fieldOwner = 0; }
+    void setDisabled();
+    virtual void setEmptyValue(EventBehavior = DispatchNoEvent) = 0;
+    virtual void setValueAsDate(const DateComponents&) = 0;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) = 0;
+    virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) = 0;
+    virtual void stepDown() = 0;
+    virtual void stepUp() = 0;
+    virtual String value() const = 0;
+    virtual String visibleValue() const = 0;
+
+protected:
+    DateTimeFieldElement(Document*, FieldOwner&);
+    virtual void didBlur();
+    virtual void didFocus();
+    void focusOnNextField();
+    virtual void handleKeyboardEvent(KeyboardEvent*) = 0;
+    void initialize(const AtomicString& pseudo, const String& axHelpText, int axMinimum, int axMaximum);
+    Locale& localeForOwner() const;
+    AtomicString localeIdentifier() const;
+    void updateVisibleValue(EventBehavior);
+    virtual int valueAsInteger() const = 0;
+    virtual int valueForARIAValueNow() const;
+
+private:
+    void defaultKeyboardEventHandler(KeyboardEvent*);
+    virtual bool isDateTimeFieldElement() const OVERRIDE;
+    bool isFieldOwnerDisabled() const;
+    bool isFieldOwnerReadOnly() const;
+    virtual bool supportsFocus() const OVERRIDE FINAL;
+
+    FieldOwner* m_fieldOwner;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/shadow/DateTimeFieldElements.cpp b/Source/core/html/shadow/DateTimeFieldElements.cpp
new file mode 100644
index 0000000..d7aff17
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeFieldElements.cpp
@@ -0,0 +1,635 @@
+/*
+ * Copyright (C) 2012 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. 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"
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/shadow/DateTimeFieldElements.h"
+
+#include "core/html/DateTimeFieldsState.h"
+#include "core/platform/DateComponents.h"
+#include "core/platform/LocalizedStrings.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/DateMath.h>
+
+namespace WebCore {
+
+DateTimeAMPMFieldElement::DateTimeAMPMFieldElement(Document* document, FieldOwner& fieldOwner, const Vector<String>& ampmLabels)
+    : DateTimeSymbolicFieldElement(document, fieldOwner, ampmLabels, 0, 1)
+{
+}
+
+PassRefPtr<DateTimeAMPMFieldElement> DateTimeAMPMFieldElement::create(Document* document, FieldOwner& fieldOwner, const Vector<String>& ampmLabels)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, ampmPsuedoId, ("-webkit-datetime-edit-ampm-field", AtomicString::ConstructFromLiteral));
+    RefPtr<DateTimeAMPMFieldElement> field = adoptRef(new DateTimeAMPMFieldElement(document, fieldOwner, ampmLabels));
+    field->initialize(ampmPsuedoId, AXAMPMFieldText());
+    return field.release();
+}
+
+void DateTimeAMPMFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (hasValue())
+        dateTimeFieldsState.setAMPM(valueAsInteger() ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM);
+    else
+        dateTimeFieldsState.setAMPM(DateTimeFieldsState::AMPMValueEmpty);
+}
+
+void DateTimeAMPMFieldElement::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.hour() >= 12 ? 1 : 0);
+}
+
+void DateTimeAMPMFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (dateTimeFieldsState.hasAMPM())
+        setValueAsInteger(dateTimeFieldsState.ampm());
+    else
+        setEmptyValue();
+}
+
+// ----------------------------
+
+DateTimeDayFieldElement::DateTimeDayFieldElement(Document* document, FieldOwner& fieldOwner, const String& placeholder, const Range& range)
+    : DateTimeNumericFieldElement(document, fieldOwner, range, Range(1, 31), placeholder)
+{
+}
+
+PassRefPtr<DateTimeDayFieldElement> DateTimeDayFieldElement::create(Document* document, FieldOwner& fieldOwner, const String& placeholder, const Range& range)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, dayPsuedoId, ("-webkit-datetime-edit-day-field", AtomicString::ConstructFromLiteral));
+    RefPtr<DateTimeDayFieldElement> field = adoptRef(new DateTimeDayFieldElement(document, fieldOwner, placeholder.isEmpty() ? ASCIILiteral("--") : placeholder, range));
+    field->initialize(dayPsuedoId, AXDayOfMonthFieldText());
+    return field.release();
+}
+
+void DateTimeDayFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    dateTimeFieldsState.setDayOfMonth(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
+}
+
+void DateTimeDayFieldElement::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.monthDay());
+}
+
+void DateTimeDayFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!dateTimeFieldsState.hasDayOfMonth()) {
+        setEmptyValue();
+        return;
+    }
+
+    const unsigned value = dateTimeFieldsState.dayOfMonth();
+    if (range().isInRange(static_cast<int>(value))) {
+        setValueAsInteger(value);
+        return;
+    }
+
+    setEmptyValue();
+}
+
+// ----------------------------
+
+DateTimeHourFieldElementBase::DateTimeHourFieldElementBase(Document* document, FieldOwner& fieldOwner, const Range& range, const Range& hardLimits, const Step& step)
+    : DateTimeNumericFieldElement(document, fieldOwner, range, hardLimits, "--", step)
+{
+}
+
+void DateTimeHourFieldElementBase::initialize()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, hourPsuedoId, ("-webkit-datetime-edit-hour-field", AtomicString::ConstructFromLiteral));
+    DateTimeNumericFieldElement::initialize(hourPsuedoId, AXHourFieldText());
+}
+
+void DateTimeHourFieldElementBase::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.hour());
+}
+
+void DateTimeHourFieldElementBase::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!dateTimeFieldsState.hasHour()) {
+        setEmptyValue();
+        return;
+    }
+
+    const int hour12 = dateTimeFieldsState.hour();
+    if (hour12 < 1 || hour12 > 12) {
+        setEmptyValue();
+        return;
+    }
+
+    if (dateTimeFieldsState.ampm() == DateTimeFieldsState::AMPMValuePM)
+        setValueAsInteger((hour12 + 12) % 24);
+    else
+        setValueAsInteger(hour12 % 12);
+}
+// ----------------------------
+
+DateTimeHour11FieldElement::DateTimeHour11FieldElement(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+    : DateTimeHourFieldElementBase(document, fieldOwner, range, Range(0, 11), step)
+{
+}
+
+PassRefPtr<DateTimeHour11FieldElement> DateTimeHour11FieldElement::create(Document* document, FieldOwner& fieldOwner, const Range& hour23Range, const Step& step)
+{
+    ASSERT(hour23Range.minimum >= 0);
+    ASSERT(hour23Range.maximum <= 23);
+    ASSERT(hour23Range.minimum <= hour23Range.maximum);
+    Range range(0, 11);
+    if (hour23Range.maximum < 12)
+        range = hour23Range;
+    else if (hour23Range.minimum >= 12) {
+        range.minimum = hour23Range.minimum - 12;
+        range.maximum = hour23Range.maximum - 12;
+    }
+
+    RefPtr<DateTimeHour11FieldElement> field = adoptRef(new DateTimeHour11FieldElement(document, fieldOwner, range, step));
+    field->initialize();
+    return field.release();
+}
+
+void DateTimeHour11FieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!hasValue()) {
+        dateTimeFieldsState.setHour(DateTimeFieldsState::emptyValue);
+        return;
+    }
+    const int value = valueAsInteger();
+    dateTimeFieldsState.setHour(value ? value : 12);
+}
+
+void DateTimeHour11FieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
+{
+    value = Range(0, 23).clampValue(value) % 12;
+    DateTimeNumericFieldElement::setValueAsInteger(value, eventBehavior);
+}
+
+// ----------------------------
+
+DateTimeHour12FieldElement::DateTimeHour12FieldElement(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+    : DateTimeHourFieldElementBase(document, fieldOwner, range, Range(1, 12), step)
+{
+}
+
+PassRefPtr<DateTimeHour12FieldElement> DateTimeHour12FieldElement::create(Document* document, FieldOwner& fieldOwner, const Range& hour23Range, const Step& step)
+{
+    ASSERT(hour23Range.minimum >= 0);
+    ASSERT(hour23Range.maximum <= 23);
+    ASSERT(hour23Range.minimum <= hour23Range.maximum);
+    Range range(1, 12);
+    if (hour23Range.maximum < 12)
+        range = hour23Range;
+    else if (hour23Range.minimum >= 12) {
+        range.minimum = hour23Range.minimum - 12;
+        range.maximum = hour23Range.maximum - 12;
+    }
+    if (!range.minimum)
+        range.minimum = 12;
+    if (!range.maximum)
+        range.maximum = 12;
+    if (range.minimum > range.maximum) {
+        range.minimum = 1;
+        range.maximum = 12;
+    }
+    RefPtr<DateTimeHour12FieldElement> field = adoptRef(new DateTimeHour12FieldElement(document, fieldOwner, range, step));
+    field->initialize();
+    return field.release();
+}
+
+void DateTimeHour12FieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    dateTimeFieldsState.setHour(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
+}
+
+void DateTimeHour12FieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
+{
+    value = Range(0, 24).clampValue(value) % 12;
+    DateTimeNumericFieldElement::setValueAsInteger(value ? value : 12, eventBehavior);
+}
+
+// ----------------------------
+
+DateTimeHour23FieldElement::DateTimeHour23FieldElement(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+    : DateTimeHourFieldElementBase(document, fieldOwner, range, Range(0, 23), step)
+{
+}
+
+PassRefPtr<DateTimeHour23FieldElement> DateTimeHour23FieldElement::create(Document* document, FieldOwner& fieldOwner, const Range& hour23Range, const Step& step)
+{
+    ASSERT(hour23Range.minimum >= 0);
+    ASSERT(hour23Range.maximum <= 23);
+    ASSERT(hour23Range.minimum <= hour23Range.maximum);
+    RefPtr<DateTimeHour23FieldElement> field = adoptRef(new DateTimeHour23FieldElement(document, fieldOwner, hour23Range, step));
+    field->initialize();
+    return field.release();
+}
+
+void DateTimeHour23FieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!hasValue()) {
+        dateTimeFieldsState.setHour(DateTimeFieldsState::emptyValue);
+        return;
+    }
+
+    const int value = valueAsInteger();
+
+    dateTimeFieldsState.setHour(value ? value % 12 : 12);
+    dateTimeFieldsState.setAMPM(value >= 12 ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM);
+}
+
+void DateTimeHour23FieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
+{
+    value = Range(0, 23).clampValue(value);
+    DateTimeNumericFieldElement::setValueAsInteger(value, eventBehavior);
+}
+
+// ----------------------------
+
+DateTimeHour24FieldElement::DateTimeHour24FieldElement(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+    : DateTimeHourFieldElementBase(document, fieldOwner, range, Range(1, 24), step)
+{
+}
+
+PassRefPtr<DateTimeHour24FieldElement> DateTimeHour24FieldElement::create(Document* document, FieldOwner& fieldOwner, const Range& hour23Range, const Step& step)
+{
+    ASSERT(hour23Range.minimum >= 0);
+    ASSERT(hour23Range.maximum <= 23);
+    ASSERT(hour23Range.minimum <= hour23Range.maximum);
+    Range range(hour23Range.minimum ? hour23Range.minimum : 24, hour23Range.maximum ? hour23Range.maximum : 24);
+    if (range.minimum > range.maximum) {
+        range.minimum = 1;
+        range.maximum = 24;
+    }
+
+    RefPtr<DateTimeHour24FieldElement> field = adoptRef(new DateTimeHour24FieldElement(document, fieldOwner, range, step));
+    field->initialize();
+    return field.release();
+}
+
+void DateTimeHour24FieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!hasValue()) {
+        dateTimeFieldsState.setHour(DateTimeFieldsState::emptyValue);
+        return;
+    }
+
+    const int value = valueAsInteger();
+
+    if (value == 24) {
+        dateTimeFieldsState.setHour(12);
+        dateTimeFieldsState.setAMPM(DateTimeFieldsState::AMPMValueAM);
+    } else {
+        dateTimeFieldsState.setHour(value == 12 ? 12 : value % 12);
+        dateTimeFieldsState.setAMPM(value >= 12 ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM);
+    }
+}
+
+void DateTimeHour24FieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
+{
+    value = Range(0, 24).clampValue(value);
+    DateTimeNumericFieldElement::setValueAsInteger(value ? value : 24, eventBehavior);
+}
+
+// ----------------------------
+
+DateTimeMillisecondFieldElement::DateTimeMillisecondFieldElement(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+    : DateTimeNumericFieldElement(document, fieldOwner, range, Range(0, 999), "---", step)
+{
+}
+
+PassRefPtr<DateTimeMillisecondFieldElement> DateTimeMillisecondFieldElement::create(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, millisecondPsuedoId, ("-webkit-datetime-edit-millisecond-field", AtomicString::ConstructFromLiteral));
+    RefPtr<DateTimeMillisecondFieldElement> field = adoptRef(new DateTimeMillisecondFieldElement(document, fieldOwner, range, step));
+    field->initialize(millisecondPsuedoId, AXMillisecondFieldText());
+    return field.release();
+}
+
+void DateTimeMillisecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    dateTimeFieldsState.setMillisecond(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
+}
+
+void DateTimeMillisecondFieldElement::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.millisecond());
+}
+
+void DateTimeMillisecondFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!dateTimeFieldsState.hasMillisecond()) {
+        setEmptyValue();
+        return;
+    }
+
+    const unsigned value = dateTimeFieldsState.millisecond();
+    if (value > static_cast<unsigned>(maximum())) {
+        setEmptyValue();
+        return;
+    }
+
+    setValueAsInteger(value);
+}
+
+// ----------------------------
+
+DateTimeMinuteFieldElement::DateTimeMinuteFieldElement(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+    : DateTimeNumericFieldElement(document, fieldOwner, range, Range(0, 59), "--", step)
+{
+}
+
+PassRefPtr<DateTimeMinuteFieldElement> DateTimeMinuteFieldElement::create(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, minutePsuedoId, ("-webkit-datetime-edit-minute-field", AtomicString::ConstructFromLiteral));
+    RefPtr<DateTimeMinuteFieldElement> field = adoptRef(new DateTimeMinuteFieldElement(document, fieldOwner, range, step));
+    field->initialize(minutePsuedoId, AXMinuteFieldText());
+    return field.release();
+}
+
+void DateTimeMinuteFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    dateTimeFieldsState.setMinute(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
+}
+
+void DateTimeMinuteFieldElement::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.minute());
+}
+
+void DateTimeMinuteFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!dateTimeFieldsState.hasMinute()) {
+        setEmptyValue();
+        return;
+    }
+
+    const unsigned value = dateTimeFieldsState.minute();
+    if (value > static_cast<unsigned>(maximum())) {
+        setEmptyValue();
+        return;
+    }
+
+    setValueAsInteger(value);
+}
+
+// ----------------------------
+
+DateTimeMonthFieldElement::DateTimeMonthFieldElement(Document* document, FieldOwner& fieldOwner, const String& placeholder, const Range& range)
+    : DateTimeNumericFieldElement(document, fieldOwner, range, Range(1, 12), placeholder)
+{
+}
+
+PassRefPtr<DateTimeMonthFieldElement> DateTimeMonthFieldElement::create(Document* document, FieldOwner& fieldOwner, const String& placeholder, const Range& range)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, monthPsuedoId, ("-webkit-datetime-edit-month-field", AtomicString::ConstructFromLiteral));
+    RefPtr<DateTimeMonthFieldElement> field = adoptRef(new DateTimeMonthFieldElement(document, fieldOwner, placeholder.isEmpty() ? ASCIILiteral("--") : placeholder, range));
+    field->initialize(monthPsuedoId, AXMonthFieldText());
+    return field.release();
+}
+
+void DateTimeMonthFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    dateTimeFieldsState.setMonth(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
+}
+
+void DateTimeMonthFieldElement::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.month() + 1);
+}
+
+void DateTimeMonthFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!dateTimeFieldsState.hasMonth()) {
+        setEmptyValue();
+        return;
+    }
+
+    const unsigned value = dateTimeFieldsState.month();
+    if (range().isInRange(static_cast<int>(value))) {
+        setValueAsInteger(value);
+        return;
+    }
+
+    setEmptyValue();
+}
+
+// ----------------------------
+
+DateTimeSecondFieldElement::DateTimeSecondFieldElement(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+    : DateTimeNumericFieldElement(document, fieldOwner, range, Range(0, 59), "--", step)
+{
+}
+
+PassRefPtr<DateTimeSecondFieldElement> DateTimeSecondFieldElement::create(Document* document, FieldOwner& fieldOwner, const Range& range, const Step& step)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, secondPsuedoId, ("-webkit-datetime-edit-second-field", AtomicString::ConstructFromLiteral));
+    RefPtr<DateTimeSecondFieldElement> field = adoptRef(new DateTimeSecondFieldElement(document, fieldOwner, range, step));
+    field->initialize(secondPsuedoId, AXSecondFieldText());
+    return field.release();
+}
+
+void DateTimeSecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    dateTimeFieldsState.setSecond(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
+}
+
+void DateTimeSecondFieldElement::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.second());
+}
+
+void DateTimeSecondFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!dateTimeFieldsState.hasSecond()) {
+        setEmptyValue();
+        return;
+    }
+
+    const unsigned value = dateTimeFieldsState.second();
+    if (value > static_cast<unsigned>(maximum())) {
+        setEmptyValue();
+        return;
+    }
+
+    setValueAsInteger(value);
+}
+
+// ----------------------------
+
+DateTimeSymbolicMonthFieldElement::DateTimeSymbolicMonthFieldElement(Document* document, FieldOwner& fieldOwner, const Vector<String>& labels, int minimum, int maximum)
+    : DateTimeSymbolicFieldElement(document, fieldOwner, labels, minimum, maximum)
+{
+}
+
+PassRefPtr<DateTimeSymbolicMonthFieldElement> DateTimeSymbolicMonthFieldElement::create(Document* document, FieldOwner& fieldOwner, const Vector<String>& labels, int minimum, int maximum)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, monthPsuedoId, ("-webkit-datetime-edit-month-field", AtomicString::ConstructFromLiteral));
+    RefPtr<DateTimeSymbolicMonthFieldElement> field = adoptRef(new DateTimeSymbolicMonthFieldElement(document, fieldOwner, labels, minimum, maximum));
+    field->initialize(monthPsuedoId, AXMonthFieldText());
+    return field.release();
+}
+
+void DateTimeSymbolicMonthFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!hasValue())
+        dateTimeFieldsState.setMonth(DateTimeFieldsState::emptyValue);
+    ASSERT(valueAsInteger() < static_cast<int>(symbolsSize()));
+    dateTimeFieldsState.setMonth(valueAsInteger() + 1);
+}
+
+void DateTimeSymbolicMonthFieldElement::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.month());
+}
+
+void DateTimeSymbolicMonthFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!dateTimeFieldsState.hasMonth()) {
+        setEmptyValue();
+        return;
+    }
+
+    const unsigned value = dateTimeFieldsState.month() - 1;
+    if (value >= symbolsSize()) {
+        setEmptyValue();
+        return;
+    }
+
+    setValueAsInteger(value);
+}
+
+// ----------------------------
+
+DateTimeWeekFieldElement::DateTimeWeekFieldElement(Document* document, FieldOwner& fieldOwner, const Range& range)
+    : DateTimeNumericFieldElement(document, fieldOwner, range, Range(DateComponents::minimumWeekNumber, DateComponents::maximumWeekNumber), "--")
+{
+}
+
+PassRefPtr<DateTimeWeekFieldElement> DateTimeWeekFieldElement::create(Document* document, FieldOwner& fieldOwner, const Range& range)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, weekPsuedoId, ("-webkit-datetime-edit-week-field", AtomicString::ConstructFromLiteral));
+    RefPtr<DateTimeWeekFieldElement> field = adoptRef(new DateTimeWeekFieldElement(document, fieldOwner, range));
+    field->initialize(weekPsuedoId, AXWeekOfYearFieldText());
+    return field.release();
+}
+
+void DateTimeWeekFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    dateTimeFieldsState.setWeekOfYear(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
+}
+
+void DateTimeWeekFieldElement::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.week());
+}
+
+void DateTimeWeekFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!dateTimeFieldsState.hasWeekOfYear()) {
+        setEmptyValue();
+        return;
+    }
+
+    const unsigned value = dateTimeFieldsState.weekOfYear();
+    if (range().isInRange(static_cast<int>(value))) {
+        setValueAsInteger(value);
+        return;
+    }
+
+    setEmptyValue();
+}
+
+// ----------------------------
+
+DateTimeYearFieldElement::DateTimeYearFieldElement(Document* document, FieldOwner& fieldOwner, const DateTimeYearFieldElement::Parameters& parameters)
+    : DateTimeNumericFieldElement(document, fieldOwner, Range(parameters.minimumYear, parameters.maximumYear), Range(DateComponents::minimumYear(), DateComponents::maximumYear()), parameters.placeholder.isEmpty() ? ASCIILiteral("----") : parameters.placeholder)
+    , m_minIsSpecified(parameters.minIsSpecified)
+    , m_maxIsSpecified(parameters.maxIsSpecified)
+{
+    ASSERT(parameters.minimumYear >= DateComponents::minimumYear());
+    ASSERT(parameters.maximumYear <= DateComponents::maximumYear());
+}
+
+PassRefPtr<DateTimeYearFieldElement> DateTimeYearFieldElement::create(Document* document, FieldOwner& fieldOwner, const DateTimeYearFieldElement::Parameters& parameters)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, yearPsuedoId, ("-webkit-datetime-edit-year-field", AtomicString::ConstructFromLiteral));
+    RefPtr<DateTimeYearFieldElement> field = adoptRef(new DateTimeYearFieldElement(document, fieldOwner, parameters));
+    field->initialize(yearPsuedoId, AXYearFieldText());
+    return field.release();
+}
+
+static int currentFullYear()
+{
+    double current = currentTimeMS();
+    double utcOffset = calculateUTCOffset();
+    double dstOffset = calculateDSTOffset(current, utcOffset);
+    int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+    current += offset * msPerMinute;
+
+    DateComponents date;
+    date.setMillisecondsSinceEpochForMonth(current);
+    return date.fullYear();
+}
+
+int DateTimeYearFieldElement::defaultValueForStepDown() const
+{
+    return m_maxIsSpecified ? DateTimeNumericFieldElement::defaultValueForStepDown() : currentFullYear();
+}
+
+int DateTimeYearFieldElement::defaultValueForStepUp() const
+{
+    return m_minIsSpecified ? DateTimeNumericFieldElement::defaultValueForStepUp() : currentFullYear();
+}
+
+void DateTimeYearFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
+{
+    dateTimeFieldsState.setYear(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
+}
+
+void DateTimeYearFieldElement::setValueAsDate(const DateComponents& date)
+{
+    setValueAsInteger(date.fullYear());
+}
+
+void DateTimeYearFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    if (!dateTimeFieldsState.hasYear()) {
+        setEmptyValue();
+        return;
+    }
+
+    const unsigned value = dateTimeFieldsState.year();
+    if (range().isInRange(static_cast<int>(value))) {
+        setValueAsInteger(value);
+        return;
+    }
+
+    setEmptyValue();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/shadow/DateTimeFieldElements.h b/Source/core/html/shadow/DateTimeFieldElements.h
new file mode 100644
index 0000000..60f53a8
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeFieldElements.h
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2012 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. 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 DateTimeFieldElements_h
+#define DateTimeFieldElements_h
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/shadow/DateTimeNumericFieldElement.h"
+#include "core/html/shadow/DateTimeSymbolicFieldElement.h"
+
+namespace WebCore {
+
+class DateTimeAMPMFieldElement FINAL : public DateTimeSymbolicFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeAMPMFieldElement);
+
+public:
+    static PassRefPtr<DateTimeAMPMFieldElement> create(Document*, FieldOwner&, const Vector<String>&);
+
+private:
+    DateTimeAMPMFieldElement(Document*, FieldOwner&, const Vector<String>&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+};
+
+class DateTimeDayFieldElement FINAL : public DateTimeNumericFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeDayFieldElement);
+
+public:
+    static PassRefPtr<DateTimeDayFieldElement> create(Document*, FieldOwner&, const String& placeholder, const Range&);
+
+private:
+    DateTimeDayFieldElement(Document*, FieldOwner&, const String& placeholder, const Range&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+};
+
+class DateTimeHourFieldElementBase : public DateTimeNumericFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeHourFieldElementBase);
+
+protected:
+    DateTimeHourFieldElementBase(Document*, FieldOwner&, const Range&, const Range& hardLimits, const Step&);
+    void initialize();
+
+private:
+    // DateTimeFieldElement functions.
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+};
+
+class DateTimeHour11FieldElement FINAL : public DateTimeHourFieldElementBase {
+    WTF_MAKE_NONCOPYABLE(DateTimeHour11FieldElement);
+
+public:
+    static PassRefPtr<DateTimeHour11FieldElement> create(Document*, FieldOwner&, const Range&, const Step&);
+
+private:
+    DateTimeHour11FieldElement(Document*, FieldOwner&, const Range& hour23Range, const Step&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE FINAL;
+};
+
+class DateTimeHour12FieldElement FINAL : public DateTimeHourFieldElementBase {
+    WTF_MAKE_NONCOPYABLE(DateTimeHour12FieldElement);
+
+public:
+    static PassRefPtr<DateTimeHour12FieldElement> create(Document*, FieldOwner&, const Range&, const Step&);
+
+private:
+    DateTimeHour12FieldElement(Document*, FieldOwner&, const Range& hour23Range, const Step&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE FINAL;
+};
+
+class DateTimeHour23FieldElement FINAL : public DateTimeHourFieldElementBase {
+    WTF_MAKE_NONCOPYABLE(DateTimeHour23FieldElement);
+
+public:
+    static PassRefPtr<DateTimeHour23FieldElement> create(Document*, FieldOwner&, const Range&, const Step&);
+
+private:
+    DateTimeHour23FieldElement(Document*, FieldOwner&, const Range& hour23Range, const Step&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE FINAL;
+};
+
+class DateTimeHour24FieldElement FINAL : public DateTimeHourFieldElementBase {
+    WTF_MAKE_NONCOPYABLE(DateTimeHour24FieldElement);
+
+public:
+    static PassRefPtr<DateTimeHour24FieldElement> create(Document*, FieldOwner&, const Range&, const Step&);
+
+private:
+    DateTimeHour24FieldElement(Document*, FieldOwner&, const Range& hour23Range, const Step&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE FINAL;
+};
+
+class DateTimeMillisecondFieldElement FINAL : public DateTimeNumericFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeMillisecondFieldElement);
+
+public:
+    static PassRefPtr<DateTimeMillisecondFieldElement> create(Document*, FieldOwner&, const Range&, const Step&);
+
+private:
+    DateTimeMillisecondFieldElement(Document*, FieldOwner&, const Range&, const Step&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+};
+
+class DateTimeMinuteFieldElement FINAL : public DateTimeNumericFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeMinuteFieldElement);
+
+public:
+    static PassRefPtr<DateTimeMinuteFieldElement> create(Document*, FieldOwner&, const Range&, const Step&);
+
+private:
+    DateTimeMinuteFieldElement(Document*, FieldOwner&, const Range&, const Step&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+};
+
+class DateTimeMonthFieldElement FINAL : public DateTimeNumericFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeMonthFieldElement);
+
+public:
+    static PassRefPtr<DateTimeMonthFieldElement> create(Document*, FieldOwner&, const String& placeholder, const Range&);
+
+private:
+    DateTimeMonthFieldElement(Document*, FieldOwner&, const String& placeholder, const Range&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+};
+
+class DateTimeSecondFieldElement FINAL : public DateTimeNumericFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeSecondFieldElement);
+
+public:
+    static PassRefPtr<DateTimeSecondFieldElement> create(Document*, FieldOwner&, const Range&, const Step&);
+
+private:
+    DateTimeSecondFieldElement(Document*, FieldOwner&, const Range&, const Step&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+};
+
+class DateTimeSymbolicMonthFieldElement FINAL : public DateTimeSymbolicFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeSymbolicMonthFieldElement);
+
+public:
+    static PassRefPtr<DateTimeSymbolicMonthFieldElement> create(Document*, FieldOwner&, const Vector<String>&, int minimum, int maximum);
+
+private:
+    DateTimeSymbolicMonthFieldElement(Document*, FieldOwner&, const Vector<String>&, int minimum, int maximum);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+};
+
+class DateTimeWeekFieldElement FINAL : public DateTimeNumericFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeWeekFieldElement);
+
+public:
+    static PassRefPtr<DateTimeWeekFieldElement> create(Document*, FieldOwner&, const Range&);
+
+private:
+    DateTimeWeekFieldElement(Document*, FieldOwner&, const Range&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+};
+
+class DateTimeYearFieldElement FINAL : public DateTimeNumericFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeYearFieldElement);
+
+public:
+    struct Parameters {
+        int minimumYear;
+        int maximumYear;
+        bool minIsSpecified;
+        bool maxIsSpecified;
+        String placeholder;
+
+        Parameters()
+            : minimumYear(-1)
+            , maximumYear(-1)
+            , minIsSpecified(false)
+            , maxIsSpecified(false)
+        {
+        }
+    };
+
+    static PassRefPtr<DateTimeYearFieldElement> create(Document*, FieldOwner&, const Parameters&);
+
+private:
+    DateTimeYearFieldElement(Document*, FieldOwner&, const Parameters&);
+
+    // DateTimeFieldElement functions.
+    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL;
+    virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL;
+    virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&) OVERRIDE FINAL;
+
+    // DateTimeNumericFieldElement functions.
+    virtual int defaultValueForStepDown() const OVERRIDE FINAL;
+    virtual int defaultValueForStepUp() const OVERRIDE FINAL;
+
+    bool m_minIsSpecified;
+    bool m_maxIsSpecified;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/shadow/DateTimeNumericFieldElement.cpp b/Source/core/html/shadow/DateTimeNumericFieldElement.cpp
new file mode 100644
index 0000000..0b9e174
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeNumericFieldElement.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2012 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. 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"
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/shadow/DateTimeNumericFieldElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/platform/graphics/Font.h"
+#include "core/platform/text/PlatformLocale.h"
+#include <wtf/text/StringBuilder.h>
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+static const DOMTimeStamp typeAheadTimeout = 1000;
+
+int DateTimeNumericFieldElement::Range::clampValue(int value) const
+{
+    return std::min(std::max(value, minimum), maximum);
+}
+
+bool DateTimeNumericFieldElement::Range::isInRange(int value) const
+{
+    return value >= minimum && value <= maximum;
+}
+
+// ----------------------------
+
+DateTimeNumericFieldElement::DateTimeNumericFieldElement(Document* document, FieldOwner& fieldOwner, const Range& range, const Range& hardLimits, const String& placeholder, const DateTimeNumericFieldElement::Step& step)
+    : DateTimeFieldElement(document, fieldOwner)
+    , m_lastDigitCharTime(0)
+    , m_placeholder(placeholder)
+    , m_range(range)
+    , m_hardLimits(hardLimits)
+    , m_step(step)
+    , m_value(0)
+    , m_hasValue(false)
+{
+    ASSERT(m_step.step);
+    ASSERT(m_range.minimum <= m_range.maximum);
+    ASSERT(m_hardLimits.minimum <= m_hardLimits.maximum);
+
+    // We show a direction-neutral string such as "--" as a placeholder. It
+    // should follow the direction of numeric values.
+    if (localeForOwner().isRTL()) {
+        Direction dir = direction(formatValue(this->maximum())[0]);
+        if (dir == LeftToRight || dir == EuropeanNumber || dir == ArabicNumber) {
+            setInlineStyleProperty(CSSPropertyUnicodeBidi, CSSValueBidiOverride);
+            setInlineStyleProperty(CSSPropertyDirection, CSSValueLtr);
+        }
+    }
+}
+
+float DateTimeNumericFieldElement::maximumWidth(const Font& font)
+{
+    float maximumWidth = font.width(m_placeholder);
+    maximumWidth = std::max(maximumWidth, font.width(formatValue(maximum())));
+    maximumWidth = std::max(maximumWidth, font.width(value()));
+    return maximumWidth + DateTimeFieldElement::maximumWidth(font);
+}
+
+int DateTimeNumericFieldElement::defaultValueForStepDown() const
+{
+    return m_range.maximum;
+}
+
+int DateTimeNumericFieldElement::defaultValueForStepUp() const
+{
+    return m_range.minimum;
+}
+
+void DateTimeNumericFieldElement::didBlur()
+{
+    int value = typeAheadValue();
+    m_typeAheadBuffer.clear();
+    if (value >= 0)
+        setValueAsInteger(value, DispatchEvent);
+    DateTimeFieldElement::didBlur();
+}
+
+String DateTimeNumericFieldElement::formatValue(int value) const
+{
+    Locale& locale = localeForOwner();
+    if (m_hardLimits.maximum > 999)
+        return locale.convertToLocalizedNumber(String::format("%04d", value));
+    if (m_hardLimits.maximum > 99)
+        return locale.convertToLocalizedNumber(String::format("%03d", value));
+    return locale.convertToLocalizedNumber(String::format("%02d", value));
+}
+
+void DateTimeNumericFieldElement::handleKeyboardEvent(KeyboardEvent* keyboardEvent)
+{
+    ASSERT(!isDisabled());
+    if (keyboardEvent->type() != eventNames().keypressEvent)
+        return;
+
+    UChar charCode = static_cast<UChar>(keyboardEvent->charCode());
+    String number = localeForOwner().convertFromLocalizedNumber(String(&charCode, 1));
+    const int digit = number[0] - '0';
+    if (digit < 0 || digit > 9)
+        return;
+
+    DOMTimeStamp delta = keyboardEvent->timeStamp() - m_lastDigitCharTime;
+    m_lastDigitCharTime = keyboardEvent->timeStamp();
+
+    if (delta > typeAheadTimeout)
+        m_typeAheadBuffer.clear();
+    m_typeAheadBuffer.append(number);
+
+    int newValue = typeAheadValue();
+    if (newValue >= m_hardLimits.minimum)
+        setValueAsInteger(newValue, DispatchEvent);
+    else {
+        m_hasValue = false;
+        updateVisibleValue(DispatchEvent);
+    }
+
+    if (m_typeAheadBuffer.length() >= DateTimeNumericFieldElement::formatValue(m_range.maximum).length() || newValue * 10 > m_range.maximum)
+        focusOnNextField();
+
+    keyboardEvent->setDefaultHandled();
+}
+
+bool DateTimeNumericFieldElement::hasValue() const
+{
+    return m_hasValue;
+}
+
+void DateTimeNumericFieldElement::initialize(const AtomicString& pseudo, const String& axHelpText)
+{
+    DateTimeFieldElement::initialize(pseudo, axHelpText, m_range.minimum, m_range.maximum);
+}
+
+int DateTimeNumericFieldElement::maximum() const
+{
+    return m_range.maximum;
+}
+
+void DateTimeNumericFieldElement::setEmptyValue(EventBehavior eventBehavior)
+{
+    if (isDisabled())
+        return;
+
+    m_hasValue = false;
+    m_value = 0;
+    m_typeAheadBuffer.clear();
+    updateVisibleValue(eventBehavior);
+}
+
+void DateTimeNumericFieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
+{
+    m_value = m_hardLimits.clampValue(value);
+    m_hasValue = true;
+    updateVisibleValue(eventBehavior);
+}
+
+void DateTimeNumericFieldElement::stepDown()
+{
+    int newValue = roundDown(m_hasValue ? m_value - 1 : defaultValueForStepDown());
+    if (!m_range.isInRange(newValue))
+        newValue = roundDown(m_range.maximum);
+    m_typeAheadBuffer.clear();
+    setValueAsInteger(newValue, DispatchEvent);
+}
+
+void DateTimeNumericFieldElement::stepUp()
+{
+    int newValue = roundUp(m_hasValue ? m_value + 1 : defaultValueForStepUp());
+    if (!m_range.isInRange(newValue))
+        newValue = roundUp(m_range.minimum);
+    m_typeAheadBuffer.clear();
+    setValueAsInteger(newValue, DispatchEvent);
+}
+
+String DateTimeNumericFieldElement::value() const
+{
+    return m_hasValue ? formatValue(m_value) : emptyString();
+}
+
+int DateTimeNumericFieldElement::valueAsInteger() const
+{
+    return m_hasValue ? m_value : -1;
+}
+
+int DateTimeNumericFieldElement::typeAheadValue() const
+{
+    if (m_typeAheadBuffer.length())
+        return m_typeAheadBuffer.toString().toInt();
+    return -1;
+}
+
+String DateTimeNumericFieldElement::visibleValue() const
+{
+    if (m_typeAheadBuffer.length())
+        return formatValue(typeAheadValue());
+    return m_hasValue ? value() : m_placeholder;
+}
+
+int DateTimeNumericFieldElement::roundDown(int n) const
+{
+    n -= m_step.stepBase;
+    if (n >= 0)
+        n = n / m_step.step * m_step.step;
+    else
+        n = -((-n + m_step.step - 1) / m_step.step * m_step.step);
+    return n + m_step.stepBase;
+}
+
+int DateTimeNumericFieldElement::roundUp(int n) const
+{
+    n -= m_step.stepBase;
+    if (n >= 0)
+        n = (n + m_step.step - 1) / m_step.step * m_step.step;
+    else
+        n = -(-n / m_step.step * m_step.step);
+    return n + m_step.stepBase;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/shadow/DateTimeNumericFieldElement.h b/Source/core/html/shadow/DateTimeNumericFieldElement.h
new file mode 100644
index 0000000..80390ee
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeNumericFieldElement.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012 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. 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 DateTimeNumericFieldElement_h
+#define DateTimeNumericFieldElement_h
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/shadow/DateTimeFieldElement.h"
+
+namespace WebCore {
+
+// DateTimeNumericFieldElement represents numeric field of date time format,
+// such as:
+//  - hour
+//  - minute
+//  - millisecond
+//  - second
+//  - year
+class DateTimeNumericFieldElement : public DateTimeFieldElement {
+    WTF_MAKE_NONCOPYABLE(DateTimeNumericFieldElement);
+
+public:
+    struct Step {
+        Step(int step = 1, int stepBase = 0) : step(step), stepBase(stepBase) { }
+        int step;
+        int stepBase;
+    };
+
+    struct Range {
+        Range(int minimum, int maximum) : minimum(minimum), maximum(maximum) { }
+        int clampValue(int) const;
+        bool isInRange(int) const;
+        bool isSingleton() const { return minimum == maximum; }
+
+        int minimum;
+        int maximum;
+    };
+
+protected:
+    DateTimeNumericFieldElement(Document*, FieldOwner&, const Range&, const Range& hardLimits, const String& placeholder, const Step& = Step());
+
+    int clampValue(int value) const { return m_range.clampValue(value); }
+    virtual int defaultValueForStepDown() const;
+    virtual int defaultValueForStepUp() const;
+    const Range& range() const { return m_range; }
+
+    // DateTimeFieldElement functions.
+    virtual bool hasValue() const OVERRIDE FINAL;
+    void initialize(const AtomicString& pseudo, const String& axHelpText);
+    int maximum() const;
+    virtual void setEmptyValue(EventBehavior = DispatchNoEvent) OVERRIDE FINAL;
+    virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE;
+    virtual int valueAsInteger() const OVERRIDE FINAL;
+    virtual String visibleValue() const OVERRIDE FINAL;
+
+private:
+    // DateTimeFieldElement functions.
+    virtual void didBlur() OVERRIDE FINAL;
+    virtual void handleKeyboardEvent(KeyboardEvent*) OVERRIDE FINAL;
+    virtual float maximumWidth(const Font&) OVERRIDE;
+    virtual void stepDown() OVERRIDE FINAL;
+    virtual void stepUp() OVERRIDE FINAL;
+    virtual String value() const OVERRIDE FINAL;
+
+    String formatValue(int) const;
+    int roundUp(int) const;
+    int roundDown(int) const;
+    int typeAheadValue() const;
+
+    DOMTimeStamp m_lastDigitCharTime;
+    const String m_placeholder;
+    const Range m_range;
+    const Range m_hardLimits;
+    const Step m_step;
+    int m_value;
+    bool m_hasValue;
+    mutable StringBuilder m_typeAheadBuffer;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/shadow/DateTimeSymbolicFieldElement.cpp b/Source/core/html/shadow/DateTimeSymbolicFieldElement.cpp
new file mode 100644
index 0000000..d2ff82d
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeSymbolicFieldElement.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012 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. 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"
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/shadow/DateTimeSymbolicFieldElement.h"
+
+#include "core/dom/KeyboardEvent.h"
+#include "core/platform/graphics/Font.h"
+#include "core/platform/text/TextBreakIterator.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+static AtomicString makeVisibleEmptyValue(const Vector<String>& symbols)
+{
+    unsigned maximumLength = 0;
+    for (unsigned index = 0; index < symbols.size(); ++index)
+        maximumLength = std::max(maximumLength, numGraphemeClusters(symbols[index]));
+    StringBuilder builder;
+    builder.reserveCapacity(maximumLength);
+    for (unsigned length = 0; length < maximumLength; ++length)
+        builder.append('-');
+    return builder.toAtomicString();
+}
+
+DateTimeSymbolicFieldElement::DateTimeSymbolicFieldElement(Document* document, FieldOwner& fieldOwner, const Vector<String>& symbols, int minimum, int maximum)
+    : DateTimeFieldElement(document, fieldOwner)
+    , m_symbols(symbols)
+    , m_visibleEmptyValue(makeVisibleEmptyValue(symbols))
+    , m_selectedIndex(-1)
+    , m_typeAhead(this)
+    , m_minimumIndex(minimum)
+    , m_maximumIndex(maximum)
+{
+    ASSERT(!symbols.isEmpty());
+    ASSERT(m_minimumIndex >= 0);
+    ASSERT_WITH_SECURITY_IMPLICATION(m_maximumIndex < static_cast<int>(m_symbols.size()));
+    ASSERT(m_minimumIndex <= m_maximumIndex);
+}
+
+float DateTimeSymbolicFieldElement::maximumWidth(const Font& font)
+{
+    float maximumWidth = font.width(visibleEmptyValue());
+    for (unsigned index = 0; index < m_symbols.size(); ++index)
+        maximumWidth = std::max(maximumWidth, font.width(m_symbols[index]));
+    return maximumWidth + DateTimeFieldElement::maximumWidth(font);
+}
+
+void DateTimeSymbolicFieldElement::handleKeyboardEvent(KeyboardEvent* keyboardEvent)
+{
+    if (keyboardEvent->type() != eventNames().keypressEvent)
+        return;
+
+    const UChar charCode = WTF::Unicode::toLower(keyboardEvent->charCode());
+    if (charCode < ' ')
+        return;
+
+    keyboardEvent->setDefaultHandled();
+
+    int index = m_typeAhead.handleEvent(keyboardEvent, TypeAhead::MatchPrefix | TypeAhead::CycleFirstChar | TypeAhead::MatchIndex);
+    if (index < 0)
+        return;
+    setValueAsInteger(index, DispatchEvent);
+}
+
+bool DateTimeSymbolicFieldElement::hasValue() const
+{
+    return m_selectedIndex >= 0;
+}
+
+void DateTimeSymbolicFieldElement::initialize(const AtomicString& pseudo, const String& axHelpText)
+{
+    // The minimum and maximum below are exposed to users, and 1-based numbers
+    // are natural for symbolic fields. For example, the minimum value of a
+    // month field should be 1, not 0.
+    DateTimeFieldElement::initialize(pseudo, axHelpText, m_minimumIndex + 1, m_maximumIndex + 1);
+}
+
+void DateTimeSymbolicFieldElement::setEmptyValue(EventBehavior eventBehavior)
+{
+    if (isDisabled())
+        return;
+    m_selectedIndex = invalidIndex;
+    updateVisibleValue(eventBehavior);
+}
+
+void DateTimeSymbolicFieldElement::setValueAsInteger(int newSelectedIndex, EventBehavior eventBehavior)
+{
+    m_selectedIndex = std::max(0, std::min(newSelectedIndex, static_cast<int>(m_symbols.size() - 1)));
+    updateVisibleValue(eventBehavior);
+}
+
+void DateTimeSymbolicFieldElement::stepDown()
+{
+    if (hasValue()) {
+        if (!indexIsInRange(--m_selectedIndex))
+            m_selectedIndex = m_maximumIndex;
+    } else
+        m_selectedIndex = m_maximumIndex;
+    updateVisibleValue(DispatchEvent);
+}
+
+void DateTimeSymbolicFieldElement::stepUp()
+{
+    if (hasValue()) {
+        if (!indexIsInRange(++m_selectedIndex))
+            m_selectedIndex = m_minimumIndex;
+    } else
+        m_selectedIndex = m_minimumIndex;
+    updateVisibleValue(DispatchEvent);
+}
+
+String DateTimeSymbolicFieldElement::value() const
+{
+    return hasValue() ? m_symbols[m_selectedIndex] : emptyString();
+}
+
+int DateTimeSymbolicFieldElement::valueAsInteger() const
+{
+    return m_selectedIndex;
+}
+
+int DateTimeSymbolicFieldElement::valueForARIAValueNow() const
+{
+    // Synchronize with minimum/maximum adjustment in initialize().
+    return m_selectedIndex + 1;
+}
+
+String DateTimeSymbolicFieldElement::visibleEmptyValue() const
+{
+    return m_visibleEmptyValue;
+}
+
+String DateTimeSymbolicFieldElement::visibleValue() const
+{
+    return hasValue() ? m_symbols[m_selectedIndex] : visibleEmptyValue();
+}
+
+int DateTimeSymbolicFieldElement::indexOfSelectedOption() const
+{
+    return m_selectedIndex;
+}
+
+int DateTimeSymbolicFieldElement::optionCount() const
+{
+    return m_symbols.size();
+}
+
+String DateTimeSymbolicFieldElement::optionAtIndex(int index) const
+{
+    return m_symbols[index];
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/shadow/DateTimeSymbolicFieldElement.h b/Source/core/html/shadow/DateTimeSymbolicFieldElement.h
new file mode 100644
index 0000000..321fa34
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeSymbolicFieldElement.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 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. 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 DateTimeSymbolicFieldElement_h
+#define DateTimeSymbolicFieldElement_h
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/TypeAhead.h"
+#include "core/html/shadow/DateTimeFieldElement.h"
+
+namespace WebCore {
+
+// DateTimeSymbolicFieldElement represents non-numeric field of data time
+// format, such as: AM/PM, and month.
+class DateTimeSymbolicFieldElement : public DateTimeFieldElement, public TypeAheadDataSource {
+    WTF_MAKE_NONCOPYABLE(DateTimeSymbolicFieldElement);
+
+protected:
+    DateTimeSymbolicFieldElement(Document*, FieldOwner&, const Vector<String>&, int minimum, int maximum);
+    size_t symbolsSize() const { return m_symbols.size(); }
+    virtual bool hasValue() const OVERRIDE FINAL;
+    void initialize(const AtomicString& pseudo, const String& axHelpText);
+    virtual void setEmptyValue(EventBehavior = DispatchNoEvent) OVERRIDE FINAL;
+    virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE FINAL;
+    virtual int valueAsInteger() const OVERRIDE FINAL;
+
+private:
+    static const int invalidIndex = -1;
+
+    String visibleEmptyValue() const;
+    bool indexIsInRange(int index) const { return index >= m_minimumIndex && index <= m_maximumIndex; }
+
+    // DateTimeFieldElement functions.
+    virtual void handleKeyboardEvent(KeyboardEvent*) OVERRIDE FINAL;
+    virtual float maximumWidth(const Font&) OVERRIDE;
+    virtual void stepDown() OVERRIDE FINAL;
+    virtual void stepUp() OVERRIDE FINAL;
+    virtual String value() const OVERRIDE FINAL;
+    virtual int valueForARIAValueNow() const OVERRIDE FINAL;
+    virtual String visibleValue() const OVERRIDE FINAL;
+
+    // TypeAheadDataSource functions.
+    virtual int indexOfSelectedOption() const OVERRIDE;
+    virtual int optionCount() const OVERRIDE;
+    virtual String optionAtIndex(int index) const OVERRIDE;
+
+    const Vector<String> m_symbols;
+
+    // We use AtomicString to share visible empty value among multiple
+    // DateTimeEditElements in the page.
+    const AtomicString m_visibleEmptyValue;
+    int m_selectedIndex;
+    TypeAhead m_typeAhead;
+    const int m_minimumIndex;
+    const int m_maximumIndex;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/shadow/DetailsMarkerControl.cpp b/Source/core/html/shadow/DetailsMarkerControl.cpp
new file mode 100644
index 0000000..e797072
--- /dev/null
+++ b/Source/core/html/shadow/DetailsMarkerControl.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/DetailsMarkerControl.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLSummaryElement.h"
+#include "core/rendering/RenderDetailsMarker.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+DetailsMarkerControl::DetailsMarkerControl(Document* document) 
+    : HTMLDivElement(divTag, document)
+{
+}
+
+RenderObject* DetailsMarkerControl::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderDetailsMarker(this);
+}
+
+bool DetailsMarkerControl::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    return summaryElement()->isMainSummary() && HTMLDivElement::rendererIsNeeded(context);
+}
+
+const AtomicString& DetailsMarkerControl::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, pseudId, ("-webkit-details-marker", AtomicString::ConstructFromLiteral));
+    return pseudId;
+}
+
+HTMLSummaryElement* DetailsMarkerControl::summaryElement()
+{
+    Element* element = shadowHost();
+    ASSERT_WITH_SECURITY_IMPLICATION(!element || element->hasTagName(summaryTag));
+    return static_cast<HTMLSummaryElement*>(element);
+}
+
+}
diff --git a/Source/core/html/shadow/DetailsMarkerControl.h b/Source/core/html/shadow/DetailsMarkerControl.h
new file mode 100644
index 0000000..867f6f1
--- /dev/null
+++ b/Source/core/html/shadow/DetailsMarkerControl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 DetailsMarkerControl_h
+#define DetailsMarkerControl_h
+
+#include "core/html/HTMLDivElement.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class HTMLSummaryElement;
+
+class DetailsMarkerControl FINAL : public HTMLDivElement {
+public:
+    DetailsMarkerControl(Document*);
+    static PassRefPtr<DetailsMarkerControl> create(Document*);
+
+private:
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+    virtual const AtomicString& shadowPseudoId() const;
+
+    HTMLSummaryElement* summaryElement();
+};
+
+inline PassRefPtr<DetailsMarkerControl> DetailsMarkerControl::create(Document* document)
+{
+    return adoptRef(new DetailsMarkerControl(document));
+}
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/HTMLContentElement.cpp b/Source/core/html/shadow/HTMLContentElement.cpp
new file mode 100644
index 0000000..90c50eb
--- /dev/null
+++ b/Source/core/html/shadow/HTMLContentElement.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/HTMLContentElement.h"
+
+#include "HTMLNames.h"
+#include "core/css/CSSParser.h"
+#include "core/dom/QualifiedName.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/shadow/ContentDistributor.h"
+#include "core/html/shadow/ContentSelectorQuery.h"
+#include "RuntimeEnabledFeatures.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+using HTMLNames::selectAttr;
+
+const QualifiedName& HTMLContentElement::contentTagName(Document*)
+{
+    return HTMLNames::contentTag;
+}
+
+PassRefPtr<HTMLContentElement> HTMLContentElement::create(Document* document)
+{
+    return adoptRef(new HTMLContentElement(contentTagName(document), document));
+}
+
+PassRefPtr<HTMLContentElement> HTMLContentElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLContentElement(tagName, document));
+}
+
+HTMLContentElement::HTMLContentElement(const QualifiedName& name, Document* document)
+    : InsertionPoint(name, document)
+    , m_shouldParseSelectorList(false)
+    , m_isValidSelector(true)
+{
+    ScriptWrappable::init(this);
+}
+
+HTMLContentElement::~HTMLContentElement()
+{
+}
+
+InsertionPoint::MatchType HTMLContentElement::matchTypeFor(Node*)
+{
+    if (select().isNull() || select().isEmpty())
+        return AlwaysMatches;
+    if (!isSelectValid())
+        return NeverMatches;
+    return HasToMatchSelector;
+}
+
+const AtomicString& HTMLContentElement::select() const
+{
+    return getAttribute(selectAttr);
+}
+
+bool HTMLContentElement::isSelectValid()
+{
+    ensureSelectParsed();
+    return m_isValidSelector;
+}
+
+void HTMLContentElement::ensureSelectParsed()
+{
+    if (!m_shouldParseSelectorList)
+        return;
+
+    CSSParser parser(document());
+    parser.parseSelector(select(), m_selectorList);
+    m_shouldParseSelectorList = false;
+    m_isValidSelector = validateSelect();
+    if (!m_isValidSelector)
+        m_selectorList = CSSSelectorList();
+}
+
+void HTMLContentElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == selectAttr) {
+        if (ShadowRoot* root = containingShadowRoot())
+            root->owner()->willAffectSelector();
+        m_shouldParseSelectorList = true;
+    } else
+        InsertionPoint::parseAttribute(name, value);
+}
+
+static bool validateSubSelector(const CSSSelector* selector)
+{
+    switch (selector->m_match) {
+    case CSSSelector::Tag:
+    case CSSSelector::Id:
+    case CSSSelector::Class:
+    case CSSSelector::Exact:
+    case CSSSelector::Set:
+    case CSSSelector::List:
+    case CSSSelector::Hyphen:
+    case CSSSelector::Contain:
+    case CSSSelector::Begin:
+    case CSSSelector::End:
+        return true;
+    case CSSSelector::PseudoElement:
+        return false;
+    case CSSSelector::PagePseudoClass:
+    case CSSSelector::PseudoClass:
+        break;
+    }
+
+    switch (selector->pseudoType()) {
+    case CSSSelector::PseudoEmpty:
+    case CSSSelector::PseudoLink:
+    case CSSSelector::PseudoVisited:
+    case CSSSelector::PseudoTarget:
+    case CSSSelector::PseudoEnabled:
+    case CSSSelector::PseudoDisabled:
+    case CSSSelector::PseudoChecked:
+    case CSSSelector::PseudoIndeterminate:
+    case CSSSelector::PseudoNthChild:
+    case CSSSelector::PseudoNthLastChild:
+    case CSSSelector::PseudoNthOfType:
+    case CSSSelector::PseudoNthLastOfType:
+    case CSSSelector::PseudoFirstChild:
+    case CSSSelector::PseudoLastChild:
+    case CSSSelector::PseudoFirstOfType:
+    case CSSSelector::PseudoLastOfType:
+    case CSSSelector::PseudoOnlyOfType:
+        return true;
+    default:
+        return false;
+    }
+}
+
+static bool validateSelector(const CSSSelector* selector)
+{
+    ASSERT(selector);
+
+    if (!validateSubSelector(selector))
+        return false;
+
+    const CSSSelector* prevSubSelector = selector;
+    const CSSSelector* subSelector = selector->tagHistory();
+
+    while (subSelector) {
+        if (prevSubSelector->relation() != CSSSelector::SubSelector)
+            return false;
+        if (!validateSubSelector(subSelector))
+            return false;
+
+        prevSubSelector = subSelector;
+        subSelector = subSelector->tagHistory();
+    }
+
+    return true;
+}
+
+bool HTMLContentElement::validateSelect() const
+{
+    ASSERT(!m_shouldParseSelectorList);
+
+    if (select().isNull() || select().isEmpty())
+        return true;
+
+    if (!m_selectorList.isValid())
+        return false;
+
+    for (const CSSSelector* selector = m_selectorList.first(); selector; selector = m_selectorList.next(selector)) {
+        if (!validateSelector(selector))
+            return false;
+    }
+
+    return true;
+}
+}
+
diff --git a/Source/core/html/shadow/HTMLContentElement.h b/Source/core/html/shadow/HTMLContentElement.h
new file mode 100644
index 0000000..a03e00b
--- /dev/null
+++ b/Source/core/html/shadow/HTMLContentElement.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 HTMLContentElement_h
+#define HTMLContentElement_h
+
+#include "core/css/CSSSelectorList.h"
+#include "core/html/shadow/InsertionPoint.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class HTMLContentElement FINAL : public InsertionPoint {
+public:
+    static const QualifiedName& contentTagName(Document*);
+    static PassRefPtr<HTMLContentElement> create(const QualifiedName&, Document*);
+    static PassRefPtr<HTMLContentElement> create(Document*);
+
+    virtual ~HTMLContentElement();
+
+    void setSelect(const AtomicString&);
+    const AtomicString& select() const;
+
+    virtual MatchType matchTypeFor(Node*) OVERRIDE;
+    virtual const CSSSelectorList& selectorList() OVERRIDE;
+    virtual Type insertionPointType() const OVERRIDE { return ContentInsertionPoint; }
+    virtual bool canAffectSelector() const OVERRIDE { return true; }
+    virtual bool isSelectValid();
+
+protected:
+    HTMLContentElement(const QualifiedName&, Document*);
+
+private:
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    void ensureSelectParsed();
+    bool validateSelect() const;
+
+    bool m_shouldParseSelectorList;
+    bool m_isValidSelector;
+    CSSSelectorList m_selectorList;
+};
+
+inline void HTMLContentElement::setSelect(const AtomicString& selectValue)
+{
+    setAttribute(HTMLNames::selectAttr, selectValue);
+    m_shouldParseSelectorList = true;
+}
+
+inline const CSSSelectorList& HTMLContentElement::selectorList()
+{
+    ensureSelectParsed();
+    return m_selectorList;
+}
+
+inline bool isHTMLContentElement(const Node* node)
+{
+    ASSERT(node);
+    return node->isInsertionPoint() && toInsertionPoint(node)->insertionPointType() == InsertionPoint::ContentInsertionPoint;
+}
+
+inline HTMLContentElement* toHTMLContentElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLContentElement(node));
+    return static_cast<HTMLContentElement*>(node);
+}
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/HTMLContentElement.idl b/Source/core/html/shadow/HTMLContentElement.idl
new file mode 100644
index 0000000..e5c20d8
--- /dev/null
+++ b/Source/core/html/shadow/HTMLContentElement.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+[
+    SkipVTableValidation
+] interface HTMLContentElement : HTMLElement {
+    [Reflect] attribute DOMString select;
+    attribute boolean resetStyleInheritance;
+    NodeList getDistributedNodes();
+};
diff --git a/Source/core/html/shadow/HTMLShadowElement.cpp b/Source/core/html/shadow/HTMLShadowElement.cpp
new file mode 100644
index 0000000..ad304ea
--- /dev/null
+++ b/Source/core/html/shadow/HTMLShadowElement.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/HTMLShadowElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/ShadowRoot.h"
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+class Document;
+
+inline HTMLShadowElement::HTMLShadowElement(const QualifiedName& tagName, Document* document)
+    : InsertionPoint(tagName, document)
+{
+    ASSERT(hasTagName(HTMLNames::shadowTag));
+    ScriptWrappable::init(this);
+}
+
+PassRefPtr<HTMLShadowElement> HTMLShadowElement::create(const QualifiedName& tagName, Document* document)
+{
+    return adoptRef(new HTMLShadowElement(tagName, document));
+}
+
+HTMLShadowElement::~HTMLShadowElement()
+{
+}
+
+ShadowRoot* HTMLShadowElement::olderShadowRoot()
+{
+    ShadowRoot* containingRoot = containingShadowRoot();
+    if (!containingRoot)
+        return 0;
+
+    ContentDistributor::ensureDistribution(containingRoot);
+
+    ShadowRoot* older = containingRoot->olderShadowRoot();
+    if (!older || older->type() != ShadowRoot::AuthorShadowRoot || ScopeContentDistribution::assignedTo(older) != this)
+        return 0;
+
+    return older;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/html/shadow/HTMLShadowElement.h b/Source/core/html/shadow/HTMLShadowElement.h
new file mode 100644
index 0000000..4ea0b66
--- /dev/null
+++ b/Source/core/html/shadow/HTMLShadowElement.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 HTMLShadowElement_h
+#define HTMLShadowElement_h
+
+#include "core/html/shadow/InsertionPoint.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class HTMLShadowElement FINAL : public InsertionPoint {
+public:
+    static PassRefPtr<HTMLShadowElement> create(const QualifiedName&, Document*);
+
+    virtual ~HTMLShadowElement();
+
+    virtual Type insertionPointType() const OVERRIDE { return ShadowInsertionPoint; }
+
+    ShadowRoot* olderShadowRoot();
+
+private:
+    HTMLShadowElement(const QualifiedName&, Document*);
+};
+
+inline bool isHTMLShadowElement(const Node* node)
+{
+    ASSERT(node);
+    return node->hasTagName(HTMLNames::shadowTag);
+}
+
+inline HTMLShadowElement* toHTMLShadowElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLShadowElement(node));
+    return static_cast<HTMLShadowElement*>(node);
+}
+
+inline const HTMLShadowElement* toHTMLShadowElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLShadowElement(node));
+    return static_cast<const HTMLShadowElement*>(node);
+}
+} // namespace WebCore
+
+#endif // HTMLShadowElement_h
diff --git a/Source/core/html/shadow/HTMLShadowElement.idl b/Source/core/html/shadow/HTMLShadowElement.idl
new file mode 100644
index 0000000..a252e14
--- /dev/null
+++ b/Source/core/html/shadow/HTMLShadowElement.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+interface HTMLShadowElement : HTMLElement {
+    attribute boolean resetStyleInheritance;
+    readonly attribute ShadowRoot olderShadowRoot;
+};
diff --git a/Source/core/html/shadow/InsertionPoint.cpp b/Source/core/html/shadow/InsertionPoint.cpp
new file mode 100644
index 0000000..b3608d6
--- /dev/null
+++ b/Source/core/html/shadow/InsertionPoint.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/InsertionPoint.h"
+
+#include "HTMLNames.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/QualifiedName.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/StaticNodeList.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+InsertionPoint::InsertionPoint(const QualifiedName& tagName, Document* document)
+    : HTMLElement(tagName, document, CreateInsertionPoint)
+    , m_registeredWithShadowRoot(false)
+{
+}
+
+InsertionPoint::~InsertionPoint()
+{
+}
+
+void InsertionPoint::attach()
+{
+    if (ShadowRoot* shadowRoot = containingShadowRoot())
+        ContentDistributor::ensureDistribution(shadowRoot);
+    for (size_t i = 0; i < m_distribution.size(); ++i) {
+        if (!m_distribution.at(i)->attached())
+            m_distribution.at(i)->attach();
+    }
+
+    HTMLElement::attach();
+}
+
+void InsertionPoint::detach()
+{
+    if (ShadowRoot* shadowRoot = containingShadowRoot())
+        ContentDistributor::ensureDistribution(shadowRoot);
+
+    for (size_t i = 0; i < m_distribution.size(); ++i)
+        m_distribution.at(i)->detach();
+
+    HTMLElement::detach();
+}
+
+bool InsertionPoint::shouldUseFallbackElements() const
+{
+    return isActive() && !hasDistribution();
+}
+
+bool InsertionPoint::isShadowBoundary() const
+{
+    return treeScope()->rootNode()->isShadowRoot() && isActive();
+}
+
+bool InsertionPoint::isActive() const
+{
+    if (!containingShadowRoot())
+        return false;
+    const Node* node = parentNode();
+    while (node) {
+        if (node->isInsertionPoint())
+            return false;
+
+        node = node->parentNode();
+    }
+    return true;
+}
+
+PassRefPtr<NodeList> InsertionPoint::getDistributedNodes() const
+{
+    if (ShadowRoot* shadowRoot = containingShadowRoot())
+        ContentDistributor::ensureDistribution(shadowRoot);
+
+    Vector<RefPtr<Node> > nodes;
+
+    for (size_t i = 0; i < m_distribution.size(); ++i)
+        nodes.append(m_distribution.at(i));
+
+    return StaticNodeList::adopt(nodes);
+}
+
+bool InsertionPoint::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    return !isShadowBoundary() && HTMLElement::rendererIsNeeded(context);
+}
+
+void InsertionPoint::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+    if (ShadowRoot* root = containingShadowRoot())
+        if (ElementShadow* rootOwner = root->owner())
+            rootOwner->invalidateDistribution();
+}
+
+Node::InsertionNotificationRequest InsertionPoint::insertedInto(ContainerNode* insertionPoint)
+{
+    HTMLElement::insertedInto(insertionPoint);
+
+    if (ShadowRoot* root = containingShadowRoot()) {
+        if (ElementShadow* rootOwner = root->owner()) {
+            rootOwner->distributor().didShadowBoundaryChange(root->host());
+            if (isActive() && !m_registeredWithShadowRoot && insertionPoint->treeScope()->rootNode() == root) {
+                m_registeredWithShadowRoot = true;
+                root->ensureScopeDistribution()->registerInsertionPoint(this);
+                if (canAffectSelector())
+                    rootOwner->willAffectSelector();
+            }
+        }
+    }
+
+    return InsertionDone;
+}
+
+void InsertionPoint::removedFrom(ContainerNode* insertionPoint)
+{
+    ShadowRoot* root = containingShadowRoot();
+    if (!root)
+        root = insertionPoint->containingShadowRoot();
+
+    // host can be null when removedFrom() is called from ElementShadow destructor.
+    ElementShadow* rootOwner = root ? root->owner() : 0;
+    if (rootOwner)
+        rootOwner->invalidateDistribution();
+
+    // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up.
+    clearDistribution();
+
+    if (m_registeredWithShadowRoot && insertionPoint->treeScope()->rootNode() == root) {
+        ASSERT(root);
+        m_registeredWithShadowRoot = false;
+        root->ensureScopeDistribution()->unregisterInsertionPoint(this);
+        if (rootOwner && canAffectSelector())
+            rootOwner->willAffectSelector();
+    }
+
+    HTMLElement::removedFrom(insertionPoint);
+}
+
+void InsertionPoint::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+    if (name == reset_style_inheritanceAttr) {
+        if (!inDocument() || !attached() || !isActive())
+            return;
+        containingShadowRoot()->host()->setNeedsStyleRecalc();
+    } else
+        HTMLElement::parseAttribute(name, value);
+}
+
+bool InsertionPoint::resetStyleInheritance() const
+{
+    return fastHasAttribute(reset_style_inheritanceAttr);
+}
+
+void InsertionPoint::setResetStyleInheritance(bool value)
+{
+    setBooleanAttribute(reset_style_inheritanceAttr, value);
+}
+
+bool InsertionPoint::contains(const Node* node) const
+{
+    return m_distribution.contains(const_cast<Node*>(node)) || (node->isShadowRoot() && ScopeContentDistribution::assignedTo(toShadowRoot(node)) == this);
+}
+
+const CSSSelectorList& InsertionPoint::emptySelectorList()
+{
+    DEFINE_STATIC_LOCAL(CSSSelectorList, selectorList, (CSSSelectorList()));
+    return selectorList;
+}
+
+InsertionPoint* resolveReprojection(const Node* projectedNode)
+{
+    InsertionPoint* insertionPoint = 0;
+    const Node* current = projectedNode;
+
+    while (current) {
+        if (ElementShadow* shadow = shadowOfParentForDistribution(current)) {
+            if (ShadowRoot* root = current->containingShadowRoot())
+                ContentDistributor::ensureDistribution(root);
+            if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(projectedNode)) {
+                current = insertedTo;
+                insertionPoint = insertedTo;
+                continue;
+            }
+        }
+
+        if (Node* parent = parentNodeForDistribution(current)) {
+            if (InsertionPoint* insertedTo = parent->isShadowRoot() ? ScopeContentDistribution::assignedTo(toShadowRoot(parent)) : 0) {
+                current = insertedTo;
+                insertionPoint = insertedTo;
+                continue;
+            }
+        }
+
+        break;
+    }
+
+    return insertionPoint;
+}
+
+void collectInsertionPointsWhereNodeIsDistributed(const Node* node, Vector<InsertionPoint*, 8>& results)
+{
+    const Node* current = node;
+    while (true) {
+        if (ElementShadow* shadow = shadowOfParentForDistribution(current)) {
+            if (ShadowRoot* root = current->containingShadowRoot())
+                ContentDistributor::ensureDistribution(root);
+            if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(node)) {
+                current = insertedTo;
+                results.append(insertedTo);
+                continue;
+            }
+        }
+        if (Node* parent = parentNodeForDistribution(current)) {
+            if (InsertionPoint* insertedTo = parent->isShadowRoot() ? ScopeContentDistribution::assignedTo(toShadowRoot(parent)) : 0) {
+                current = insertedTo;
+                results.append(insertedTo);
+                continue;
+            }
+        }
+        return;
+    }
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/shadow/InsertionPoint.h b/Source/core/html/shadow/InsertionPoint.h
new file mode 100644
index 0000000..587ef2e
--- /dev/null
+++ b/Source/core/html/shadow/InsertionPoint.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 InsertionPoint_h
+#define InsertionPoint_h
+
+#include "HTMLNames.h"
+#include "core/css/CSSSelectorList.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/HTMLElement.h"
+#include "core/html/shadow/ContentDistributor.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class InsertionPoint : public HTMLElement {
+public:
+    enum Type {
+        ShadowInsertionPoint,
+        ContentInsertionPoint
+    };
+
+    enum MatchType {
+        AlwaysMatches,
+        NeverMatches,
+        HasToMatchSelector
+    };
+
+    virtual ~InsertionPoint();
+
+    bool hasDistribution() const { return !m_distribution.isEmpty(); }
+    void setDistribution(ContentDistribution& distribution) { m_distribution.swap(distribution); }
+    void clearDistribution() { m_distribution.clear(); }
+    bool isShadowBoundary() const;
+    bool isActive() const;
+
+    PassRefPtr<NodeList> getDistributedNodes() const;
+
+    virtual MatchType matchTypeFor(Node*) { return AlwaysMatches; }
+    virtual const CSSSelectorList& selectorList() { return emptySelectorList(); }
+    virtual Type insertionPointType() const = 0;
+    virtual bool canAffectSelector() const { return false; }
+
+    bool resetStyleInheritance() const;
+    void setResetStyleInheritance(bool);
+
+    virtual void attach();
+    virtual void detach();
+
+    bool shouldUseFallbackElements() const;
+
+    size_t indexOf(Node* node) const { return m_distribution.find(node); }
+    bool contains(const Node*) const;
+    size_t size() const { return m_distribution.size(); }
+    Node* at(size_t index)  const { return m_distribution.at(index).get(); }
+    Node* first() const { return m_distribution.isEmpty() ? 0 : m_distribution.first().get(); }
+    Node* last() const { return m_distribution.isEmpty() ? 0 : m_distribution.last().get(); }
+    Node* nextTo(const Node* node) const { return m_distribution.nextTo(node); }
+    Node* previousTo(const Node* node) const { return m_distribution.previousTo(node); }
+
+    static const CSSSelectorList& emptySelectorList();
+
+protected:
+    InsertionPoint(const QualifiedName&, Document*);
+    virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
+    virtual void childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) OVERRIDE;
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
+    virtual bool isInsertionPointNode() const OVERRIDE { return true; }
+
+private:
+
+    ContentDistribution m_distribution;
+    bool m_registeredWithShadowRoot;
+};
+
+inline InsertionPoint* toInsertionPoint(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isInsertionPoint());
+    return static_cast<InsertionPoint*>(node);
+}
+
+inline const InsertionPoint* toInsertionPoint(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isInsertionPoint());
+    return static_cast<const InsertionPoint*>(node);
+}
+
+inline bool isActiveInsertionPoint(const Node* node)
+{
+    return node->isInsertionPoint() && toInsertionPoint(node)->isActive();
+}
+
+inline bool isLowerEncapsulationBoundary(Node* node)
+{
+    if (!node || !node->isInsertionPoint())
+        return false;
+    return toInsertionPoint(node)->isShadowBoundary();
+}
+
+inline Node* parentNodeForDistribution(const Node* node)
+{
+    ASSERT(node);
+
+    if (Node* parent = node->parentNode()) {
+        if (parent->isInsertionPoint() && toInsertionPoint(parent)->shouldUseFallbackElements())
+            return parent->parentNode();
+        return parent;
+    }
+
+    return 0;
+}
+
+inline Element* parentElementForDistribution(const Node* node)
+{
+    if (Node* parent = parentNodeForDistribution(node)) {
+        if (parent->isElementNode())
+            return toElement(parent);
+    }
+
+    return 0;
+}
+
+inline ElementShadow* shadowOfParentForDistribution(const Node* node)
+{
+    ASSERT(node);
+    if (Element* parent = parentElementForDistribution(node))
+        return parent->shadow();
+
+    return 0;
+}
+
+InsertionPoint* resolveReprojection(const Node*);
+
+void collectInsertionPointsWhereNodeIsDistributed(const Node*, Vector<InsertionPoint*, 8>& results);
+
+} // namespace WebCore
+
+#endif // InsertionPoint_h
diff --git a/Source/core/html/shadow/MediaControlElementTypes.cpp b/Source/core/html/shadow/MediaControlElementTypes.cpp
new file mode 100644
index 0000000..37f23d8
--- /dev/null
+++ b/Source/core/html/shadow/MediaControlElementTypes.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/html/shadow/MediaControlElementTypes.h"
+
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/css/StylePropertySet.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/MouseEvent.h"
+#include "core/rendering/RenderMedia.h"
+#include "core/rendering/RenderMediaControlElements.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+class Event;
+
+// FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
+static const double cSkipRepeatDelay = 0.1;
+static const double cSkipTime = 0.2;
+static const double cScanRepeatDelay = 1.5;
+static const double cScanMaximumRate = 8;
+
+HTMLMediaElement* toParentMediaElement(Node* node)
+{
+    if (!node)
+        return 0;
+    Node* mediaNode = node->shadowHost();
+    if (!mediaNode)
+        mediaNode = node;
+    if (!mediaNode || !mediaNode->isElementNode() || !toElement(mediaNode)->isMediaElement())
+        return 0;
+
+    return static_cast<HTMLMediaElement*>(mediaNode);
+}
+
+MediaControlElementType mediaControlElementType(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(node->isMediaControlElement());
+    HTMLElement* element = toHTMLElement(node);
+    if (element->hasTagName(inputTag))
+        return static_cast<MediaControlInputElement*>(element)->displayType();
+    return static_cast<MediaControlDivElement*>(element)->displayType();
+}
+
+const AtomicString& trackIndexAttributeName()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, name, ("x-webkit-track-index", AtomicString::ConstructFromLiteral));
+    return name;
+}
+
+int trackListIndexForElement(Element* element)
+{
+    const AtomicString trackIndexAttributeValue = element->getAttribute(trackIndexAttributeName());
+    if (trackIndexAttributeValue.isNull() || trackIndexAttributeValue.isEmpty())
+        return HTMLMediaElement::textTracksIndexNotFound();
+    bool ok;
+    int trackIndex = trackIndexAttributeValue.toInt(&ok);
+    if (!ok)
+        return HTMLMediaElement::textTracksIndexNotFound();
+    return trackIndex;
+}
+
+MediaControlElement::MediaControlElement(MediaControlElementType displayType, HTMLElement* element)
+    : m_mediaController(0)
+    , m_displayType(displayType)
+    , m_element(element)
+{
+}
+
+void MediaControlElement::hide()
+{
+    m_element->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
+}
+
+void MediaControlElement::show()
+{
+    m_element->removeInlineStyleProperty(CSSPropertyDisplay);
+}
+
+bool MediaControlElement::isShowing() const
+{
+    const StylePropertySet* propertySet = m_element->inlineStyle();
+    // Following the code from show() and hide() above, we only have
+    // to check for the presense of inline display.
+    return (!propertySet || !propertySet->getPropertyCSSValue(CSSPropertyDisplay));
+}
+
+void MediaControlElement::setDisplayType(MediaControlElementType displayType)
+{
+    if (displayType == m_displayType)
+        return;
+
+    m_displayType = displayType;
+    if (RenderObject* object = m_element->renderer())
+        object->repaint();
+}
+
+// ----------------------------
+
+MediaControlDivElement::MediaControlDivElement(Document* document, MediaControlElementType displayType)
+    : HTMLDivElement(divTag, document)
+    , MediaControlElement(displayType, this)
+{
+}
+
+// ----------------------------
+
+MediaControlInputElement::MediaControlInputElement(Document* document, MediaControlElementType displayType)
+    : HTMLInputElement(inputTag, document, 0, false)
+    , MediaControlElement(displayType, this)
+{
+}
+
+// ----------------------------
+
+MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* document, MediaControlElementType displayType)
+    : MediaControlDivElement(document, displayType)
+    , m_currentValue(0)
+{
+}
+
+void MediaControlTimeDisplayElement::setCurrentValue(double time)
+{
+    m_currentValue = time;
+}
+
+// ----------------------------
+
+MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* document, MediaControlElementType displayType)
+    : MediaControlInputElement(document, displayType)
+{
+}
+
+void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().clickEvent) {
+        mediaController()->setMuted(!mediaController()->muted());
+        event->setDefaultHandled();
+    }
+
+    HTMLInputElement::defaultEventHandler(event);
+}
+
+void MediaControlMuteButtonElement::changedMute()
+{
+    updateDisplayType();
+}
+
+void MediaControlMuteButtonElement::updateDisplayType()
+{
+    setDisplayType(mediaController()->muted() ? MediaUnMuteButton : MediaMuteButton);
+}
+
+// ----------------------------
+
+MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* document, MediaControlElementType displayType)
+    : MediaControlInputElement(document, displayType)
+    , m_actionOnStop(Nothing)
+    , m_seekType(Skip)
+    , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
+{
+}
+
+void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
+{
+    // Set the mousedown and mouseup events as defaultHandled so they
+    // do not trigger drag start or end actions in MediaControlPanelElement.
+    if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
+        event->setDefaultHandled();
+}
+
+void MediaControlSeekButtonElement::setActive(bool flag, bool pause)
+{
+    if (flag == active())
+        return;
+
+    if (flag)
+        startTimer();
+    else
+        stopTimer();
+
+    MediaControlInputElement::setActive(flag, pause);
+}
+
+void MediaControlSeekButtonElement::startTimer()
+{
+    m_seekType = mediaController()->supportsScanning() ? Scan : Skip;
+
+    if (m_seekType == Skip) {
+        // Seeking by skipping requires the video to be paused during seeking.
+        m_actionOnStop = mediaController()->paused() ? Nothing : Play;
+        mediaController()->pause();
+    } else {
+        // Seeking by scanning requires the video to be playing during seeking.
+        m_actionOnStop = mediaController()->paused() ? Pause : Nothing;
+        mediaController()->play();
+        mediaController()->setPlaybackRate(nextRate());
+    }
+
+    m_seekTimer.start(0, m_seekType == Skip ? cSkipRepeatDelay : cScanRepeatDelay);
+}
+
+void MediaControlSeekButtonElement::stopTimer()
+{
+    if (m_seekType == Scan)
+        mediaController()->setPlaybackRate(mediaController()->defaultPlaybackRate());
+
+    if (m_actionOnStop == Play)
+        mediaController()->play();
+    else if (m_actionOnStop == Pause)
+        mediaController()->pause();
+
+    if (m_seekTimer.isActive())
+        m_seekTimer.stop();
+}
+
+double MediaControlSeekButtonElement::nextRate() const
+{
+    double rate = std::min(cScanMaximumRate, fabs(mediaController()->playbackRate() * 2));
+    if (!isForwardButton())
+        rate *= -1;
+    return rate;
+}
+
+void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
+{
+    if (m_seekType == Skip) {
+        double skipTime = isForwardButton() ? cSkipTime : -cSkipTime;
+        mediaController()->setCurrentTime(mediaController()->currentTime() + skipTime, IGNORE_EXCEPTION);
+    } else
+        mediaController()->setPlaybackRate(nextRate());
+}
+
+// ----------------------------
+
+MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document)
+    : MediaControlInputElement(document, MediaVolumeSlider)
+    , m_clearMutedOnUserInteraction(false)
+{
+}
+
+void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
+{
+    // Left button is 0. Rejects mouse events not from left button.
+    if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
+        return;
+
+    if (!attached())
+        return;
+
+    MediaControlInputElement::defaultEventHandler(event);
+
+    if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
+        return;
+
+    double volume = value().toDouble();
+    if (volume != mediaController()->volume())
+        mediaController()->setVolume(volume, ASSERT_NO_EXCEPTION);
+    if (m_clearMutedOnUserInteraction)
+        mediaController()->setMuted(false);
+}
+
+bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents()
+{
+    if (!attached())
+        return false;
+
+    return MediaControlInputElement::willRespondToMouseMoveEvents();
+}
+
+bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents()
+{
+    if (!attached())
+        return false;
+
+    return MediaControlInputElement::willRespondToMouseClickEvents();
+}
+
+void MediaControlVolumeSliderElement::setVolume(double volume)
+{
+    if (value().toDouble() != volume)
+        setValue(String::number(volume));
+}
+
+void MediaControlVolumeSliderElement::setClearMutedOnUserInteraction(bool clearMute)
+{
+    m_clearMutedOnUserInteraction = clearMute;
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/shadow/MediaControlElementTypes.h b/Source/core/html/shadow/MediaControlElementTypes.h
new file mode 100644
index 0000000..771f820
--- /dev/null
+++ b/Source/core/html/shadow/MediaControlElementTypes.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 MediaControlElementTypes_h
+#define MediaControlElementTypes_h
+
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/html/MediaControllerInterface.h"
+#include "core/rendering/RenderBlock.h"
+
+namespace WebCore {
+
+// Must match WebKitSystemInterface.h
+enum MediaControlElementType {
+    MediaEnterFullscreenButton = 0,
+    MediaMuteButton,
+    MediaPlayButton,
+    MediaSeekBackButton,
+    MediaSeekForwardButton,
+    MediaSlider,
+    MediaSliderThumb,
+    MediaRewindButton,
+    MediaReturnToRealtimeButton,
+    MediaShowClosedCaptionsButton,
+    MediaHideClosedCaptionsButton,
+    MediaUnMuteButton,
+    MediaPauseButton,
+    MediaTimelineContainer,
+    MediaCurrentTimeDisplay,
+    MediaTimeRemainingDisplay,
+    MediaStatusDisplay,
+    MediaControlsPanel,
+    MediaVolumeSliderContainer,
+    MediaVolumeSlider,
+    MediaVolumeSliderThumb,
+    MediaFullScreenVolumeSlider,
+    MediaFullScreenVolumeSliderThumb,
+    MediaVolumeSliderMuteButton,
+    MediaTextTrackDisplayContainer,
+    MediaTextTrackDisplay,
+    MediaExitFullscreenButton,
+    MediaOverlayPlayButton,
+    MediaClosedCaptionsContainer,
+    MediaClosedCaptionsTrackList,
+};
+
+HTMLMediaElement* toParentMediaElement(Node*);
+inline HTMLMediaElement* toParentMediaElement(RenderObject* renderer) { return toParentMediaElement(renderer->node()); }
+
+MediaControlElementType mediaControlElementType(Node*);
+
+const AtomicString& trackIndexAttributeName();
+int trackListIndexForElement(Element*);
+
+// ----------------------------
+
+class MediaControlElement {
+public:
+    virtual void hide();
+    virtual void show();
+    virtual bool isShowing() const;
+
+    virtual MediaControlElementType displayType() { return m_displayType; }
+    virtual const AtomicString& shadowPseudoId() const = 0;
+
+    virtual void setMediaController(MediaControllerInterface* controller) { m_mediaController = controller; }
+    virtual MediaControllerInterface* mediaController() const { return m_mediaController; }
+
+protected:
+    explicit MediaControlElement(MediaControlElementType, HTMLElement*);
+    ~MediaControlElement() { }
+
+    virtual void setDisplayType(MediaControlElementType);
+    virtual bool isMediaControlElement() const { return true; }
+
+private:
+    MediaControllerInterface* m_mediaController;
+    MediaControlElementType m_displayType;
+    HTMLElement* m_element;
+};
+
+// ----------------------------
+
+class MediaControlDivElement : public HTMLDivElement, public MediaControlElement {
+protected:
+    virtual bool isMediaControlElement() const OVERRIDE { return MediaControlElement::isMediaControlElement(); }
+    explicit MediaControlDivElement(Document*, MediaControlElementType);
+};
+
+// ----------------------------
+
+class MediaControlInputElement : public HTMLInputElement, public MediaControlElement {
+protected:
+    virtual bool isMediaControlElement() const OVERRIDE { return MediaControlElement::isMediaControlElement(); }
+    explicit MediaControlInputElement(Document*, MediaControlElementType);
+
+private:
+    virtual void updateDisplayType() { }
+};
+
+// ----------------------------
+
+class MediaControlTimeDisplayElement : public MediaControlDivElement {
+public:
+    void setCurrentValue(double);
+    double currentValue() const { return m_currentValue; }
+
+protected:
+    explicit MediaControlTimeDisplayElement(Document*, MediaControlElementType);
+
+private:
+    double m_currentValue;
+};
+
+// ----------------------------
+
+class MediaControlMuteButtonElement : public MediaControlInputElement {
+public:
+    void changedMute();
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+
+protected:
+    explicit MediaControlMuteButtonElement(Document*, MediaControlElementType);
+
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+
+private:
+    virtual void updateDisplayType() OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlSeekButtonElement : public MediaControlInputElement {
+public:
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+
+protected:
+    explicit MediaControlSeekButtonElement(Document*, MediaControlElementType);
+
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+    virtual bool isForwardButton() const = 0;
+
+private:
+    void setActive(bool /*flag*/ = true, bool /*pause*/ = false);
+
+    void startTimer();
+    void stopTimer();
+    double nextRate() const;
+    void seekTimerFired(Timer<MediaControlSeekButtonElement>*);
+
+    enum ActionType { Nothing, Play, Pause };
+    ActionType m_actionOnStop;
+    enum SeekType { Skip, Scan };
+    SeekType m_seekType;
+    Timer<MediaControlSeekButtonElement> m_seekTimer;
+};
+
+// ----------------------------
+
+class MediaControlVolumeSliderElement : public MediaControlInputElement {
+public:
+    virtual bool willRespondToMouseMoveEvents() OVERRIDE;
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+    void setVolume(double);
+    void setClearMutedOnUserInteraction(bool);
+
+protected:
+    explicit MediaControlVolumeSliderElement(Document*);
+
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+
+private:
+    bool m_clearMutedOnUserInteraction;
+};
+
+} // namespace WebCore
+
+#endif // MediaControlElementTypes_h
diff --git a/Source/core/html/shadow/MediaControlElements.cpp b/Source/core/html/shadow/MediaControlElements.cpp
new file mode 100644
index 0000000..83e2e1b
--- /dev/null
+++ b/Source/core/html/shadow/MediaControlElements.cpp
@@ -0,0 +1,1052 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/html/shadow/MediaControlElements.h"
+
+#include "core/dom/EventNames.h"
+#include "core/dom/EventTarget.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/MouseEvent.h"
+#include "core/html/DOMTokenList.h"
+#include "core/html/HTMLVideoElement.h"
+#include "core/html/shadow/MediaControls.h"
+#include "core/html/track/TextTrack.h"
+#include "core/html/track/TextTrackList.h"
+#include "core/page/CaptionUserPreferences.h"
+#include "core/page/EventHandler.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/page/PageGroup.h"
+#include "core/page/Settings.h"
+#include "core/platform/Language.h"
+#include "core/platform/LocalizedStrings.h"
+#include "core/platform/graphics/GraphicsContext.h"
+#include "core/rendering/RenderLayer.h"
+#include "core/rendering/RenderMediaControlElements.h"
+#include "core/rendering/RenderSlider.h"
+#include "core/rendering/RenderTheme.h"
+#include "core/rendering/RenderVideo.h"
+#include "core/rendering/RenderView.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId();
+static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId();
+
+static const char* textTracksOffAttrValue = "-1"; // This must match HTMLMediaElement::textTracksOffIndex()
+
+MediaControlPanelElement::MediaControlPanelElement(Document* document)
+    : MediaControlDivElement(document, MediaControlsPanel)
+    , m_canBeDragged(false)
+    , m_isBeingDragged(false)
+    , m_isDisplayed(false)
+    , m_opaque(true)
+    , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
+{
+}
+
+PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(Document* document)
+{
+    return adoptRef(new MediaControlPanelElement(document));
+}
+
+const AtomicString& MediaControlPanelElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+void MediaControlPanelElement::startDrag(const LayoutPoint& eventLocation)
+{
+    if (!m_canBeDragged)
+        return;
+
+    if (m_isBeingDragged)
+        return;
+
+    RenderObject* renderer = this->renderer();
+    if (!renderer || !renderer->isBox())
+        return;
+
+    Frame* frame = document()->frame();
+    if (!frame)
+        return;
+
+    m_lastDragEventLocation = eventLocation;
+
+    frame->eventHandler()->setCapturingMouseEventsNode(this);
+
+    m_isBeingDragged = true;
+}
+
+void MediaControlPanelElement::continueDrag(const LayoutPoint& eventLocation)
+{
+    if (!m_isBeingDragged)
+        return;
+
+    LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation;
+    m_cumulativeDragOffset.move(distanceDragged);
+    m_lastDragEventLocation = eventLocation;
+    setPosition(m_cumulativeDragOffset);
+}
+
+void MediaControlPanelElement::endDrag()
+{
+    if (!m_isBeingDragged)
+        return;
+
+    m_isBeingDragged = false;
+
+    Frame* frame = document()->frame();
+    if (!frame)
+        return;
+
+    frame->eventHandler()->setCapturingMouseEventsNode(0);
+}
+
+void MediaControlPanelElement::startTimer()
+{
+    stopTimer();
+
+    // The timer is required to set the property display:'none' on the panel,
+    // such that captions are correctly displayed at the bottom of the video
+    // at the end of the fadeout transition.
+    double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0;
+    m_transitionTimer.startOneShot(duration);
+}
+
+void MediaControlPanelElement::stopTimer()
+{
+    if (m_transitionTimer.isActive())
+        m_transitionTimer.stop();
+}
+
+void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>*)
+{
+    if (!m_opaque)
+        hide();
+
+    stopTimer();
+}
+
+void MediaControlPanelElement::setPosition(const LayoutPoint& position)
+{
+    double left = position.x();
+    double top = position.y();
+
+    // Set the left and top to control the panel's position; this depends on it being absolute positioned.
+    // Set the margin to zero since the position passed in will already include the effect of the margin.
+    setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX);
+    setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX);
+    setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX);
+    setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX);
+
+    classList()->add("dragged", IGNORE_EXCEPTION);
+}
+
+void MediaControlPanelElement::resetPosition()
+{
+    removeInlineStyleProperty(CSSPropertyLeft);
+    removeInlineStyleProperty(CSSPropertyTop);
+    removeInlineStyleProperty(CSSPropertyMarginLeft);
+    removeInlineStyleProperty(CSSPropertyMarginTop);
+
+    classList()->remove("dragged", IGNORE_EXCEPTION);
+
+    m_cumulativeDragOffset.setX(0);
+    m_cumulativeDragOffset.setY(0);
+}
+
+void MediaControlPanelElement::makeOpaque()
+{
+    if (m_opaque)
+        return;
+
+    double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeInDuration() : 0;
+
+    setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
+    setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
+    setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
+
+    m_opaque = true;
+
+    if (m_isDisplayed)
+        show();
+}
+
+void MediaControlPanelElement::makeTransparent()
+{
+    if (!m_opaque)
+        return;
+
+    double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0;
+
+    setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
+    setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
+    setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
+
+    m_opaque = false;
+    startTimer();
+}
+
+void MediaControlPanelElement::defaultEventHandler(Event* event)
+{
+    MediaControlDivElement::defaultEventHandler(event);
+
+    if (event->isMouseEvent()) {
+        LayoutPoint location = static_cast<MouseEvent*>(event)->absoluteLocation();
+        if (event->type() == eventNames().mousedownEvent && event->target() == this) {
+            startDrag(location);
+            event->setDefaultHandled();
+        } else if (event->type() == eventNames().mousemoveEvent && m_isBeingDragged)
+            continueDrag(location);
+        else if (event->type() == eventNames().mouseupEvent && m_isBeingDragged) {
+            continueDrag(location);
+            endDrag();
+            event->setDefaultHandled();
+        }
+    }
+}
+
+void MediaControlPanelElement::setCanBeDragged(bool canBeDragged)
+{
+    if (m_canBeDragged == canBeDragged)
+        return;
+
+    m_canBeDragged = canBeDragged;
+
+    if (!canBeDragged)
+        endDrag();
+}
+
+void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
+{
+    m_isDisplayed = isDisplayed;
+}
+
+// ----------------------------
+
+MediaControlPanelEnclosureElement::MediaControlPanelEnclosureElement(Document* document)
+    // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
+    : MediaControlDivElement(document, MediaControlsPanel)
+{
+}
+
+PassRefPtr<MediaControlPanelEnclosureElement> MediaControlPanelEnclosureElement::create(Document* document)
+{
+    return adoptRef(new MediaControlPanelEnclosureElement(document));
+}
+
+const AtomicString& MediaControlPanelEnclosureElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+MediaControlOverlayEnclosureElement::MediaControlOverlayEnclosureElement(Document* document)
+    // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
+    : MediaControlDivElement(document, MediaControlsPanel)
+{
+}
+
+PassRefPtr<MediaControlOverlayEnclosureElement> MediaControlOverlayEnclosureElement::create(Document* document)
+{
+    return adoptRef(new MediaControlOverlayEnclosureElement(document));
+}
+
+const AtomicString& MediaControlOverlayEnclosureElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-enclosure", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(Document* document, MediaControls* controls)
+    : MediaControlMuteButtonElement(document, MediaMuteButton)
+    , m_controls(controls)
+{
+}
+
+PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(Document* document, MediaControls* controls)
+{
+    ASSERT(controls);
+
+    RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(document, controls));
+    button->ensureUserAgentShadowRoot();
+    button->setType("button");
+    return button.release();
+}
+
+void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().mouseoverEvent)
+        m_controls->showVolumeSlider();
+
+    MediaControlMuteButtonElement::defaultEventHandler(event);
+}
+
+const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(Document* document)
+    : MediaControlMuteButtonElement(document, MediaMuteButton)
+{
+}
+
+PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(Document* document)
+{
+    RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(document));
+    button->ensureUserAgentShadowRoot();
+    button->setType("button");
+    return button.release();
+}
+
+const AtomicString& MediaControlVolumeSliderMuteButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* document)
+    : MediaControlInputElement(document, MediaPlayButton)
+{
+}
+
+PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(Document* document)
+{
+    RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(document));
+    button->ensureUserAgentShadowRoot();
+    button->setType("button");
+    return button.release();
+}
+
+void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().clickEvent) {
+        if (mediaController()->canPlay())
+            mediaController()->play();
+        else
+            mediaController()->pause();
+        updateDisplayType();
+        event->setDefaultHandled();
+    }
+    HTMLInputElement::defaultEventHandler(event);
+}
+
+void MediaControlPlayButtonElement::updateDisplayType()
+{
+    setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton);
+}
+
+const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(Document* document)
+    : MediaControlInputElement(document, MediaOverlayPlayButton)
+{
+}
+
+PassRefPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(Document* document)
+{
+    RefPtr<MediaControlOverlayPlayButtonElement> button = adoptRef(new MediaControlOverlayPlayButtonElement(document));
+    button->ensureUserAgentShadowRoot();
+    button->setType("button");
+    return button.release();
+}
+
+void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().clickEvent && mediaController()->canPlay()) {
+        mediaController()->play();
+        updateDisplayType();
+        event->setDefaultHandled();
+    }
+    HTMLInputElement::defaultEventHandler(event);
+}
+
+void MediaControlOverlayPlayButtonElement::updateDisplayType()
+{
+    if (mediaController()->canPlay()) {
+        show();
+    } else
+        hide();
+}
+
+const AtomicString& MediaControlOverlayPlayButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+
+// ----------------------------
+
+MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* document, MediaControls* controls)
+    : MediaControlInputElement(document, MediaShowClosedCaptionsButton)
+{
+    UNUSED_PARAM(controls);
+}
+
+PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(Document* document, MediaControls* controls)
+{
+    ASSERT(controls);
+
+    RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document, controls));
+    button->ensureUserAgentShadowRoot();
+    button->setType("button");
+    button->hide();
+    return button.release();
+}
+
+void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
+{
+    bool captionsVisible = mediaController()->closedCaptionsVisible();
+    setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
+    setChecked(captionsVisible);
+}
+
+void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().clickEvent) {
+        // FIXME: It's not great that the shared code is dictating behavior of platform-specific
+        // UI. Not all ports may want the closed captions button to toggle a list of tracks, so
+        // we have to use #if.
+        // https://bugs.webkit.org/show_bug.cgi?id=101877
+        mediaController()->setClosedCaptionsVisible(!mediaController()->closedCaptionsVisible());
+        setChecked(mediaController()->closedCaptionsVisible());
+        updateDisplayType();
+        event->setDefaultHandled();
+    }
+
+    HTMLInputElement::defaultEventHandler(event);
+}
+
+const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+MediaControlClosedCaptionsContainerElement::MediaControlClosedCaptionsContainerElement(Document* document)
+    : MediaControlDivElement(document, MediaClosedCaptionsContainer)
+{
+}
+
+PassRefPtr<MediaControlClosedCaptionsContainerElement> MediaControlClosedCaptionsContainerElement::create(Document* document)
+{
+    RefPtr<MediaControlClosedCaptionsContainerElement> element = adoptRef(new MediaControlClosedCaptionsContainerElement(document));
+    element->hide();
+    return element.release();
+}
+
+const AtomicString& MediaControlClosedCaptionsContainerElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-closed-captions-container", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+MediaControlClosedCaptionsTrackListElement::MediaControlClosedCaptionsTrackListElement(Document* document, MediaControls* controls)
+    : MediaControlDivElement(document, MediaClosedCaptionsTrackList)
+    , m_controls(controls)
+    , m_trackListHasChanged(true)
+{
+}
+
+PassRefPtr<MediaControlClosedCaptionsTrackListElement> MediaControlClosedCaptionsTrackListElement::create(Document* document, MediaControls* controls)
+{
+    ASSERT(controls);
+    RefPtr<MediaControlClosedCaptionsTrackListElement> element = adoptRef(new MediaControlClosedCaptionsTrackListElement(document, controls));
+    return element.release();
+}
+
+void MediaControlClosedCaptionsTrackListElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().clickEvent) {
+        Node* target = event->target()->toNode();
+        if (!target || !target->isElementNode())
+            return;
+
+        // When we created the elements in the track list, we gave them a custom
+        // attribute representing the index in the HTMLMediaElement's list of tracks.
+        // Check if the event target has such a custom element and, if so,
+        // tell the HTMLMediaElement to enable that track.
+
+        RefPtr<TextTrack> textTrack;
+        MenuItemToTrackMap::iterator iter = m_menuToTrackMap.find(toElement(target));
+        if (iter != m_menuToTrackMap.end())
+            textTrack = iter->value;
+        m_menuToTrackMap.clear();
+        m_controls->toggleClosedCaptionTrackList();
+
+        int trackIndex = trackListIndexForElement(toElement(target));
+        if (trackIndex == HTMLMediaElement::textTracksIndexNotFound())
+            return;
+
+        HTMLMediaElement* mediaElement = toParentMediaElement(this);
+        if (!mediaElement)
+            return;
+
+        if (textTrack)
+            mediaElement->setSelectedTextTrack(textTrack.get());
+        else if (trackIndex == HTMLMediaElement::textTracksOffIndex())
+            mediaElement->setSelectedTextTrack(0);
+
+        updateDisplay();
+    }
+
+    MediaControlDivElement::defaultEventHandler(event);
+}
+
+const AtomicString& MediaControlClosedCaptionsTrackListElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-closed-captions-track-list", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+void MediaControlClosedCaptionsTrackListElement::updateDisplay()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, selectedClassValue, ("selected", AtomicString::ConstructFromLiteral));
+
+    if (!mediaController()->hasClosedCaptions())
+        return;
+
+    HTMLMediaElement* mediaElement = toParentMediaElement(this);
+    if (!mediaElement)
+        return;
+
+    TextTrackList* trackList = mediaElement->textTracks();
+
+    if (!trackList || !trackList->length())
+        return;
+
+    if (m_trackListHasChanged)
+        rebuildTrackListMenu();
+
+    bool captionsVisible = mediaElement->closedCaptionsVisible();
+    for (unsigned i = 0, length = m_menuItems.size(); i < length; ++i) {
+        RefPtr<Element> trackItem = m_menuItems[i];
+
+        int trackIndex = trackListIndexForElement(trackItem.get());
+        if (trackIndex == HTMLMediaElement::textTracksIndexNotFound())
+            continue;
+
+        if (trackIndex == HTMLMediaElement::textTracksOffIndex()) {
+            if (captionsVisible)
+                trackItem->classList()->remove(selectedClassValue, ASSERT_NO_EXCEPTION);
+            else
+                trackItem->classList()->add(selectedClassValue, ASSERT_NO_EXCEPTION);
+            continue;
+        }
+
+        RefPtr<TextTrack> textTrack;
+        MenuItemToTrackMap::iterator iter = m_menuToTrackMap.find(trackItem.get());
+        if (iter == m_menuToTrackMap.end())
+            continue;
+        textTrack = iter->value;
+        if (!textTrack)
+            continue;
+        if (textTrack->mode() == TextTrack::showingKeyword())
+            trackItem->classList()->add(selectedClassValue, ASSERT_NO_EXCEPTION);
+        else
+            trackItem->classList()->remove(selectedClassValue, ASSERT_NO_EXCEPTION);
+    }
+}
+
+void MediaControlClosedCaptionsTrackListElement::rebuildTrackListMenu()
+{
+    // Remove any existing content.
+    removeChildren();
+    m_menuItems.clear();
+
+    m_trackListHasChanged = false;
+    m_menuToTrackMap.clear();
+
+    if (!mediaController()->hasClosedCaptions())
+        return;
+
+    HTMLMediaElement* mediaElement = toParentMediaElement(this);
+    if (!mediaElement)
+        return;
+
+    TextTrackList* trackList = mediaElement->textTracks();
+    if (!trackList || !trackList->length())
+        return;
+
+    Document* doc = document();
+    CaptionUserPreferences* captionsUserPreferences = doc->page()->group().captionPreferences();
+    Vector<RefPtr<TextTrack> > tracksForMenu = captionsUserPreferences->sortedTrackListForMenu(trackList);
+
+    RefPtr<Element> captionsHeader = doc->createElement(h3Tag, ASSERT_NO_EXCEPTION);
+    captionsHeader->appendChild(doc->createTextNode(textTrackSubtitlesText()));
+    appendChild(captionsHeader);
+    RefPtr<Element> captionsMenuList = doc->createElement(ulTag, ASSERT_NO_EXCEPTION);
+
+    RefPtr<Element> menuItem;
+    menuItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
+    menuItem->appendChild(doc->createTextNode(textTrackOffText()));
+    menuItem->setAttribute(trackIndexAttributeName(), textTracksOffAttrValue, ASSERT_NO_EXCEPTION);
+    captionsMenuList->appendChild(menuItem);
+    m_menuItems.append(menuItem);
+
+    for (unsigned i = 0, length = tracksForMenu.size(); i < length; ++i) {
+        RefPtr<TextTrack> textTrack = tracksForMenu[i];
+        menuItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
+
+        // Add a custom attribute to the <li> element which will allow
+        // us to easily associate the user tapping here with the
+        // track. Since this list is rebuilt if the tracks change, we
+        // should always be in sync.
+        menuItem->setAttribute(trackIndexAttributeName(), String::number(i), ASSERT_NO_EXCEPTION);
+
+        menuItem->appendChild(doc->createTextNode(captionsUserPreferences->displayNameForTrack(textTrack.get())));
+
+        captionsMenuList->appendChild(menuItem);
+        m_menuItems.append(menuItem);
+        m_menuToTrackMap.add(menuItem, textTrack);
+    }
+
+    appendChild(captionsMenuList);
+
+    updateDisplay();
+}
+
+// ----------------------------
+
+MediaControlTimelineElement::MediaControlTimelineElement(Document* document, MediaControls* controls)
+    : MediaControlInputElement(document, MediaSlider)
+    , m_controls(controls)
+{
+}
+
+PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(Document* document, MediaControls* controls)
+{
+    ASSERT(controls);
+
+    RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(document, controls));
+    timeline->ensureUserAgentShadowRoot();
+    timeline->setType("range");
+    timeline->setAttribute(precisionAttr, "float");
+    return timeline.release();
+}
+
+void MediaControlTimelineElement::defaultEventHandler(Event* event)
+{
+    // Left button is 0. Rejects mouse events not from left button.
+    if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
+        return;
+
+    if (!attached())
+        return;
+
+    if (event->type() == eventNames().mousedownEvent)
+        mediaController()->beginScrubbing();
+
+    if (event->type() == eventNames().mouseupEvent)
+        mediaController()->endScrubbing();
+
+    MediaControlInputElement::defaultEventHandler(event);
+
+    if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
+        return;
+
+    double time = value().toDouble();
+    if (event->type() == eventNames().inputEvent && time != mediaController()->currentTime())
+        mediaController()->setCurrentTime(time, IGNORE_EXCEPTION);
+
+    RenderSlider* slider = toRenderSlider(renderer());
+    if (slider && slider->inDragMode())
+        m_controls->updateCurrentTimeDisplay();
+}
+
+bool MediaControlTimelineElement::willRespondToMouseClickEvents()
+{
+    if (!attached())
+        return false;
+
+    return true;
+}
+
+void MediaControlTimelineElement::setPosition(double currentTime)
+{
+    setValue(String::number(currentTime));
+}
+
+void MediaControlTimelineElement::setDuration(double duration)
+{
+    setAttribute(maxAttr, String::number(std::isfinite(duration) ? duration : 0));
+}
+
+
+const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+MediaControlPanelVolumeSliderElement::MediaControlPanelVolumeSliderElement(Document* document)
+    : MediaControlVolumeSliderElement(document)
+{
+}
+
+PassRefPtr<MediaControlPanelVolumeSliderElement> MediaControlPanelVolumeSliderElement::create(Document* document)
+{
+    RefPtr<MediaControlPanelVolumeSliderElement> slider = adoptRef(new MediaControlPanelVolumeSliderElement(document));
+    slider->ensureUserAgentShadowRoot();
+    slider->setType("range");
+    slider->setAttribute(precisionAttr, "float");
+    slider->setAttribute(maxAttr, "1");
+    return slider.release();
+}
+
+const AtomicString& MediaControlPanelVolumeSliderElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+// ----------------------------
+
+MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document)
+    : MediaControlInputElement(document, MediaEnterFullscreenButton)
+{
+}
+
+PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(Document* document)
+{
+    RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(document));
+    button->ensureUserAgentShadowRoot();
+    button->setType("button");
+    button->hide();
+    return button.release();
+}
+
+void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
+{
+    if (event->type() == eventNames().clickEvent) {
+        // Only use the new full screen API if the fullScreenEnabled setting has
+        // been explicitly enabled. Otherwise, use the old fullscreen API. This
+        // allows apps which embed a WebView to retain the existing full screen
+        // video implementation without requiring them to implement their own full
+        // screen behavior.
+        if (document()->settings() && document()->settings()->fullScreenEnabled()) {
+            if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == toParentMediaElement(this))
+                document()->webkitCancelFullScreen();
+            else
+                document()->requestFullScreenForElement(toParentMediaElement(this), 0, Document::ExemptIFrameAllowFullScreenRequirement);
+        } else
+            mediaController()->enterFullscreen();
+        event->setDefaultHandled();
+    }
+    HTMLInputElement::defaultEventHandler(event);
+}
+
+const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
+{
+    setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
+}
+
+// ----------------------------
+
+MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(Document* document)
+    : MediaControlTimeDisplayElement(document, MediaTimeRemainingDisplay)
+{
+}
+
+PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(Document* document)
+{
+    return adoptRef(new MediaControlTimeRemainingDisplayElement(document));
+}
+
+static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const
+{
+    return getMediaControlTimeRemainingDisplayElementShadowPseudoId();
+}
+
+// ----------------------------
+
+MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(Document* document)
+    : MediaControlTimeDisplayElement(document, MediaCurrentTimeDisplay)
+{
+}
+
+PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(Document* document)
+{
+    return adoptRef(new MediaControlCurrentTimeDisplayElement(document));
+}
+
+static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral));
+    return id;
+}
+
+const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const
+{
+    return getMediaControlCurrentTimeDisplayElementShadowPseudoId();
+}
+
+// ----------------------------
+
+MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document* document)
+    : MediaControlDivElement(document, MediaTextTrackDisplayContainer)
+    , m_fontSize(0)
+{
+}
+
+PassRefPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(Document* document)
+{
+    RefPtr<MediaControlTextTrackContainerElement> element = adoptRef(new MediaControlTextTrackContainerElement(document));
+    element->hide();
+    return element.release();
+}
+
+RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderTextTrackContainerElement(this);
+}
+
+const AtomicString& MediaControlTextTrackContainerElement::textTrackContainerElementShadowPseudoId()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral));
+    return id;
+}
+    
+const AtomicString& MediaControlTextTrackContainerElement::shadowPseudoId() const
+{
+    return textTrackContainerElementShadowPseudoId();
+}
+
+void MediaControlTextTrackContainerElement::updateDisplay()
+{
+    if (!mediaController()->closedCaptionsVisible()) {
+        removeChildren();
+        return;
+    }
+
+    HTMLMediaElement* mediaElement = toParentMediaElement(this);
+    // 1. If the media element is an audio element, or is another playback
+    // mechanism with no rendering area, abort these steps. There is nothing to
+    // render.
+    if (!mediaElement || !mediaElement->isVideo())
+        return;
+
+    // 2. Let video be the media element or other playback mechanism.
+    HTMLVideoElement* video = static_cast<HTMLVideoElement*>(mediaElement);
+
+    // 3. Let output be an empty list of absolutely positioned CSS block boxes.
+    Vector<RefPtr<HTMLDivElement> > output;
+
+    // 4. If the user agent is exposing a user interface for video, add to
+    // output one or more completely transparent positioned CSS block boxes that
+    // cover the same region as the user interface.
+
+    // 5. If the last time these rules were run, the user agent was not exposing
+    // a user interface for video, but now it is, let reset be true. Otherwise,
+    // let reset be false.
+
+    // There is nothing to be done explicitly for 4th and 5th steps, as
+    // everything is handled through CSS. The caption box is on top of the
+    // controls box, in a container set with the -webkit-box display property.
+
+    // 6. Let tracks be the subset of video's list of text tracks that have as
+    // their rules for updating the text track rendering these rules for
+    // updating the display of WebVTT text tracks, and whose text track mode is
+    // showing or showing by default.
+    // 7. Let cues be an empty list of text track cues.
+    // 8. For each track track in tracks, append to cues all the cues from
+    // track's list of cues that have their text track cue active flag set.
+    CueList activeCues = video->currentlyActiveCues();
+
+    // 9. If reset is false, then, for each text track cue cue in cues: if cue's
+    // text track cue display state has a set of CSS boxes, then add those boxes
+    // to output, and remove cue from cues.
+
+    // There is nothing explicitly to be done here, as all the caching occurs
+    // within the TextTrackCue instance itself. If parameters of the cue change,
+    // the display tree is cleared.
+
+    // 10. For each text track cue cue in cues that has not yet had
+    // corresponding CSS boxes added to output, in text track cue order, run the
+    // following substeps:
+    for (size_t i = 0; i < activeCues.size(); ++i) {
+        TextTrackCue* cue = activeCues[i].data();
+
+        ASSERT(cue->isActive());
+        if (!cue->track() || !cue->track()->isRendered() || !cue->isActive())
+            continue;
+
+        RefPtr<TextTrackCueBox> displayBox = cue->getDisplayTree(m_videoDisplaySize.size());
+        if (displayBox->hasChildNodes() && !contains(static_cast<Node*>(displayBox.get())))
+            // Note: the display tree of a cue is removed when the active flag of the cue is unset.
+            appendChild(displayBox, ASSERT_NO_EXCEPTION, AttachNow);
+    }
+
+    // 11. Return output.
+    if (hasChildNodes()) {
+        show();
+        if (mediaElement->requiresTextTrackRepresentation()) {
+            if (!m_textTrackRepresentation)
+                m_textTrackRepresentation = TextTrackRepresentation::create(this);
+            mediaElement->setTextTrackRepresentation(m_textTrackRepresentation.get());
+
+            if (Page* page = document()->page())
+                m_textTrackRepresentation->setContentScale(page->deviceScaleFactor());
+
+            m_textTrackRepresentation->update();
+            setInlineStyleProperty(CSSPropertyWidth, String::number(m_videoDisplaySize.size().width()) + "px");
+            setInlineStyleProperty(CSSPropertyHeight, String::number(m_videoDisplaySize.size().height()) + "px");
+        }
+    } else {
+        hide();
+        m_textTrackRepresentation = nullptr;
+        mediaElement->setTextTrackRepresentation(0);
+        removeInlineStyleProperty(CSSPropertyWidth);
+        removeInlineStyleProperty(CSSPropertyHeight);
+    }
+}
+
+void MediaControlTextTrackContainerElement::updateSizes(bool forceUpdate)
+{
+    HTMLMediaElement* mediaElement = toParentMediaElement(this);
+    if (!mediaElement)
+        return;
+
+    if (!document()->page())
+        return;
+
+    IntRect videoBox;
+
+    if (m_textTrackRepresentation)
+        videoBox = m_textTrackRepresentation->bounds();
+    else {
+        if (!mediaElement->renderer() || !mediaElement->renderer()->isVideo())
+            return;
+        videoBox = toRenderVideo(mediaElement->renderer())->videoBox();
+    }
+
+    if (!forceUpdate && m_videoDisplaySize == videoBox)
+        return;
+    m_videoDisplaySize = videoBox;
+
+    if (m_textTrackRepresentation) {
+        setInlineStyleProperty(CSSPropertyWidth, String::number(m_videoDisplaySize.size().width()) + "px");
+        setInlineStyleProperty(CSSPropertyHeight, String::number(m_videoDisplaySize.size().height()) + "px");
+    }
+
+    float smallestDimension = std::min(m_videoDisplaySize.size().height(), m_videoDisplaySize.size().width());
+
+    bool important;
+    float fontSize = smallestDimension * (document()->page()->group().captionPreferences()->captionFontSizeScale(important));
+    if (fontSize != m_fontSize) {
+        m_fontSize = fontSize;
+        setInlineStyleProperty(CSSPropertyFontSize, String::number(fontSize) + "px", important);
+    }
+
+    CueList activeCues = mediaElement->currentlyActiveCues();
+    for (size_t i = 0; i < activeCues.size(); ++i) {
+        TextTrackCue* cue = activeCues[i].data();
+        cue->videoSizeDidChange(m_videoDisplaySize.size());
+    }
+}
+
+void MediaControlTextTrackContainerElement::paintTextTrackRepresentation(GraphicsContext* context, const IntRect& contextRect)
+{
+    if (!hasChildNodes())
+        return;
+
+    RenderObject* renderer = this->renderer();
+    if (!renderer)
+        return;
+
+    Frame* frame = document()->frame();
+    if (!frame)
+        return;
+
+    document()->updateLayout();
+
+    LayoutRect topLevelRect;
+    IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
+
+    // Translate the renderer painting rect into graphics context coordinates.
+    FloatSize translation(-paintingRect.x(), -paintingRect.y());
+
+    // But anchor to the bottom of the graphics context rect.
+    translation.expand(max(0, contextRect.width() - paintingRect.width()), max(0, contextRect.height() - paintingRect.height()));
+
+    context->translate(translation);
+
+    RenderLayer* layer = frame->contentRenderer()->layer();
+    layer->paint(context, paintingRect, PaintBehaviorFlattenCompositingLayers, renderer, 0, RenderLayer::PaintLayerPaintingCompositingAllPhases);
+}
+
+void MediaControlTextTrackContainerElement::textTrackRepresentationBoundsChanged(const IntRect&)
+{
+    updateSizes();
+}
+
+// ----------------------------
+
+} // namespace WebCore
diff --git a/Source/core/html/shadow/MediaControlElements.h b/Source/core/html/shadow/MediaControlElements.h
new file mode 100644
index 0000000..0d52015
--- /dev/null
+++ b/Source/core/html/shadow/MediaControlElements.h
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 MediaControlElements_h
+#define MediaControlElements_h
+
+#include "core/html/shadow/MediaControlElementTypes.h"
+#include "core/platform/graphics/TextTrackRepresentation.h"
+
+namespace WebCore {
+
+// ----------------------------
+
+class MediaControlPanelElement FINAL : public MediaControlDivElement {
+public:
+    static PassRefPtr<MediaControlPanelElement> create(Document*);
+
+    void setCanBeDragged(bool);
+    void setIsDisplayed(bool);
+
+    void resetPosition();
+    void makeOpaque();
+    void makeTransparent();
+
+    virtual bool willRespondToMouseMoveEvents() OVERRIDE { return true; }
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+
+private:
+    explicit MediaControlPanelElement(Document*);
+
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+
+    void startDrag(const LayoutPoint& eventLocation);
+    void continueDrag(const LayoutPoint& eventLocation);
+    void endDrag();
+
+    void startTimer();
+    void stopTimer();
+    void transitionTimerFired(Timer<MediaControlPanelElement>*);
+
+    void setPosition(const LayoutPoint&);
+
+    bool m_canBeDragged;
+    bool m_isBeingDragged;
+    bool m_isDisplayed;
+    bool m_opaque;
+    LayoutPoint m_lastDragEventLocation;
+    LayoutPoint m_cumulativeDragOffset;
+
+    Timer<MediaControlPanelElement> m_transitionTimer;
+};
+
+// ----------------------------
+
+class MediaControlPanelEnclosureElement FINAL : public MediaControlDivElement {
+public:
+    static PassRefPtr<MediaControlPanelEnclosureElement> create(Document*);
+
+private:
+    explicit MediaControlPanelEnclosureElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlOverlayEnclosureElement FINAL : public MediaControlDivElement {
+public:
+    static PassRefPtr<MediaControlOverlayEnclosureElement> create(Document*);
+
+private:
+    explicit MediaControlOverlayEnclosureElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlPanelMuteButtonElement FINAL : public MediaControlMuteButtonElement {
+public:
+    static PassRefPtr<MediaControlPanelMuteButtonElement> create(Document*, MediaControls*);
+
+    virtual bool willRespondToMouseMoveEvents() OVERRIDE { return true; }
+
+private:
+    explicit MediaControlPanelMuteButtonElement(Document*, MediaControls*);
+
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+
+    MediaControls* m_controls;
+};
+
+// ----------------------------
+
+class MediaControlVolumeSliderMuteButtonElement FINAL : public MediaControlMuteButtonElement {
+public:
+    static PassRefPtr<MediaControlVolumeSliderMuteButtonElement> create(Document*);
+
+private:
+    explicit MediaControlVolumeSliderMuteButtonElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+};
+
+
+// ----------------------------
+
+class MediaControlPlayButtonElement FINAL : public MediaControlInputElement {
+public:
+    static PassRefPtr<MediaControlPlayButtonElement> create(Document*);
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+    virtual void updateDisplayType() OVERRIDE;
+
+private:
+    explicit MediaControlPlayButtonElement(Document*);
+
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlOverlayPlayButtonElement FINAL : public MediaControlInputElement {
+public:
+    static PassRefPtr<MediaControlOverlayPlayButtonElement> create(Document*);
+
+    virtual void updateDisplayType() OVERRIDE;
+
+private:
+    explicit MediaControlOverlayPlayButtonElement(Document*);
+
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlToggleClosedCaptionsButtonElement FINAL : public MediaControlInputElement {
+public:
+    static PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> create(Document*, MediaControls*);
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+
+    virtual void updateDisplayType() OVERRIDE;
+
+private:
+    explicit MediaControlToggleClosedCaptionsButtonElement(Document*, MediaControls*);
+
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlClosedCaptionsContainerElement FINAL : public MediaControlDivElement {
+public:
+    static PassRefPtr<MediaControlClosedCaptionsContainerElement> create(Document*);
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+
+private:
+    MediaControlClosedCaptionsContainerElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlClosedCaptionsTrackListElement FINAL : public MediaControlDivElement {
+public:
+    static PassRefPtr<MediaControlClosedCaptionsTrackListElement> create(Document*, MediaControls*);
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+
+    void updateDisplay();
+    void resetTrackListMenu() { m_trackListHasChanged = true; }
+
+private:
+    MediaControlClosedCaptionsTrackListElement(Document*, MediaControls*);
+
+    void rebuildTrackListMenu();
+
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+
+    typedef Vector<RefPtr<Element> > TrackMenuItems;
+    TrackMenuItems m_menuItems;
+    typedef HashMap<RefPtr<Element>, RefPtr<TextTrack> > MenuItemToTrackMap;
+    MenuItemToTrackMap m_menuToTrackMap;
+    MediaControls* m_controls;
+    bool m_trackListHasChanged;
+};
+
+// ----------------------------
+
+class MediaControlTimelineElement FINAL : public MediaControlInputElement {
+public:
+    static PassRefPtr<MediaControlTimelineElement> create(Document*, MediaControls*);
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+    void setPosition(double);
+    void setDuration(double);
+
+private:
+    explicit MediaControlTimelineElement(Document*, MediaControls*);
+
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+
+    MediaControls* m_controls;
+};
+
+// ----------------------------
+
+class MediaControlFullscreenButtonElement FINAL : public MediaControlInputElement {
+public:
+    static PassRefPtr<MediaControlFullscreenButtonElement> create(Document*);
+
+    virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; }
+
+    virtual void setIsFullscreen(bool);
+
+private:
+    explicit MediaControlFullscreenButtonElement(Document*);
+
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlPanelVolumeSliderElement FINAL : public MediaControlVolumeSliderElement {
+public:
+    static PassRefPtr<MediaControlPanelVolumeSliderElement> create(Document*);
+
+private:
+    explicit MediaControlPanelVolumeSliderElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlTimeRemainingDisplayElement FINAL : public MediaControlTimeDisplayElement {
+public:
+    static PassRefPtr<MediaControlTimeRemainingDisplayElement> create(Document*);
+
+private:
+    explicit MediaControlTimeRemainingDisplayElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlCurrentTimeDisplayElement FINAL : public MediaControlTimeDisplayElement {
+public:
+    static PassRefPtr<MediaControlCurrentTimeDisplayElement> create(Document*);
+
+private:
+    explicit MediaControlCurrentTimeDisplayElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+};
+
+// ----------------------------
+
+class MediaControlTextTrackContainerElement FINAL : public MediaControlDivElement, public TextTrackRepresentationClient {
+public:
+    static PassRefPtr<MediaControlTextTrackContainerElement> create(Document*);
+
+    void updateDisplay();
+    void updateSizes(bool forceUpdate = false);
+    static const AtomicString& textTrackContainerElementShadowPseudoId();
+
+private:
+    explicit MediaControlTextTrackContainerElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+
+    virtual void paintTextTrackRepresentation(GraphicsContext*, const IntRect&) OVERRIDE;
+    virtual void textTrackRepresentationBoundsChanged(const IntRect&) OVERRIDE;
+    OwnPtr<TextTrackRepresentation> m_textTrackRepresentation;
+
+    IntRect m_videoDisplaySize;
+    float m_fontSize;
+};
+
+
+} // namespace WebCore
+
+#endif // MediaControlElements_h
diff --git a/Source/core/html/shadow/MediaControls.cpp b/Source/core/html/shadow/MediaControls.cpp
new file mode 100644
index 0000000..3c4d5d9
--- /dev/null
+++ b/Source/core/html/shadow/MediaControls.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/shadow/MediaControls.h"
+
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/page/Settings.h"
+
+namespace WebCore {
+
+static const double timeWithoutMouseMovementBeforeHidingFullscreenControls = 3;
+
+MediaControls::MediaControls(Document* document)
+    : HTMLDivElement(HTMLNames::divTag, document)
+    , m_mediaController(0)
+    , m_panel(0)
+    , m_textDisplayContainer(0)
+    , m_playButton(0)
+    , m_currentTimeDisplay(0)
+    , m_timeline(0)
+    , m_panelMuteButton(0)
+    , m_volumeSlider(0)
+    , m_toggleClosedCaptionsButton(0)
+    , m_fullScreenButton(0)
+    , m_hideFullscreenControlsTimer(this, &MediaControls::hideFullscreenControlsTimerFired)
+    , m_isFullscreen(false)
+    , m_isMouseOverControls(false)
+{
+}
+
+void MediaControls::setMediaController(MediaControllerInterface* controller)
+{
+    if (m_mediaController == controller)
+        return;
+    m_mediaController = controller;
+
+    if (m_panel)
+        m_panel->setMediaController(controller);
+    if (m_textDisplayContainer)
+        m_textDisplayContainer->setMediaController(controller);
+    if (m_playButton)
+        m_playButton->setMediaController(controller);
+    if (m_currentTimeDisplay)
+        m_currentTimeDisplay->setMediaController(controller);
+    if (m_timeline)
+        m_timeline->setMediaController(controller);
+    if (m_panelMuteButton)
+        m_panelMuteButton->setMediaController(controller);
+    if (m_volumeSlider)
+        m_volumeSlider->setMediaController(controller);
+    if (m_toggleClosedCaptionsButton)
+        m_toggleClosedCaptionsButton->setMediaController(controller);
+    if (m_fullScreenButton)
+        m_fullScreenButton->setMediaController(controller);
+}
+
+void MediaControls::reset()
+{
+    Page* page = document()->page();
+    if (!page)
+        return;
+
+    m_playButton->updateDisplayType();
+
+    updateCurrentTimeDisplay();
+
+    double duration = m_mediaController->duration();
+    if (std::isfinite(duration) || page->theme()->hasOwnDisabledStateHandlingFor(MediaSliderPart)) {
+        m_timeline->setDuration(duration);
+        m_timeline->setPosition(m_mediaController->currentTime());
+    }
+
+    if (m_mediaController->hasAudio() || page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart))
+        m_panelMuteButton->show();
+    else
+        m_panelMuteButton->hide();
+
+    if (m_volumeSlider) {
+        if (!m_mediaController->hasAudio())
+            m_volumeSlider->hide();
+        else {
+            m_volumeSlider->show();
+            m_volumeSlider->setVolume(m_mediaController->volume());
+        }
+    }
+
+    refreshClosedCaptionsButtonVisibility();
+
+    if (m_fullScreenButton) {
+        if (m_mediaController->supportsFullscreen() && m_mediaController->hasVideo())
+            m_fullScreenButton->show();
+        else
+            m_fullScreenButton->hide();
+    }
+
+    makeOpaque();
+}
+
+void MediaControls::reportedError()
+{
+    Page* page = document()->page();
+    if (!page)
+        return;
+
+    if (!page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) {
+        m_panelMuteButton->hide();
+        m_volumeSlider->hide();
+    }
+
+    if (m_toggleClosedCaptionsButton && !page->theme()->hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart))
+        m_toggleClosedCaptionsButton->hide();
+
+    if (m_fullScreenButton && !page->theme()->hasOwnDisabledStateHandlingFor(MediaEnterFullscreenButtonPart))
+        m_fullScreenButton->hide();
+}
+
+void MediaControls::loadedMetadata()
+{
+    reset();
+}
+
+void MediaControls::show()
+{
+    makeOpaque();
+    m_panel->setIsDisplayed(true);
+    m_panel->show();
+}
+
+void MediaControls::hide()
+{
+    m_panel->setIsDisplayed(false);
+    m_panel->hide();
+}
+
+void MediaControls::makeOpaque()
+{
+    m_panel->makeOpaque();
+}
+
+void MediaControls::makeTransparent()
+{
+    m_panel->makeTransparent();
+}
+
+bool MediaControls::shouldHideControls()
+{
+    return !m_panel->hovered();
+}
+
+void MediaControls::bufferingProgressed()
+{
+    // We only need to update buffering progress when paused, during normal
+    // playback playbackProgressed() will take care of it.
+    if (m_mediaController->paused())
+        m_timeline->setPosition(m_mediaController->currentTime());
+}
+
+void MediaControls::playbackStarted()
+{
+    m_playButton->updateDisplayType();
+    m_timeline->setPosition(m_mediaController->currentTime());
+    updateCurrentTimeDisplay();
+
+    if (m_isFullscreen)
+        startHideFullscreenControlsTimer();
+}
+
+void MediaControls::playbackProgressed()
+{
+    m_timeline->setPosition(m_mediaController->currentTime());
+    updateCurrentTimeDisplay();
+
+    if (!m_isMouseOverControls && m_mediaController->hasVideo())
+        makeTransparent();
+}
+
+void MediaControls::playbackStopped()
+{
+    m_playButton->updateDisplayType();
+    m_timeline->setPosition(m_mediaController->currentTime());
+    updateCurrentTimeDisplay();
+    makeOpaque();
+
+    stopHideFullscreenControlsTimer();
+}
+
+void MediaControls::showVolumeSlider()
+{
+    if (!m_mediaController->hasAudio())
+        return;
+
+    m_volumeSlider->show();
+}
+
+void MediaControls::changedMute()
+{
+    m_panelMuteButton->changedMute();
+}
+
+void MediaControls::changedVolume()
+{
+    if (m_volumeSlider)
+        m_volumeSlider->setVolume(m_mediaController->volume());
+}
+
+void MediaControls::changedClosedCaptionsVisibility()
+{
+    if (m_toggleClosedCaptionsButton)
+        m_toggleClosedCaptionsButton->updateDisplayType();
+}
+
+void MediaControls::refreshClosedCaptionsButtonVisibility()
+{
+    if (!m_toggleClosedCaptionsButton)
+        return;
+
+    if (m_mediaController->hasClosedCaptions())
+        m_toggleClosedCaptionsButton->show();
+    else
+        m_toggleClosedCaptionsButton->hide();
+}
+
+void MediaControls::closedCaptionTracksChanged()
+{
+    refreshClosedCaptionsButtonVisibility();
+}
+
+void MediaControls::enteredFullscreen()
+{
+    m_isFullscreen = true;
+    m_fullScreenButton->setIsFullscreen(true);
+
+    if (Page* page = document()->page())
+        page->chrome()->setCursorHiddenUntilMouseMoves(true);
+
+    startHideFullscreenControlsTimer();
+}
+
+void MediaControls::exitedFullscreen()
+{
+    m_isFullscreen = false;
+    m_fullScreenButton->setIsFullscreen(false);
+    stopHideFullscreenControlsTimer();
+}
+
+void MediaControls::defaultEventHandler(Event* event)
+{
+    HTMLDivElement::defaultEventHandler(event);
+
+    if (event->type() == eventNames().mouseoverEvent) {
+        if (!containsRelatedTarget(event)) {
+            m_isMouseOverControls = true;
+            if (!m_mediaController->canPlay()) {
+                makeOpaque();
+                if (shouldHideControls())
+                    startHideFullscreenControlsTimer();
+            }
+        }
+        return;
+    }
+
+    if (event->type() == eventNames().mouseoutEvent) {
+        if (!containsRelatedTarget(event)) {
+            m_isMouseOverControls = false;
+            stopHideFullscreenControlsTimer();
+        }
+        return;
+    }
+
+    if (event->type() == eventNames().mousemoveEvent) {
+        if (m_isFullscreen) {
+            // When we get a mouse move in fullscreen mode, show the media controls, and start a timer
+            // that will hide the media controls after a 3 seconds without a mouse move.
+            makeOpaque();
+            if (shouldHideControls())
+                startHideFullscreenControlsTimer();
+        }
+        return;
+    }
+}
+
+void MediaControls::hideFullscreenControlsTimerFired(Timer<MediaControls>*)
+{
+    if (m_mediaController->paused())
+        return;
+
+    if (!m_isFullscreen)
+        return;
+
+    if (!shouldHideControls())
+        return;
+
+    if (Page* page = document()->page())
+        page->chrome()->setCursorHiddenUntilMouseMoves(true);
+
+    makeTransparent();
+}
+
+void MediaControls::startHideFullscreenControlsTimer()
+{
+    if (!m_isFullscreen)
+        return;
+
+    Page* page = document()->page();
+    if (!page)
+        return;
+
+    m_hideFullscreenControlsTimer.startOneShot(timeWithoutMouseMovementBeforeHidingFullscreenControls);
+}
+
+void MediaControls::stopHideFullscreenControlsTimer()
+{
+    m_hideFullscreenControlsTimer.stop();
+}
+
+const AtomicString& MediaControls::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls"));
+    return id;
+}
+
+bool MediaControls::containsRelatedTarget(Event* event)
+{
+    if (!event->isMouseEvent())
+        return false;
+    EventTarget* relatedTarget = static_cast<MouseEvent*>(event)->relatedTarget();
+    if (!relatedTarget)
+        return false;
+    return contains(relatedTarget->toNode());
+}
+
+void MediaControls::createTextTrackDisplay()
+{
+    if (m_textDisplayContainer)
+        return;
+
+    RefPtr<MediaControlTextTrackContainerElement> textDisplayContainer = MediaControlTextTrackContainerElement::create(document());
+    m_textDisplayContainer = textDisplayContainer.get();
+
+    if (m_mediaController)
+        m_textDisplayContainer->setMediaController(m_mediaController);
+
+    // Insert it before the first controller element so it always displays behind the controls.
+    insertBefore(textDisplayContainer.release(), m_panel, IGNORE_EXCEPTION, AttachLazily);
+}
+
+void MediaControls::showTextTrackDisplay()
+{
+    if (!m_textDisplayContainer)
+        createTextTrackDisplay();
+    m_textDisplayContainer->show();
+}
+
+void MediaControls::hideTextTrackDisplay()
+{
+    if (!m_textDisplayContainer)
+        createTextTrackDisplay();
+    m_textDisplayContainer->hide();
+}
+
+void MediaControls::updateTextTrackDisplay()
+{
+    if (!m_textDisplayContainer)
+        createTextTrackDisplay();
+
+    m_textDisplayContainer->updateDisplay();
+}
+    
+void MediaControls::textTrackPreferencesChanged()
+{
+    if (m_textDisplayContainer)
+        m_textDisplayContainer->updateSizes(true);
+    closedCaptionTracksChanged();
+}
+
+}
diff --git a/Source/core/html/shadow/MediaControls.h b/Source/core/html/shadow/MediaControls.h
new file mode 100644
index 0000000..ef336f7
--- /dev/null
+++ b/Source/core/html/shadow/MediaControls.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 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 COMPUTER, 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 COMPUTER, 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 MediaControls_h
+#define MediaControls_h
+
+#include "HTMLNames.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/html/shadow/MediaControlElements.h"
+#include "core/page/Chrome.h"
+#include "core/page/Page.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/RefPtr.h>
+
+#include "core/html/track/TextTrackCue.h"
+
+namespace WebCore {
+
+class Document;
+class Event;
+class Page;
+class MediaPlayer;
+
+class RenderBox;
+class RenderMedia;
+
+// An abstract class with the media control elements that all ports support.
+class MediaControls : public HTMLDivElement {
+  public:
+    virtual ~MediaControls() {}
+
+    // This function is to be implemented in your port-specific media
+    // controls implementation since it will return a child instance.
+    static PassRefPtr<MediaControls> create(Document*);
+
+    virtual void setMediaController(MediaControllerInterface*);
+
+    virtual void reset();
+    virtual void reportedError();
+    virtual void loadedMetadata();
+
+    virtual void show();
+    virtual void hide();
+    virtual void makeOpaque();
+    virtual void makeTransparent();
+    virtual bool shouldHideControls();
+
+    virtual void bufferingProgressed();
+    virtual void playbackStarted();
+    virtual void playbackProgressed();
+    virtual void playbackStopped();
+
+    virtual void updateStatusDisplay() { };
+    virtual void updateCurrentTimeDisplay() = 0;
+    virtual void showVolumeSlider();
+
+    virtual void changedMute();
+    virtual void changedVolume();
+
+    virtual void changedClosedCaptionsVisibility();
+    virtual void refreshClosedCaptionsButtonVisibility();
+    virtual void toggleClosedCaptionTrackList() { }
+    virtual void closedCaptionTracksChanged();
+
+    virtual void enteredFullscreen();
+    virtual void exitedFullscreen();
+
+    virtual bool willRespondToMouseMoveEvents() OVERRIDE { return true; }
+
+    virtual void hideFullscreenControlsTimerFired(Timer<MediaControls>*);
+    virtual void startHideFullscreenControlsTimer();
+    virtual void stopHideFullscreenControlsTimer();
+
+    virtual void createTextTrackDisplay();
+    virtual void showTextTrackDisplay();
+    virtual void hideTextTrackDisplay();
+    virtual void updateTextTrackDisplay();
+    virtual void textTrackPreferencesChanged();
+
+protected:
+    explicit MediaControls(Document*);
+
+    virtual void defaultEventHandler(Event*);
+
+    virtual bool containsRelatedTarget(Event*);
+
+    MediaControllerInterface* m_mediaController;
+
+    // Container for the media control elements.
+    MediaControlPanelElement* m_panel;
+
+    // Container for the text track cues.
+    MediaControlTextTrackContainerElement* m_textDisplayContainer;
+
+    // Media control elements.
+    MediaControlPlayButtonElement* m_playButton;
+    MediaControlCurrentTimeDisplayElement* m_currentTimeDisplay;
+    MediaControlTimelineElement* m_timeline;
+    MediaControlPanelMuteButtonElement* m_panelMuteButton;
+    MediaControlPanelVolumeSliderElement* m_volumeSlider;
+    MediaControlToggleClosedCaptionsButtonElement* m_toggleClosedCaptionsButton;
+    MediaControlFullscreenButtonElement* m_fullScreenButton;
+
+    Timer<MediaControls> m_hideFullscreenControlsTimer;
+    bool m_isFullscreen;
+    bool m_isMouseOverControls;
+
+private:
+    virtual bool isMediaControls() const { return true; }
+
+    virtual const AtomicString& shadowPseudoId() const;
+};
+
+inline MediaControls* toMediaControls(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isMediaControls());
+    return static_cast<MediaControls*>(node);
+}
+
+// This will catch anyone doing an unneccessary cast.
+void toMediaControls(const MediaControls*);
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/MediaControlsChromium.cpp b/Source/core/html/shadow/MediaControlsChromium.cpp
new file mode 100644
index 0000000..4d94377
--- /dev/null
+++ b/Source/core/html/shadow/MediaControlsChromium.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/shadow/MediaControlsChromium.h"
+
+#include "core/dom/ExceptionCodePlaceholder.h"
+
+using namespace std;
+
+namespace WebCore {
+
+MediaControlsChromium::MediaControlsChromium(Document* document)
+    : MediaControls(document)
+    , m_durationDisplay(0)
+    , m_enclosure(0)
+{
+}
+
+// MediaControls::create() for Android is defined in MediaControlsChromiumAndroid.cpp.
+#if !OS(ANDROID)
+PassRefPtr<MediaControls> MediaControls::create(Document* document)
+{
+    return MediaControlsChromium::createControls(document);
+}
+#endif
+
+PassRefPtr<MediaControlsChromium> MediaControlsChromium::createControls(Document* document)
+{
+    if (!document->page())
+        return 0;
+
+    RefPtr<MediaControlsChromium> controls = adoptRef(new MediaControlsChromium(document));
+
+    if (controls->initializeControls(document))
+        return controls.release();
+
+    return 0;
+}
+
+bool MediaControlsChromium::initializeControls(Document* document)
+{
+    // Create an enclosing element for the panel so we can visually offset the controls correctly.
+    RefPtr<MediaControlPanelEnclosureElement> enclosure = MediaControlPanelEnclosureElement::create(document);
+
+    RefPtr<MediaControlPanelElement> panel = MediaControlPanelElement::create(document);
+
+    ExceptionCode ec;
+
+    RefPtr<MediaControlPlayButtonElement> playButton = MediaControlPlayButtonElement::create(document);
+    m_playButton = playButton.get();
+    panel->appendChild(playButton.release(), ec, AttachLazily);
+    if (ec)
+        return false;
+
+    RefPtr<MediaControlTimelineElement> timeline = MediaControlTimelineElement::create(document, this);
+    m_timeline = timeline.get();
+    panel->appendChild(timeline.release(), ec, AttachLazily);
+    if (ec)
+        return false;
+
+    RefPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(document);
+    m_currentTimeDisplay = currentTimeDisplay.get();
+    m_currentTimeDisplay->hide();
+    panel->appendChild(currentTimeDisplay.release(), ec, AttachLazily);
+    if (ec)
+        return false;
+
+    RefPtr<MediaControlTimeRemainingDisplayElement> durationDisplay = MediaControlTimeRemainingDisplayElement::create(document);
+    m_durationDisplay = durationDisplay.get();
+    panel->appendChild(durationDisplay.release(), ec, AttachLazily);
+    if (ec)
+        return false;
+
+    RefPtr<MediaControlPanelMuteButtonElement> panelMuteButton = MediaControlPanelMuteButtonElement::create(document, this);
+    m_panelMuteButton = panelMuteButton.get();
+    panel->appendChild(panelMuteButton.release(), ec, AttachLazily);
+    if (ec)
+        return false;
+
+    RefPtr<MediaControlPanelVolumeSliderElement> slider = MediaControlPanelVolumeSliderElement::create(document);
+    m_volumeSlider = slider.get();
+    m_volumeSlider->setClearMutedOnUserInteraction(true);
+    panel->appendChild(slider.release(), ec, AttachLazily);
+    if (ec)
+        return false;
+
+    if (document->page()->theme()->supportsClosedCaptioning()) {
+        RefPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document, this);
+        m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get();
+        panel->appendChild(toggleClosedCaptionsButton.release(), ec, AttachLazily);
+        if (ec)
+            return false;
+    }
+
+    RefPtr<MediaControlFullscreenButtonElement> fullscreenButton = MediaControlFullscreenButtonElement::create(document);
+    m_fullScreenButton = fullscreenButton.get();
+    panel->appendChild(fullscreenButton.release(), ec, AttachLazily);
+    if (ec)
+        return false;
+
+    m_panel = panel.get();
+    enclosure->appendChild(panel.release(), ec, AttachLazily);
+    if (ec)
+        return false;
+
+    m_enclosure = enclosure.get();
+    appendChild(enclosure.release(), ec, AttachLazily);
+    if (ec)
+        return false;
+
+    return true;
+}
+
+void MediaControlsChromium::setMediaController(MediaControllerInterface* controller)
+{
+    if (m_mediaController == controller)
+        return;
+
+    MediaControls::setMediaController(controller);
+
+    if (m_durationDisplay)
+        m_durationDisplay->setMediaController(controller);
+    if (m_enclosure)
+        m_enclosure->setMediaController(controller);
+}
+
+void MediaControlsChromium::reset()
+{
+    Page* page = document()->page();
+    if (!page)
+        return;
+
+    double duration = m_mediaController->duration();
+    m_durationDisplay->setInnerText(page->theme()->formatMediaControlsTime(duration), ASSERT_NO_EXCEPTION);
+    m_durationDisplay->setCurrentValue(duration);
+
+    MediaControls::reset();
+}
+
+void MediaControlsChromium::playbackStarted()
+{
+    m_currentTimeDisplay->show();
+    m_durationDisplay->hide();
+
+    MediaControls::playbackStarted();
+}
+
+void MediaControlsChromium::updateCurrentTimeDisplay()
+{
+    double now = m_mediaController->currentTime();
+    double duration = m_mediaController->duration();
+
+    Page* page = document()->page();
+    if (!page)
+        return;
+
+    // After seek, hide duration display and show current time.
+    if (now > 0) {
+        m_currentTimeDisplay->show();
+        m_durationDisplay->hide();
+    }
+
+    // Allow the theme to format the time.
+    m_currentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), IGNORE_EXCEPTION);
+    m_currentTimeDisplay->setCurrentValue(now);
+}
+
+void MediaControlsChromium::changedMute()
+{
+    MediaControls::changedMute();
+
+    if (m_mediaController->muted())
+        m_volumeSlider->setVolume(0);
+    else
+        m_volumeSlider->setVolume(m_mediaController->volume());
+}
+
+void MediaControlsChromium::createTextTrackDisplay()
+{
+    if (m_textDisplayContainer)
+        return;
+
+    RefPtr<MediaControlTextTrackContainerElement> textDisplayContainer = MediaControlTextTrackContainerElement::create(document());
+    m_textDisplayContainer = textDisplayContainer.get();
+
+    if (m_mediaController)
+        m_textDisplayContainer->setMediaController(m_mediaController);
+
+    insertTextTrackContainer(textDisplayContainer.release());
+}
+
+void MediaControlsChromium::insertTextTrackContainer(PassRefPtr<MediaControlTextTrackContainerElement> textTrackContainer)
+{
+    // Insert it before the first controller element so it always displays behind the controls.
+    // In the Chromium case, that's the enclosure element.
+    insertBefore(textTrackContainer, m_enclosure, ASSERT_NO_EXCEPTION, AttachLazily);
+}
+
+
+}
diff --git a/Source/core/html/shadow/MediaControlsChromium.h b/Source/core/html/shadow/MediaControlsChromium.h
new file mode 100644
index 0000000..3e8b7c7
--- /dev/null
+++ b/Source/core/html/shadow/MediaControlsChromium.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 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 COMPUTER, 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 COMPUTER, 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 MediaControlsChromium_h
+#define MediaControlsChromium_h
+
+#include "core/html/shadow/MediaControls.h"
+
+namespace WebCore {
+
+class MediaControlsChromium : public MediaControls {
+public:
+    // Called from port-specific parent create function to create custom controls.
+    static PassRefPtr<MediaControlsChromium> createControls(Document*);
+
+    virtual void setMediaController(MediaControllerInterface*) OVERRIDE;
+
+    virtual void reset() OVERRIDE;
+
+    virtual void playbackStarted() OVERRIDE;
+
+    void changedMute() OVERRIDE;
+
+    virtual void updateCurrentTimeDisplay() OVERRIDE;
+
+    void createTextTrackDisplay() OVERRIDE;
+
+    virtual void insertTextTrackContainer(PassRefPtr<MediaControlTextTrackContainerElement>);
+
+protected:
+    explicit MediaControlsChromium(Document*);
+
+    bool initializeControls(Document*);
+
+private:
+    MediaControlTimeRemainingDisplayElement* m_durationDisplay;
+    MediaControlPanelEnclosureElement* m_enclosure;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/MediaControlsChromiumAndroid.cpp b/Source/core/html/shadow/MediaControlsChromiumAndroid.cpp
new file mode 100644
index 0000000..34e61af
--- /dev/null
+++ b/Source/core/html/shadow/MediaControlsChromiumAndroid.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/shadow/MediaControlsChromiumAndroid.h"
+
+namespace WebCore {
+
+MediaControlsChromiumAndroid::MediaControlsChromiumAndroid(Document* document)
+    : MediaControlsChromium(document)
+    , m_overlayPlayButton(0)
+    , m_overlayEnclosure(0)
+{
+}
+
+PassRefPtr<MediaControls> MediaControls::create(Document* document)
+{
+    return MediaControlsChromiumAndroid::createControls(document);
+}
+
+PassRefPtr<MediaControlsChromiumAndroid> MediaControlsChromiumAndroid::createControls(Document* document)
+{
+    if (!document->page())
+        return 0;
+
+    RefPtr<MediaControlsChromiumAndroid> controls = adoptRef(new MediaControlsChromiumAndroid(document));
+
+    ExceptionCode ec;
+
+    RefPtr<MediaControlOverlayEnclosureElement> overlayEnclosure = MediaControlOverlayEnclosureElement::create(document);
+    RefPtr<MediaControlOverlayPlayButtonElement> overlayPlayButton = MediaControlOverlayPlayButtonElement::create(document);
+    controls->m_overlayPlayButton = overlayPlayButton.get();
+    overlayEnclosure->appendChild(overlayPlayButton.release(), ec, AttachLazily);
+    if (ec)
+        return 0;
+
+    controls->m_overlayEnclosure = overlayEnclosure.get();
+    controls->appendChild(overlayEnclosure.release(), ec, AttachLazily);
+    if (ec)
+        return 0;
+
+    if (controls->initializeControls(document))
+        return controls.release();
+
+    return 0;
+}
+
+void MediaControlsChromiumAndroid::setMediaController(MediaControllerInterface* controller)
+{
+    if (m_overlayPlayButton)
+        m_overlayPlayButton->setMediaController(controller);
+    if (m_overlayEnclosure)
+        m_overlayEnclosure->setMediaController(controller);
+    MediaControlsChromium::setMediaController(controller);
+}
+
+void MediaControlsChromiumAndroid::playbackStarted()
+{
+    m_overlayPlayButton->updateDisplayType();
+    MediaControlsChromium::playbackStarted();
+}
+
+void MediaControlsChromiumAndroid::playbackStopped()
+{
+    m_overlayPlayButton->updateDisplayType();
+    MediaControlsChromium::playbackStopped();
+}
+
+void MediaControlsChromiumAndroid::insertTextTrackContainer(PassRefPtr<MediaControlTextTrackContainerElement> textTrackContainer)
+{
+    // Insert it before the overlay play button so it always displays behind it.
+    m_overlayEnclosure->insertBefore(textTrackContainer, m_overlayPlayButton, ASSERT_NO_EXCEPTION, AttachLazily);
+}
+}
diff --git a/Source/core/html/shadow/MediaControlsChromiumAndroid.h b/Source/core/html/shadow/MediaControlsChromiumAndroid.h
new file mode 100644
index 0000000..2980160
--- /dev/null
+++ b/Source/core/html/shadow/MediaControlsChromiumAndroid.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 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 COMPUTER, 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 COMPUTER, 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 MediaControlsChromiumAndroid_h
+#define MediaControlsChromiumAndroid_h
+
+#include "core/html/shadow/MediaControls.h"
+#include "core/html/shadow/MediaControlsChromium.h"
+
+namespace WebCore {
+
+class MediaControlsChromiumAndroid : public MediaControlsChromium {
+public:
+    static PassRefPtr<MediaControlsChromiumAndroid> createControls(Document*);
+
+    virtual void setMediaController(MediaControllerInterface*) OVERRIDE;
+    virtual void playbackStarted() OVERRIDE;
+    virtual void playbackStopped() OVERRIDE;
+
+    void insertTextTrackContainer(PassRefPtr<MediaControlTextTrackContainerElement>) OVERRIDE;
+
+private:
+    explicit MediaControlsChromiumAndroid(Document*);
+
+    MediaControlOverlayPlayButtonElement* m_overlayPlayButton;
+    MediaControlOverlayEnclosureElement* m_overlayEnclosure;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/MeterShadowElement.cpp b/Source/core/html/shadow/MeterShadowElement.cpp
new file mode 100644
index 0000000..826bf93
--- /dev/null
+++ b/Source/core/html/shadow/MeterShadowElement.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/shadow/MeterShadowElement.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "core/css/StylePropertySet.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/HTMLMeterElement.h"
+#include "core/rendering/RenderMeter.h"
+#include "core/rendering/RenderTheme.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+MeterShadowElement::MeterShadowElement(Document* document) 
+    : HTMLDivElement(HTMLNames::divTag, document)
+{
+}
+
+HTMLMeterElement* MeterShadowElement::meterElement() const
+{
+    return toHTMLMeterElement(shadowHost());
+}
+
+bool MeterShadowElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    RenderObject* render = meterElement()->renderer();
+    return render && !render->theme()->supportsMeter(render->style()->appearance()) && HTMLDivElement::rendererIsNeeded(context);
+}
+
+MeterInnerElement::MeterInnerElement(Document* document)
+    : MeterShadowElement(document)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-meter-inner-element", AtomicString::ConstructFromLiteral));
+    setPseudo(pseudoId);
+}
+
+bool MeterInnerElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    if (meterElement()->hasAuthorShadowRoot())
+        return HTMLDivElement::rendererIsNeeded(context);
+
+    RenderObject* render = meterElement()->renderer();
+    return render && !render->theme()->supportsMeter(render->style()->appearance()) && HTMLDivElement::rendererIsNeeded(context);
+}
+
+RenderObject* MeterInnerElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderMeter(this);
+}
+
+const AtomicString& MeterValueElement::valuePseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, optimumPseudoId, ("-webkit-meter-optimum-value", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(AtomicString, suboptimumPseudoId, ("-webkit-meter-suboptimum-value", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(AtomicString, evenLessGoodPseudoId, ("-webkit-meter-even-less-good-value", AtomicString::ConstructFromLiteral));
+
+    HTMLMeterElement* meter = meterElement();
+    if (!meter)
+        return optimumPseudoId;
+
+    switch (meter->gaugeRegion()) {
+    case HTMLMeterElement::GaugeRegionOptimum:
+        return optimumPseudoId;
+    case HTMLMeterElement::GaugeRegionSuboptimal:
+        return suboptimumPseudoId;
+    case HTMLMeterElement::GaugeRegionEvenLessGood:
+        return evenLessGoodPseudoId;
+    default:
+        ASSERT_NOT_REACHED();
+        return optimumPseudoId;
+    }
+}
+
+void MeterValueElement::setWidthPercentage(double width)
+{
+    setInlineStyleProperty(CSSPropertyWidth, width, CSSPrimitiveValue::CSS_PERCENTAGE);
+}
+
+}
diff --git a/Source/core/html/shadow/MeterShadowElement.h b/Source/core/html/shadow/MeterShadowElement.h
new file mode 100644
index 0000000..3f4bdd4
--- /dev/null
+++ b/Source/core/html/shadow/MeterShadowElement.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 MeterShadowElement_h
+#define MeterShadowElement_h
+
+#include "core/html/HTMLDivElement.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class HTMLMeterElement;
+class RenderMeter;
+
+class MeterShadowElement : public HTMLDivElement {
+public:
+    MeterShadowElement(Document*);
+    HTMLMeterElement* meterElement() const;
+
+private:
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+};
+
+class MeterInnerElement FINAL : public MeterShadowElement {
+public:
+    MeterInnerElement(Document*);
+    static PassRefPtr<MeterInnerElement> create(Document*);
+
+private:
+    virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE;
+};
+
+inline PassRefPtr<MeterInnerElement> MeterInnerElement::create(Document* document)
+{
+    return adoptRef(new MeterInnerElement(document));
+}
+
+class MeterBarElement FINAL : public MeterShadowElement {
+public:
+    MeterBarElement(Document* document) 
+        : MeterShadowElement(document)
+    {
+        DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-meter-bar", AtomicString::ConstructFromLiteral));
+        setPseudo(pseudoId);
+    }
+
+    static PassRefPtr<MeterBarElement> create(Document*);
+};
+
+inline PassRefPtr<MeterBarElement> MeterBarElement::create(Document* document)
+{
+    return adoptRef(new MeterBarElement(document));
+}
+
+class MeterValueElement FINAL : public MeterShadowElement {
+public:
+    MeterValueElement(Document* document) 
+        : MeterShadowElement(document)
+    {
+        updatePseudo();
+    }
+
+    static PassRefPtr<MeterValueElement> create(Document*);
+    void setWidthPercentage(double);
+    void updatePseudo() { setPseudo(valuePseudoId()); }
+
+private:
+    const AtomicString& valuePseudoId() const;
+};
+
+inline PassRefPtr<MeterValueElement> MeterValueElement::create(Document* document)
+{
+    return adoptRef(new MeterValueElement(document));
+}
+
+}
+
+#endif // MeterShadowElement_h
diff --git a/Source/core/html/shadow/PickerIndicatorElement.cpp b/Source/core/html/shadow/PickerIndicatorElement.cpp
new file mode 100644
index 0000000..f377200
--- /dev/null
+++ b/Source/core/html/shadow/PickerIndicatorElement.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/shadow/PickerIndicatorElement.h"
+
+#include "core/dom/Event.h"
+#include "core/page/Chrome.h"
+#include "core/page/Page.h"
+#include "core/rendering/RenderDetailsMarker.h"
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline PickerIndicatorElement::PickerIndicatorElement(Document* document, PickerIndicatorOwner& pickerIndicatorOwner)
+    : HTMLDivElement(divTag, document)
+    , m_pickerIndicatorOwner(&pickerIndicatorOwner)
+{
+    setPseudo(AtomicString("-webkit-calendar-picker-indicator", AtomicString::ConstructFromLiteral));
+}
+
+PassRefPtr<PickerIndicatorElement> PickerIndicatorElement::create(Document* document, PickerIndicatorOwner& pickerIndicatorOwner)
+{
+    return adoptRef(new PickerIndicatorElement(document, pickerIndicatorOwner));
+}
+
+PickerIndicatorElement::~PickerIndicatorElement()
+{
+    closePopup();
+    ASSERT(!m_chooser);
+}
+
+RenderObject* PickerIndicatorElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderDetailsMarker(this);
+}
+
+void PickerIndicatorElement::defaultEventHandler(Event* event)
+{
+    if (!renderer())
+        return;
+    if (!m_pickerIndicatorOwner || m_pickerIndicatorOwner->isPickerIndicatorOwnerDisabledOrReadOnly())
+        return;
+
+    if (event->type() == eventNames().clickEvent) {
+        openPopup();
+        event->setDefaultHandled();
+    }
+
+    if (!event->defaultHandled())
+        HTMLDivElement::defaultEventHandler(event);
+}
+
+bool PickerIndicatorElement::willRespondToMouseClickEvents()
+{
+    if (renderer() && m_pickerIndicatorOwner && !m_pickerIndicatorOwner->isPickerIndicatorOwnerDisabledOrReadOnly())
+        return true;
+
+    return HTMLDivElement::willRespondToMouseClickEvents();
+}
+
+void PickerIndicatorElement::didChooseValue(const String& value)
+{
+    if (!m_pickerIndicatorOwner)
+        return;
+    m_pickerIndicatorOwner->pickerIndicatorChooseValue(value);
+}
+
+void PickerIndicatorElement::didEndChooser()
+{
+    m_chooser.clear();
+}
+
+void PickerIndicatorElement::openPopup()
+{
+    if (m_chooser)
+        return;
+    if (!document()->page())
+        return;
+    if (!m_pickerIndicatorOwner)
+        return;
+    Chrome* chrome = document()->page()->chrome();
+    if (!chrome)
+        return;
+    DateTimeChooserParameters parameters;
+    if (!m_pickerIndicatorOwner->setupDateTimeChooserParameters(parameters))
+        return;
+    m_chooser = chrome->openDateTimeChooser(this, parameters);
+}
+
+void PickerIndicatorElement::closePopup()
+{
+    if (!m_chooser)
+        return;
+    m_chooser->endChooser();
+}
+
+void PickerIndicatorElement::detach()
+{
+    closePopup();
+    HTMLDivElement::detach();
+}
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/PickerIndicatorElement.h b/Source/core/html/shadow/PickerIndicatorElement.h
new file mode 100644
index 0000000..87712b2
--- /dev/null
+++ b/Source/core/html/shadow/PickerIndicatorElement.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 PickerIndicatorElement_h
+#define PickerIndicatorElement_h
+
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/HTMLDivElement.h"
+#include "core/platform/DateTimeChooser.h"
+#include "core/platform/DateTimeChooserClient.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class HTMLInputElement;
+class PagePopup;
+
+class PickerIndicatorElement FINAL : public HTMLDivElement, public DateTimeChooserClient {
+public:
+    // PickerIndicatorOwner implementer must call removePickerIndicatorOwner when
+    // it doesn't handle event, e.g. at destruction.
+    class PickerIndicatorOwner {
+    public:
+        virtual ~PickerIndicatorOwner() { }
+        virtual bool isPickerIndicatorOwnerDisabledOrReadOnly() const = 0;
+        virtual void pickerIndicatorChooseValue(const String&) = 0;
+        virtual bool setupDateTimeChooserParameters(DateTimeChooserParameters&) = 0;
+    };
+
+    static PassRefPtr<PickerIndicatorElement> create(Document*, PickerIndicatorOwner&);
+    virtual ~PickerIndicatorElement();
+    void openPopup();
+    void closePopup();
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+    void removePickerIndicatorOwner() { m_pickerIndicatorOwner = 0; }
+
+    // DateTimeChooserClient implementation.
+    virtual void didChooseValue(const String&) OVERRIDE;
+    virtual void didEndChooser() OVERRIDE;
+
+private:
+    PickerIndicatorElement(Document*, PickerIndicatorOwner&);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+    virtual void detach() OVERRIDE;
+
+    HTMLInputElement* hostInput();
+
+    PickerIndicatorOwner* m_pickerIndicatorOwner;
+    RefPtr<DateTimeChooser> m_chooser;
+};
+
+}
+#endif
+#endif
diff --git a/Source/core/html/shadow/ProgressShadowElement.cpp b/Source/core/html/shadow/ProgressShadowElement.cpp
new file mode 100644
index 0000000..030c1ce
--- /dev/null
+++ b/Source/core/html/shadow/ProgressShadowElement.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/shadow/ProgressShadowElement.h"
+
+#include "HTMLNames.h"
+#include "core/html/HTMLProgressElement.h"
+#include "core/rendering/RenderProgress.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+ProgressShadowElement::ProgressShadowElement(Document* document)
+    : HTMLDivElement(HTMLNames::divTag, document)
+{
+}
+
+HTMLProgressElement* ProgressShadowElement::progressElement() const
+{
+    return toHTMLProgressElement(shadowHost());
+}
+
+bool ProgressShadowElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    RenderObject* progressRenderer = progressElement()->renderer();
+    return progressRenderer && !progressRenderer->style()->hasAppearance() && HTMLDivElement::rendererIsNeeded(context);
+}
+
+ProgressInnerElement::ProgressInnerElement(Document* document)
+    : ProgressShadowElement(document)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-progress-inner-element", AtomicString::ConstructFromLiteral));
+    setPseudo(pseudoId);
+}
+
+PassRefPtr<ProgressInnerElement> ProgressInnerElement::create(Document* document)
+{
+    return adoptRef(new ProgressInnerElement(document));
+}
+
+RenderObject* ProgressInnerElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderProgress(this);
+}
+
+bool ProgressInnerElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    if (progressElement()->hasAuthorShadowRoot())
+        return HTMLDivElement::rendererIsNeeded(context);
+
+    RenderObject* progressRenderer = progressElement()->renderer();
+    return progressRenderer && !progressRenderer->style()->hasAppearance() && HTMLDivElement::rendererIsNeeded(context);    
+}
+
+void ProgressValueElement::setWidthPercentage(double width)
+{
+    setInlineStyleProperty(CSSPropertyWidth, width, CSSPrimitiveValue::CSS_PERCENTAGE);
+}
+
+}
diff --git a/Source/core/html/shadow/ProgressShadowElement.h b/Source/core/html/shadow/ProgressShadowElement.h
new file mode 100644
index 0000000..db6e4d2
--- /dev/null
+++ b/Source/core/html/shadow/ProgressShadowElement.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 ProgressShadowElement_h
+#define ProgressShadowElement_h
+
+#include "core/html/HTMLDivElement.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class HTMLProgressElement;
+
+class ProgressShadowElement : public HTMLDivElement {
+public:
+    ProgressShadowElement(Document*);
+    HTMLProgressElement* progressElement() const;
+
+protected:
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+};
+
+class ProgressInnerElement FINAL : public ProgressShadowElement {
+public:
+    ProgressInnerElement(Document*);
+
+    static PassRefPtr<ProgressInnerElement> create(Document*);
+private:
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE;
+    virtual bool rendererIsNeeded(const NodeRenderingContext&);
+};
+
+class ProgressBarElement FINAL : public ProgressShadowElement {
+public:
+    ProgressBarElement(Document* document) 
+        : ProgressShadowElement(document)
+    {
+        DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-progress-bar", AtomicString::ConstructFromLiteral));
+        setPseudo(pseudoId);
+    }
+
+    static PassRefPtr<ProgressBarElement> create(Document*);
+};
+
+inline PassRefPtr<ProgressBarElement> ProgressBarElement::create(Document* document)
+{
+    return adoptRef(new ProgressBarElement(document));
+}
+
+class ProgressValueElement FINAL : public ProgressShadowElement {
+public:
+    ProgressValueElement(Document* document) 
+        : ProgressShadowElement(document)
+    {
+        DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-progress-value", AtomicString::ConstructFromLiteral));
+        setPseudo(pseudoId);
+    }
+
+    static PassRefPtr<ProgressValueElement> create(Document*);
+    void setWidthPercentage(double);
+};
+
+inline PassRefPtr<ProgressValueElement> ProgressValueElement::create(Document* document)
+{
+    return adoptRef(new ProgressValueElement(document));
+}
+
+}
+
+#endif // ProgressShadowElement_h
diff --git a/Source/core/html/shadow/SelectRuleFeatureSet.cpp b/Source/core/html/shadow/SelectRuleFeatureSet.cpp
new file mode 100644
index 0000000..2a38adc
--- /dev/null
+++ b/Source/core/html/shadow/SelectRuleFeatureSet.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/SelectRuleFeatureSet.h"
+
+#include "core/css/CSSSelector.h"
+
+namespace WebCore {
+
+SelectRuleFeatureSet::SelectRuleFeatureSet()
+    : m_featureFlags(0)
+{
+}
+
+void SelectRuleFeatureSet::add(const SelectRuleFeatureSet& featureSet)
+{
+    m_cssRuleFeatureSet.add(featureSet.m_cssRuleFeatureSet);
+    m_featureFlags |= featureSet.m_featureFlags;
+}
+
+void SelectRuleFeatureSet::clear()
+{
+    m_cssRuleFeatureSet.clear();
+    m_featureFlags = 0;
+}
+
+void SelectRuleFeatureSet::collectFeaturesFromSelector(const CSSSelector* selector)
+{
+    m_cssRuleFeatureSet.collectFeaturesFromSelector(selector);
+
+    switch (selector->pseudoType()) {
+    case CSSSelector::PseudoChecked:
+        setSelectRuleFeature(AffectedSelectorChecked);
+        break;
+    case CSSSelector::PseudoEnabled:
+        setSelectRuleFeature(AffectedSelectorEnabled);
+        break;
+    case CSSSelector::PseudoDisabled:
+        setSelectRuleFeature(AffectedSelectorDisabled);
+        break;
+    case CSSSelector::PseudoIndeterminate:
+        setSelectRuleFeature(AffectedSelectorIndeterminate);
+        break;
+    case CSSSelector::PseudoLink:
+        setSelectRuleFeature(AffectedSelectorLink);
+        break;
+    case CSSSelector::PseudoTarget:
+        setSelectRuleFeature(AffectedSelectorTarget);
+        break;
+    case CSSSelector::PseudoVisited:
+        setSelectRuleFeature(AffectedSelectorVisited);
+        break;
+    default:
+        break;
+    }
+}
+
+}
+
diff --git a/Source/core/html/shadow/SelectRuleFeatureSet.h b/Source/core/html/shadow/SelectRuleFeatureSet.h
new file mode 100644
index 0000000..7292b12
--- /dev/null
+++ b/Source/core/html/shadow/SelectRuleFeatureSet.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 SelectRuleFeatureSet_h
+#define SelectRuleFeatureSet_h
+
+#include "core/css/RuleFeature.h"
+#include "core/dom/Element.h"
+
+namespace WebCore {
+
+class SelectRuleFeatureSet {
+public:
+    SelectRuleFeatureSet();
+
+    void add(const SelectRuleFeatureSet&);
+    void clear();
+    void collectFeaturesFromSelector(const CSSSelector*);
+
+    bool hasSelectorForId(const AtomicString&) const;
+    bool hasSelectorForClass(const AtomicString&) const;
+    bool hasSelectorForAttribute(const AtomicString&) const;
+
+    bool hasSelectorForChecked() const { return hasSelectorFor(AffectedSelectorChecked); }
+    bool hasSelectorForEnabled() const { return hasSelectorFor(AffectedSelectorEnabled); }
+    bool hasSelectorForDisabled() const { return hasSelectorFor(AffectedSelectorDisabled); }
+    bool hasSelectorForIndeterminate() const { return hasSelectorFor(AffectedSelectorIndeterminate); }
+    bool hasSelectorForLink() const { return hasSelectorFor(AffectedSelectorLink); }
+    bool hasSelectorForTarget() const { return hasSelectorFor(AffectedSelectorTarget); }
+    bool hasSelectorForVisited() const { return hasSelectorFor(AffectedSelectorVisited); }
+
+    bool hasSelectorFor(AffectedSelectorMask features) const { return m_featureFlags & features; }
+
+private:
+    void setSelectRuleFeature(AffectedSelectorType feature) { m_featureFlags |= feature; }
+
+    RuleFeatureSet m_cssRuleFeatureSet;
+    int m_featureFlags;
+};
+
+inline bool SelectRuleFeatureSet::hasSelectorForId(const AtomicString& idValue) const
+{
+    ASSERT(!idValue.isEmpty());
+    return m_cssRuleFeatureSet.idsInRules.contains(idValue.impl());
+}
+
+inline bool SelectRuleFeatureSet::hasSelectorForClass(const AtomicString& classValue) const
+{
+    ASSERT(!classValue.isEmpty());
+    return m_cssRuleFeatureSet.classesInRules.contains(classValue.impl());
+}
+
+inline bool SelectRuleFeatureSet::hasSelectorForAttribute(const AtomicString& attributeName) const
+{
+    ASSERT(!attributeName.isEmpty());
+    return m_cssRuleFeatureSet.attrsInRules.contains(attributeName.impl());
+}
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/SliderThumbElement.cpp b/Source/core/html/shadow/SliderThumbElement.cpp
new file mode 100644
index 0000000..775deb3
--- /dev/null
+++ b/Source/core/html/shadow/SliderThumbElement.cpp
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+
+#include "config.h"
+#include "core/html/shadow/SliderThumbElement.h"
+
+#include "CSSValueKeywords.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/Event.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/StepRange.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/page/EventHandler.h"
+#include "core/page/Frame.h"
+#include "core/rendering/RenderFlexibleBox.h"
+#include "core/rendering/RenderSlider.h"
+#include "core/rendering/RenderTheme.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline static Decimal sliderPosition(HTMLInputElement* element)
+{
+    const StepRange stepRange(element->createStepRange(RejectAny));
+    const Decimal oldValue = parseToDecimalForNumberType(element->value(), stepRange.defaultValue());
+    return stepRange.proportionFromValue(stepRange.clampValue(oldValue));
+}
+
+inline static bool hasVerticalAppearance(HTMLInputElement* input)
+{
+    ASSERT(input->renderer());
+    RenderStyle* sliderStyle = input->renderer()->style();
+
+    if (sliderStyle->appearance() == MediaVolumeSliderPart && input->renderer()->theme()->usesVerticalVolumeSlider())
+        return true;
+
+    return sliderStyle->appearance() == SliderVerticalPart;
+}
+
+SliderThumbElement* sliderThumbElementOf(Node* node)
+{
+    ASSERT(node);
+    ShadowRoot* shadow = node->toInputElement()->userAgentShadowRoot();
+    ASSERT(shadow);
+    Node* thumb = shadow->firstChild()->firstChild()->firstChild();
+    ASSERT(thumb);
+    return toSliderThumbElement(thumb);
+}
+
+HTMLElement* sliderTrackElementOf(Node* node)
+{
+    ASSERT(node);
+    ShadowRoot* shadow = node->toInputElement()->userAgentShadowRoot();
+    ASSERT(shadow);
+    Node* track = shadow->firstChild()->firstChild();
+    ASSERT(track);
+    return toHTMLElement(track);
+}
+
+// --------------------------------
+
+RenderSliderThumb::RenderSliderThumb(SliderThumbElement* element)
+    : RenderBlock(element)
+{
+}
+
+void RenderSliderThumb::updateAppearance(RenderStyle* parentStyle)
+{
+    if (parentStyle->appearance() == SliderVerticalPart)
+        style()->setAppearance(SliderThumbVerticalPart);
+    else if (parentStyle->appearance() == SliderHorizontalPart)
+        style()->setAppearance(SliderThumbHorizontalPart);
+    else if (parentStyle->appearance() == MediaSliderPart)
+        style()->setAppearance(MediaSliderThumbPart);
+    else if (parentStyle->appearance() == MediaVolumeSliderPart)
+        style()->setAppearance(MediaVolumeSliderThumbPart);
+    else if (parentStyle->appearance() == MediaFullScreenVolumeSliderPart)
+        style()->setAppearance(MediaFullScreenVolumeSliderThumbPart);
+    if (style()->hasAppearance())
+        theme()->adjustSliderThumbSize(style(), toElement(node()));
+}
+
+bool RenderSliderThumb::isSliderThumb() const
+{
+    return true;
+}
+
+// --------------------------------
+
+// FIXME: Find a way to cascade appearance and adjust heights, and get rid of this class.
+// http://webkit.org/b/62535
+class RenderSliderContainer : public RenderFlexibleBox {
+public:
+    RenderSliderContainer(SliderContainerElement* element)
+        : RenderFlexibleBox(element) { }
+public:
+    virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE;
+
+private:
+    virtual void layout() OVERRIDE;
+};
+
+void RenderSliderContainer::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
+{
+    HTMLInputElement* input = node()->shadowHost()->toInputElement();
+    bool isVertical = hasVerticalAppearance(input);
+
+#if ENABLE(DATALIST_ELEMENT)
+    if (input->renderer()->isSlider() && !isVertical && input->list()) {
+        int offsetFromCenter = theme()->sliderTickOffsetFromTrackCenter();
+        LayoutUnit trackHeight = 0;
+        if (offsetFromCenter < 0)
+            trackHeight = -2 * offsetFromCenter;
+        else {
+            int tickLength = theme()->sliderTickSize().height();
+            trackHeight = 2 * (offsetFromCenter + tickLength);
+        }
+        float zoomFactor = style()->effectiveZoom();
+        if (zoomFactor != 1.0)
+            trackHeight *= zoomFactor;
+
+        RenderBox::computeLogicalHeight(trackHeight, logicalTop, computedValues);
+        return;
+    }
+#endif
+    if (isVertical)
+        logicalHeight = RenderSlider::defaultTrackLength;
+    RenderBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues);
+}
+
+void RenderSliderContainer::layout()
+{
+    HTMLInputElement* input = node()->shadowHost()->toInputElement();
+    bool isVertical = hasVerticalAppearance(input);
+    style()->setFlexDirection(isVertical ? FlowColumn : FlowRow);
+    TextDirection oldTextDirection = style()->direction();
+    if (isVertical) {
+        // FIXME: Work around rounding issues in RTL vertical sliders. We want them to
+        // render identically to LTR vertical sliders. We can remove this work around when
+        // subpixel rendering is enabled on all ports.
+        style()->setDirection(LTR);
+    }
+
+    RenderBox* thumb = input->sliderThumbElement() ? input->sliderThumbElement()->renderBox() : 0;
+    RenderBox* track = input->sliderTrackElement() ? input->sliderTrackElement()->renderBox() : 0;
+    // Force a layout to reset the position of the thumb so the code below doesn't move the thumb to the wrong place.
+    // FIXME: Make a custom Render class for the track and move the thumb positioning code there.
+    if (track)
+        track->setChildNeedsLayout(true, MarkOnlyThis);
+
+    RenderFlexibleBox::layout();
+
+    style()->setDirection(oldTextDirection);
+    // These should always exist, unless someone mutates the shadow DOM (e.g., in the inspector).
+    if (!thumb || !track)
+        return;
+
+    double percentageOffset = sliderPosition(input).toDouble();
+    LayoutUnit availableExtent = isVertical ? track->contentHeight() : track->contentWidth();
+    availableExtent -= isVertical ? thumb->height() : thumb->width();
+    LayoutUnit offset = percentageOffset * availableExtent;
+    LayoutPoint thumbLocation = thumb->location();
+    if (isVertical)
+        thumbLocation.setY(thumbLocation.y() + track->contentHeight() - thumb->height() - offset);
+    else if (style()->isLeftToRightDirection())
+        thumbLocation.setX(thumbLocation.x() + offset);
+    else
+        thumbLocation.setX(thumbLocation.x() - offset);
+    thumb->setLocation(thumbLocation);
+    if (checkForRepaintDuringLayout() && parent()
+        && (parent()->style()->appearance() == MediaVolumeSliderPart || parent()->style()->appearance() == MediaSliderPart)) {
+        // This will sometimes repaint too much. However, it is necessary to
+        // correctly repaint media controls (volume and timeline sliders) -
+        // they have special painting code in RenderMediaControls.cpp:paintMediaVolumeSlider
+        // and paintMediaSlider that gets called via -webkit-appearance and RenderTheme,
+        // so nothing else would otherwise invalidate the slider.
+        repaint();
+    }
+}
+
+// --------------------------------
+
+void SliderThumbElement::setPositionFromValue()
+{
+    // Since the code to calculate position is in the RenderSliderThumb layout
+    // path, we don't actually update the value here. Instead, we poke at the
+    // renderer directly to trigger layout.
+    if (renderer())
+        renderer()->setNeedsLayout(true);
+}
+
+RenderObject* SliderThumbElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderSliderThumb(this);
+}
+
+bool SliderThumbElement::isDisabledFormControl() const
+{
+    return hostInput()->isDisabledFormControl();
+}
+
+bool SliderThumbElement::matchesReadOnlyPseudoClass() const
+{
+    return hostInput()->matchesReadOnlyPseudoClass();
+}
+
+bool SliderThumbElement::matchesReadWritePseudoClass() const
+{
+    return hostInput()->matchesReadWritePseudoClass();
+}
+
+Node* SliderThumbElement::focusDelegate()
+{
+    return hostInput();
+}
+
+void SliderThumbElement::dragFrom(const LayoutPoint& point)
+{
+    setPositionFromPoint(point);
+    startDragging();
+}
+
+void SliderThumbElement::setPositionFromPoint(const LayoutPoint& point)
+{
+    HTMLInputElement* input = hostInput();
+    HTMLElement* trackElement = sliderTrackElementOf(input);
+
+    if (!input->renderer() || !renderBox() || !trackElement->renderBox())
+        return;
+
+    input->setTextAsOfLastFormControlChangeEvent(input->value());
+    LayoutPoint offset = roundedLayoutPoint(input->renderer()->absoluteToLocal(point, UseTransforms));
+    bool isVertical = hasVerticalAppearance(input);
+    bool isLeftToRightDirection = renderBox()->style()->isLeftToRightDirection();
+    LayoutUnit trackSize;
+    LayoutUnit position;
+    LayoutUnit currentPosition;
+    // We need to calculate currentPosition from absolute points becaue the
+    // renderer for this node is usually on a layer and renderBox()->x() and
+    // y() are unusable.
+    // FIXME: This should probably respect transforms.
+    LayoutPoint absoluteThumbOrigin = renderBox()->absoluteBoundingBoxRectIgnoringTransforms().location();
+    LayoutPoint absoluteSliderContentOrigin = roundedLayoutPoint(input->renderer()->localToAbsolute());
+    IntRect trackBoundingBox = trackElement->renderer()->absoluteBoundingBoxRectIgnoringTransforms();
+    IntRect inputBoundingBox = input->renderer()->absoluteBoundingBoxRectIgnoringTransforms();
+    if (isVertical) {
+        trackSize = trackElement->renderBox()->contentHeight() - renderBox()->height();
+        position = offset.y() - renderBox()->height() / 2 - trackBoundingBox.y() + inputBoundingBox.y() - renderBox()->marginBottom();
+        currentPosition = absoluteThumbOrigin.y() - absoluteSliderContentOrigin.y();
+    } else {
+        trackSize = trackElement->renderBox()->contentWidth() - renderBox()->width();
+        position = offset.x() - renderBox()->width() / 2 - trackBoundingBox.x() + inputBoundingBox.x();
+        position -= isLeftToRightDirection ? renderBox()->marginLeft() : renderBox()->marginRight();
+        currentPosition = absoluteThumbOrigin.x() - absoluteSliderContentOrigin.x();
+    }
+    position = max<LayoutUnit>(0, min(position, trackSize));
+    const Decimal ratio = Decimal::fromDouble(static_cast<double>(position) / trackSize);
+    const Decimal fraction = isVertical || !isLeftToRightDirection ? Decimal(1) - ratio : ratio;
+    StepRange stepRange(input->createStepRange(RejectAny));
+    Decimal value = stepRange.clampValue(stepRange.valueFromProportion(fraction));
+
+#if ENABLE(DATALIST_ELEMENT)
+    const LayoutUnit snappingThreshold = renderer()->theme()->sliderTickSnappingThreshold();
+    if (snappingThreshold > 0) {
+        Decimal closest = input->findClosestTickMarkValue(value);
+        if (closest.isFinite()) {
+            double closestFraction = stepRange.proportionFromValue(closest).toDouble();
+            double closestRatio = isVertical || !isLeftToRightDirection ? 1.0 - closestFraction : closestFraction;
+            LayoutUnit closestPosition = trackSize * closestRatio;
+            if ((closestPosition - position).abs() <= snappingThreshold)
+                value = closest;
+        }
+    }
+#endif
+
+    String valueString = serializeForNumberType(value);
+    if (valueString == input->value())
+        return;
+
+    // FIXME: This is no longer being set from renderer. Consider updating the method name.
+    input->setValueFromRenderer(valueString);
+    renderer()->setNeedsLayout(true);
+    input->dispatchFormControlChangeEvent();
+}
+
+void SliderThumbElement::startDragging()
+{
+    if (Frame* frame = document()->frame()) {
+        frame->eventHandler()->setCapturingMouseEventsNode(this);
+        m_inDragMode = true;
+    }
+}
+
+void SliderThumbElement::stopDragging()
+{
+    if (!m_inDragMode)
+        return;
+
+    if (Frame* frame = document()->frame())
+        frame->eventHandler()->setCapturingMouseEventsNode(0);
+    m_inDragMode = false;
+    if (renderer())
+        renderer()->setNeedsLayout(true);
+}
+
+void SliderThumbElement::defaultEventHandler(Event* event)
+{
+    if (!event->isMouseEvent()) {
+        HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    // FIXME: Should handle this readonly/disabled check in more general way.
+    // Missing this kind of check is likely to occur elsewhere if adding it in each shadow element.
+    HTMLInputElement* input = hostInput();
+    if (!input || input->isDisabledOrReadOnly()) {
+        stopDragging();
+        HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+    bool isLeftButton = mouseEvent->button() == LeftButton;
+    const AtomicString& eventType = event->type();
+
+    // We intentionally do not call event->setDefaultHandled() here because
+    // MediaControlTimelineElement::defaultEventHandler() wants to handle these
+    // mouse events.
+    if (eventType == eventNames().mousedownEvent && isLeftButton) {
+        startDragging();
+        return;
+    } else if (eventType == eventNames().mouseupEvent && isLeftButton) {
+        stopDragging();
+        return;
+    } else if (eventType == eventNames().mousemoveEvent) {
+        if (m_inDragMode)
+            setPositionFromPoint(mouseEvent->absoluteLocation());
+        return;
+    }
+
+    HTMLDivElement::defaultEventHandler(event);
+}
+
+bool SliderThumbElement::willRespondToMouseMoveEvents()
+{
+    const HTMLInputElement* input = hostInput();
+    if (input && !input->isDisabledOrReadOnly() && m_inDragMode)
+        return true;
+
+    return HTMLDivElement::willRespondToMouseMoveEvents();
+}
+
+bool SliderThumbElement::willRespondToMouseClickEvents()
+{
+    const HTMLInputElement* input = hostInput();
+    if (input && !input->isDisabledOrReadOnly())
+        return true;
+
+    return HTMLDivElement::willRespondToMouseClickEvents();
+}
+
+void SliderThumbElement::detach()
+{
+    if (m_inDragMode) {
+        if (Frame* frame = document()->frame())
+            frame->eventHandler()->setCapturingMouseEventsNode(0);
+    }
+    HTMLDivElement::detach();
+}
+
+HTMLInputElement* SliderThumbElement::hostInput() const
+{
+    // Only HTMLInputElement creates SliderThumbElement instances as its shadow nodes.
+    // So, shadowHost() must be an HTMLInputElement.
+    return shadowHost()->toInputElement();
+}
+
+static const AtomicString& sliderThumbShadowPseudoId()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, sliderThumb, ("-webkit-slider-thumb", AtomicString::ConstructFromLiteral));
+    return sliderThumb;
+}
+
+static const AtomicString& mediaSliderThumbShadowPseudoId()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, mediaSliderThumb, ("-webkit-media-slider-thumb", AtomicString::ConstructFromLiteral));
+    return mediaSliderThumb;
+}
+
+const AtomicString& SliderThumbElement::shadowPseudoId() const
+{
+    HTMLInputElement* input = hostInput();
+    if (!input)
+        return sliderThumbShadowPseudoId();
+
+    RenderStyle* sliderStyle = input->renderer()->style();
+    switch (sliderStyle->appearance()) {
+    case MediaSliderPart:
+    case MediaSliderThumbPart:
+    case MediaVolumeSliderPart:
+    case MediaVolumeSliderThumbPart:
+    case MediaFullScreenVolumeSliderPart:
+    case MediaFullScreenVolumeSliderThumbPart:
+        return mediaSliderThumbShadowPseudoId();
+    default:
+        return sliderThumbShadowPseudoId();
+    }
+}
+
+// --------------------------------
+
+inline SliderContainerElement::SliderContainerElement(Document* document)
+    : HTMLDivElement(HTMLNames::divTag, document)
+{
+}
+
+PassRefPtr<SliderContainerElement> SliderContainerElement::create(Document* document)
+{
+    return adoptRef(new SliderContainerElement(document));
+}
+
+RenderObject* SliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderSliderContainer(this);
+}
+
+const AtomicString& SliderContainerElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, mediaSliderContainer, ("-webkit-media-slider-container", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(const AtomicString, sliderContainer, ("-webkit-slider-container", AtomicString::ConstructFromLiteral));
+
+    HTMLInputElement* input = shadowHost()->toInputElement();
+    if (!input)
+        return sliderContainer;
+
+    RenderStyle* sliderStyle = input->renderer()->style();
+    switch (sliderStyle->appearance()) {
+    case MediaSliderPart:
+    case MediaSliderThumbPart:
+    case MediaVolumeSliderPart:
+    case MediaVolumeSliderThumbPart:
+    case MediaFullScreenVolumeSliderPart:
+    case MediaFullScreenVolumeSliderThumbPart:
+        return mediaSliderContainer;
+    default:
+        return sliderContainer;
+    }
+}
+
+}
diff --git a/Source/core/html/shadow/SliderThumbElement.h b/Source/core/html/shadow/SliderThumbElement.h
new file mode 100644
index 0000000..1b935e6
--- /dev/null
+++ b/Source/core/html/shadow/SliderThumbElement.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 SliderThumbElement_h
+#define SliderThumbElement_h
+
+#include "HTMLNames.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/platform/graphics/FloatPoint.h"
+#include "core/rendering/RenderBlock.h"
+#include "core/rendering/style/RenderStyleConstants.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class HTMLElement;
+class HTMLInputElement;
+class Event;
+class FloatPoint;
+
+class SliderThumbElement FINAL : public HTMLDivElement {
+public:
+    static PassRefPtr<SliderThumbElement> create(Document*);
+
+    void setPositionFromValue();
+
+    void dragFrom(const LayoutPoint&);
+    virtual void defaultEventHandler(Event*);
+    virtual bool willRespondToMouseMoveEvents() OVERRIDE;
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+    virtual void detach();
+    virtual const AtomicString& shadowPseudoId() const;
+    HTMLInputElement* hostInput() const;
+    void setPositionFromPoint(const LayoutPoint&);
+
+private:
+    SliderThumbElement(Document*);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren();
+    virtual bool isDisabledFormControl() const OVERRIDE;
+    virtual bool matchesReadOnlyPseudoClass() const OVERRIDE;
+    virtual bool matchesReadWritePseudoClass() const OVERRIDE;
+    virtual Node* focusDelegate();
+    void startDragging();
+    void stopDragging();
+
+    bool m_inDragMode;
+};
+
+inline SliderThumbElement::SliderThumbElement(Document* document)
+    : HTMLDivElement(HTMLNames::divTag, document)
+    , m_inDragMode(false)
+{
+}
+
+inline PassRefPtr<SliderThumbElement> SliderThumbElement::create(Document* document)
+{
+    return adoptRef(new SliderThumbElement(document));
+}
+
+inline PassRefPtr<Element> SliderThumbElement::cloneElementWithoutAttributesAndChildren()
+{
+    return create(document());
+}
+
+inline SliderThumbElement* toSliderThumbElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isHTMLElement());
+    return static_cast<SliderThumbElement*>(node);
+}
+
+// This always return a valid pointer.
+// An assertion fails if the specified node is not a range input.
+SliderThumbElement* sliderThumbElementOf(Node*);
+HTMLElement* sliderTrackElementOf(Node*);
+
+// --------------------------------
+
+class RenderSliderThumb FINAL : public RenderBlock {
+public:
+    RenderSliderThumb(SliderThumbElement*);
+    void updateAppearance(RenderStyle* parentStyle);
+
+private:
+    virtual bool isSliderThumb() const;
+};
+
+// --------------------------------
+
+class SliderContainerElement FINAL : public HTMLDivElement {
+public:
+    static PassRefPtr<SliderContainerElement> create(Document*);
+
+private:
+    SliderContainerElement(Document*);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual const AtomicString& shadowPseudoId() const;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/shadow/SpinButtonElement.cpp b/Source/core/html/shadow/SpinButtonElement.cpp
new file mode 100644
index 0000000..aad5bbf
--- /dev/null
+++ b/Source/core/html/shadow/SpinButtonElement.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/SpinButtonElement.h"
+
+#include "HTMLNames.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/WheelEvent.h"
+#include "core/page/Chrome.h"
+#include "core/page/EventHandler.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/platform/ScrollbarTheme.h"
+#include "core/rendering/RenderBox.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline SpinButtonElement::SpinButtonElement(Document* document, SpinButtonOwner& spinButtonOwner)
+    : HTMLDivElement(divTag, document)
+    , m_spinButtonOwner(&spinButtonOwner)
+    , m_capturing(false)
+    , m_upDownState(Indeterminate)
+    , m_pressStartingState(Indeterminate)
+    , m_repeatingTimer(this, &SpinButtonElement::repeatingTimerFired)
+{
+}
+
+PassRefPtr<SpinButtonElement> SpinButtonElement::create(Document* document, SpinButtonOwner& spinButtonOwner)
+{
+    return adoptRef(new SpinButtonElement(document, spinButtonOwner));
+}
+
+const AtomicString& SpinButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, innerPseudoId, ("-webkit-inner-spin-button", AtomicString::ConstructFromLiteral));
+    return innerPseudoId;
+}
+
+void SpinButtonElement::detach()
+{
+    releaseCapture();
+    HTMLDivElement::detach();
+}
+
+void SpinButtonElement::defaultEventHandler(Event* event)
+{
+    if (!event->isMouseEvent()) {
+        if (!event->defaultHandled())
+            HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    RenderBox* box = renderBox();
+    if (!box) {
+        if (!event->defaultHandled())
+            HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    if (!shouldRespondToMouseEvents()) {
+        if (!event->defaultHandled())
+            HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+    IntPoint local = roundedIntPoint(box->absoluteToLocal(mouseEvent->absoluteLocation(), UseTransforms));
+    if (mouseEvent->type() == eventNames().mousedownEvent && mouseEvent->button() == LeftButton) {
+        if (box->pixelSnappedBorderBoxRect().contains(local)) {
+            // The following functions of HTMLInputElement may run JavaScript
+            // code which detaches this shadow node. We need to take a reference
+            // and check renderer() after such function calls.
+            RefPtr<Node> protector(this);
+            if (m_spinButtonOwner)
+                m_spinButtonOwner->focusAndSelectSpinButtonOwner();
+            if (renderer()) {
+                if (m_upDownState != Indeterminate) {
+                    // A JavaScript event handler called in doStepAction() below
+                    // might change the element state and we might need to
+                    // cancel the repeating timer by the state change. If we
+                    // started the timer after doStepAction(), we would have no
+                    // chance to cancel the timer.
+                    startRepeatingTimer();
+                    doStepAction(m_upDownState == Up ? 1 : -1);
+                }
+            }
+            event->setDefaultHandled();
+        }
+    } else if (mouseEvent->type() == eventNames().mouseupEvent && mouseEvent->button() == LeftButton)
+        stopRepeatingTimer();
+    else if (event->type() == eventNames().mousemoveEvent) {
+        if (box->pixelSnappedBorderBoxRect().contains(local)) {
+            if (!m_capturing) {
+                if (Frame* frame = document()->frame()) {
+                    frame->eventHandler()->setCapturingMouseEventsNode(this);
+                    m_capturing = true;
+                    if (Page* page = document()->page()) {
+                        if (page->chrome())
+                            page->chrome()->registerPopupOpeningObserver(this);
+                    }
+                }
+            }
+            UpDownState oldUpDownState = m_upDownState;
+            m_upDownState = local.y() < box->height() / 2 ? Up : Down;
+            if (m_upDownState != oldUpDownState)
+                renderer()->repaint();
+        } else {
+            releaseCapture();
+            m_upDownState = Indeterminate;
+        }
+    }
+
+    if (!event->defaultHandled())
+        HTMLDivElement::defaultEventHandler(event);
+}
+
+void SpinButtonElement::willOpenPopup()
+{
+    releaseCapture();
+    m_upDownState = Indeterminate;
+}
+
+void SpinButtonElement::forwardEvent(Event* event)
+{
+    if (!renderBox())
+        return;
+
+    if (!event->hasInterface(eventNames().interfaceForWheelEvent))
+        return;
+
+    if (!m_spinButtonOwner)
+        return;
+
+    if (!m_spinButtonOwner->shouldSpinButtonRespondToWheelEvents())
+        return;
+
+    doStepAction(static_cast<WheelEvent*>(event)->wheelDeltaY());
+    event->setDefaultHandled();
+}
+
+bool SpinButtonElement::willRespondToMouseMoveEvents()
+{
+    if (renderBox() && shouldRespondToMouseEvents())
+        return true;
+
+    return HTMLDivElement::willRespondToMouseMoveEvents();
+}
+
+bool SpinButtonElement::willRespondToMouseClickEvents()
+{
+    if (renderBox() && shouldRespondToMouseEvents())
+        return true;
+
+    return HTMLDivElement::willRespondToMouseClickEvents();
+}
+
+void SpinButtonElement::doStepAction(int amount)
+{
+    if (!m_spinButtonOwner)
+        return;
+
+    if (amount > 0)
+        m_spinButtonOwner->spinButtonStepUp();
+    else if (amount < 0)
+        m_spinButtonOwner->spinButtonStepDown();
+}
+
+void SpinButtonElement::releaseCapture()
+{
+    stopRepeatingTimer();
+    if (m_capturing) {
+        if (Frame* frame = document()->frame()) {
+            frame->eventHandler()->setCapturingMouseEventsNode(0);
+            m_capturing = false;
+            if (Page* page = document()->page()) {
+                if (page->chrome())
+                    page->chrome()->unregisterPopupOpeningObserver(this);
+            }
+        }
+    }
+}
+
+bool SpinButtonElement::matchesReadOnlyPseudoClass() const
+{
+    return shadowHost()->matchesReadOnlyPseudoClass();
+}
+
+bool SpinButtonElement::matchesReadWritePseudoClass() const
+{
+    return shadowHost()->matchesReadWritePseudoClass();
+}
+
+void SpinButtonElement::startRepeatingTimer()
+{
+    m_pressStartingState = m_upDownState;
+    ScrollbarTheme* theme = ScrollbarTheme::theme();
+    m_repeatingTimer.start(theme->initialAutoscrollTimerDelay(), theme->autoscrollTimerDelay());
+}
+
+void SpinButtonElement::stopRepeatingTimer()
+{
+    m_repeatingTimer.stop();
+}
+
+void SpinButtonElement::step(int amount)
+{
+    if (!shouldRespondToMouseEvents())
+        return;
+    // On Mac OS, NSStepper updates the value for the button under the mouse
+    // cursor regardless of the button pressed at the beginning. So the
+    // following check is not needed for Mac OS.
+#if !OS(DARWIN)
+    if (m_upDownState != m_pressStartingState)
+        return;
+#endif
+    doStepAction(amount);
+}
+    
+void SpinButtonElement::repeatingTimerFired(Timer<SpinButtonElement>*)
+{
+    if (m_upDownState != Indeterminate)
+        step(m_upDownState == Up ? 1 : -1);
+}
+
+void SpinButtonElement::setHovered(bool flag)
+{
+    if (!flag)
+        m_upDownState = Indeterminate;
+    HTMLDivElement::setHovered(flag);
+}
+
+bool SpinButtonElement::shouldRespondToMouseEvents()
+{
+    return !m_spinButtonOwner || m_spinButtonOwner->shouldSpinButtonRespondToMouseEvents();
+}
+
+}
diff --git a/Source/core/html/shadow/SpinButtonElement.h b/Source/core/html/shadow/SpinButtonElement.h
new file mode 100644
index 0000000..99e4b3e
--- /dev/null
+++ b/Source/core/html/shadow/SpinButtonElement.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * 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 COMPUTER, 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 COMPUTER, 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 SpinButtonElement_h
+#define SpinButtonElement_h
+
+#include "core/html/HTMLDivElement.h"
+#include "core/page/PopupOpeningObserver.h"
+#include "core/platform/Timer.h"
+
+namespace WebCore {
+
+class SpinButtonElement FINAL : public HTMLDivElement, public PopupOpeningObserver {
+public:
+    enum UpDownState {
+        Indeterminate, // Hovered, but the event is not handled.
+        Down,
+        Up,
+    };
+
+    class SpinButtonOwner {
+    public:
+        virtual ~SpinButtonOwner() { }
+        virtual void focusAndSelectSpinButtonOwner() = 0;
+        virtual bool shouldSpinButtonRespondToMouseEvents() = 0;
+        virtual bool shouldSpinButtonRespondToWheelEvents() = 0;
+        virtual void spinButtonStepDown() = 0;
+        virtual void spinButtonStepUp() = 0;
+    };
+
+    // The owner of SpinButtonElement must call removeSpinButtonOwner
+    // because SpinButtonElement can be outlive SpinButtonOwner
+    // implementation, e.g. during event handling.
+    static PassRefPtr<SpinButtonElement> create(Document*, SpinButtonOwner&);
+    UpDownState upDownState() const { return m_upDownState; }
+    virtual void releaseCapture();
+    void removeSpinButtonOwner() { m_spinButtonOwner = 0; }
+
+    void step(int amount);
+    
+    virtual bool willRespondToMouseMoveEvents() OVERRIDE;
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+    void forwardEvent(Event*);
+
+private:
+    SpinButtonElement(Document*, SpinButtonOwner&);
+
+    virtual const AtomicString& shadowPseudoId() const;
+    virtual void detach();
+    virtual bool isSpinButtonElement() const { return true; }
+    virtual bool isDisabledFormControl() const OVERRIDE { return shadowHost() && shadowHost()->isDisabledFormControl(); }
+    virtual bool matchesReadOnlyPseudoClass() const OVERRIDE;
+    virtual bool matchesReadWritePseudoClass() const OVERRIDE;
+    virtual void defaultEventHandler(Event*);
+    virtual void willOpenPopup() OVERRIDE;
+    void doStepAction(int);
+    void startRepeatingTimer();
+    void stopRepeatingTimer();
+    void repeatingTimerFired(Timer<SpinButtonElement>*);
+    virtual void setHovered(bool = true);
+    bool shouldRespondToMouseEvents();
+    virtual bool isMouseFocusable() const { return false; }
+
+    SpinButtonOwner* m_spinButtonOwner;
+    bool m_capturing;
+    UpDownState m_upDownState;
+    UpDownState m_pressStartingState;
+    Timer<SpinButtonElement> m_repeatingTimer;
+};
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/shadow/TextControlInnerElements.cpp b/Source/core/html/shadow/TextControlInnerElements.cpp
new file mode 100644
index 0000000..06931b4
--- /dev/null
+++ b/Source/core/html/shadow/TextControlInnerElements.cpp
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/TextControlInnerElements.h"
+
+#include "HTMLNames.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/BeforeTextInsertedEvent.h"
+#include "core/dom/Document.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/TextEvent.h"
+#include "core/dom/TextEventInputType.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLTextAreaElement.h"
+#include "core/page/EventHandler.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/page/SpeechInput.h"
+#include "core/page/SpeechInputEvent.h"
+#include "core/rendering/RenderSearchField.h"
+#include "core/rendering/RenderTextControl.h"
+#include "core/rendering/RenderView.h"
+#include "core/rendering/style/StyleInheritedData.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+TextControlInnerContainer::TextControlInnerContainer(Document* document)
+    : HTMLDivElement(divTag, document)
+{
+}
+
+PassRefPtr<TextControlInnerContainer> TextControlInnerContainer::create(Document* document)
+{
+    return adoptRef(new TextControlInnerContainer(document));
+}
+    
+RenderObject* TextControlInnerContainer::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderTextControlInnerContainer(this);
+}
+
+TextControlInnerElement::TextControlInnerElement(Document* document)
+    : HTMLDivElement(divTag, document)
+{
+    setHasCustomStyleCallbacks();
+}
+
+PassRefPtr<TextControlInnerElement> TextControlInnerElement::create(Document* document)
+{
+    return adoptRef(new TextControlInnerElement(document));
+}
+
+PassRefPtr<RenderStyle> TextControlInnerElement::customStyleForRenderer()
+{
+    RenderTextControlSingleLine* parentRenderer = toRenderTextControlSingleLine(shadowHost()->renderer());
+    return parentRenderer->createInnerBlockStyle(parentRenderer->style());
+}
+
+// ---------------------------
+
+inline TextControlInnerTextElement::TextControlInnerTextElement(Document* document)
+    : HTMLDivElement(divTag, document)
+{
+    setHasCustomStyleCallbacks();
+}
+
+PassRefPtr<TextControlInnerTextElement> TextControlInnerTextElement::create(Document* document)
+{
+    return adoptRef(new TextControlInnerTextElement(document));
+}
+
+void TextControlInnerTextElement::defaultEventHandler(Event* event)
+{
+    // FIXME: In the future, we should add a way to have default event listeners.
+    // Then we would add one to the text field's inner div, and we wouldn't need this subclass.
+    // Or possibly we could just use a normal event listener.
+    if (event->isBeforeTextInsertedEvent() || event->type() == eventNames().webkitEditableContentChangedEvent) {
+        Element* shadowAncestor = shadowHost();
+        // A TextControlInnerTextElement can have no host if its been detached,
+        // but kept alive by an EditCommand. In this case, an undo/redo can
+        // cause events to be sent to the TextControlInnerTextElement. To
+        // prevent an infinite loop, we must check for this case before sending
+        // the event up the chain.
+        if (shadowAncestor)
+            shadowAncestor->defaultEventHandler(event);
+    }
+    if (!event->defaultHandled())
+        HTMLDivElement::defaultEventHandler(event);
+}
+
+RenderObject* TextControlInnerTextElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderTextControlInnerBlock(this);
+}
+
+PassRefPtr<RenderStyle> TextControlInnerTextElement::customStyleForRenderer()
+{
+    RenderTextControl* parentRenderer = toRenderTextControl(shadowHost()->renderer());
+    return parentRenderer->createInnerTextStyle(parentRenderer->style());
+}
+
+// ----------------------------
+
+inline SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document* document)
+    : HTMLDivElement(divTag, document)
+{
+}
+
+PassRefPtr<SearchFieldResultsButtonElement> SearchFieldResultsButtonElement::create(Document* document)
+{
+    return adoptRef(new SearchFieldResultsButtonElement(document));
+}
+
+const AtomicString& SearchFieldResultsButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, resultsId, ("-webkit-search-results-button", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(AtomicString, resultsDecorationId, ("-webkit-search-results-decoration", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(AtomicString, decorationId, ("-webkit-search-decoration", AtomicString::ConstructFromLiteral));
+    Element* host = shadowHost();
+    if (!host)
+        return resultsId;
+    if (HTMLInputElement* input = host->toInputElement()) {
+        if (input->maxResults() < 0)
+            return decorationId;
+        if (input->maxResults() > 0)
+            return resultsId;
+        return resultsDecorationId;
+    }
+    return resultsId;
+}
+
+void SearchFieldResultsButtonElement::defaultEventHandler(Event* event)
+{
+    // On mousedown, bring up a menu, if needed
+    HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost());
+    if (input && event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+        input->focus();
+        input->select();
+        RenderSearchField* renderer = toRenderSearchField(input->renderer());
+        if (renderer->popupIsVisible())
+            renderer->hidePopup();
+        else if (input->maxResults() > 0)
+            renderer->showPopup();
+        event->setDefaultHandled();
+    }
+
+    if (!event->defaultHandled())
+        HTMLDivElement::defaultEventHandler(event);
+}
+
+bool SearchFieldResultsButtonElement::willRespondToMouseClickEvents()
+{
+    return true;
+}
+
+// ----------------------------
+
+inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* document)
+    : HTMLDivElement(divTag, document)
+    , m_capturing(false)
+{
+}
+
+PassRefPtr<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document* document)
+{
+    return adoptRef(new SearchFieldCancelButtonElement(document));
+}
+
+const AtomicString& SearchFieldCancelButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-search-cancel-button", AtomicString::ConstructFromLiteral));
+    return pseudoId;
+}
+
+void SearchFieldCancelButtonElement::detach()
+{
+    if (m_capturing) {
+        if (Frame* frame = document()->frame())
+            frame->eventHandler()->setCapturingMouseEventsNode(0);
+    }
+    HTMLDivElement::detach();
+}
+
+
+void SearchFieldCancelButtonElement::defaultEventHandler(Event* event)
+{
+    // If the element is visible, on mouseup, clear the value, and set selection
+    RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost()));
+    if (!input || input->isDisabledOrReadOnly()) {
+        if (!event->defaultHandled())
+            HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+        if (renderer() && renderer()->visibleToHitTesting()) {
+            if (Frame* frame = document()->frame()) {
+                frame->eventHandler()->setCapturingMouseEventsNode(this);
+                m_capturing = true;
+            }
+        }
+        input->focus();
+        input->select();
+        event->setDefaultHandled();
+    }
+    if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+        if (m_capturing) {
+            if (Frame* frame = document()->frame()) {
+                frame->eventHandler()->setCapturingMouseEventsNode(0);
+                m_capturing = false;
+            }
+            if (hovered()) {
+                String oldValue = input->value();
+                input->setValueForUser("");
+                input->onSearch();
+                event->setDefaultHandled();
+            }
+        }
+    }
+
+    if (!event->defaultHandled())
+        HTMLDivElement::defaultEventHandler(event);
+}
+
+bool SearchFieldCancelButtonElement::willRespondToMouseClickEvents()
+{
+    const HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost());
+    if (input && !input->isDisabledOrReadOnly())
+        return true;
+
+    return HTMLDivElement::willRespondToMouseClickEvents();
+}
+
+// ----------------------------
+
+#if ENABLE(INPUT_SPEECH)
+
+inline InputFieldSpeechButtonElement::InputFieldSpeechButtonElement(Document* document)
+    : HTMLDivElement(divTag, document)
+    , m_capturing(false)
+    , m_state(Idle)
+    , m_listenerId(0)
+{
+}
+
+InputFieldSpeechButtonElement::~InputFieldSpeechButtonElement()
+{
+    SpeechInput* speech = speechInput();
+    if (speech && m_listenerId)  { // Could be null when page is unloading.
+        if (m_state != Idle)
+            speech->cancelRecognition(m_listenerId);
+        speech->unregisterListener(m_listenerId);
+    }
+}
+
+PassRefPtr<InputFieldSpeechButtonElement> InputFieldSpeechButtonElement::create(Document* document)
+{
+    return adoptRef(new InputFieldSpeechButtonElement(document));
+}
+
+void InputFieldSpeechButtonElement::defaultEventHandler(Event* event)
+{
+    // For privacy reasons, only allow clicks directly coming from the user.
+    if (!ScriptController::processingUserGesture()) {
+        HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    // The call to focus() below dispatches a focus event, and an event handler in the page might
+    // remove the input element from DOM. To make sure it remains valid until we finish our work
+    // here, we take a temporary reference.
+    RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost()));
+
+    if (!input || input->isDisabledOrReadOnly()) {
+        if (!event->defaultHandled())
+            HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    // On mouse down, select the text and set focus.
+    if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+        if (renderer() && renderer()->visibleToHitTesting()) {
+            if (Frame* frame = document()->frame()) {
+                frame->eventHandler()->setCapturingMouseEventsNode(this);
+                m_capturing = true;
+            }
+        }
+        RefPtr<InputFieldSpeechButtonElement> holdRefButton(this);
+        input->focus();
+        input->select();
+        event->setDefaultHandled();
+    }
+    // On mouse up, release capture cleanly.
+    if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+        if (m_capturing && renderer() && renderer()->visibleToHitTesting()) {
+            if (Frame* frame = document()->frame()) {
+                frame->eventHandler()->setCapturingMouseEventsNode(0);
+                m_capturing = false;
+            }
+        }
+    }
+
+    if (event->type() == eventNames().clickEvent && m_listenerId) {
+        switch (m_state) {
+        case Idle:
+            startSpeechInput();
+            break;
+        case Recording:
+            stopSpeechInput();
+            break;
+        case Recognizing:
+            // Nothing to do here, we will continue to wait for results.
+            break;
+        }
+        event->setDefaultHandled();
+    }
+
+    if (!event->defaultHandled())
+        HTMLDivElement::defaultEventHandler(event);
+}
+
+bool InputFieldSpeechButtonElement::willRespondToMouseClickEvents()
+{
+    const HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost());
+    if (input && !input->isDisabledOrReadOnly())
+        return true;
+
+    return HTMLDivElement::willRespondToMouseClickEvents();
+}
+
+void InputFieldSpeechButtonElement::setState(SpeechInputState state)
+{
+    if (m_state != state) {
+        m_state = state;
+        shadowHost()->renderer()->repaint();
+    }
+}
+
+SpeechInput* InputFieldSpeechButtonElement::speechInput()
+{
+    return SpeechInput::from(document()->page());
+}
+
+void InputFieldSpeechButtonElement::didCompleteRecording(int)
+{
+    setState(Recognizing);
+}
+
+void InputFieldSpeechButtonElement::didCompleteRecognition(int)
+{
+    setState(Idle);
+}
+
+void InputFieldSpeechButtonElement::setRecognitionResult(int, const SpeechInputResultArray& results)
+{
+    m_results = results;
+
+    // The call to setValue() below dispatches an event, and an event handler in the page might
+    // remove the input element from DOM. To make sure it remains valid until we finish our work
+    // here, we take a temporary reference.
+    RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost()));
+    if (!input || input->isDisabledOrReadOnly())
+        return;
+
+    RefPtr<InputFieldSpeechButtonElement> holdRefButton(this);
+    if (document() && document()->domWindow()) {
+        // Call selectionChanged, causing the element to cache the selection,
+        // so that the text event inserts the text in this element even if
+        // focus has moved away from it.
+        input->selectionChanged(false);
+        input->dispatchEvent(TextEvent::create(document()->domWindow(), results.isEmpty() ? "" : results[0]->utterance(), TextEventInputOther));
+    }
+
+    // This event is sent after the text event so the website can perform actions using the input field content immediately.
+    // It provides alternative recognition hypotheses and notifies that the results come from speech input.
+    input->dispatchEvent(SpeechInputEvent::create(eventNames().webkitspeechchangeEvent, results));
+
+    // Check before accessing the renderer as the above event could have potentially turned off
+    // speech in the input element, hence removing this button and renderer from the hierarchy.
+    if (renderer())
+        renderer()->repaint();
+}
+
+void InputFieldSpeechButtonElement::attach()
+{
+    ASSERT(!m_listenerId);
+    if (SpeechInput* input = SpeechInput::from(document()->page()))
+        m_listenerId = input->registerListener(this);
+    HTMLDivElement::attach();
+}
+
+void InputFieldSpeechButtonElement::detach()
+{
+    if (m_capturing) {
+        if (Frame* frame = document()->frame())
+            frame->eventHandler()->setCapturingMouseEventsNode(0);
+    }
+
+    if (m_listenerId) {
+        if (m_state != Idle)
+            speechInput()->cancelRecognition(m_listenerId);
+        speechInput()->unregisterListener(m_listenerId);
+        m_listenerId = 0;
+    }
+
+    HTMLDivElement::detach();
+}
+
+void InputFieldSpeechButtonElement::startSpeechInput()
+{
+    if (m_state != Idle)
+        return;
+
+    RefPtr<HTMLInputElement> input = static_cast<HTMLInputElement*>(shadowHost());
+    AtomicString language = input->computeInheritedLanguage();
+    String grammar = input->getAttribute(webkitgrammarAttr);
+    IntRect rect = document()->view()->contentsToRootView(pixelSnappedBoundingBox());
+    if (speechInput()->startRecognition(m_listenerId, rect, language, grammar, document()->securityOrigin()))
+        setState(Recording);
+}
+
+void InputFieldSpeechButtonElement::stopSpeechInput()
+{
+    if (m_state == Recording)
+        speechInput()->stopRecording(m_listenerId);
+}
+
+const AtomicString& InputFieldSpeechButtonElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-input-speech-button", AtomicString::ConstructFromLiteral));
+    return pseudoId;
+}
+
+#endif // ENABLE(INPUT_SPEECH)
+
+}
diff --git a/Source/core/html/shadow/TextControlInnerElements.h b/Source/core/html/shadow/TextControlInnerElements.h
new file mode 100644
index 0000000..6ec0336
--- /dev/null
+++ b/Source/core/html/shadow/TextControlInnerElements.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * 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 COMPUTER, 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 COMPUTER, 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 TextControlInnerElements_h
+#define TextControlInnerElements_h
+
+#include "core/html/HTMLDivElement.h"
+#include "core/page/SpeechInputListener.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class SpeechInput;
+
+class TextControlInnerContainer FINAL : public HTMLDivElement {
+public:
+    static PassRefPtr<TextControlInnerContainer> create(Document*);
+protected:
+    TextControlInnerContainer(Document*);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+};
+
+class TextControlInnerElement FINAL : public HTMLDivElement {
+public:
+    static PassRefPtr<TextControlInnerElement> create(Document*);
+
+protected:
+    TextControlInnerElement(Document*);
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+
+private:
+    virtual bool isMouseFocusable() const { return false; }
+};
+
+class TextControlInnerTextElement FINAL : public HTMLDivElement {
+public:
+    static PassRefPtr<TextControlInnerTextElement> create(Document*);
+
+    virtual void defaultEventHandler(Event*);
+
+private:
+    TextControlInnerTextElement(Document*);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+    virtual bool isMouseFocusable() const { return false; }
+};
+
+class SearchFieldResultsButtonElement FINAL : public HTMLDivElement {
+public:
+    static PassRefPtr<SearchFieldResultsButtonElement> create(Document*);
+
+    virtual void defaultEventHandler(Event*);
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+private:
+    SearchFieldResultsButtonElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const;
+    virtual bool isMouseFocusable() const { return false; }
+};
+
+class SearchFieldCancelButtonElement FINAL : public HTMLDivElement {
+public:
+    static PassRefPtr<SearchFieldCancelButtonElement> create(Document*);
+
+    virtual void defaultEventHandler(Event*);
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+private:
+    SearchFieldCancelButtonElement(Document*);
+    virtual const AtomicString& shadowPseudoId() const;
+    virtual void detach();
+    virtual bool isMouseFocusable() const { return false; }
+
+    bool m_capturing;
+};
+
+#if ENABLE(INPUT_SPEECH)
+
+class InputFieldSpeechButtonElement FINAL
+    : public HTMLDivElement,
+      public SpeechInputListener {
+public:
+    enum SpeechInputState {
+        Idle,
+        Recording,
+        Recognizing,
+    };
+
+    static PassRefPtr<InputFieldSpeechButtonElement> create(Document*);
+    virtual ~InputFieldSpeechButtonElement();
+
+    virtual void detach();
+    virtual void defaultEventHandler(Event*);
+    virtual bool willRespondToMouseClickEvents();
+    virtual bool isInputFieldSpeechButtonElement() const { return true; }
+    SpeechInputState state() const { return m_state; }
+    void startSpeechInput();
+    void stopSpeechInput();
+
+    // SpeechInputListener methods.
+    void didCompleteRecording(int);
+    void didCompleteRecognition(int);
+    void setRecognitionResult(int, const SpeechInputResultArray&);
+
+private:
+    InputFieldSpeechButtonElement(Document*);
+    SpeechInput* speechInput();
+    void setState(SpeechInputState state);
+    virtual const AtomicString& shadowPseudoId() const;
+    virtual bool isMouseFocusable() const { return false; }
+    virtual void attach();
+
+    bool m_capturing;
+    SpeechInputState m_state;
+    int m_listenerId;
+    SpeechInputResultArray m_results;
+};
+
+inline InputFieldSpeechButtonElement* toInputFieldSpeechButtonElement(Element* element)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!element || element->isInputFieldSpeechButtonElement());
+    return static_cast<InputFieldSpeechButtonElement*>(element);
+}
+
+#endif // ENABLE(INPUT_SPEECH)
+
+} // namespace
+
+#endif
diff --git a/Source/core/html/shadow/TextFieldDecorationElement.cpp b/Source/core/html/shadow/TextFieldDecorationElement.cpp
new file mode 100644
index 0000000..c330767
--- /dev/null
+++ b/Source/core/html/shadow/TextFieldDecorationElement.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+#include "core/html/shadow/TextFieldDecorationElement.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/Event.h"
+#include "core/dom/NodeRenderStyle.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/shadow/HTMLShadowElement.h"
+#include "core/rendering/RenderImage.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// TextFieldDecorator ----------------------------------------------------------------
+
+TextFieldDecorator::~TextFieldDecorator()
+{
+}
+
+// TextFieldDecorationElement ----------------------------------------------------------------
+
+// FIXME: This class is only used in Chromium, and has no layout tests!!
+
+TextFieldDecorationElement::TextFieldDecorationElement(Document* document, TextFieldDecorator* decorator)
+    : HTMLDivElement(HTMLNames::divTag, document)
+    , m_textFieldDecorator(decorator)
+    , m_isInHoverState(false)
+{
+    ASSERT(decorator);
+    setHasCustomStyleCallbacks();
+}
+
+PassRefPtr<TextFieldDecorationElement> TextFieldDecorationElement::create(Document* document, TextFieldDecorator* decorator)
+{
+    return adoptRef(new TextFieldDecorationElement(document, decorator));
+}
+
+TextFieldDecorationElement* TextFieldDecorationElement::fromShadowRoot(ShadowRoot* shadowRoot)
+{
+    if (!shadowRoot->firstChild()
+        || !shadowRoot->firstChild()->lastChild()
+        || !shadowRoot->firstChild()->lastChild()->isElementNode()
+        || !toElement(shadowRoot->firstChild()->lastChild())->isTextFieldDecoration())
+        return 0;
+    return toTextFieldDecorationElement(shadowRoot->firstChild()->lastChild());
+}
+
+static inline void getDecorationRootAndDecoratedRoot(HTMLInputElement* input, ShadowRoot*& decorationRoot, ShadowRoot*& decoratedRoot)
+{
+    ShadowRoot* existingRoot = input->youngestShadowRoot();
+    ShadowRoot* newRoot = 0;
+    while (existingRoot->childNodeCount() == 1 && existingRoot->firstChild()->hasTagName(shadowTag)) {
+        newRoot = existingRoot;
+        existingRoot = existingRoot->olderShadowRoot();
+        ASSERT(existingRoot);
+    }
+    if (newRoot)
+        newRoot->removeChild(newRoot->firstChild());
+    else {
+        // FIXME: This interacts really badly with author shadow roots because now
+        // we can interleave user agent and author shadow roots on the element meaning
+        // input.shadowRoot may be inaccessible if the browser has decided to decorate
+        // the input.
+        newRoot = input->ensureShadow()->addShadowRoot(input, ShadowRoot::UserAgentShadowRoot);
+    }
+    decorationRoot = newRoot;
+    decoratedRoot = existingRoot;
+}
+
+void TextFieldDecorationElement::decorate(HTMLInputElement* input, bool visible)
+{
+    ASSERT(input);
+    ShadowRoot* existingRoot;
+    ShadowRoot* decorationRoot;
+    getDecorationRootAndDecoratedRoot(input, decorationRoot, existingRoot);
+    ASSERT(decorationRoot);
+    ASSERT(existingRoot);
+    RefPtr<HTMLDivElement> box = HTMLDivElement::create(input->document());
+    decorationRoot->appendChild(box);
+    box->setInlineStyleProperty(CSSPropertyDisplay, CSSValueWebkitFlex);
+    box->setInlineStyleProperty(CSSPropertyWebkitAlignItems, CSSValueCenter);
+    ASSERT(existingRoot->childNodeCount() == 1);
+    toHTMLElement(existingRoot->firstChild())->setInlineStyleProperty(CSSPropertyWebkitFlexGrow, 1.0, CSSPrimitiveValue::CSS_NUMBER);
+    box->appendChild(HTMLShadowElement::create(HTMLNames::shadowTag, input->document()));
+    setInlineStyleProperty(CSSPropertyDisplay, visible ? CSSValueBlock : CSSValueNone);
+    box->appendChild(this);
+}
+
+inline HTMLInputElement* TextFieldDecorationElement::hostInput()
+{
+    // TextFieldDecorationElement is created only by C++ code, and it is always
+    // in <input> shadow.
+    ASSERT_WITH_SECURITY_IMPLICATION(!shadowHost() || shadowHost()->hasTagName(inputTag));
+    return static_cast<HTMLInputElement*>(shadowHost());
+}
+
+bool TextFieldDecorationElement::isTextFieldDecoration() const
+{
+    return true;
+}
+
+void TextFieldDecorationElement::updateImage()
+{
+    if (!renderer() || !renderer()->isImage())
+        return;
+    RenderImageResource* resource = toRenderImage(renderer())->imageResource();
+    CachedImage* image;
+    if (hostInput()->isDisabledFormControl())
+        image = m_textFieldDecorator->imageForDisabledState();
+    else if (hostInput()->isReadOnly())
+        image = m_textFieldDecorator->imageForReadonlyState();
+    else if (m_isInHoverState)
+        image = m_textFieldDecorator->imageForHoverState();
+    else
+        image = m_textFieldDecorator->imageForNormalState();
+    ASSERT(image);
+    resource->setCachedImage(image);
+}
+
+PassRefPtr<RenderStyle> TextFieldDecorationElement::customStyleForRenderer()
+{
+    RefPtr<RenderStyle> originalStyle = document()->styleResolver()->styleForElement(this);
+    RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
+    RenderStyle* inputStyle = hostInput()->renderStyle();
+    ASSERT(inputStyle);
+    style->setWidth(Length(inputStyle->fontSize(), Fixed));
+    style->setHeight(Length(inputStyle->fontSize(), Fixed));
+    updateImage();
+    return style.release();
+}
+
+RenderObject* TextFieldDecorationElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    RenderImage* image = new (arena) RenderImage(this);
+    image->setImageResource(RenderImageResource::create());
+    return image;
+}
+
+void TextFieldDecorationElement::attach()
+{
+    HTMLDivElement::attach();
+    updateImage();
+}
+
+void TextFieldDecorationElement::detach()
+{
+    m_textFieldDecorator->willDetach(hostInput());
+    HTMLDivElement::detach();
+}
+
+bool TextFieldDecorationElement::isMouseFocusable() const
+{
+    return false;
+}
+
+void TextFieldDecorationElement::defaultEventHandler(Event* event)
+{
+    RefPtr<HTMLInputElement> input(hostInput());
+    if (!input || input->isDisabledOrReadOnly() || !event->isMouseEvent()) {
+        if (!event->defaultHandled())
+            HTMLDivElement::defaultEventHandler(event);
+        return;
+    }
+
+    RefPtr<TextFieldDecorationElement> protector(this);
+    if (event->type() == eventNames().clickEvent) {
+        m_textFieldDecorator->handleClick(input.get());
+        event->setDefaultHandled();
+    }
+
+    if (event->type() == eventNames().mouseoverEvent) {
+        m_isInHoverState = true;
+        updateImage();
+    }
+
+    if (event->type() == eventNames().mouseoutEvent) {
+        m_isInHoverState = false;
+        updateImage();
+    }
+
+    if (!event->defaultHandled())
+        HTMLDivElement::defaultEventHandler(event);
+}
+
+bool TextFieldDecorationElement::willRespondToMouseMoveEvents()
+{
+    const HTMLInputElement* input = hostInput();
+    if (!input->isDisabledOrReadOnly())
+        return true;
+
+    return HTMLDivElement::willRespondToMouseMoveEvents();
+}
+
+bool TextFieldDecorationElement::willRespondToMouseClickEvents()
+{
+    const HTMLInputElement* input = hostInput();
+    if (!input->isDisabledOrReadOnly())
+        return true;
+
+    return HTMLDivElement::willRespondToMouseClickEvents();
+}
+
+} // namespace WebCore
diff --git a/Source/core/html/shadow/TextFieldDecorationElement.h b/Source/core/html/shadow/TextFieldDecorationElement.h
new file mode 100644
index 0000000..cf34338
--- /dev/null
+++ b/Source/core/html/shadow/TextFieldDecorationElement.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 TextFieldDecorationElement_h
+#define TextFieldDecorationElement_h
+
+#include "core/html/HTMLDivElement.h"
+
+namespace WebCore {
+
+class CachedImage;
+class HTMLInputElement;
+class ShadowRoot;
+
+// A TextFieldDecorator object must live until all of text fields which were
+// decorated by it die.
+class TextFieldDecorator {
+public:
+    // Returns true if this TextFieldDecorator wants to add a
+    // decoration to the specified text field.
+    virtual bool willAddDecorationTo(HTMLInputElement*) = 0;
+    virtual bool visibleByDefault() = 0;
+
+    // A TextFieldDecorator object should own the CachedImage objects.
+    virtual CachedImage* imageForNormalState() = 0;
+    virtual CachedImage* imageForDisabledState() = 0;
+    virtual CachedImage* imageForReadonlyState() = 0;
+    virtual CachedImage* imageForHoverState() = 0;
+
+    virtual void handleClick(HTMLInputElement*) = 0;
+    // This function is called just before detaching the decoration. It must not
+    // call functions which updating state of the specified HTMLInputElement
+    // object.
+    virtual void willDetach(HTMLInputElement*) = 0;
+
+    virtual ~TextFieldDecorator();
+};
+
+// A TextFieldDecorationElement object must be in a shadow tree of an
+// HTMLInputElement.
+class TextFieldDecorationElement FINAL : public HTMLDivElement {
+public:
+    static PassRefPtr<TextFieldDecorationElement> create(Document*, TextFieldDecorator*);
+    static TextFieldDecorationElement* fromShadowRoot(ShadowRoot*);
+    TextFieldDecorator* textFieldDecorator() { return m_textFieldDecorator; }
+    void decorate(HTMLInputElement*, bool visible);
+
+    virtual bool willRespondToMouseMoveEvents() OVERRIDE;
+    virtual bool willRespondToMouseClickEvents() OVERRIDE;
+
+private:
+    TextFieldDecorationElement(Document*, TextFieldDecorator*);
+    virtual bool isTextFieldDecoration() const OVERRIDE;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE;
+    virtual void attach() OVERRIDE;
+    virtual void detach() OVERRIDE;
+    virtual bool isMouseFocusable() const OVERRIDE;
+    virtual void defaultEventHandler(Event*) OVERRIDE;
+
+    HTMLInputElement* hostInput();
+    void updateImage();
+
+    TextFieldDecorator* m_textFieldDecorator;
+    bool m_isInHoverState;
+};
+
+inline TextFieldDecorationElement* toTextFieldDecorationElement(Node* node)
+{
+    ASSERT(node);
+    ASSERT_WITH_SECURITY_IMPLICATION(node->isElementNode());
+    ASSERT_WITH_SECURITY_IMPLICATION(toElement(node)->isTextFieldDecoration());
+    return static_cast<TextFieldDecorationElement*>(node);
+}
+
+}
+#endif
diff --git a/Source/core/html/track/InbandTextTrack.cpp b/Source/core/html/track/InbandTextTrack.cpp
new file mode 100644
index 0000000..e4f22a1
--- /dev/null
+++ b/Source/core/html/track/InbandTextTrack.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2012 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/track/InbandTextTrack.h"
+
+#include <math.h>
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/html/track/TextTrackCueGeneric.h"
+#include "core/html/track/TextTrackCueList.h"
+#include "core/platform/Logging.h"
+#include "core/platform/graphics/InbandTextTrackPrivate.h"
+#include "core/platform/graphics/MediaPlayer.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+PassRefPtr<InbandTextTrack> InbandTextTrack::create(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> playerPrivate)
+{
+    return adoptRef(new InbandTextTrack(context, client, playerPrivate));
+}
+
+InbandTextTrack::InbandTextTrack(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> tracksPrivate)
+    : TextTrack(context, client, emptyString(), tracksPrivate->label(), tracksPrivate->language(), InBand)
+    , m_private(tracksPrivate)
+{
+    m_private->setClient(this);
+    
+    switch (m_private->kind()) {
+    case InbandTextTrackPrivate::Subtitles:
+        setKind(TextTrack::subtitlesKeyword());
+        break;
+    case InbandTextTrackPrivate::Captions:
+        setKind(TextTrack::captionsKeyword());
+        break;
+    case InbandTextTrackPrivate::Descriptions:
+        setKind(TextTrack::descriptionsKeyword());
+        break;
+    case InbandTextTrackPrivate::Chapters:
+        setKind(TextTrack::chaptersKeyword());
+        break;
+    case InbandTextTrackPrivate::Metadata:
+        setKind(TextTrack::metadataKeyword());
+        break;
+    case InbandTextTrackPrivate::None:
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+InbandTextTrack::~InbandTextTrack()
+{
+    m_private->setClient(0);
+}
+
+void InbandTextTrack::setMode(const AtomicString& mode)
+{
+    TextTrack::setMode(mode);
+
+    if (mode == TextTrack::disabledKeyword())
+        m_private->setMode(InbandTextTrackPrivate::Disabled);
+    else if (mode == TextTrack::hiddenKeyword())
+        m_private->setMode(InbandTextTrackPrivate::Hidden);
+    else if (mode == TextTrack::showingKeyword())
+        m_private->setMode(InbandTextTrackPrivate::Showing);
+    else
+        ASSERT_NOT_REACHED();
+}
+
+bool InbandTextTrack::isClosedCaptions() const
+{
+    if (!m_private)
+        return false;
+
+    return m_private->isClosedCaptions();
+}
+
+bool InbandTextTrack::containsOnlyForcedSubtitles() const
+{
+    if (!m_private)
+        return false;
+    
+    return m_private->containsOnlyForcedSubtitles();
+}
+
+bool InbandTextTrack::isMainProgramContent() const
+{
+    if (!m_private)
+        return false;
+    
+    return m_private->isMainProgramContent();
+}
+
+bool InbandTextTrack::isEasyToRead() const
+{
+    if (!m_private)
+        return false;
+    
+    return m_private->isEasyToRead();
+}
+    
+size_t InbandTextTrack::inbandTrackIndex()
+{
+    ASSERT(m_private);
+    return m_private->textTrackIndex();
+}
+
+void InbandTextTrack::addGenericCue(InbandTextTrackPrivate* trackPrivate, GenericCueData* cueData)
+{
+    UNUSED_PARAM(trackPrivate);
+    ASSERT(trackPrivate == m_private);
+
+    RefPtr<TextTrackCueGeneric> cue = TextTrackCueGeneric::create(scriptExecutionContext(), cueData->startTime(), cueData->endTime(), cueData->content());
+
+    cue->setId(cueData->id());
+    cue->setBaseFontSizeRelativeToVideoHeight(cueData->baseFontSize());
+    cue->setFontSizeMultiplier(cueData->relativeFontSize());
+    cue->setFontName(cueData->fontName());
+
+    if (cueData->position() > 0)
+        cue->setPosition(lround(cueData->position()), IGNORE_EXCEPTION);
+    if (cueData->line() > 0)
+        cue->setLine(lround(cueData->line()), IGNORE_EXCEPTION);
+    if (cueData->size() > 0)
+        cue->setSize(lround(cueData->size()), IGNORE_EXCEPTION);
+    if (cueData->backgroundColor().isValid())
+        cue->setBackgroundColor(cueData->backgroundColor().rgb());
+    if (cueData->foregroundColor().isValid())
+        cue->setForegroundColor(cueData->foregroundColor().rgb());
+
+    if (cueData->align() == GenericCueData::Start)
+        cue->setAlign(ASCIILiteral("start"), IGNORE_EXCEPTION);
+    else if (cueData->align() == GenericCueData::Middle)
+        cue->setAlign(ASCIILiteral("middle"), IGNORE_EXCEPTION);
+    else if (cueData->align() == GenericCueData::End)
+        cue->setAlign(ASCIILiteral("end"), IGNORE_EXCEPTION);
+    cue->setSnapToLines(false);
+
+    if (hasCue(cue.get())) {
+        LOG(Media, "InbandTextTrack::addGenericCue ignoring already added cue: start=%.2f, end=%.2f, content=\"%s\"\n",
+            cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
+        return;
+    }
+
+    addCue(cue);
+}
+
+void InbandTextTrack::addWebVTTCue(InbandTextTrackPrivate* trackPrivate, double start, double end, const String& id, const String& content, const String& settings)
+{
+    UNUSED_PARAM(trackPrivate);
+    ASSERT(trackPrivate == m_private);
+
+    RefPtr<TextTrackCue> cue = TextTrackCue::create(scriptExecutionContext(), start, end, content);
+    cue->setId(id);
+    cue->setCueSettings(settings);
+    
+    if (hasCue(cue.get()))
+        return;
+
+    addCue(cue);
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/html/track/InbandTextTrack.h b/Source/core/html/track/InbandTextTrack.h
new file mode 100644
index 0000000..01add05
--- /dev/null
+++ b/Source/core/html/track/InbandTextTrack.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012, 2013 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 COMPUTER, 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 COMPUTER, 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 InbandTextTrack_h
+#define InbandTextTrack_h
+
+#include "core/html/track/TextTrack.h"
+#include "core/platform/graphics/InbandTextTrackPrivate.h"
+#include "core/platform/graphics/InbandTextTrackPrivateClient.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Document;
+class InbandTextTrackPrivate;
+class MediaPlayer;
+class TextTrackCue;
+
+class InbandTextTrack : public TextTrack, public InbandTextTrackPrivateClient {
+public:
+    static PassRefPtr<InbandTextTrack> create(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+    virtual ~InbandTextTrack();
+
+    virtual bool isClosedCaptions() const OVERRIDE;
+    virtual bool containsOnlyForcedSubtitles() const OVERRIDE;
+    virtual bool isMainProgramContent() const OVERRIDE;
+    virtual bool isEasyToRead() const OVERRIDE;
+    virtual void setMode(const AtomicString&) OVERRIDE;
+    size_t inbandTrackIndex();
+
+private:
+    InbandTextTrack(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+
+    virtual void addGenericCue(InbandTextTrackPrivate*, GenericCueData*) OVERRIDE;
+    virtual void addWebVTTCue(InbandTextTrackPrivate*, double, double, const String&, const String&, const String&) OVERRIDE;
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    virtual InbandTextTrackPrivate* privateTrack() OVERRIDE { return m_private.get(); }
+#endif
+
+    RefPtr<InbandTextTrackPrivate> m_private;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/LoadableTextTrack.cpp b/Source/core/html/track/LoadableTextTrack.cpp
new file mode 100644
index 0000000..a6a17da
--- /dev/null
+++ b/Source/core/html/track/LoadableTextTrack.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/track/LoadableTextTrack.h"
+
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/dom/Event.h"
+#include "core/dom/ScriptExecutionContext.h"
+#include "core/html/HTMLTrackElement.h"
+#include "core/html/track/TextTrackCueList.h"
+#include "core/html/track/TextTrackRegionList.h"
+
+namespace WebCore {
+
+LoadableTextTrack::LoadableTextTrack(HTMLTrackElement* track, const String& kind, const String& label, const String& language)
+    : TextTrack(track->document(), track, kind, label, language, TrackElement)
+    , m_trackElement(track)
+    , m_loadTimer(this, &LoadableTextTrack::loadTimerFired)
+    , m_isDefault(false)
+{
+}
+
+LoadableTextTrack::~LoadableTextTrack()
+{
+}
+
+void LoadableTextTrack::clearClient()
+{
+    m_trackElement = 0;
+    TextTrack::clearClient();
+}
+
+void LoadableTextTrack::scheduleLoad(const KURL& url)
+{
+    if (url == m_url)
+        return;
+
+    // 4.8.10.12.3 Sourcing out-of-band text tracks (continued)
+
+    // 2. Let URL be the track URL of the track element.
+    m_url = url;
+    
+    // 3. Asynchronously run the remaining steps, while continuing with whatever task 
+    // was responsible for creating the text track or changing the text track mode.
+    if (!m_loadTimer.isActive())
+        m_loadTimer.startOneShot(0);
+}
+
+void LoadableTextTrack::loadTimerFired(Timer<LoadableTextTrack>*)
+{
+    if (m_loader)
+        m_loader->cancelLoad();
+
+    if (!m_trackElement)
+        return;
+
+    // 4.8.10.12.3 Sourcing out-of-band text tracks (continued)
+
+    // 4. Download: If URL is not the empty string, perform a potentially CORS-enabled fetch of URL, with the
+    // mode being the state of the media element's crossorigin content attribute, the origin being the
+    // origin of the media element's Document, and the default origin behaviour set to fail.
+    m_loader = TextTrackLoader::create(this, static_cast<ScriptExecutionContext*>(m_trackElement->document()));
+    if (!m_loader->load(m_url, m_trackElement->mediaElementCrossOriginAttribute()))
+        m_trackElement->didCompleteLoad(this, HTMLTrackElement::Failure);
+}
+
+void LoadableTextTrack::newCuesAvailable(TextTrackLoader* loader)
+{
+    ASSERT_UNUSED(loader, m_loader == loader);
+
+    Vector<RefPtr<TextTrackCue> > newCues;
+    m_loader->getNewCues(newCues);
+
+    if (!m_cues)
+        m_cues = TextTrackCueList::create();    
+
+    for (size_t i = 0; i < newCues.size(); ++i) {
+        newCues[i]->setTrack(this);
+        m_cues->add(newCues[i]);
+    }
+
+    if (client())
+        client()->textTrackAddCues(this, m_cues.get());
+}
+
+void LoadableTextTrack::cueLoadingStarted(TextTrackLoader* loader)
+{
+    ASSERT_UNUSED(loader, m_loader == loader);
+}
+
+void LoadableTextTrack::cueLoadingCompleted(TextTrackLoader* loader, bool loadingFailed)
+{
+    ASSERT_UNUSED(loader, m_loader == loader);
+
+    if (!m_trackElement)
+        return;
+
+    m_trackElement->didCompleteLoad(this, loadingFailed ? HTMLTrackElement::Failure : HTMLTrackElement::Success);
+}
+
+#if ENABLE(WEBVTT_REGIONS)
+void LoadableTextTrack::newRegionsAvailable(TextTrackLoader* loader)
+{
+    ASSERT_UNUSED(loader, m_loader == loader);
+
+    Vector<RefPtr<TextTrackRegion> > newRegions;
+    m_loader->getNewRegions(newRegions);
+
+    for (size_t i = 0; i < newRegions.size(); ++i) {
+        newRegions[i]->setTrack(this);
+        regionList()->add(newRegions[i]);
+    }
+}
+#endif
+
+size_t LoadableTextTrack::trackElementIndex()
+{
+    ASSERT(m_trackElement);
+    ASSERT(m_trackElement->parentNode());
+
+    size_t index = 0;
+    for (Node* node = m_trackElement->parentNode()->firstChild(); node; node = node->nextSibling()) {
+        if (!node->hasTagName(trackTag) || !node->parentNode())
+            continue;
+        if (node == m_trackElement)
+            return index;
+        ++index;
+    }
+    ASSERT_NOT_REACHED();
+
+    return 0;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/html/track/LoadableTextTrack.h b/Source/core/html/track/LoadableTextTrack.h
new file mode 100644
index 0000000..a8ffc9e
--- /dev/null
+++ b/Source/core/html/track/LoadableTextTrack.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 LoadableTextTrack_h
+#define LoadableTextTrack_h
+
+#include "core/html/track/TextTrack.h"
+#include "core/loader/TextTrackLoader.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class HTMLTrackElement;
+class LoadableTextTrack;
+
+class LoadableTextTrackClient : public TextTrackClient {
+public:
+    virtual ~LoadableTextTrackClient() { }
+    
+    virtual bool canLoadUrl(LoadableTextTrack*, const KURL&) { return false; }
+    virtual void loadingCompleted(LoadableTextTrack*, bool /* loadingFailed */) { }
+};
+
+class LoadableTextTrack : public TextTrack, private TextTrackLoaderClient {
+public:
+    static PassRefPtr<LoadableTextTrack> create(HTMLTrackElement* track, const String& kind, const String& label, const String& language)
+    {
+        return adoptRef(new LoadableTextTrack(track, kind, label, language));
+    }
+    virtual ~LoadableTextTrack();
+
+    void scheduleLoad(const KURL&);
+
+    virtual void clearClient();
+
+    size_t trackElementIndex();
+    HTMLTrackElement* trackElement() { return m_trackElement; }
+
+    virtual bool isDefault() const OVERRIDE { return m_isDefault; }
+    virtual void setIsDefault(bool isDefault) OVERRIDE  { m_isDefault = isDefault; }
+
+private:
+    // TextTrackLoaderClient
+    virtual bool shouldLoadCues(TextTrackLoader*) { return true; }
+    virtual void newCuesAvailable(TextTrackLoader*);
+    virtual void cueLoadingStarted(TextTrackLoader*);
+    virtual void cueLoadingCompleted(TextTrackLoader*, bool loadingFailed);
+#if ENABLE(WEBVTT_REGIONS)
+    virtual void newRegionsAvailable(TextTrackLoader*);
+#endif
+
+    LoadableTextTrack(HTMLTrackElement*, const String& kind, const String& label, const String& language);
+
+    void loadTimerFired(Timer<LoadableTextTrack>*);
+
+    HTMLTrackElement* m_trackElement;
+    Timer<LoadableTextTrack> m_loadTimer;
+    OwnPtr<TextTrackLoader> m_loader;
+    KURL m_url;
+    bool m_isDefault;
+};
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/TextTrack.cpp b/Source/core/html/track/TextTrack.cpp
new file mode 100644
index 0000000..0e86b91
--- /dev/null
+++ b/Source/core/html/track/TextTrack.cpp
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2011 Google Inc.  All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/track/TextTrack.h"
+
+#include "core/dom/Event.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/html/track/TextTrackCueList.h"
+#include "core/html/track/TextTrackList.h"
+#include "core/html/track/TextTrackRegionList.h"
+#include "core/html/track/TrackBase.h"
+
+namespace WebCore {
+
+static const int invalidTrackIndex = -1;
+
+const AtomicString& TextTrack::subtitlesKeyword()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, subtitles, ("subtitles", AtomicString::ConstructFromLiteral));
+    return subtitles;
+}
+
+const AtomicString& TextTrack::captionsKeyword()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, captions, ("captions", AtomicString::ConstructFromLiteral));
+    return captions;
+}
+
+const AtomicString& TextTrack::descriptionsKeyword()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, descriptions, ("descriptions", AtomicString::ConstructFromLiteral));
+    return descriptions;
+}
+
+const AtomicString& TextTrack::chaptersKeyword()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, chapters, ("chapters", AtomicString::ConstructFromLiteral));
+    return chapters;
+}
+
+const AtomicString& TextTrack::metadataKeyword()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, metadata, ("metadata", AtomicString::ConstructFromLiteral));
+    return metadata;
+}
+
+const AtomicString& TextTrack::disabledKeyword()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, open, ("disabled", AtomicString::ConstructFromLiteral));
+    return open;
+}
+
+const AtomicString& TextTrack::hiddenKeyword()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, closed, ("hidden", AtomicString::ConstructFromLiteral));
+    return closed;
+}
+
+const AtomicString& TextTrack::showingKeyword()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, ended, ("showing", AtomicString::ConstructFromLiteral));
+    return ended;
+}
+
+TextTrack::TextTrack(ScriptExecutionContext* context, TextTrackClient* client, const AtomicString& kind, const AtomicString& label, const AtomicString& language, TextTrackType type)
+    : TrackBase(context, TrackBase::TextTrack)
+    , m_cues(0)
+#if ENABLE(WEBVTT_REGIONS)
+    , m_regions(0)
+#endif
+    , m_mediaElement(0)
+    , m_label(label)
+    , m_language(language)
+    , m_mode(disabledKeyword().string())
+    , m_client(client)
+    , m_trackType(type)
+    , m_readinessState(NotLoaded)
+    , m_trackIndex(invalidTrackIndex)
+    , m_renderedTrackIndex(invalidTrackIndex)
+    , m_hasBeenConfigured(false)
+{
+    setKind(kind);
+}
+
+TextTrack::~TextTrack()
+{
+    if (m_cues) {
+        if (m_client)
+            m_client->textTrackRemoveCues(this, m_cues.get());
+
+        for (size_t i = 0; i < m_cues->length(); ++i)
+            m_cues->item(i)->setTrack(0);
+#if ENABLE(WEBVTT_REGIONS)
+        for (size_t i = 0; i < m_regions->length(); ++i)
+            m_regions->item(i)->setTrack(0);
+#endif
+    }
+    clearClient();
+}
+
+bool TextTrack::isValidKindKeyword(const AtomicString& value)
+{
+    if (value == subtitlesKeyword())
+        return true;
+    if (value == captionsKeyword())
+        return true;
+    if (value == descriptionsKeyword())
+        return true;
+    if (value == chaptersKeyword())
+        return true;
+    if (value == metadataKeyword())
+        return true;
+
+    return false;
+}
+
+void TextTrack::setKind(const AtomicString& kind)
+{
+    String oldKind = m_kind;
+
+    if (isValidKindKeyword(kind))
+        m_kind = kind;
+    else
+        m_kind = subtitlesKeyword();
+
+    if (m_client && oldKind != m_kind)
+        m_client->textTrackKindChanged(this);
+}
+
+void TextTrack::setMode(const AtomicString& mode)
+{
+    // On setting, if the new value isn't equal to what the attribute would currently
+    // return, the new value must be processed as follows ...
+    if (mode != disabledKeyword() && mode != hiddenKeyword() && mode != showingKeyword())
+        return;
+
+    if (m_mode == mode)
+        return;
+
+    // If mode changes to disabled, remove this track's cues from the client
+    // because they will no longer be accessible from the cues() function.
+    if (mode == disabledKeyword() && m_client && m_cues)
+        m_client->textTrackRemoveCues(this, m_cues.get());
+         
+    if (mode != showingKeyword() && m_cues)
+        for (size_t i = 0; i < m_cues->length(); ++i)
+            m_cues->item(i)->removeDisplayTree();
+
+    m_mode = mode;
+
+    if (m_client)
+        m_client->textTrackModeChanged(this);
+}
+
+TextTrackCueList* TextTrack::cues()
+{
+    // 4.8.10.12.5 If the text track mode ... is not the text track disabled mode,
+    // then the cues attribute must return a live TextTrackCueList object ...
+    // Otherwise, it must return null. When an object is returned, the
+    // same object must be returned each time.
+    // http://www.whatwg.org/specs/web-apps/current-work/#dom-texttrack-cues
+    if (m_mode != disabledKeyword())
+        return ensureTextTrackCueList();
+    return 0;
+}
+
+void TextTrack::removeAllCues()
+{
+    if (!m_cues)
+        return;
+
+    if (m_client)
+        m_client->textTrackRemoveCues(this, m_cues.get());
+    
+    for (size_t i = 0; i < m_cues->length(); ++i)
+        m_cues->item(i)->setTrack(0);
+    
+    m_cues = 0;
+}
+
+TextTrackCueList* TextTrack::activeCues() const
+{
+    // 4.8.10.12.5 If the text track mode ... is not the text track disabled mode,
+    // then the activeCues attribute must return a live TextTrackCueList object ...
+    // ... whose active flag was set when the script started, in text track cue
+    // order. Otherwise, it must return null. When an object is returned, the
+    // same object must be returned each time.
+    // http://www.whatwg.org/specs/web-apps/current-work/#dom-texttrack-activecues
+    if (m_cues && m_mode != disabledKeyword())
+        return m_cues->activeCues();
+    return 0;
+}
+
+void TextTrack::addCue(PassRefPtr<TextTrackCue> prpCue)
+{
+    if (!prpCue)
+        return;
+
+    RefPtr<TextTrackCue> cue = prpCue;
+
+    // TODO(93143): Add spec-compliant behavior for negative time values.
+    if (std::isnan(cue->startTime()) || std::isnan(cue->endTime()) || cue->startTime() < 0 || cue->endTime() < 0)
+        return;
+
+    // 4.8.10.12.5 Text track API
+
+    // The addCue(cue) method of TextTrack objects, when invoked, must run the following steps:
+
+    // 1. If the given cue is in a text track list of cues, then remove cue from that text track
+    // list of cues.
+    TextTrack* cueTrack = cue->track();
+    if (cueTrack && cueTrack != this)
+        cueTrack->removeCue(cue.get(), ASSERT_NO_EXCEPTION);
+
+    // 2. Add cue to the method's TextTrack object's text track's text track list of cues.
+    cue->setTrack(this);
+    ensureTextTrackCueList()->add(cue);
+    
+    if (m_client)
+        m_client->textTrackAddCue(this, cue.get());
+}
+
+void TextTrack::removeCue(TextTrackCue* cue, ExceptionCode& ec)
+{
+    if (!cue)
+        return;
+
+    // 4.8.10.12.5 Text track API
+
+    // The removeCue(cue) method of TextTrack objects, when invoked, must run the following steps:
+
+    // 1. If the given cue is not currently listed in the method's TextTrack 
+    // object's text track's text track list of cues, then throw a NotFoundError exception.
+    if (cue->track() != this) {
+        ec = NOT_FOUND_ERR;
+        return;
+    }
+
+    // 2. Remove cue from the method's TextTrack object's text track's text track list of cues.
+    if (!m_cues || !m_cues->remove(cue)) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    cue->setTrack(0);
+    if (m_client)
+        m_client->textTrackRemoveCue(this, cue);
+}
+
+#if ENABLE(WEBVTT_REGIONS)
+TextTrackRegionList* TextTrack::regionList()
+{
+    return ensureTextTrackRegionList();
+}
+
+TextTrackRegionList* TextTrack::ensureTextTrackRegionList()
+{
+    if (!m_regions)
+        m_regions = TextTrackRegionList::create();
+
+    return m_regions.get();
+}
+
+TextTrackRegionList* TextTrack::regions()
+{
+    // If the text track mode of the text track that the TextTrack object
+    // represents is not the text track disabled mode, then the regions
+    // attribute must return a live TextTrackRegionList object that represents
+    // the text track list of regions of the text track. Otherwise, it must
+    // return null. When an object is returned, the same object must be returned
+    // each time.
+    if (m_mode != disabledKeyword())
+        return ensureTextTrackRegionList();
+
+    return 0;
+}
+
+void TextTrack::addRegion(PassRefPtr<TextTrackRegion> prpRegion)
+{
+    if (!prpRegion)
+        return;
+
+    RefPtr<TextTrackRegion> region = prpRegion;
+    TextTrackRegionList* regionList = ensureTextTrackRegionList();
+
+    // 1. If the given region is in a text track list of regions, then remove
+    // region from that text track list of regions.
+    TextTrack* regionTrack = region->track();
+    if (regionTrack && regionTrack != this)
+        regionTrack->removeRegion(region.get(), ASSERT_NO_EXCEPTION);
+
+    // 2. If the method's TextTrack object's text track list of regions contains
+    // a region with the same identifier as region replace the values of that
+    // region's width, height, anchor point, viewport anchor point and scroll
+    // attributes with those of region.
+    TextTrackRegion* existingRegion = regionList->getRegionById(region->id());
+    if (existingRegion) {
+        existingRegion->updateParametersFromRegion(region.get());
+        return;
+    }
+
+    // Otherwise: add region to the method's TextTrack object's text track
+    // list of regions.
+    region->setTrack(this);
+    regionList->add(region);
+}
+
+void TextTrack::removeRegion(TextTrackRegion* region, ExceptionCode &ec)
+{
+    if (!region)
+        return;
+
+    // 1. If the given region is not currently listed in the method's TextTrack
+    // object's text track list of regions, then throw a NotFoundError exception.
+    if (region->track() != this) {
+        ec = NOT_FOUND_ERR;
+        return;
+    }
+
+    if (!m_regions || !m_regions->remove(region)) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    region->setTrack(0);
+}
+#endif
+
+void TextTrack::cueWillChange(TextTrackCue* cue)
+{
+    if (!m_client)
+        return;
+
+    // The cue may need to be repositioned in the media element's interval tree, may need to
+    // be re-rendered, etc, so remove it before the modification...
+    m_client->textTrackRemoveCue(this, cue);
+}
+
+void TextTrack::cueDidChange(TextTrackCue* cue)
+{
+    if (!m_client)
+        return;
+
+    // Make sure the TextTrackCueList order is up-to-date.
+    ensureTextTrackCueList()->updateCueIndex(cue);
+
+    // ... and add it back again.
+    m_client->textTrackAddCue(this, cue);
+}
+
+int TextTrack::trackIndex()
+{
+    ASSERT(m_mediaElement);
+
+    if (m_trackIndex == invalidTrackIndex)
+        m_trackIndex = m_mediaElement->textTracks()->getTrackIndex(this);
+
+    return m_trackIndex;
+}
+
+void TextTrack::invalidateTrackIndex()
+{
+    m_trackIndex = invalidTrackIndex;
+    m_renderedTrackIndex = invalidTrackIndex;
+}
+
+bool TextTrack::isRendered()
+{
+    if (m_kind != captionsKeyword() && m_kind != subtitlesKeyword())
+        return false;
+
+    if (m_mode != showingKeyword())
+        return false;
+
+    return true;
+}
+
+TextTrackCueList* TextTrack::ensureTextTrackCueList()
+{
+    if (!m_cues)
+        m_cues = TextTrackCueList::create();
+
+    return m_cues.get();
+}
+
+int TextTrack::trackIndexRelativeToRenderedTracks()
+{
+    ASSERT(m_mediaElement);
+    
+    if (m_renderedTrackIndex == invalidTrackIndex)
+        m_renderedTrackIndex = m_mediaElement->textTracks()->getTrackIndexRelativeToRenderedTracks(this);
+    
+    return m_renderedTrackIndex;
+}
+
+bool TextTrack::hasCue(TextTrackCue* cue)
+{
+    if (cue->startTime() < 0 || cue->endTime() < 0)
+        return false;
+    
+    if (!m_cues || !m_cues->length())
+        return false;
+    
+    size_t searchStart = 0;
+    size_t searchEnd = m_cues->length();
+    
+    while (1) {
+        ASSERT(searchStart <= m_cues->length());
+        ASSERT(searchEnd <= m_cues->length());
+        
+        TextTrackCue* existingCue;
+        
+        // Cues in the TextTrackCueList are maintained in start time order.
+        if (searchStart == searchEnd) {
+            if (!searchStart)
+                return false;
+
+            // If there is more than one cue with the same start time, back up to first one so we
+            // consider all of them.
+            while (searchStart >= 2 && cue->startTime() == m_cues->item(searchStart - 2)->startTime())
+                --searchStart;
+            
+            bool firstCompare = true;
+            while (1) {
+                if (!firstCompare)
+                    ++searchStart;
+                firstCompare = false;
+                if (searchStart > m_cues->length())
+                    return false;
+
+                existingCue = m_cues->item(searchStart - 1);
+                if (!existingCue || cue->startTime() > existingCue->startTime())
+                    return false;
+
+                if (*existingCue != *cue)
+                    continue;
+                
+                return true;
+            }
+        }
+        
+        size_t index = (searchStart + searchEnd) / 2;
+        existingCue = m_cues->item(index);
+        if (cue->startTime() < existingCue->startTime() || (cue->startTime() == existingCue->startTime() && cue->endTime() > existingCue->endTime()))
+            searchEnd = index;
+        else
+            searchStart = index + 1;
+    }
+    
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+PassRefPtr<PlatformTextTrack> TextTrack::platformTextTrack()
+{
+    if (m_platformTextTrack)
+        return m_platformTextTrack;
+
+    PlatformTextTrack::TrackKind kind = PlatformTextTrack::Caption;
+    if (m_kind == subtitlesKeyword())
+        kind = PlatformTextTrack::Subtitle;
+    else if (m_kind == captionsKeyword())
+        kind = PlatformTextTrack::Caption;
+    else if (m_kind == descriptionsKeyword())
+        kind = PlatformTextTrack::Description;
+    else if (m_kind == chaptersKeyword())
+        kind = PlatformTextTrack::Chapter;
+    else if (m_kind == metadataKeyword())
+        kind = PlatformTextTrack::MetaData;
+
+    PlatformTextTrack::TrackType type = PlatformTextTrack::OutOfBand;
+    if (m_trackType == TrackElement)
+        type = PlatformTextTrack::OutOfBand;
+    else if (m_trackType == AddTrack)
+        type = PlatformTextTrack::Script;
+    else if (m_trackType == InBand)
+        type = PlatformTextTrack::InBand;
+
+    m_platformTextTrack = PlatformTextTrack::create(this, m_label, m_language, kind, type);
+
+    return m_platformTextTrack;
+}
+#endif
+
+bool TextTrack::isMainProgramContent() const
+{
+    // "Main program" content is intrinsic to the presentation of the media file, regardless of locale. Content such as
+    // directors commentary is not "main program" because it is not essential for the presentation. HTML5 doesn't have
+    // a way to express this in a machine-reable form, it is typically done with the track label, so we assume that caption
+    // tracks are main content and all other track types are not.
+    return m_kind == captionsKeyword();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/html/track/TextTrack.h b/Source/core/html/track/TextTrack.h
new file mode 100644
index 0000000..ba8734f
--- /dev/null
+++ b/Source/core/html/track/TextTrack.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 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 COMPUTER, 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 COMPUTER, 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 TextTrack_h
+#define TextTrack_h
+
+#include "core/dom/ExceptionCode.h"
+#include "core/html/track/TrackBase.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+#include "core/platform/graphics/PlatformTextTrack.h"
+#endif
+
+namespace WebCore {
+
+class HTMLMediaElement;
+class TextTrack;
+class TextTrackCue;
+class TextTrackCueList;
+#if ENABLE(WEBVTT_REGIONS)
+class TextTrackRegion;
+class TextTrackRegionList;
+#endif
+
+class TextTrackClient {
+public:
+    virtual ~TextTrackClient() { }
+    virtual void textTrackKindChanged(TextTrack*) = 0;
+    virtual void textTrackModeChanged(TextTrack*) = 0;
+    virtual void textTrackAddCues(TextTrack*, const TextTrackCueList*) = 0;
+    virtual void textTrackRemoveCues(TextTrack*, const TextTrackCueList*) = 0;
+    virtual void textTrackAddCue(TextTrack*, PassRefPtr<TextTrackCue>) = 0;
+    virtual void textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue>) = 0;
+};
+
+class TextTrack : public TrackBase
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    , public PlatformTextTrackClient
+#endif
+    {
+public:
+    static PassRefPtr<TextTrack> create(ScriptExecutionContext* context, TextTrackClient* client, const AtomicString& kind, const AtomicString& label, const AtomicString& language)
+    {
+        return adoptRef(new TextTrack(context, client, kind, label, language, AddTrack));
+    }
+    virtual ~TextTrack();
+
+    void setMediaElement(HTMLMediaElement* element) { m_mediaElement = element; }
+    HTMLMediaElement* mediaElement() { return m_mediaElement; }
+
+    AtomicString kind() const { return m_kind; }
+    void setKind(const AtomicString&);
+
+    static const AtomicString& subtitlesKeyword();
+    static const AtomicString& captionsKeyword();
+    static const AtomicString& descriptionsKeyword();
+    static const AtomicString& chaptersKeyword();
+    static const AtomicString& metadataKeyword();
+    static bool isValidKindKeyword(const AtomicString&);
+
+    AtomicString label() const { return m_label; }
+    void setLabel(const AtomicString& label) { m_label = label; }
+
+    AtomicString language() const { return m_language; }
+    void setLanguage(const AtomicString& language) { m_language = language; }
+
+    static const AtomicString& disabledKeyword();
+    static const AtomicString& hiddenKeyword();
+    static const AtomicString& showingKeyword();
+
+    AtomicString mode() const { return m_mode; }
+    virtual void setMode(const AtomicString&);
+
+    enum ReadinessState { NotLoaded = 0, Loading = 1, Loaded = 2, FailedToLoad = 3 };
+    ReadinessState readinessState() const { return m_readinessState; }
+    void setReadinessState(ReadinessState state) { m_readinessState = state; }
+
+    TextTrackCueList* cues();
+    TextTrackCueList* activeCues() const;
+
+    void clearClient() { m_client = 0; }
+    TextTrackClient* client() { return m_client; }
+
+    void addCue(PassRefPtr<TextTrackCue>);
+    void removeCue(TextTrackCue*, ExceptionCode&);
+    bool hasCue(TextTrackCue*);
+
+#if ENABLE(WEBVTT_REGIONS)
+    TextTrackRegionList* regions();
+    void addRegion(PassRefPtr<TextTrackRegion>);
+    void removeRegion(TextTrackRegion*, ExceptionCode&);
+#endif
+
+    void cueWillChange(TextTrackCue*);
+    void cueDidChange(TextTrackCue*);
+
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(cuechange);
+
+    enum TextTrackType { TrackElement, AddTrack, InBand };
+    TextTrackType trackType() const { return m_trackType; }
+
+    virtual bool isClosedCaptions() const { return false; }
+
+    virtual bool containsOnlyForcedSubtitles() const { return false; }
+    virtual bool isMainProgramContent() const;
+    virtual bool isEasyToRead() const { return false; }
+
+    int trackIndex();
+    void invalidateTrackIndex();
+
+    bool isRendered();
+    int trackIndexRelativeToRenderedTracks();
+
+    bool hasBeenConfigured() const { return m_hasBeenConfigured; }
+    void setHasBeenConfigured(bool flag) { m_hasBeenConfigured = flag; }
+
+    virtual bool isDefault() const { return false; }
+    virtual void setIsDefault(bool) { }
+
+    void removeAllCues();
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    PassRefPtr<PlatformTextTrack> platformTextTrack();
+#endif
+
+protected:
+    TextTrack(ScriptExecutionContext*, TextTrackClient*, const AtomicString& kind, const AtomicString& label, const AtomicString& language, TextTrackType);
+#if ENABLE(WEBVTT_REGIONS)
+    TextTrackRegionList* regionList();
+#endif
+
+    RefPtr<TextTrackCueList> m_cues;
+
+private:
+
+#if ENABLE(WEBVTT_REGIONS)
+    TextTrackRegionList* ensureTextTrackRegionList();
+    RefPtr<TextTrackRegionList> m_regions;
+#endif
+
+#if USE(PLATFORM_TEXT_TRACK_MENU)
+    virtual TextTrack* publicTrack() OVERRIDE { return this; }
+
+    RefPtr<PlatformTextTrack> m_platformTextTrack;
+#endif
+
+    TextTrackCueList* ensureTextTrackCueList();
+
+    HTMLMediaElement* m_mediaElement;
+    AtomicString m_kind;
+    AtomicString m_label;
+    AtomicString m_language;
+    AtomicString m_mode;
+    TextTrackClient* m_client;
+    TextTrackType m_trackType;
+    ReadinessState m_readinessState;
+    int m_trackIndex;
+    int m_renderedTrackIndex;
+    bool m_hasBeenConfigured;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/TextTrack.idl b/Source/core/html/track/TextTrack.idl
new file mode 100644
index 0000000..a2ad6d1
--- /dev/null
+++ b/Source/core/html/track/TextTrack.idl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    EnabledAtRuntime=webkitVideoTrack,
+    EventTarget,
+    SkipVTableValidation
+] interface TextTrack {
+    readonly attribute DOMString kind;
+    readonly attribute DOMString label;
+    readonly attribute DOMString language;
+
+    attribute DOMString mode;
+
+    readonly attribute TextTrackCueList cues;
+    readonly attribute TextTrackCueList activeCues;
+             attribute EventListener oncuechange;
+
+    void addCue(TextTrackCue cue);
+    [RaisesException] void removeCue(TextTrackCue cue);
+
+#if defined(ENABLE_WEBVTT_REGIONS) && ENABLE_WEBVTT_REGIONS
+    readonly attribute TextTrackRegionList regions;
+    void addRegion(TextTrackRegion region);
+    [RaisesException] void removeRegion(TextTrackRegion region);
+#endif
+
+    // EventTarget interface
+    void addEventListener(DOMString type, 
+                          EventListener listener, 
+                          optional boolean useCapture);
+    void removeEventListener(DOMString type, 
+                             EventListener listener, 
+                             optional boolean useCapture);
+    [RaisesException] boolean dispatchEvent(Event evt);
+};
diff --git a/Source/core/html/track/TextTrackCue.cpp b/Source/core/html/track/TextTrackCue.cpp
new file mode 100644
index 0000000..b35b2eb
--- /dev/null
+++ b/Source/core/html/track/TextTrackCue.cpp
@@ -0,0 +1,1181 @@
+/*
+ * Copyright (C) 2011 Google Inc.  All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/track/TextTrackCue.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/dom/Event.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/html/HTMLSpanElement.h"
+#include "core/html/track/TextTrack.h"
+#include "core/html/track/TextTrackCueList.h"
+#include "core/html/track/WebVTTElement.h"
+#include "core/html/track/WebVTTParser.h"
+#include "core/rendering/RenderTextTrackCue.h"
+#include <wtf/MathExtras.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+static const int invalidCueIndex = -1;
+static const int undefinedPosition = -1;
+static const int autoSize = 0;
+
+static const String& startKeyword()
+{
+    DEFINE_STATIC_LOCAL(const String, start, (ASCIILiteral("start")));
+    return start;
+}
+
+static const String& middleKeyword()
+{
+    DEFINE_STATIC_LOCAL(const String, middle, (ASCIILiteral("middle")));
+    return middle;
+}
+
+static const String& endKeyword()
+{
+    DEFINE_STATIC_LOCAL(const String, end, (ASCIILiteral("end")));
+    return end;
+}
+
+static const String& horizontalKeyword()
+{
+    return emptyString();
+}
+
+static const String& verticalGrowingLeftKeyword()
+{
+    DEFINE_STATIC_LOCAL(const String, verticalrl, (ASCIILiteral("rl")));
+    return verticalrl;
+}
+
+static const String& verticalGrowingRightKeyword()
+{
+    DEFINE_STATIC_LOCAL(const String, verticallr, (ASCIILiteral("lr")));
+    return verticallr;
+}
+
+// ----------------------------
+
+TextTrackCueBox::TextTrackCueBox(Document* document, TextTrackCue* cue)
+    : HTMLDivElement(divTag, document)
+    , m_cue(cue)
+{
+    setPseudo(textTrackCueBoxShadowPseudoId());
+}
+
+TextTrackCue* TextTrackCueBox::getCue() const
+{
+    return m_cue;
+}
+
+void TextTrackCueBox::applyCSSProperties(const IntSize&)
+{
+    // FIXME: Apply all the initial CSS positioning properties. http://wkb.ug/79916
+
+    // 3.5.1 On the (root) List of WebVTT Node Objects:
+
+    // the 'position' property must be set to 'absolute'
+    setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute);
+
+    //  the 'unicode-bidi' property must be set to 'plaintext'
+    setInlineStyleProperty(CSSPropertyUnicodeBidi, CSSValueWebkitPlaintext);
+
+    // the 'direction' property must be set to direction
+    setInlineStyleProperty(CSSPropertyDirection, m_cue->getCSSWritingDirection());
+
+    // the 'writing-mode' property must be set to writing-mode
+    setInlineStyleProperty(CSSPropertyWebkitWritingMode, m_cue->getCSSWritingMode(), false);
+
+    std::pair<float, float> position = m_cue->getCSSPosition();
+
+    // the 'top' property must be set to top,
+    setInlineStyleProperty(CSSPropertyTop, static_cast<double>(position.second), CSSPrimitiveValue::CSS_PERCENTAGE);
+
+    // the 'left' property must be set to left
+    setInlineStyleProperty(CSSPropertyLeft, static_cast<double>(position.first), CSSPrimitiveValue::CSS_PERCENTAGE);
+
+    // the 'width' property must be set to width, and the 'height' property  must be set to height
+    if (m_cue->vertical() == horizontalKeyword()) {
+        setInlineStyleProperty(CSSPropertyWidth, static_cast<double>(m_cue->getCSSSize()), CSSPrimitiveValue::CSS_PERCENTAGE);
+        setInlineStyleProperty(CSSPropertyHeight, CSSValueAuto);
+    } else {
+        setInlineStyleProperty(CSSPropertyWidth, CSSValueAuto);
+        setInlineStyleProperty(CSSPropertyHeight, static_cast<double>(m_cue->getCSSSize()),  CSSPrimitiveValue::CSS_PERCENTAGE);
+    }
+
+    // The 'text-align' property on the (root) List of WebVTT Node Objects must
+    // be set to the value in the second cell of the row of the table below
+    // whose first cell is the value of the corresponding cue's text track cue
+    // alignment:
+    if (m_cue->align() == startKeyword())
+        setInlineStyleProperty(CSSPropertyTextAlign, CSSValueStart);
+    else if (m_cue->align() == endKeyword())
+        setInlineStyleProperty(CSSPropertyTextAlign, CSSValueEnd);
+    else
+        setInlineStyleProperty(CSSPropertyTextAlign, CSSValueCenter);
+
+    if (!m_cue->snapToLines()) {
+        // 10.13.1 Set up x and y:
+        // Note: x and y are set through the CSS left and top above.
+
+        // 10.13.2 Position the boxes in boxes such that the point x% along the
+        // width of the bounding box of the boxes in boxes is x% of the way
+        // across the width of the video's rendering area, and the point y%
+        // along the height of the bounding box of the boxes in boxes is y%
+        // of the way across the height of the video's rendering area, while
+        // maintaining the relative positions of the boxes in boxes to each
+        // other.
+        setInlineStyleProperty(CSSPropertyWebkitTransform,
+                String::format("translate(-%.2f%%, -%.2f%%)", position.first, position.second));
+
+        setInlineStyleProperty(CSSPropertyWhiteSpace, CSSValuePre);
+    }
+}
+
+const AtomicString& TextTrackCueBox::textTrackCueBoxShadowPseudoId()
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, trackDisplayBoxShadowPseudoId, ("-webkit-media-text-track-display", AtomicString::ConstructFromLiteral));
+    return trackDisplayBoxShadowPseudoId;
+}
+
+RenderObject* TextTrackCueBox::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderTextTrackCue(this);
+}
+
+// ----------------------------
+
+TextTrackCue::TextTrackCue(ScriptExecutionContext* context, double start, double end, const String& content)
+    : m_startTime(start)
+    , m_endTime(end)
+    , m_content(content)
+    , m_linePosition(undefinedPosition)
+    , m_computedLinePosition(undefinedPosition)
+    , m_textPosition(50)
+    , m_cueSize(100)
+    , m_cueIndex(invalidCueIndex)
+    , m_writingDirection(Horizontal)
+    , m_cueAlignment(Middle)
+    , m_webVTTNodeTree(0)
+    , m_track(0)
+    , m_scriptExecutionContext(context)
+    , m_isActive(false)
+    , m_pauseOnExit(false)
+    , m_snapToLines(true)
+    , m_cueBackgroundBox(HTMLDivElement::create(toDocument(context)))
+    , m_displayTreeShouldChange(true)
+    , m_displayDirection(CSSValueLtr)
+{
+    ASSERT(m_scriptExecutionContext->isDocument());
+
+    // 4. If the text track cue writing direction is horizontal, then let
+    // writing-mode be 'horizontal-tb'. Otherwise, if the text track cue writing
+    // direction is vertical growing left, then let writing-mode be
+    // 'vertical-rl'. Otherwise, the text track cue writing direction is
+    // vertical growing right; let writing-mode be 'vertical-lr'.
+    m_displayWritingModeMap[Horizontal] = CSSValueHorizontalTb;
+    m_displayWritingModeMap[VerticalGrowingLeft] = CSSValueVerticalRl;
+    m_displayWritingModeMap[VerticalGrowingRight] = CSSValueVerticalLr;
+}
+
+TextTrackCue::~TextTrackCue()
+{
+    removeDisplayTree();
+}
+
+PassRefPtr<TextTrackCueBox> TextTrackCue::createDisplayTree()
+{
+    return TextTrackCueBox::create(ownerDocument(), this);
+}
+
+PassRefPtr<TextTrackCueBox> TextTrackCue::displayTreeInternal()
+{
+    if (!m_displayTree)
+        m_displayTree = createDisplayTree();
+    return m_displayTree;
+}
+
+void TextTrackCue::cueWillChange()
+{
+    if (m_track)
+        m_track->cueWillChange(this);
+}
+
+void TextTrackCue::cueDidChange()
+{
+    if (m_track)
+        m_track->cueDidChange(this);
+
+    m_displayTreeShouldChange = true;
+}
+
+TextTrack* TextTrackCue::track() const
+{
+    return m_track;
+}
+
+void TextTrackCue::setTrack(TextTrack* track)
+{
+    m_track = track;
+}
+
+void TextTrackCue::setId(const String& id)
+{
+    if (m_id == id)
+        return;
+
+    cueWillChange();
+    m_id = id;
+    cueDidChange();
+}
+
+void TextTrackCue::setStartTime(double value, ExceptionCode& ec)
+{
+    // NaN, Infinity and -Infinity values should trigger a TypeError.
+    if (std::isinf(value) || std::isnan(value)) {
+        ec = TypeError;
+        return;
+    }
+    
+    // TODO(93143): Add spec-compliant behavior for negative time values.
+    if (m_startTime == value || value < 0)
+        return;
+    
+    cueWillChange();
+    m_startTime = value;
+    cueDidChange();
+}
+    
+void TextTrackCue::setEndTime(double value, ExceptionCode& ec)
+{
+    // NaN, Infinity and -Infinity values should trigger a TypeError.
+    if (std::isinf(value) || std::isnan(value)) {
+        ec = TypeError;
+        return;
+    }
+
+    // TODO(93143): Add spec-compliant behavior for negative time values.
+    if (m_endTime == value || value < 0)
+        return;
+    
+    cueWillChange();
+    m_endTime = value;
+    cueDidChange();
+}
+    
+void TextTrackCue::setPauseOnExit(bool value)
+{
+    if (m_pauseOnExit == value)
+        return;
+    
+    cueWillChange();
+    m_pauseOnExit = value;
+    cueDidChange();
+}
+
+const String& TextTrackCue::vertical() const
+{
+    switch (m_writingDirection) {
+    case Horizontal: 
+        return horizontalKeyword();
+    case VerticalGrowingLeft:
+        return verticalGrowingLeftKeyword();
+    case VerticalGrowingRight:
+        return verticalGrowingRightKeyword();
+    default:
+        ASSERT_NOT_REACHED();
+        return emptyString();
+    }
+}
+
+void TextTrackCue::setVertical(const String& value, ExceptionCode& ec)
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-vertical
+    // On setting, the text track cue writing direction must be set to the value given 
+    // in the first cell of the row in the table above whose second cell is a 
+    // case-sensitive match for the new value, if any. If none of the values match, then
+    // the user agent must instead throw a SyntaxError exception.
+    
+    WritingDirection direction = m_writingDirection;
+    if (value == horizontalKeyword())
+        direction = Horizontal;
+    else if (value == verticalGrowingLeftKeyword())
+        direction = VerticalGrowingLeft;
+    else if (value == verticalGrowingRightKeyword())
+        direction = VerticalGrowingRight;
+    else
+        ec = SYNTAX_ERR;
+    
+    if (direction == m_writingDirection)
+        return;
+
+    cueWillChange();
+    m_writingDirection = direction;
+    cueDidChange();
+}
+
+void TextTrackCue::setSnapToLines(bool value)
+{
+    if (m_snapToLines == value)
+        return;
+    
+    cueWillChange();
+    m_snapToLines = value;
+    cueDidChange();
+}
+
+void TextTrackCue::setLine(int position, ExceptionCode& ec)
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-line
+    // On setting, if the text track cue snap-to-lines flag is not set, and the new
+    // value is negative or greater than 100, then throw an IndexSizeError exception.
+    if (!m_snapToLines && (position < 0 || position > 100)) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    // Otherwise, set the text track cue line position to the new value.
+    if (m_linePosition == position)
+        return;
+
+    cueWillChange();
+    m_linePosition = position;
+    m_computedLinePosition = calculateComputedLinePosition();
+    cueDidChange();
+}
+
+void TextTrackCue::setPosition(int position, ExceptionCode& ec)
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-position
+    // On setting, if the new value is negative or greater than 100, then throw an IndexSizeError exception.
+    // Otherwise, set the text track cue text position to the new value.
+    if (position < 0 || position > 100) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+    
+    // Otherwise, set the text track cue line position to the new value.
+    if (m_textPosition == position)
+        return;
+    
+    cueWillChange();
+    m_textPosition = position;
+    cueDidChange();
+}
+
+void TextTrackCue::setSize(int size, ExceptionCode& ec)
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-size
+    // On setting, if the new value is negative or greater than 100, then throw an IndexSizeError
+    // exception. Otherwise, set the text track cue size to the new value.
+    if (size < 0 || size > 100) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+    
+    // Otherwise, set the text track cue line position to the new value.
+    if (m_cueSize == size)
+        return;
+    
+    cueWillChange();
+    m_cueSize = size;
+    cueDidChange();
+}
+
+const String& TextTrackCue::align() const
+{
+    switch (m_cueAlignment) {
+    case Start:
+        return startKeyword();
+    case Middle:
+        return middleKeyword();
+    case End:
+        return endKeyword();
+    default:
+        ASSERT_NOT_REACHED();
+        return emptyString();
+    }
+}
+
+void TextTrackCue::setAlign(const String& value, ExceptionCode& ec)
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrackcue-align
+    // On setting, the text track cue alignment must be set to the value given in the 
+    // first cell of the row in the table above whose second cell is a case-sensitive
+    // match for the new value, if any. If none of the values match, then the user
+    // agent must instead throw a SyntaxError exception.
+    
+    CueAlignment alignment = m_cueAlignment;
+    if (value == startKeyword())
+        alignment = Start;
+    else if (value == middleKeyword())
+        alignment = Middle;
+    else if (value == endKeyword())
+        alignment = End;
+    else
+        ec = SYNTAX_ERR;
+    
+    if (alignment == m_cueAlignment)
+        return;
+
+    cueWillChange();
+    m_cueAlignment = alignment;
+    cueDidChange();
+}
+    
+void TextTrackCue::setText(const String& text)
+{
+    if (m_content == text)
+        return;
+    
+    cueWillChange();
+    // Clear the document fragment but don't bother to create it again just yet as we can do that
+    // when it is requested.
+    m_webVTTNodeTree = 0;
+    m_content = text;
+    cueDidChange();
+}
+
+int TextTrackCue::cueIndex()
+{
+    if (m_cueIndex == invalidCueIndex)
+        m_cueIndex = track()->cues()->getCueIndex(this);
+
+    return m_cueIndex;
+}
+
+void TextTrackCue::invalidateCueIndex()
+{
+    m_cueIndex = invalidCueIndex;
+}
+
+void TextTrackCue::createWebVTTNodeTree()
+{
+    if (!m_webVTTNodeTree)
+        m_webVTTNodeTree = WebVTTParser::create(0, m_scriptExecutionContext)->createDocumentFragmentFromCueText(m_content);
+}
+
+void TextTrackCue::copyWebVTTNodeToDOMTree(ContainerNode* webVTTNode, ContainerNode* parent)
+{
+    for (Node* node = webVTTNode->firstChild(); node; node = node->nextSibling()) {
+        RefPtr<Node> clonedNode;
+        if (node->isWebVTTElement())
+            clonedNode = toWebVTTElement(node)->createEquivalentHTMLElement(ownerDocument());
+        else
+            clonedNode = node->cloneNode(false);
+        parent->appendChild(clonedNode, ASSERT_NO_EXCEPTION);
+        if (node->isContainerNode())
+            copyWebVTTNodeToDOMTree(toContainerNode(node), toContainerNode(clonedNode.get()));
+    }
+}
+
+PassRefPtr<DocumentFragment> TextTrackCue::getCueAsHTML()
+{
+    createWebVTTNodeTree();
+    RefPtr<DocumentFragment> clonedFragment = DocumentFragment::create(ownerDocument());
+    copyWebVTTNodeToDOMTree(m_webVTTNodeTree.get(), clonedFragment.get());
+    return clonedFragment.release();
+}
+
+PassRefPtr<DocumentFragment> TextTrackCue::createCueRenderingTree()
+{
+    RefPtr<DocumentFragment> clonedFragment;
+    createWebVTTNodeTree();
+    clonedFragment = DocumentFragment::create(ownerDocument());
+    m_webVTTNodeTree->cloneChildNodes(clonedFragment.get());
+    return clonedFragment.release();
+}
+
+bool TextTrackCue::dispatchEvent(PassRefPtr<Event> event)
+{
+    // When a TextTrack's mode is disabled: no cues are active, no events fired.
+    if (!track() || track()->mode() == TextTrack::disabledKeyword())
+        return false;
+
+    return EventTarget::dispatchEvent(event);
+}
+
+#if ENABLE(WEBVTT_REGIONS)
+void TextTrackCue::setRegionId(const String& regionId)
+{
+    if (m_regionId == regionId)
+        return;
+
+    cueWillChange();
+    m_regionId = regionId;
+    cueDidChange();
+}
+#endif
+
+bool TextTrackCue::isActive()
+{
+    return m_isActive && track() && track()->mode() != TextTrack::disabledKeyword();
+}
+
+void TextTrackCue::setIsActive(bool active)
+{
+    m_isActive = active;
+
+    if (!active) {
+        // Remove the display tree as soon as the cue becomes inactive.
+        displayTreeInternal()->remove(ASSERT_NO_EXCEPTION);
+    }
+}
+
+int TextTrackCue::calculateComputedLinePosition()
+{
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-computed-line-position
+
+    // If the text track cue line position is numeric, then that is the text
+    // track cue computed line position.
+    if (m_linePosition != undefinedPosition)
+        return m_linePosition;
+
+    // If the text track cue snap-to-lines flag of the text track cue is not
+    // set, the text track cue computed line position is the value 100;
+    if (!m_snapToLines)
+        return 100;
+
+    // Otherwise, it is the value returned by the following algorithm:
+
+    // If cue is not associated with a text track, return -1 and abort these
+    // steps.
+    if (!track())
+        return -1;
+
+    // Let n be the number of text tracks whose text track mode is showing or
+    // showing by default and that are in the media element's list of text
+    // tracks before track.
+    int n = track()->trackIndexRelativeToRenderedTracks();
+
+    // Increment n by one.
+    n++;
+
+    // Negate n.
+    n = -n;
+
+    return n;
+}
+
+static bool isCueParagraphSeparator(UChar character)
+{
+    // Within a cue, paragraph boundaries are only denoted by Type B characters,
+    // such as U+000A LINE FEED (LF), U+0085 NEXT LINE (NEL), and U+2029 PARAGRAPH SEPARATOR.
+    return WTF::Unicode::category(character) & WTF::Unicode::Separator_Paragraph;
+}
+
+void TextTrackCue::determineTextDirection()
+{
+    DEFINE_STATIC_LOCAL(const String, rtTag, (ASCIILiteral("rt")));
+    createWebVTTNodeTree();
+
+    // Apply the Unicode Bidirectional Algorithm's Paragraph Level steps to the
+    // concatenation of the values of each WebVTT Text Object in nodes, in a
+    // pre-order, depth-first traversal, excluding WebVTT Ruby Text Objects and
+    // their descendants.
+    StringBuilder paragraphBuilder;
+    for (Node* node = m_webVTTNodeTree->firstChild(); node; node = NodeTraversal::next(node, m_webVTTNodeTree.get())) {
+        if (!node->isTextNode() || node->localName() == rtTag)
+            continue;
+
+        paragraphBuilder.append(node->nodeValue());
+    }
+
+    String paragraph = paragraphBuilder.toString();
+    if (!paragraph.length())
+        return;
+
+    for (size_t i = 0; i < paragraph.length(); ++i) {
+        UChar current = paragraph[i];
+        if (!current || isCueParagraphSeparator(current))
+            return;
+
+        if (UChar current = paragraph[i]) {
+            WTF::Unicode::Direction charDirection = WTF::Unicode::direction(current);
+            if (charDirection == WTF::Unicode::LeftToRight) {
+                m_displayDirection = CSSValueLtr;
+                return;
+            }
+            if (charDirection == WTF::Unicode::RightToLeft
+                || charDirection == WTF::Unicode::RightToLeftArabic) {
+                m_displayDirection = CSSValueRtl;
+                return;
+            }
+        }
+    }
+}
+
+void TextTrackCue::calculateDisplayParameters()
+{
+    // Steps 10.2, 10.3
+    determineTextDirection();
+
+    // 10.4 If the text track cue writing direction is horizontal, then let
+    // block-flow be 'tb'. Otherwise, if the text track cue writing direction is
+    // vertical growing left, then let block-flow be 'lr'. Otherwise, the text
+    // track cue writing direction is vertical growing right; let block-flow be
+    // 'rl'.
+    m_displayWritingMode = m_displayWritingModeMap[m_writingDirection];
+
+    // 10.5 Determine the value of maximum size for cue as per the appropriate
+    // rules from the following list:
+    int maximumSize = m_textPosition;
+    if ((m_writingDirection == Horizontal && m_cueAlignment == Start && m_displayDirection == CSSValueLtr)
+            || (m_writingDirection == Horizontal && m_cueAlignment == End && m_displayDirection == CSSValueRtl)
+            || (m_writingDirection == VerticalGrowingLeft && m_cueAlignment == Start)
+            || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == Start)) {
+        maximumSize = 100 - m_textPosition;
+    } else if ((m_writingDirection == Horizontal && m_cueAlignment == End && m_displayDirection == CSSValueLtr)
+            || (m_writingDirection == Horizontal && m_cueAlignment == Start && m_displayDirection == CSSValueRtl)
+            || (m_writingDirection == VerticalGrowingLeft && m_cueAlignment == End)
+            || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == End)) {
+        maximumSize = m_textPosition;
+    } else if (m_cueAlignment == Middle) {
+        maximumSize = m_textPosition <= 50 ? m_textPosition : (100 - m_textPosition);
+        maximumSize = maximumSize * 2;
+    }
+
+    // 10.6 If the text track cue size is less than maximum size, then let size
+    // be text track cue size. Otherwise, let size be maximum size.
+    m_displaySize = std::min(m_cueSize, maximumSize);
+
+    // 10.8 Determine the value of x-position or y-position for cue as per the
+    // appropriate rules from the following list:
+    if (m_writingDirection == Horizontal) {
+        if (m_cueAlignment == Start) {
+            if (m_displayDirection == CSSValueLtr)
+                m_displayPosition.first = m_textPosition;
+            else
+                m_displayPosition.first = 100 - m_textPosition - m_displaySize;
+        } else if (m_cueAlignment == End) {
+            if (m_displayDirection == CSSValueRtl)
+                m_displayPosition.first = 100 - m_textPosition;
+            else
+                m_displayPosition.first = m_textPosition - m_displaySize;
+        }
+    }
+
+    if ((m_writingDirection == VerticalGrowingLeft && m_cueAlignment == Start)
+            || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == Start)) {
+        m_displayPosition.second = m_textPosition;
+    } else if ((m_writingDirection == VerticalGrowingLeft && m_cueAlignment == End)
+            || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == End)) {
+        m_displayPosition.second = 100 - m_textPosition;
+    }
+
+    if (m_writingDirection == Horizontal && m_cueAlignment == Middle) {
+        if (m_displayDirection == CSSValueLtr)
+            m_displayPosition.first = m_textPosition - m_displaySize / 2;
+        else
+           m_displayPosition.first = 100 - m_textPosition - m_displaySize / 2;
+    }
+
+    if ((m_writingDirection == VerticalGrowingLeft && m_cueAlignment == Middle)
+        || (m_writingDirection == VerticalGrowingRight && m_cueAlignment == Middle))
+        m_displayPosition.second = m_textPosition - m_displaySize / 2;
+
+    // 10.9 Determine the value of whichever of x-position or y-position is not
+    // yet calculated for cue as per the appropriate rules from the following
+    // list:
+    if (m_snapToLines && m_displayPosition.second == undefinedPosition && m_writingDirection == Horizontal)
+        m_displayPosition.second = 0;
+
+    if (!m_snapToLines && m_displayPosition.second == undefinedPosition && m_writingDirection == Horizontal)
+        m_displayPosition.second = m_computedLinePosition;
+
+    if (m_snapToLines && m_displayPosition.first == undefinedPosition
+            && (m_writingDirection == VerticalGrowingLeft || m_writingDirection == VerticalGrowingRight))
+        m_displayPosition.first = 0;
+
+    if (!m_snapToLines && (m_writingDirection == VerticalGrowingLeft || m_writingDirection == VerticalGrowingRight))
+        m_displayPosition.first = m_computedLinePosition;
+
+    // A text track cue has a text track cue computed line position whose value
+    // is defined in terms of the other aspects of the cue.
+    m_computedLinePosition = calculateComputedLinePosition();
+}
+    
+void TextTrackCue::markFutureAndPastNodes(ContainerNode* root, double previousTimestamp, double movieTime)
+{
+    DEFINE_STATIC_LOCAL(const String, timestampTag, (ASCIILiteral("timestamp")));
+    
+    bool isPastNode = true;
+    double currentTimestamp = previousTimestamp;
+    if (currentTimestamp > movieTime)
+        isPastNode = false;
+    
+    for (Node* child = root->firstChild(); child; child = NodeTraversal::next(child, root)) {
+        if (child->nodeName() == timestampTag) {
+            unsigned position = 0;
+            String timestamp = child->nodeValue();
+            double currentTimestamp = WebVTTParser::create(0, m_scriptExecutionContext)->collectTimeStamp(timestamp, &position);
+            ASSERT(currentTimestamp != -1);
+            
+            if (currentTimestamp > movieTime)
+                isPastNode = false;
+        }
+        
+        if (child->isWebVTTElement()) {
+            toWebVTTElement(child)->setIsPastNode(isPastNode);
+            // Make an elemenet id match a cue id for style matching purposes.
+            if (!m_id.isEmpty())
+                toElement(child)->setIdAttribute(AtomicString(m_id.characters(), m_id.length()));
+        }
+    }
+}
+
+void TextTrackCue::updateDisplayTree(double movieTime)
+{
+    // The display tree may contain WebVTT timestamp objects representing
+    // timestamps (processing instructions), along with displayable nodes.
+
+    if (!track()->isRendered())
+      return;
+
+    // Clear the contents of the set.
+    m_cueBackgroundBox->removeChildren();
+
+    // Update the two sets containing past and future WebVTT objects.
+    RefPtr<DocumentFragment> referenceTree = createCueRenderingTree();
+    markFutureAndPastNodes(referenceTree.get(), startTime(), movieTime);
+    m_cueBackgroundBox->appendChild(referenceTree);
+}
+
+PassRefPtr<TextTrackCueBox> TextTrackCue::getDisplayTree(const IntSize& videoSize)
+{
+    RefPtr<TextTrackCueBox> displayTree = displayTreeInternal();
+    if (!m_displayTreeShouldChange || !track()->isRendered())
+        return displayTree;
+
+    // 10.1 - 10.10
+    calculateDisplayParameters();
+
+    // 10.11. Apply the terms of the CSS specifications to nodes within the
+    // following constraints, thus obtaining a set of CSS boxes positioned
+    // relative to an initial containing block:
+    displayTree->removeChildren();
+
+    // The document tree is the tree of WebVTT Node Objects rooted at nodes.
+
+    // The children of the nodes must be wrapped in an anonymous box whose
+    // 'display' property has the value 'inline'. This is the WebVTT cue
+    // background box.
+
+    // Note: This is contained by default in m_cueBackgroundBox.
+    m_cueBackgroundBox->setPseudo(cueShadowPseudoId());
+    displayTree->appendChild(m_cueBackgroundBox, ASSERT_NO_EXCEPTION, AttachLazily);
+
+    // FIXME(BUG 79916): Runs of children of WebVTT Ruby Objects that are not
+    // WebVTT Ruby Text Objects must be wrapped in anonymous boxes whose
+    // 'display' property has the value 'ruby-base'.
+
+    // FIXME(BUG 79916): Text runs must be wrapped according to the CSS
+    // line-wrapping rules, except that additionally, regardless of the value of
+    // the 'white-space' property, lines must be wrapped at the edge of their
+    // containing blocks, even if doing so requires splitting a word where there
+    // is no line breaking opportunity. (Thus, normally text wraps as needed,
+    // but if there is a particularly long word, it does not overflow as it
+    // normally would in CSS, it is instead forcibly wrapped at the box's edge.)
+    displayTree->applyCSSProperties(videoSize);
+
+    m_displayTreeShouldChange = false;
+
+    // 10.15. Let cue's text track cue display state have the CSS boxes in
+    // boxes.
+    return displayTree;
+}
+
+void TextTrackCue::removeDisplayTree()
+{
+    displayTreeInternal()->remove(ASSERT_NO_EXCEPTION);
+}
+
+std::pair<double, double> TextTrackCue::getPositionCoordinates() const
+{
+    // This method is used for setting x and y when snap to lines is not set.
+    std::pair<double, double> coordinates;
+
+    if (m_writingDirection == Horizontal && m_displayDirection == CSSValueLtr) {
+        coordinates.first = m_textPosition;
+        coordinates.second = m_computedLinePosition;
+
+        return coordinates;
+    }
+
+    if (m_writingDirection == Horizontal && m_displayDirection == CSSValueRtl) {
+        coordinates.first = 100 - m_textPosition;
+        coordinates.second = m_computedLinePosition;
+
+        return coordinates;
+    }
+
+    if (m_writingDirection == VerticalGrowingLeft) {
+        coordinates.first = 100 - m_computedLinePosition;
+        coordinates.second = m_textPosition;
+
+        return coordinates;
+    }
+
+    if (m_writingDirection == VerticalGrowingRight) {
+        coordinates.first = m_computedLinePosition;
+        coordinates.second = m_textPosition;
+
+        return coordinates;
+    }
+
+    ASSERT_NOT_REACHED();
+
+    return coordinates;
+}
+
+TextTrackCue::CueSetting TextTrackCue::settingName(const String& name)
+{
+    DEFINE_STATIC_LOCAL(const String, verticalKeyword, (ASCIILiteral("vertical")));
+    DEFINE_STATIC_LOCAL(const String, lineKeyword, (ASCIILiteral("line")));
+    DEFINE_STATIC_LOCAL(const String, positionKeyword, (ASCIILiteral("position")));
+    DEFINE_STATIC_LOCAL(const String, sizeKeyword, (ASCIILiteral("size")));
+    DEFINE_STATIC_LOCAL(const String, alignKeyword, (ASCIILiteral("align")));
+#if ENABLE(WEBVTT_REGIONS)
+    DEFINE_STATIC_LOCAL(const String, regionIdKeyword, (ASCIILiteral("region")));
+#endif
+
+    if (name == verticalKeyword)
+        return Vertical;
+    else if (name == lineKeyword)
+        return Line;
+    else if (name == positionKeyword)
+        return Position;
+    else if (name == sizeKeyword)
+        return Size;
+    else if (name == alignKeyword)
+        return Align;
+#if ENABLE(WEBVTT_REGIONS)
+    else if (name == regionIdKeyword)
+        return RegionId;
+#endif
+
+    return None;
+}
+
+void TextTrackCue::setCueSettings(const String& input)
+{
+    m_settings = input;
+    unsigned position = 0;
+
+    while (position < input.length()) {
+
+        // The WebVTT cue settings part of a WebVTT cue consists of zero or more of the following components, in any order, 
+        // separated from each other by one or more U+0020 SPACE characters or U+0009 CHARACTER TABULATION (tab) characters. 
+        while (position < input.length() && WebVTTParser::isValidSettingDelimiter(input[position]))
+            position++;
+        if (position >= input.length())
+            break;
+
+        // When the user agent is to parse the WebVTT settings given by a string input for a text track cue cue, 
+        // the user agent must run the following steps:
+        // 1. Let settings be the result of splitting input on spaces.
+        // 2. For each token setting in the list settings, run the following substeps:
+        //    1. If setting does not contain a U+003A COLON character (:), or if the first U+003A COLON character (:) 
+        //       in setting is either the first or last character of setting, then jump to the step labeled next setting.
+        unsigned endOfSetting = position;
+        String setting = WebVTTParser::collectWord(input, &endOfSetting);
+        CueSetting name;
+        size_t colonOffset = setting.find(':', 1);
+        if (colonOffset == notFound || colonOffset == 0 || colonOffset == setting.length() - 1)
+            goto NextSetting;
+
+        // 2. Let name be the leading substring of setting up to and excluding the first U+003A COLON character (:) in that string.
+        name = settingName(setting.substring(0, colonOffset));
+
+        // 3. Let value be the trailing substring of setting starting from the character immediately after the first U+003A COLON character (:) in that string.
+        position += colonOffset + 1;
+        if (position >= input.length())
+            break;
+
+        // 4. Run the appropriate substeps that apply for the value of name, as follows:
+        switch (name) {
+        case Vertical:
+            {
+            // If name is a case-sensitive match for "vertical"
+            // 1. If value is a case-sensitive match for the string "rl", then let cue's text track cue writing direction 
+            //    be vertical growing left.
+            String writingDirection = WebVTTParser::collectWord(input, &position);
+            if (writingDirection == verticalGrowingLeftKeyword())
+                m_writingDirection = VerticalGrowingLeft;
+            
+            // 2. Otherwise, if value is a case-sensitive match for the string "lr", then let cue's text track cue writing 
+            //    direction be vertical growing right.
+            else if (writingDirection == verticalGrowingRightKeyword())
+                m_writingDirection = VerticalGrowingRight;
+            }
+            break;
+        case Line:
+            {
+            // 1-2 - Collect chars that are either '-', '%', or a digit.
+            // 1. If value contains any characters other than U+002D HYPHEN-MINUS characters (-), U+0025 PERCENT SIGN 
+            //    characters (%), and characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then jump
+            //    to the step labeled next setting.
+            StringBuilder linePositionBuilder;
+            while (position < input.length() && (input[position] == '-' || input[position] == '%' || isASCIIDigit(input[position])))
+                linePositionBuilder.append(input[position++]);
+            if (position < input.length() && !WebVTTParser::isValidSettingDelimiter(input[position]))
+                break;
+
+            // 2. If value does not contain at least one character in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT 
+            //    NINE (9), then jump to the step labeled next setting.
+            // 3. If any character in value other than the first character is a U+002D HYPHEN-MINUS character (-), then 
+            //    jump to the step labeled next setting.
+            // 4. If any character in value other than the last character is a U+0025 PERCENT SIGN character (%), then
+            //    jump to the step labeled next setting.
+            String linePosition = linePositionBuilder.toString();
+            if (linePosition.find('-', 1) != notFound || linePosition.reverseFind("%", linePosition.length() - 2) != notFound)
+                break;
+
+            // 5. If the first character in value is a U+002D HYPHEN-MINUS character (-) and the last character in value is a 
+            //    U+0025 PERCENT SIGN character (%), then jump to the step labeled next setting.
+            if (linePosition[0] == '-' && linePosition[linePosition.length() - 1] == '%')
+                break;
+
+            // 6. Ignoring the trailing percent sign, if any, interpret value as a (potentially signed) integer, and 
+            //    let number be that number. 
+            // NOTE: toInt ignores trailing non-digit characters, such as '%'.
+            bool validNumber;
+            int number = linePosition.toInt(&validNumber);
+            if (!validNumber)
+                break;
+
+            // 7. If the last character in value is a U+0025 PERCENT SIGN character (%), but number is not in the range 
+            //    0 ≤ number ≤ 100, then jump to the step labeled next setting.
+            // 8. Let cue's text track cue line position be number.
+            // 9. If the last character in value is a U+0025 PERCENT SIGN character (%), then let cue's text track cue 
+            //    snap-to-lines flag be false. Otherwise, let it be true.
+            if (linePosition[linePosition.length() - 1] == '%') {
+                if (number < 0 || number > 100)
+                    break;
+
+                // 10 - If '%' then set snap-to-lines flag to false.
+                m_snapToLines = false;
+            }
+
+            m_linePosition = number;
+            }
+            break;
+        case Position:
+            {
+            // 1. If value contains any characters other than U+0025 PERCENT SIGN characters (%) and characters in the range 
+            //    U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then jump to the step labeled next setting.
+            // 2. If value does not contain at least one character in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9),
+            //    then jump to the step labeled next setting.
+            String textPosition = WebVTTParser::collectDigits(input, &position);
+            if (textPosition.isEmpty())
+                break;
+            if (position >= input.length())
+                break;
+
+            // 3. If any character in value other than the last character is a U+0025 PERCENT SIGN character (%), then jump
+            //    to the step labeled next setting.
+            // 4. If the last character in value is not a U+0025 PERCENT SIGN character (%), then jump to the step labeled
+            //    next setting.
+            if (input[position++] != '%')
+                break;
+            if (position < input.length() && !WebVTTParser::isValidSettingDelimiter(input[position]))
+                break;
+
+            // 5. Ignoring the trailing percent sign, interpret value as an integer, and let number be that number.
+            // 6. If number is not in the range 0 ≤ number ≤ 100, then jump to the step labeled next setting.
+            // NOTE: toInt ignores trailing non-digit characters, such as '%'.
+            bool validNumber;
+            int number = textPosition.toInt(&validNumber);
+            if (!validNumber)
+                break;
+            if (number < 0 || number > 100)
+              break;
+
+            // 7. Let cue's text track cue text position be number.
+            m_textPosition = number;
+            }
+            break;
+        case Size:
+            {
+            // 1. If value contains any characters other than U+0025 PERCENT SIGN characters (%) and characters in the
+            //    range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then jump to the step labeled next setting.
+            // 2. If value does not contain at least one character in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT 
+            //    NINE (9), then jump to the step labeled next setting.
+            String cueSize = WebVTTParser::collectDigits(input, &position);
+            if (cueSize.isEmpty())
+                break;
+            if (position >= input.length())
+                break;
+
+            // 3. If any character in value other than the last character is a U+0025 PERCENT SIGN character (%),
+            //    then jump to the step labeled next setting.
+            // 4. If the last character in value is not a U+0025 PERCENT SIGN character (%), then jump to the step
+            //    labeled next setting.
+            if (input[position++] != '%')
+                break;
+            if (position < input.length() && !WebVTTParser::isValidSettingDelimiter(input[position]))
+                break;
+
+            // 5. Ignoring the trailing percent sign, interpret value as an integer, and let number be that number.
+            // 6. If number is not in the range 0 ≤ number ≤ 100, then jump to the step labeled next setting.
+            bool validNumber;
+            int number = cueSize.toInt(&validNumber);
+            if (!validNumber)
+                break;
+            if (number < 0 || number > 100)
+                break;
+
+            // 7. Let cue's text track cue size be number.
+            m_cueSize = number;
+            }
+            break;
+        case Align:
+            {
+            String cueAlignment = WebVTTParser::collectWord(input, &position);
+
+            // 1. If value is a case-sensitive match for the string "start", then let cue's text track cue alignment be start alignment.
+            if (cueAlignment == startKeyword())
+                m_cueAlignment = Start;
+
+            // 2. If value is a case-sensitive match for the string "middle", then let cue's text track cue alignment be middle alignment.
+            else if (cueAlignment == middleKeyword())
+                m_cueAlignment = Middle;
+
+            // 3. If value is a case-sensitive match for the string "end", then let cue's text track cue alignment be end alignment.
+            else if (cueAlignment == endKeyword())
+                m_cueAlignment = End;
+            }
+            break;
+#if ENABLE(WEBVTT_REGIONS)
+        case RegionId:
+            m_regionId = WebVTTParser::collectWord(input, &position);
+            break;
+#endif
+        case None:
+            break;
+        }
+
+NextSetting:
+        position = endOfSetting;
+    }
+#if ENABLE(WEBVTT_REGIONS)
+    // If cue's line position is not auto or cue's size is not 100 or cue's
+    // writing direction is not horizontal, but cue's region identifier is not
+    // the empty string, let cue's region identifier be the empty string.
+    if (m_regionId.isEmpty())
+        return;
+
+    if (m_linePosition != undefinedPosition || m_cueSize != 100 || m_writingDirection != Horizontal)
+        m_regionId = emptyString();
+#endif
+}
+
+int TextTrackCue::getCSSWritingDirection() const
+{
+    return m_displayDirection;
+}
+
+int TextTrackCue::getCSSWritingMode() const
+{
+    return m_displayWritingMode;
+}
+
+int TextTrackCue::getCSSSize() const
+{
+    return m_displaySize;
+}
+
+std::pair<double, double> TextTrackCue::getCSSPosition() const
+{
+    if (!m_snapToLines)
+        return getPositionCoordinates();
+
+    return m_displayPosition;
+}
+
+const AtomicString& TextTrackCue::interfaceName() const
+{
+    return eventNames().interfaceForTextTrackCue;
+}
+
+ScriptExecutionContext* TextTrackCue::scriptExecutionContext() const
+{
+    return m_scriptExecutionContext;
+}
+
+EventTargetData* TextTrackCue::eventTargetData()
+{
+    return &m_eventTargetData;
+}
+
+EventTargetData* TextTrackCue::ensureEventTargetData()
+{
+    return &m_eventTargetData;
+}
+
+bool TextTrackCue::operator==(const TextTrackCue& cue) const
+{
+    if (cueType() != cue.cueType())
+        return false;
+
+    if (m_endTime != cue.endTime())
+        return false;
+    if (m_startTime != cue.startTime())
+        return false;
+    if (m_content != cue.text())
+        return false;
+    if (m_settings != cue.cueSettings())
+        return false;
+    if (m_id != cue.id())
+        return false;
+    if (m_textPosition != cue.position())
+        return false;
+    if (m_linePosition != cue.line())
+        return false;
+    if (m_cueSize != cue.size())
+        return false;
+    if (align() != cue.align())
+        return false;
+    
+    return true;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/html/track/TextTrackCue.h b/Source/core/html/track/TextTrackCue.h
new file mode 100644
index 0000000..872e238
--- /dev/null
+++ b/Source/core/html/track/TextTrackCue.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2011 Google Inc.  All rights reserved.
+ * Copyright (C) 2012, 2013 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 TextTrackCue_h
+#define TextTrackCue_h
+
+#include "core/dom/EventTarget.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLElement.h"
+#include "core/html/track/TextTrack.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class DocumentFragment;
+class ScriptExecutionContext;
+class TextTrack;
+class TextTrackCue;
+
+// ----------------------------
+
+class TextTrackCueBox : public HTMLDivElement {
+public:
+    static PassRefPtr<TextTrackCueBox> create(Document* document, TextTrackCue* cue)
+    {
+        return adoptRef(new TextTrackCueBox(document, cue));
+    }
+
+    TextTrackCue* getCue() const;
+    virtual void applyCSSProperties(const IntSize& videoSize);
+
+    static const AtomicString& textTrackCueBoxShadowPseudoId();
+
+protected:
+    TextTrackCueBox(Document*, TextTrackCue*);
+
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE;
+
+    TextTrackCue* m_cue;
+};
+
+// ----------------------------
+
+class TextTrackCue : public RefCounted<TextTrackCue>, public EventTarget {
+public:
+    static PassRefPtr<TextTrackCue> create(ScriptExecutionContext* context, double start, double end, const String& content)
+    {
+        return adoptRef(new TextTrackCue(context, start, end, content));
+    }
+
+    static const AtomicString& cueShadowPseudoId()
+    {
+        DEFINE_STATIC_LOCAL(const AtomicString, cue, ("cue", AtomicString::ConstructFromLiteral));
+        return cue;
+    }
+
+    virtual ~TextTrackCue();
+
+    TextTrack* track() const;
+    void setTrack(TextTrack*);
+
+    const String& id() const { return m_id; }
+    void setId(const String&);
+
+    double startTime() const { return m_startTime; }
+    void setStartTime(double, ExceptionCode&);
+
+    double endTime() const { return m_endTime; }
+    void setEndTime(double, ExceptionCode&);
+
+    bool pauseOnExit() const { return m_pauseOnExit; }
+    void setPauseOnExit(bool);
+
+    const String& vertical() const;
+    void setVertical(const String&, ExceptionCode&);
+
+    bool snapToLines() const { return m_snapToLines; }
+    void setSnapToLines(bool);
+
+    int line() const { return m_linePosition; }
+    virtual void setLine(int, ExceptionCode&);
+
+    int position() const { return m_textPosition; }
+    virtual void setPosition(int, ExceptionCode&);
+
+    int size() const { return m_cueSize; }
+    virtual void setSize(int, ExceptionCode&);
+
+    const String& align() const;
+    void setAlign(const String&, ExceptionCode&);
+
+    const String& text() const { return m_content; }
+    void setText(const String&);
+
+    const String& cueSettings() const { return m_settings; }
+    void setCueSettings(const String&);
+
+    int cueIndex();
+    void invalidateCueIndex();
+
+    PassRefPtr<DocumentFragment> getCueAsHTML();
+    PassRefPtr<DocumentFragment> createCueRenderingTree();
+
+    using EventTarget::dispatchEvent;
+    virtual bool dispatchEvent(PassRefPtr<Event>) OVERRIDE;
+
+#if ENABLE(WEBVTT_REGIONS)
+    const String& regionId() const { return m_regionId; }
+    void setRegionId(const String&);
+#endif
+
+    bool isActive();
+    void setIsActive(bool);
+
+    bool hasDisplayTree() const { return m_displayTree; }
+    PassRefPtr<TextTrackCueBox> getDisplayTree(const IntSize& videoSize);
+    PassRefPtr<HTMLDivElement> element() const { return m_cueBackgroundBox; }
+
+    void updateDisplayTree(double);
+    void removeDisplayTree();
+    void markFutureAndPastNodes(ContainerNode*, double, double);
+
+    int calculateComputedLinePosition();
+
+    virtual const AtomicString& interfaceName() const;
+    virtual ScriptExecutionContext* scriptExecutionContext() const;
+
+    std::pair<double, double> getCSSPosition() const;
+
+    int getCSSSize() const;
+    int getCSSWritingDirection() const;
+    int getCSSWritingMode() const;
+
+    enum WritingDirection {
+        Horizontal,
+        VerticalGrowingLeft,
+        VerticalGrowingRight,
+        NumberOfWritingDirections
+    };
+    WritingDirection getWritingDirection() const { return m_writingDirection; }
+
+    enum CueAlignment {
+        Start,
+        Middle,
+        End
+    };
+    CueAlignment getAlignment() const { return m_cueAlignment; }
+
+    virtual void videoSizeDidChange(const IntSize&) { }
+
+    virtual bool operator==(const TextTrackCue&) const;
+    virtual bool operator!=(const TextTrackCue& cue) const
+    {
+        return !(*this == cue);
+    }
+    
+    enum CueType {
+        Generic,
+        WebVTT
+    };
+    virtual CueType cueType() const { return WebVTT; }
+
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(enter);
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(exit);
+
+    using RefCounted<TextTrackCue>::ref;
+    using RefCounted<TextTrackCue>::deref;
+
+protected:
+    virtual EventTargetData* eventTargetData();
+    virtual EventTargetData* ensureEventTargetData();
+
+    TextTrackCue(ScriptExecutionContext*, double start, double end, const String& content);
+
+    Document* ownerDocument() { return toDocument(m_scriptExecutionContext); }
+
+    virtual PassRefPtr<TextTrackCueBox> createDisplayTree();
+    PassRefPtr<TextTrackCueBox> displayTreeInternal();
+
+private:
+    void createWebVTTNodeTree();
+    void copyWebVTTNodeToDOMTree(ContainerNode* WebVTTNode, ContainerNode* root);
+
+    std::pair<double, double> getPositionCoordinates() const;
+    void parseSettings(const String&);
+
+    void determineTextDirection();
+    void calculateDisplayParameters();
+
+    void cueWillChange();
+    void cueDidChange();
+
+    virtual void refEventTarget() { ref(); }
+    virtual void derefEventTarget() { deref(); }
+
+    enum CueSetting {
+        None,
+        Vertical,
+        Line,
+        Position,
+        Size,
+        Align,
+#if ENABLE(WEBVTT_REGIONS)
+        RegionId
+#endif
+    };
+    CueSetting settingName(const String&);
+
+    String m_id;
+    double m_startTime;
+    double m_endTime;
+    String m_content;
+    String m_settings;
+    int m_linePosition;
+    int m_computedLinePosition;
+    int m_textPosition;
+    int m_cueSize;
+    int m_cueIndex;
+
+    WritingDirection m_writingDirection;
+
+    CueAlignment m_cueAlignment;
+
+    RefPtr<DocumentFragment> m_webVTTNodeTree;
+    TextTrack* m_track;
+
+    EventTargetData m_eventTargetData;
+    ScriptExecutionContext* m_scriptExecutionContext;
+
+    bool m_isActive;
+    bool m_pauseOnExit;
+    bool m_snapToLines;
+
+    RefPtr<HTMLDivElement> m_cueBackgroundBox;
+
+    bool m_displayTreeShouldChange;
+    RefPtr<TextTrackCueBox> m_displayTree;
+
+    int m_displayDirection;
+
+    int m_displayWritingModeMap[NumberOfWritingDirections];
+    int m_displayWritingMode;
+
+    int m_displaySize;
+
+    std::pair<float, float> m_displayPosition;
+#if ENABLE(WEBVTT_REGIONS)
+    String m_regionId;
+#endif
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/TextTrackCue.idl b/Source/core/html/track/TextTrackCue.idl
new file mode 100644
index 0000000..ea2ca4c
--- /dev/null
+++ b/Source/core/html/track/TextTrackCue.idl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    EnabledAtRuntime=webkitVideoTrack,
+    Constructor(double startTime, double endTime, DOMString text),
+    CallWith=ScriptExecutionContext,
+    EventTarget,
+    ImplementationLacksVTable
+] interface TextTrackCue {
+    readonly attribute TextTrack track;
+
+    attribute DOMString id;
+    [SetterRaisesException] attribute double startTime;
+    [SetterRaisesException] attribute double endTime;
+    attribute boolean pauseOnExit;
+
+    [SetterRaisesException] attribute DOMString vertical;
+    attribute boolean snapToLines;
+    [SetterRaisesException] attribute long line;
+    [SetterRaisesException] attribute long position;
+    [SetterRaisesException] attribute long size;
+    [SetterRaisesException] attribute DOMString align;
+
+    attribute DOMString text;
+    DocumentFragment getCueAsHTML();
+
+    attribute EventListener onenter;
+    attribute EventListener onexit;
+
+    // EventTarget interface
+    void addEventListener(DOMString type, 
+                          EventListener listener, 
+                          optional boolean useCapture);
+    void removeEventListener(DOMString type, 
+                             EventListener listener, 
+                             optional boolean useCapture);
+    [RaisesException] boolean dispatchEvent(Event evt);
+
+#if defined(ENABLE_WEBVTT_REGIONS) && ENABLE_WEBVTT_REGIONS
+    attribute DOMString regionId;
+#endif
+};
+
diff --git a/Source/core/html/track/TextTrackCueGeneric.cpp b/Source/core/html/track/TextTrackCueGeneric.cpp
new file mode 100644
index 0000000..dcdabd8
--- /dev/null
+++ b/Source/core/html/track/TextTrackCueGeneric.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/track/TextTrackCueGeneric.h"
+
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "HTMLNames.h"
+#include "core/dom/ScriptExecutionContext.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/track/TextTrackCue.h"
+#include "core/platform/graphics/InbandTextTrackPrivateClient.h"
+#include "core/rendering/RenderObject.h"
+#include "core/rendering/RenderTextTrackCue.h"
+
+namespace WebCore {
+
+class TextTrackCueGenericBoxElement FINAL : public TextTrackCueBox {
+public:
+    static PassRefPtr<TextTrackCueGenericBoxElement> create(Document* document, TextTrackCueGeneric* cue)
+    {
+        return adoptRef(new TextTrackCueGenericBoxElement(document, cue));
+    }
+    
+    virtual void applyCSSProperties(const IntSize&) OVERRIDE;
+    
+private:
+    TextTrackCueGenericBoxElement(Document*, TextTrackCue*);
+};
+
+TextTrackCueGenericBoxElement::TextTrackCueGenericBoxElement(Document* document, TextTrackCue* cue)
+    : TextTrackCueBox(document, cue)
+{
+}
+
+void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
+{
+    setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute);
+    setInlineStyleProperty(CSSPropertyUnicodeBidi, CSSValueWebkitPlaintext);
+    
+    TextTrackCueGeneric* cue = static_cast<TextTrackCueGeneric*>(getCue());
+
+    float size = static_cast<float>(cue->getCSSSize());
+    if (cue->useDefaultPosition()) {
+        setInlineStyleProperty(CSSPropertyBottom, "0");
+        setInlineStyleProperty(CSSPropertyMarginBottom, 1.0, CSSPrimitiveValue::CSS_PERCENTAGE);
+    } else {
+        setInlineStyleProperty(CSSPropertyLeft, static_cast<float>(cue->position()), CSSPrimitiveValue::CSS_PERCENTAGE);
+        setInlineStyleProperty(CSSPropertyTop, static_cast<float>(cue->line()), CSSPrimitiveValue::CSS_PERCENTAGE);
+
+        if (cue->getWritingDirection() == TextTrackCue::Horizontal)
+            setInlineStyleProperty(CSSPropertyWidth, size, CSSPrimitiveValue::CSS_PERCENTAGE);
+        else
+            setInlineStyleProperty(CSSPropertyHeight, size,  CSSPrimitiveValue::CSS_PERCENTAGE);
+    }
+
+    if (cue->foregroundColor().isValid())
+        setInlineStyleProperty(CSSPropertyColor, cue->foregroundColor().serialized());
+    
+    if (cue->backgroundColor().isValid())
+        cue->element()->setInlineStyleProperty(CSSPropertyBackgroundColor, cue->backgroundColor().serialized());
+
+    if (cue->getWritingDirection() == TextTrackCue::Horizontal)
+        setInlineStyleProperty(CSSPropertyHeight, CSSValueAuto);
+    else
+        setInlineStyleProperty(CSSPropertyWidth, CSSValueAuto);
+
+    if (cue->baseFontSizeRelativeToVideoHeight()) {
+        double fontSize = videoSize.height() * cue->baseFontSizeRelativeToVideoHeight() / 100;
+        if (cue->fontSizeMultiplier())
+            fontSize *= cue->fontSizeMultiplier() / 100;
+        setInlineStyleProperty(CSSPropertyFontSize, String::number(fontSize) + "px");
+    }
+
+    if (cue->getAlignment() == TextTrackCue::Middle)
+        setInlineStyleProperty(CSSPropertyTextAlign, CSSValueCenter);
+    else if (cue->getAlignment() == TextTrackCue::End)
+        setInlineStyleProperty(CSSPropertyTextAlign, CSSValueEnd);
+    else
+        setInlineStyleProperty(CSSPropertyTextAlign, CSSValueStart);
+
+    setInlineStyleProperty(CSSPropertyWebkitWritingMode, cue->getCSSWritingMode(), false);
+    setInlineStyleProperty(CSSPropertyWhiteSpace, CSSValuePreWrap);
+    setInlineStyleProperty(CSSPropertyWordBreak, CSSValueNormal);
+}
+
+TextTrackCueGeneric::TextTrackCueGeneric(ScriptExecutionContext* context, double start, double end, const String& content)
+    : TextTrackCue(context, start, end, content)
+    , m_baseFontSizeRelativeToVideoHeight(0)
+    , m_fontSizeMultiplier(0)
+    , m_defaultPosition(true)
+{
+}
+
+PassRefPtr<TextTrackCueBox> TextTrackCueGeneric::createDisplayTree()
+{
+    return TextTrackCueGenericBoxElement::create(ownerDocument(), this);
+}
+
+void TextTrackCueGeneric::setLine(int line, ExceptionCode& ec)
+{
+    m_defaultPosition = false;
+    TextTrackCue::setLine(line, ec);
+}
+
+void TextTrackCueGeneric::setPosition(int position, ExceptionCode& ec)
+{
+    m_defaultPosition = false;
+    TextTrackCue::setPosition(position, ec);
+}
+
+void TextTrackCueGeneric::videoSizeDidChange(const IntSize& videoSize)
+{
+    if (!hasDisplayTree())
+        return;
+
+    if (baseFontSizeRelativeToVideoHeight()) {
+        double fontSize = videoSize.height() * baseFontSizeRelativeToVideoHeight() / 100;
+        if (fontSizeMultiplier())
+            fontSize *= fontSizeMultiplier() / 100;
+        displayTreeInternal()->setInlineStyleProperty(CSSPropertyFontSize, String::number(fontSize) + "px");
+    }
+
+}
+
+bool TextTrackCueGeneric::operator==(const TextTrackCue& cue) const
+{
+    if (cue.cueType() != TextTrackCue::Generic)
+        return false;
+
+    const TextTrackCueGeneric* other = static_cast<const TextTrackCueGeneric*>(&cue);
+
+    if (m_baseFontSizeRelativeToVideoHeight != other->baseFontSizeRelativeToVideoHeight())
+        return false;
+    if (m_fontSizeMultiplier != other->fontSizeMultiplier())
+        return false;
+    if (m_fontName != other->fontName())
+        return false;
+    if (m_foregroundColor != other->foregroundColor())
+        return false;
+    if (m_backgroundColor != other->backgroundColor())
+        return false;
+
+    return TextTrackCue::operator==(cue);
+}
+    
+} // namespace WebCore
+
diff --git a/Source/core/html/track/TextTrackCueGeneric.h b/Source/core/html/track/TextTrackCueGeneric.h
new file mode 100644
index 0000000..821fa7c
--- /dev/null
+++ b/Source/core/html/track/TextTrackCueGeneric.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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 TextTrackCueGeneric_h
+#define TextTrackCueGeneric_h
+
+#include "core/html/track/TextTrackCue.h"
+#include "core/platform/graphics/Color.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class GenericCueData;
+
+// A "generic" cue is a non-WebVTT cue, so it is not positioned/sized with the WebVTT logic.
+class TextTrackCueGeneric : public TextTrackCue {
+public:
+    static PassRefPtr<TextTrackCueGeneric> create(ScriptExecutionContext* context, double start, double end, const String& content)
+    {
+        return adoptRef(new TextTrackCueGeneric(context, start, end, content));
+    }
+    
+    virtual ~TextTrackCueGeneric() { }
+
+    virtual PassRefPtr<TextTrackCueBox> createDisplayTree() OVERRIDE;
+
+    virtual void setLine(int, ExceptionCode&) OVERRIDE;
+    virtual void setPosition(int, ExceptionCode&) OVERRIDE;
+
+    bool useDefaultPosition() const { return m_defaultPosition; }
+    
+    double baseFontSizeRelativeToVideoHeight() const { return m_baseFontSizeRelativeToVideoHeight; }
+    void setBaseFontSizeRelativeToVideoHeight(double size) { m_baseFontSizeRelativeToVideoHeight = size; }
+
+    double fontSizeMultiplier() const { return m_fontSizeMultiplier; }
+    void setFontSizeMultiplier(double size) { m_fontSizeMultiplier = size; }
+
+    String fontName() const { return m_fontName; }
+    void setFontName(String name) { m_fontName = name; }
+
+    Color foregroundColor() const { return m_foregroundColor; }
+    void setForegroundColor(RGBA32 color) { m_foregroundColor.setRGB(color); }
+    
+    Color backgroundColor() const { return m_backgroundColor; }
+    void setBackgroundColor(RGBA32 color) { m_backgroundColor.setRGB(color); }
+
+    virtual void videoSizeDidChange(const IntSize&);
+
+    virtual bool operator==(const TextTrackCue&) const OVERRIDE;
+    virtual bool operator!=(const TextTrackCue& cue) const OVERRIDE
+    {
+        return !(*this == cue);
+    }
+
+    virtual TextTrackCue::CueType cueType() const OVERRIDE { return TextTrackCue::Generic; }
+
+private:
+    TextTrackCueGeneric(ScriptExecutionContext*, double start, double end, const String&);
+    
+    Color m_foregroundColor;
+    Color m_backgroundColor;
+    double m_baseFontSizeRelativeToVideoHeight;
+    double m_fontSizeMultiplier;
+    String m_fontName;
+    bool m_defaultPosition;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/TextTrackCueList.cpp b/Source/core/html/track/TextTrackCueList.cpp
new file mode 100644
index 0000000..e3330c6
--- /dev/null
+++ b/Source/core/html/track/TextTrackCueList.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/track/TextTrackCueList.h"
+
+namespace WebCore {
+
+TextTrackCueList::TextTrackCueList()
+{
+}
+
+unsigned long TextTrackCueList::length() const
+{
+    return m_list.size();
+}
+
+unsigned long TextTrackCueList::getCueIndex(TextTrackCue* cue) const
+{
+    return m_list.find(cue);
+}
+
+TextTrackCue* TextTrackCueList::item(unsigned index) const
+{
+    if (index < m_list.size())
+        return m_list[index].get();
+    return 0;
+}
+
+TextTrackCue* TextTrackCueList::getCueById(const String& id) const
+{
+    for (size_t i = 0; i < m_list.size(); ++i) {
+        if (m_list[i]->id() == id)
+            return m_list[i].get();
+    }
+    return 0;
+}
+
+TextTrackCueList* TextTrackCueList::activeCues()
+{
+    if (!m_activeCues)
+        m_activeCues = create();
+
+    m_activeCues->clear();
+    for (size_t i = 0; i < m_list.size(); ++i) {
+        RefPtr<TextTrackCue> cue = m_list[i];
+        if (cue->isActive())
+            m_activeCues->add(cue);
+    }
+    return m_activeCues.get();
+}
+
+bool TextTrackCueList::add(PassRefPtr<TextTrackCue> cue)
+{
+    ASSERT(cue->startTime() >= 0);
+    ASSERT(cue->endTime() >= 0);
+
+    return add(cue, 0, m_list.size());
+}
+
+bool TextTrackCueList::add(PassRefPtr<TextTrackCue> prpCue, size_t start, size_t end)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(start <= m_list.size());
+    ASSERT_WITH_SECURITY_IMPLICATION(end <= m_list.size());
+
+    // Maintain text track cue order:
+    // http://www.whatwg.org/specs/web-apps/current-work/#text-track-cue-order
+    RefPtr<TextTrackCue> cue = prpCue;
+    if (start == end) {
+        if (!m_list.isEmpty() && (start > 0) && (m_list[start - 1].get() == cue.get()))
+            return false;
+
+        m_list.insert(start, cue);
+        invalidateCueIndexes(start);
+        return true;
+    }
+
+    size_t index = (start + end) / 2;
+    if (cue->startTime() < m_list[index]->startTime() || (cue->startTime() == m_list[index]->startTime() && cue->endTime() > m_list[index]->endTime()))
+        return add(cue.release(), start, index);
+
+    return add(cue.release(), index + 1, end);
+}
+
+bool TextTrackCueList::remove(TextTrackCue* cue)
+{
+    size_t index = m_list.find(cue);
+    if (index == notFound)
+        return false;
+
+    cue->setIsActive(false);
+    m_list.remove(index);
+    return true;
+}
+
+bool TextTrackCueList::contains(TextTrackCue* cue) const
+{
+    return m_list.contains(cue);
+}
+
+bool TextTrackCueList::updateCueIndex(TextTrackCue* cue)
+{
+    if (!contains(cue))
+        return false;
+    
+    remove(cue);
+    return add(cue);
+}
+
+void TextTrackCueList::clear()
+{
+    m_list.clear();
+}
+
+void TextTrackCueList::invalidateCueIndexes(size_t start)
+{
+    for (size_t i = start; i < m_list.size(); ++i)
+        m_list[i]->invalidateCueIndex();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/html/track/TextTrackCueList.h b/Source/core/html/track/TextTrackCueList.h
new file mode 100644
index 0000000..2074635
--- /dev/null
+++ b/Source/core/html/track/TextTrackCueList.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 TextTrackCueList_h
+#define TextTrackCueList_h
+
+#include "core/html/track/TextTrackCue.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class TextTrackCueList : public RefCounted<TextTrackCueList> {
+public:
+    static PassRefPtr<TextTrackCueList> create()
+    {
+        return adoptRef(new TextTrackCueList);
+    }
+
+    ~TextTrackCueList() { }
+
+    unsigned long length() const;
+    unsigned long getCueIndex(TextTrackCue*) const;
+
+    TextTrackCue* item(unsigned index) const;
+    TextTrackCue* getCueById(const String&) const;
+    TextTrackCueList* activeCues();
+
+    bool add(PassRefPtr<TextTrackCue>);
+    bool remove(TextTrackCue*);
+    bool contains(TextTrackCue*) const;
+    
+    bool updateCueIndex(TextTrackCue*);
+
+private:
+    TextTrackCueList();
+    bool add(PassRefPtr<TextTrackCue>, size_t, size_t);
+    void clear();
+    void invalidateCueIndexes(size_t);
+
+    Vector<RefPtr<TextTrackCue> > m_list;
+    RefPtr<TextTrackCueList> m_activeCues;
+
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/TextTrackCueList.idl b/Source/core/html/track/TextTrackCueList.idl
new file mode 100644
index 0000000..a77ede9
--- /dev/null
+++ b/Source/core/html/track/TextTrackCueList.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    EnabledAtRuntime=webkitVideoTrack,
+    ImplementationLacksVTable
+] interface TextTrackCueList {
+    readonly attribute unsigned long length;
+    getter TextTrackCue item(unsigned long index);
+    TextTrackCue getCueById(DOMString id);
+};
+
diff --git a/Source/core/html/track/TextTrackList.cpp b/Source/core/html/track/TextTrackList.cpp
new file mode 100644
index 0000000..77bbe99
--- /dev/null
+++ b/Source/core/html/track/TextTrackList.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2011, 2012 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/track/TextTrackList.h"
+
+#include "core/dom/EventNames.h"
+#include "core/dom/ScriptExecutionContext.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/html/track/InbandTextTrack.h"
+#include "core/html/track/LoadableTextTrack.h"
+#include "core/html/track/TextTrack.h"
+#include "core/html/track/TrackEvent.h"
+#include "core/platform/graphics/InbandTextTrackPrivate.h"
+
+using namespace WebCore;
+
+TextTrackList::TextTrackList(HTMLMediaElement* owner, ScriptExecutionContext* context)
+    : m_context(context)
+    , m_owner(owner)
+    , m_pendingEventTimer(this, &TextTrackList::asyncEventTimerFired)
+    , m_dispatchingEvents(0)
+{
+    ASSERT(context->isDocument());
+}
+
+TextTrackList::~TextTrackList()
+{
+}
+
+unsigned TextTrackList::length() const
+{
+    return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
+}
+
+int TextTrackList::getTrackIndex(TextTrack *textTrack)
+{
+    if (textTrack->trackType() == TextTrack::TrackElement)
+        return static_cast<LoadableTextTrack*>(textTrack)->trackElementIndex();
+
+    if (textTrack->trackType() == TextTrack::AddTrack)
+        return m_elementTracks.size() + m_addTrackTracks.find(textTrack);
+
+    if (textTrack->trackType() == TextTrack::InBand)
+        return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(textTrack);
+
+    ASSERT_NOT_REACHED();
+
+    return -1;
+}
+
+int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
+{
+    // Calculate the "Let n be the number of text tracks whose text track mode is showing and that are in the media element's list of text tracks before track."
+    int trackIndex = 0;
+
+    for (size_t i = 0; i < m_elementTracks.size(); ++i) {
+        if (!m_elementTracks[i]->isRendered())
+            continue;
+        
+        if (m_elementTracks[i] == textTrack)
+            return trackIndex;
+        ++trackIndex;
+    }
+
+    for (size_t i = 0; i < m_addTrackTracks.size(); ++i) {
+        if (!m_addTrackTracks[i]->isRendered())
+            continue;
+        
+        if (m_addTrackTracks[i] == textTrack)
+            return trackIndex;
+        ++trackIndex;
+    }
+
+    for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
+        if (!m_inbandTracks[i]->isRendered())
+            continue;
+        
+        if (m_inbandTracks[i] == textTrack)
+            return trackIndex;
+        ++trackIndex;
+    }
+
+    ASSERT_NOT_REACHED();
+
+    return -1;
+}
+
+TextTrack* TextTrackList::item(unsigned index)
+{
+    // 4.8.10.12.1 Text track model
+    // The text tracks are sorted as follows:
+    // 1. The text tracks corresponding to track element children of the media element, in tree order.
+    // 2. Any text tracks added using the addTextTrack() method, in the order they were added, oldest first.
+    // 3. Any media-resource-specific text tracks (text tracks corresponding to data in the media
+    // resource), in the order defined by the media resource's format specification.
+
+    if (index < m_elementTracks.size())
+        return m_elementTracks[index].get();
+
+    index -= m_elementTracks.size();
+    if (index < m_addTrackTracks.size())
+        return m_addTrackTracks[index].get();
+
+    index -= m_addTrackTracks.size();
+    if (index < m_inbandTracks.size())
+        return m_inbandTracks[index].get();
+
+    return 0;
+}
+
+void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track)
+{
+    Vector<RefPtr<TextTrack> >* tracks = 0;
+
+    if (track->trackType() == TextTrack::TrackElement) {
+        tracks = &m_elementTracks;
+        for (size_t i = 0; i < m_addTrackTracks.size(); ++i)
+            m_addTrackTracks[i]->invalidateTrackIndex();
+        for (size_t i = 0; i < m_inbandTracks.size(); ++i)
+            m_inbandTracks[i]->invalidateTrackIndex();
+    } else if (track->trackType() == TextTrack::AddTrack) {
+        tracks = &m_addTrackTracks;
+        for (size_t i = 0; i < m_inbandTracks.size(); ++i)
+            m_inbandTracks[i]->invalidateTrackIndex();
+    } else if (track->trackType() == TextTrack::InBand)
+        tracks = &m_inbandTracks;
+    else
+        ASSERT_NOT_REACHED();
+
+    size_t index = tracks->find(track);
+    if (index == notFound)
+        return;
+
+    for (size_t i = index; i < tracks->size(); ++i)
+        tracks->at(index)->invalidateTrackIndex();
+}
+
+void TextTrackList::append(PassRefPtr<TextTrack> prpTrack)
+{
+    RefPtr<TextTrack> track = prpTrack;
+
+    if (track->trackType() == TextTrack::AddTrack)
+        m_addTrackTracks.append(track);
+    else if (track->trackType() == TextTrack::TrackElement) {
+        // Insert tracks added for <track> element in tree order.
+        size_t index = static_cast<LoadableTextTrack*>(track.get())->trackElementIndex();
+        m_elementTracks.insert(index, track);
+    } else if (track->trackType() == TextTrack::InBand) {
+        // Insert tracks added for in-band in the media file order.
+        size_t index = static_cast<InbandTextTrack*>(track.get())->inbandTrackIndex();
+        m_inbandTracks.insert(index, track);
+    } else
+        ASSERT_NOT_REACHED();
+
+    invalidateTrackIndexesAfterTrack(track.get());
+
+    ASSERT(!track->mediaElement() || track->mediaElement() == m_owner);
+    track->setMediaElement(m_owner);
+
+    scheduleAddTrackEvent(track.release());
+}
+
+void TextTrackList::remove(TextTrack* track)
+{
+    Vector<RefPtr<TextTrack> >* tracks = 0;
+
+    if (track->trackType() == TextTrack::TrackElement)
+        tracks = &m_elementTracks;
+    else if (track->trackType() == TextTrack::AddTrack)
+        tracks = &m_addTrackTracks;
+    else if (track->trackType() == TextTrack::InBand)
+        tracks = &m_inbandTracks;
+    else
+        ASSERT_NOT_REACHED();
+
+    size_t index = tracks->find(track);
+    if (index == notFound)
+        return;
+
+    invalidateTrackIndexesAfterTrack(track);
+
+    ASSERT(track->mediaElement() == m_owner);
+    track->setMediaElement(0);
+
+    tracks->remove(index);
+}
+
+bool TextTrackList::contains(TextTrack* track) const
+{
+    const Vector<RefPtr<TextTrack> >* tracks = 0;
+    
+    if (track->trackType() == TextTrack::TrackElement)
+        tracks = &m_elementTracks;
+    else if (track->trackType() == TextTrack::AddTrack)
+        tracks = &m_addTrackTracks;
+    else if (track->trackType() == TextTrack::InBand)
+        tracks = &m_inbandTracks;
+    else
+        ASSERT_NOT_REACHED();
+    
+    return tracks->find(track) != notFound;
+}
+
+const AtomicString& TextTrackList::interfaceName() const
+{
+    return eventNames().interfaceForTextTrackList;
+}
+
+void TextTrackList::scheduleAddTrackEvent(PassRefPtr<TextTrack> track)
+{
+    // 4.8.10.12.3 Sourcing out-of-band text tracks
+    // 4.8.10.12.4 Text track API
+    // ... then queue a task to fire an event with the name addtrack, that does not 
+    // bubble and is not cancelable, and that uses the TrackEvent interface, with 
+    // the track attribute initialized to the text track's TextTrack object, at 
+    // the media element's textTracks attribute's TextTrackList object.
+
+    RefPtr<TextTrack> trackRef = track;
+    TrackEventInit initializer;
+    initializer.track = trackRef;
+    initializer.bubbles = false;
+    initializer.cancelable = false;
+
+    m_pendingEvents.append(TrackEvent::create(eventNames().addtrackEvent, initializer));
+    if (!m_pendingEventTimer.isActive())
+        m_pendingEventTimer.startOneShot(0);
+}
+
+void TextTrackList::asyncEventTimerFired(Timer<TextTrackList>*)
+{
+    Vector<RefPtr<Event> > pendingEvents;
+
+    ++m_dispatchingEvents;
+    m_pendingEvents.swap(pendingEvents);
+    size_t count = pendingEvents.size();
+    for (size_t index = 0; index < count; ++index)
+        dispatchEvent(pendingEvents[index].release(), IGNORE_EXCEPTION);
+    --m_dispatchingEvents;
+}
+
+Node* TextTrackList::owner() const
+{
+    return m_owner;
+}
+
diff --git a/Source/core/html/track/TextTrackList.h b/Source/core/html/track/TextTrackList.h
new file mode 100644
index 0000000..0d11381
--- /dev/null
+++ b/Source/core/html/track/TextTrackList.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011, 2012 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 COMPUTER, 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 COMPUTER, 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 TextTrackList_h
+#define TextTrackList_h
+
+#include <algorithm>
+#include "core/dom/EventListener.h"
+#include "core/dom/EventTarget.h"
+#include "core/platform/Timer.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class HTMLMediaElement;
+class TextTrack;
+class TextTrackList;
+
+class TextTrackList : public RefCounted<TextTrackList>, public EventTarget {
+public:
+    static PassRefPtr<TextTrackList> create(HTMLMediaElement* owner, ScriptExecutionContext* context)
+    {
+        return adoptRef(new TextTrackList(owner, context));
+    }
+    ~TextTrackList();
+
+    unsigned length() const;
+    int getTrackIndex(TextTrack*);
+    int getTrackIndexRelativeToRenderedTracks(TextTrack*);
+    bool contains(TextTrack*) const;
+
+    TextTrack* item(unsigned index);
+    void append(PassRefPtr<TextTrack>);
+    void remove(TextTrack*);
+
+    // EventTarget
+    virtual const AtomicString& interfaceName() const;
+    using RefCounted<TextTrackList>::ref;
+    using RefCounted<TextTrackList>::deref;
+    virtual ScriptExecutionContext* scriptExecutionContext() const { return m_context; }
+
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(addtrack);
+
+    void clearOwner() { m_owner = 0; }
+    Node* owner() const;
+
+    bool isFiringEventListeners() { return m_dispatchingEvents; }
+
+private:
+    TextTrackList(HTMLMediaElement*, ScriptExecutionContext*);
+
+    // EventTarget
+    virtual void refEventTarget() { ref(); }
+    virtual void derefEventTarget() { deref(); }
+    virtual EventTargetData* eventTargetData() { return &m_eventTargetData; }
+    virtual EventTargetData* ensureEventTargetData() { return &m_eventTargetData; }
+
+    void scheduleAddTrackEvent(PassRefPtr<TextTrack>);
+    void asyncEventTimerFired(Timer<TextTrackList>*);
+
+    void invalidateTrackIndexesAfterTrack(TextTrack*);
+
+    ScriptExecutionContext* m_context;
+    HTMLMediaElement* m_owner;
+
+    Vector<RefPtr<Event> > m_pendingEvents;
+    Timer<TextTrackList> m_pendingEventTimer;
+
+    EventTargetData m_eventTargetData;
+    Vector<RefPtr<TextTrack> > m_addTrackTracks;
+    Vector<RefPtr<TextTrack> > m_elementTracks;
+    Vector<RefPtr<TextTrack> > m_inbandTracks;
+
+    int m_dispatchingEvents;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/TextTrackList.idl b/Source/core/html/track/TextTrackList.idl
new file mode 100644
index 0000000..7fcbacd
--- /dev/null
+++ b/Source/core/html/track/TextTrackList.idl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    EnabledAtRuntime=webkitVideoTrack,
+    EventTarget,
+    GenerateIsReachable=ImplOwnerRoot
+] interface TextTrackList {
+    readonly attribute unsigned long length;
+    getter TextTrack item(unsigned long index);
+
+    attribute EventListener onaddtrack;
+
+    void addEventListener(DOMString type,
+                          EventListener listener,
+                          optional boolean useCapture);
+    void removeEventListener(DOMString type,
+                             EventListener listener,
+                             optional boolean useCapture);
+    [RaisesException] boolean dispatchEvent(Event evt);
+};
+
diff --git a/Source/core/html/track/TextTrackRegion.cpp b/Source/core/html/track/TextTrackRegion.cpp
new file mode 100644
index 0000000..217fe02
--- /dev/null
+++ b/Source/core/html/track/TextTrackRegion.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2013 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEBVTT_REGIONS)
+
+#include "core/html/track/TextTrackRegion.h"
+
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/html/track/WebVTTParser.h"
+#include "core/platform/Logging.h"
+#include <wtf/MathExtras.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+// The region occupies by default 100% of the width of the video viewport.
+static const float defaultWidth = 100;
+
+// The region has, by default, 3 lines of text.
+static const long defaultHeightInLines = 3;
+
+// The region and viewport are anchored in the bottom left corner.
+static const float defaultAnchorPointX = 0;
+static const float defaultAnchorPointY = 100;
+
+// The region doesn't have scrolling text, by default.
+static const bool defaultScroll = false;
+
+TextTrackRegion::TextTrackRegion()
+    : m_id(emptyString())
+    , m_width(defaultWidth)
+    , m_heightInLines(defaultHeightInLines)
+    , m_regionAnchor(FloatPoint(defaultAnchorPointX, defaultAnchorPointY))
+    , m_viewportAnchor(FloatPoint(defaultAnchorPointX, defaultAnchorPointY))
+    , m_scroll(defaultScroll)
+    , m_track(0)
+{
+}
+
+TextTrackRegion::~TextTrackRegion()
+{
+}
+
+void TextTrackRegion::setTrack(TextTrack* track)
+{
+    m_track = track;
+}
+
+void TextTrackRegion::setId(const String& id)
+{
+    m_id = id;
+}
+
+void TextTrackRegion::setWidth(double value, ExceptionCode& ec)
+{
+    if (std::isinf(value) || std::isnan(value)) {
+        ec = TypeError;
+        return;
+    }
+
+    if (value < 0 || value > 100) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    m_width = value;
+}
+
+void TextTrackRegion::setHeight(long value, ExceptionCode& ec)
+{
+    if (value < 0) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    m_heightInLines = value;
+}
+
+void TextTrackRegion::setRegionAnchorX(double value, ExceptionCode& ec)
+{
+    if (std::isinf(value) || std::isnan(value)) {
+        ec = TypeError;
+        return;
+    }
+
+    if (value < 0 || value > 100) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    m_regionAnchor.setX(value);
+}
+
+void TextTrackRegion::setRegionAnchorY(double value, ExceptionCode& ec)
+{
+    if (std::isinf(value) || std::isnan(value)) {
+        ec = TypeError;
+        return;
+    }
+
+    if (value < 0 || value > 100) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    m_regionAnchor.setY(value);
+}
+
+void TextTrackRegion::setViewportAnchorX(double value, ExceptionCode& ec)
+{
+    if (std::isinf(value) || std::isnan(value)) {
+        ec = TypeError;
+        return;
+    }
+
+    if (value < 0 || value > 100) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    m_viewportAnchor.setX(value);
+}
+
+void TextTrackRegion::setViewportAnchorY(double value, ExceptionCode& ec)
+{
+    if (std::isinf(value) || std::isnan(value)) {
+        ec = TypeError;
+        return;
+    }
+
+    if (value < 0 || value > 100) {
+        ec = INDEX_SIZE_ERR;
+        return;
+    }
+
+    m_viewportAnchor.setY(value);
+}
+
+const AtomicString TextTrackRegion::scroll() const
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, upScrollValueKeyword, ("up", AtomicString::ConstructFromLiteral));
+
+    if (m_scroll)
+        return upScrollValueKeyword;
+
+    return "";
+}
+
+void TextTrackRegion::setScroll(const AtomicString& value, ExceptionCode& ec)
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, upScrollValueKeyword, ("up", AtomicString::ConstructFromLiteral));
+
+    if (value != emptyString() && value != upScrollValueKeyword) {
+        ec = SYNTAX_ERR;
+        return;
+    }
+
+    m_scroll = value == upScrollValueKeyword;
+}
+
+void TextTrackRegion::updateParametersFromRegion(TextTrackRegion* region)
+{
+    m_heightInLines = region->height();
+    m_width = region->width();
+
+    m_regionAnchor = FloatPoint(region->regionAnchorX(), region->regionAnchorY());
+    m_viewportAnchor = FloatPoint(region->viewportAnchorX(), region->viewportAnchorY());
+
+    setScroll(region->scroll(), ASSERT_NO_EXCEPTION);
+}
+
+void TextTrackRegion::setRegionSettings(const String& input)
+{
+    m_settings = input;
+    unsigned position = 0;
+
+    while (position < input.length()) {
+        while (position < input.length() && WebVTTParser::isValidSettingDelimiter(input[position]))
+            position++;
+
+        if (position >= input.length())
+            break;
+
+        parseSetting(input, &position);
+    }
+}
+
+TextTrackRegion::RegionSetting TextTrackRegion::getSettingFromString(const String& setting)
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, idKeyword, ("id", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(const AtomicString, heightKeyword, ("height", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(const AtomicString, widthKeyword, ("width", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(const AtomicString, regionAnchorKeyword, ("regionanchor", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(const AtomicString, viewportAnchorKeyword, ("viewportanchor", AtomicString::ConstructFromLiteral));
+    DEFINE_STATIC_LOCAL(const AtomicString, scrollKeyword, ("scroll", AtomicString::ConstructFromLiteral));
+
+    if (setting == idKeyword)
+        return Id;
+    if (setting == heightKeyword)
+        return Height;
+    if (setting == widthKeyword)
+        return Width;
+    if (setting == viewportAnchorKeyword)
+        return ViewportAnchor;
+    if (setting == regionAnchorKeyword)
+        return RegionAnchor;
+    if (setting == scrollKeyword)
+        return Scroll;
+
+    return None;
+}
+
+void TextTrackRegion::parseSettingValue(RegionSetting setting, const String& value)
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, scrollUpValueKeyword, ("up", AtomicString::ConstructFromLiteral));
+
+    bool isValidSetting;
+    String numberAsString;
+    int number;
+    unsigned position;
+    FloatPoint anchorPosition;
+
+    switch (setting) {
+    case Id:
+        if (value.find("-->") == notFound)
+            m_id = value;
+        break;
+    case Width:
+        number = WebVTTParser::parseFloatPercentageValue(value, isValidSetting);
+        if (isValidSetting)
+            m_width = number;
+        else
+            LOG(Media, "TextTrackRegion::parseSettingValue, invalid Width");
+        break;
+    case Height:
+        position = 0;
+
+        numberAsString = WebVTTParser::collectDigits(value, &position);
+        number = value.toInt(&isValidSetting);
+
+        if (isValidSetting && number >= 0)
+            m_heightInLines = number;
+        else
+            LOG(Media, "TextTrackRegion::parseSettingValue, invalid Height");
+        break;
+    case RegionAnchor:
+        anchorPosition = WebVTTParser::parseFloatPercentageValuePair(value, ',', isValidSetting);
+        if (isValidSetting)
+            m_regionAnchor = anchorPosition;
+        else
+            LOG(Media, "TextTrackRegion::parseSettingValue, invalid RegionAnchor");
+        break;
+    case ViewportAnchor:
+        anchorPosition = WebVTTParser::parseFloatPercentageValuePair(value, ',', isValidSetting);
+        if (isValidSetting)
+            m_viewportAnchor = anchorPosition;
+        else
+            LOG(Media, "TextTrackRegion::parseSettingValue, invalid ViewportAnchor");
+        break;
+    case Scroll:
+        if (value == scrollUpValueKeyword)
+            m_scroll = true;
+        else
+            LOG(Media, "TextTrackRegion::parseSettingValue, invalid Scroll");
+        break;
+    case None:
+        break;
+    }
+}
+
+void TextTrackRegion::parseSetting(const String& input, unsigned* position)
+{
+    String setting = WebVTTParser::collectWord(input, position);
+
+    size_t equalOffset = setting.find('=', 1);
+    if (equalOffset == notFound || !equalOffset || equalOffset == setting.length() - 1)
+        return;
+
+    RegionSetting name = getSettingFromString(setting.substring(0, equalOffset));
+    String value = setting.substring(equalOffset + 1, setting.length() - 1);
+
+    parseSettingValue(name, value);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/TextTrackRegion.h b/Source/core/html/track/TextTrackRegion.h
new file mode 100644
index 0000000..8920f05
--- /dev/null
+++ b/Source/core/html/track/TextTrackRegion.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2013 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 TextTrackRegion_h
+#define TextTrackRegion_h
+
+#if ENABLE(WEBVTT_REGIONS)
+
+#include "core/html/track/TextTrack.h"
+#include "core/platform/graphics/FloatPoint.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class TextTrackRegion : public RefCounted<TextTrackRegion> {
+public:
+    static PassRefPtr<TextTrackRegion> create()
+    {
+        return adoptRef(new TextTrackRegion());
+    }
+
+    virtual ~TextTrackRegion();
+
+    TextTrack* track() const { return m_track; }
+    void setTrack(TextTrack*);
+
+    const String& id() const { return m_id; }
+    void setId(const String&);
+
+    double width() const { return m_width; }
+    void setWidth(double, ExceptionCode&);
+
+    long height() const { return m_heightInLines; }
+    void setHeight(long, ExceptionCode&);
+
+    double regionAnchorX() const { return m_regionAnchor.x(); }
+    void setRegionAnchorX(double, ExceptionCode&);
+
+    double regionAnchorY() const { return m_regionAnchor.y(); }
+    void setRegionAnchorY(double, ExceptionCode&);
+
+    double viewportAnchorX() const { return m_viewportAnchor.x(); }
+    void setViewportAnchorX(double, ExceptionCode&);
+
+    double viewportAnchorY() const { return m_viewportAnchor.y(); }
+    void setViewportAnchorY(double, ExceptionCode&);
+
+    const AtomicString scroll() const;
+    void setScroll(const AtomicString&, ExceptionCode&);
+
+    void updateParametersFromRegion(TextTrackRegion*);
+
+    const String& regionSettings() const { return m_settings; }
+    void setRegionSettings(const String&);
+
+private:
+    TextTrackRegion();
+
+    enum RegionSetting {
+        None,
+        Id,
+        Width,
+        Height,
+        RegionAnchor,
+        ViewportAnchor,
+        Scroll
+    };
+
+    RegionSetting getSettingFromString(const String&);
+
+    void parseSettingValue(RegionSetting, const String&);
+    void parseSetting(const String&, unsigned*);
+
+    String m_id;
+    String m_settings;
+
+    double m_width;
+    unsigned m_heightInLines;
+
+    FloatPoint m_regionAnchor;
+    FloatPoint m_viewportAnchor;
+
+    bool m_scroll;
+
+    // The member variable track can be a raw pointer as it will never
+    // reference a destroyed TextTrack, as this member variable
+    // is cleared in the TextTrack destructor and it is generally
+    // set/reset within the addRegion and removeRegion methods.
+    TextTrack* m_track;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/track/TextTrackRegion.idl b/Source/core/html/track/TextTrackRegion.idl
new file mode 100644
index 0000000..2e80ca3
--- /dev/null
+++ b/Source/core/html/track/TextTrackRegion.idl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBVTT_REGIONS,
+    EnabledAtRuntime=webkitVideoTrack,
+    Constructor()
+] interface TextTrackRegion {
+    readonly attribute TextTrack track;
+
+    attribute DOMString id;
+    [SetterRaisesException] attribute double width;
+    [SetterRaisesException] attribute long height;
+    [SetterRaisesException] attribute double regionAnchorX;
+    [SetterRaisesException] attribute double regionAnchorY;
+    [SetterRaisesException] attribute double viewportAnchorX;
+    [SetterRaisesException] attribute double viewportAnchorY;
+    [SetterRaisesException] attribute DOMString scroll;
+};
+
diff --git a/Source/core/html/track/TextTrackRegionList.cpp b/Source/core/html/track/TextTrackRegionList.cpp
new file mode 100644
index 0000000..81a4dd4
--- /dev/null
+++ b/Source/core/html/track/TextTrackRegionList.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEBVTT_REGIONS)
+
+#include "core/html/track/TextTrackRegionList.h"
+
+namespace WebCore {
+
+TextTrackRegionList::TextTrackRegionList()
+{
+}
+
+unsigned long TextTrackRegionList::length() const
+{
+    return m_list.size();
+}
+
+TextTrackRegion* TextTrackRegionList::item(unsigned index) const
+{
+    if (index < m_list.size())
+        return m_list[index].get();
+
+    return 0;
+}
+
+TextTrackRegion* TextTrackRegionList::getRegionById(const String& id) const
+{
+    for (size_t i = 0; i < m_list.size(); ++i) {
+        if (m_list[i]->id() == id)
+            return m_list[i].get();
+    }
+    return 0;
+}
+
+void TextTrackRegionList::add(PassRefPtr<TextTrackRegion> region)
+{
+    m_list.append(region);
+}
+
+bool TextTrackRegionList::remove(TextTrackRegion* region)
+{
+    size_t index = m_list.find(region);
+    if (index == notFound)
+        return false;
+
+    m_list.remove(index);
+    return true;
+}
+
+void TextTrackRegionList::clear()
+{
+    m_list.clear();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/TextTrackRegionList.h b/Source/core/html/track/TextTrackRegionList.h
new file mode 100644
index 0000000..1ff8956
--- /dev/null
+++ b/Source/core/html/track/TextTrackRegionList.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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 TextTrackRegionList_h
+#define TextTrackRegionList_h
+
+#if ENABLE(WEBVTT_REGIONS)
+
+#include "core/html/track/TextTrackRegion.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class TextTrackRegionList : public RefCounted<TextTrackRegionList> {
+public:
+    static PassRefPtr<TextTrackRegionList> create()
+    {
+        return adoptRef(new TextTrackRegionList());
+    }
+
+    ~TextTrackRegionList() { }
+
+    unsigned long length() const;
+
+    TextTrackRegion* item(unsigned index) const;
+    TextTrackRegion* getRegionById(const String&) const;
+
+    void add(PassRefPtr<TextTrackRegion>);
+    bool remove(TextTrackRegion*);
+
+private:
+    TextTrackRegionList();
+    void clear();
+
+    Vector<RefPtr<TextTrackRegion> > m_list;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
diff --git a/Source/core/html/track/TextTrackRegionList.idl b/Source/core/html/track/TextTrackRegionList.idl
new file mode 100644
index 0000000..c6274cb
--- /dev/null
+++ b/Source/core/html/track/TextTrackRegionList.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    Conditional=WEBVTT_REGIONS,
+    EnabledAtRuntime=webkitVideoTrack,
+    ImplementationLacksVTable
+] interface TextTrackRegionList {
+    readonly attribute unsigned long length;
+    getter TextTrackRegion item(unsigned long index);
+    TextTrackRegion getRegionById(DOMString id);
+};
+
diff --git a/Source/core/html/track/TrackBase.cpp b/Source/core/html/track/TrackBase.cpp
new file mode 100644
index 0000000..a4d1308
--- /dev/null
+++ b/Source/core/html/track/TrackBase.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+#include "core/html/track/TrackBase.h"
+
+namespace WebCore {
+
+TrackBase::TrackBase(ScriptExecutionContext* context, Type type)
+    : m_scriptExecutionContext(context)
+{
+    ASSERT(type != BaseTrack);
+    m_type = type;
+}
+
+TrackBase::~TrackBase()
+{
+}
+
+const AtomicString& TrackBase::interfaceName() const
+{
+    return eventNames().interfaceForTextTrack;
+}
+
+ScriptExecutionContext* TrackBase::scriptExecutionContext() const
+{
+    return m_scriptExecutionContext;
+}
+
+EventTargetData* TrackBase::eventTargetData()
+{
+    return &m_eventTargetData;
+}
+
+EventTargetData* TrackBase::ensureEventTargetData()
+{
+    return &m_eventTargetData;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/html/track/TrackBase.h b/Source/core/html/track/TrackBase.h
new file mode 100644
index 0000000..30cfd52
--- /dev/null
+++ b/Source/core/html/track/TrackBase.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 TrackBase_h
+#define TrackBase_h
+
+#include "core/dom/EventTarget.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class ScriptExecutionContext;
+
+class TrackBase : public RefCounted<TrackBase>, public EventTarget {
+public:
+    virtual ~TrackBase();
+
+    enum Type { BaseTrack, TextTrack, AudioTrack, VideoTrack };
+    Type type() const { return m_type; }
+
+    virtual const AtomicString& interfaceName() const;
+    virtual ScriptExecutionContext* scriptExecutionContext() const;
+    
+    using RefCounted<TrackBase>::ref;
+    using RefCounted<TrackBase>::deref;
+
+protected:
+    TrackBase(ScriptExecutionContext*, Type);
+    
+    virtual EventTargetData* eventTargetData();
+    virtual EventTargetData* ensureEventTargetData();
+
+private:
+    Type m_type;
+    
+    virtual void refEventTarget() { ref(); }
+    virtual void derefEventTarget() { deref(); }
+    
+    ScriptExecutionContext* m_scriptExecutionContext;
+    EventTargetData m_eventTargetData;
+};
+
+} // namespace WebCore
+
+#endif // TrackBase_h
diff --git a/Source/core/html/track/TrackEvent.cpp b/Source/core/html/track/TrackEvent.cpp
new file mode 100644
index 0000000..de23f29
--- /dev/null
+++ b/Source/core/html/track/TrackEvent.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#include "config.h"
+
+#include "core/html/track/TrackEvent.h"
+
+#include "core/dom/EventNames.h"
+
+namespace WebCore {
+
+TrackEventInit::TrackEventInit()
+{
+}
+
+
+TrackEvent::TrackEvent()
+{
+    ScriptWrappable::init(this);
+}
+
+TrackEvent::TrackEvent(const AtomicString& type, const TrackEventInit& initializer)
+    : Event(type, initializer)
+    , m_track(initializer.track)
+{
+    ScriptWrappable::init(this);
+}
+
+TrackEvent::~TrackEvent()
+{
+}
+
+const AtomicString& TrackEvent::interfaceName() const
+{
+    return eventNames().interfaceForTrackEvent;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/html/track/TrackEvent.h b/Source/core/html/track/TrackEvent.h
new file mode 100644
index 0000000..3dc908a
--- /dev/null
+++ b/Source/core/html/track/TrackEvent.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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 TrackEvent_h
+#define TrackEvent_h
+
+#include "core/dom/Event.h"
+#include "core/html/track/TrackBase.h"
+
+namespace WebCore {
+
+struct TrackEventInit : public EventInit {
+    TrackEventInit();
+
+    RefPtr<TrackBase> track;
+};
+
+class TrackEvent : public Event {
+public:
+    virtual ~TrackEvent();
+
+    static PassRefPtr<TrackEvent> create()
+    {
+        return adoptRef(new TrackEvent);
+    }
+
+    static PassRefPtr<TrackEvent> create(const AtomicString& type, const TrackEventInit& initializer)
+    {
+        return adoptRef(new TrackEvent(type, initializer));
+    }
+
+    virtual const AtomicString& interfaceName() const;
+
+    TrackBase* track() const { return m_track.get(); }
+
+private:
+    TrackEvent();
+    TrackEvent(const AtomicString& type, const TrackEventInit& initializer);
+
+    RefPtr<TrackBase> m_track;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/TrackEvent.idl b/Source/core/html/track/TrackEvent.idl
new file mode 100644
index 0000000..1ebb29a
--- /dev/null
+++ b/Source/core/html/track/TrackEvent.idl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    EnabledAtRuntime=webkitVideoTrack,
+    ConstructorTemplate=Event
+] interface TrackEvent : Event {
+    [InitializedByEventConstructor, CustomGetter] readonly attribute object track;
+};
+
diff --git a/Source/core/html/track/WebVTTElement.cpp b/Source/core/html/track/WebVTTElement.cpp
new file mode 100644
index 0000000..7dfc9e8
--- /dev/null
+++ b/Source/core/html/track/WebVTTElement.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "config.h"
+
+#include "core/html/track/WebVTTElement.h"
+
+#include "core/html/track/TextTrack.h"
+
+namespace WebCore {
+
+static const QualifiedName& nodeTypeToTagName(WebVTTNodeType nodeType)
+{
+    DEFINE_STATIC_LOCAL(QualifiedName, cTag, (nullAtom, "c", nullAtom));
+    DEFINE_STATIC_LOCAL(QualifiedName, vTag, (nullAtom, "v", nullAtom));
+    DEFINE_STATIC_LOCAL(QualifiedName, langTag, (nullAtom, "lang", nullAtom));
+    DEFINE_STATIC_LOCAL(QualifiedName, bTag, (nullAtom, "b", nullAtom));
+    DEFINE_STATIC_LOCAL(QualifiedName, uTag, (nullAtom, "u", nullAtom));
+    DEFINE_STATIC_LOCAL(QualifiedName, iTag, (nullAtom, "i", nullAtom));
+    DEFINE_STATIC_LOCAL(QualifiedName, rubyTag, (nullAtom, "ruby", nullAtom));
+    DEFINE_STATIC_LOCAL(QualifiedName, rtTag, (nullAtom, "rt", nullAtom));
+    switch (nodeType) {
+    case WebVTTNodeTypeClass:
+        return cTag;
+    case WebVTTNodeTypeItalic:
+        return iTag;
+    case WebVTTNodeTypeLanguage:
+        return langTag;
+    case WebVTTNodeTypeBold:
+        return bTag;
+    case WebVTTNodeTypeUnderline:
+        return uTag;
+    case WebVTTNodeTypeRuby:
+        return rubyTag;
+    case WebVTTNodeTypeRubyText:
+        return rtTag;
+    case WebVTTNodeTypeVoice:
+        return vTag;
+    case WebVTTNodeTypeNone:
+    default:
+        ASSERT_NOT_REACHED();
+        return cTag; // Make the compiler happy.
+    }
+}
+
+WebVTTElement::WebVTTElement(WebVTTNodeType nodeType, Document* document)
+    : Element(nodeTypeToTagName(nodeType), document, CreateElement)
+    , m_isPastNode(0)
+    , m_webVTTNodeType(nodeType)
+{
+}
+
+PassRefPtr<WebVTTElement> WebVTTElement::create(WebVTTNodeType nodeType, Document* document)
+{
+    return adoptRef(new WebVTTElement(nodeType, document));
+}
+
+PassRefPtr<Element> WebVTTElement::cloneElementWithoutAttributesAndChildren()
+{
+    RefPtr<WebVTTElement> clone = create(static_cast<WebVTTNodeType>(m_webVTTNodeType), document());
+    clone->setLanguage(m_language);
+    return clone;
+}
+
+PassRefPtr<HTMLElement> WebVTTElement::createEquivalentHTMLElement(Document* document)
+{
+    RefPtr<HTMLElement> htmlElement;
+    switch (m_webVTTNodeType) {
+    case WebVTTNodeTypeClass:
+    case WebVTTNodeTypeLanguage:
+    case WebVTTNodeTypeVoice:
+        htmlElement = HTMLElement::create(HTMLNames::spanTag, document);
+        htmlElement.get()->setAttribute(HTMLNames::titleAttr, getAttribute(voiceAttributeName()));
+        htmlElement.get()->setAttribute(HTMLNames::langAttr, getAttribute(langAttributeName()));
+        break;
+    case WebVTTNodeTypeItalic:
+        htmlElement = HTMLElement::create(HTMLNames::iTag, document);
+        break;
+    case WebVTTNodeTypeBold:
+        htmlElement = HTMLElement::create(HTMLNames::bTag, document);
+        break;
+    case WebVTTNodeTypeUnderline:
+        htmlElement = HTMLElement::create(HTMLNames::uTag, document);
+        break;
+    case WebVTTNodeTypeRuby:
+        htmlElement = HTMLElement::create(HTMLNames::rubyTag, document);
+        break;
+    case WebVTTNodeTypeRubyText:
+        htmlElement = HTMLElement::create(HTMLNames::rtTag, document);
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    htmlElement.get()->setAttribute(HTMLNames::classAttr, getAttribute(HTMLNames::classAttr));
+    return htmlElement;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/html/track/WebVTTElement.h b/Source/core/html/track/WebVTTElement.h
new file mode 100644
index 0000000..62d23ac
--- /dev/null
+++ b/Source/core/html/track/WebVTTElement.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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.
+ */
+
+#include "core/html/HTMLElement.h"
+
+namespace WebCore {
+
+enum WebVTTNodeType {
+    WebVTTNodeTypeNone = 0,
+    WebVTTNodeTypeClass,
+    WebVTTNodeTypeItalic,
+    WebVTTNodeTypeLanguage,
+    WebVTTNodeTypeBold,
+    WebVTTNodeTypeUnderline,
+    WebVTTNodeTypeRuby,
+    WebVTTNodeTypeRubyText,
+    WebVTTNodeTypeVoice
+};
+
+class WebVTTElement FINAL : public Element {
+public:
+    static PassRefPtr<WebVTTElement> create(const WebVTTNodeType, Document*);
+    static PassRefPtr<WebVTTElement> create(const QualifiedName&, Document*);
+    PassRefPtr<HTMLElement> createEquivalentHTMLElement(Document*);
+
+    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() OVERRIDE;
+
+    void setWebVTTNodeType(WebVTTNodeType type) { m_webVTTNodeType = static_cast<unsigned>(type); }
+    WebVTTNodeType webVTTNodeType() const { return static_cast<WebVTTNodeType>(m_webVTTNodeType); }
+
+    bool isPastNode() const { return m_isPastNode; }
+    void setIsPastNode(bool value) { m_isPastNode = value; }
+
+    virtual bool isWebVTTElement() const OVERRIDE { return true; }
+    AtomicString language() const { return m_language; }
+    void setLanguage(AtomicString value) { m_language = value; }
+
+    static const QualifiedName& voiceAttributeName()
+    {
+        DEFINE_STATIC_LOCAL(QualifiedName, voiceAttr, (nullAtom, "voice", nullAtom));
+        return voiceAttr;
+    }
+    
+    static const QualifiedName& langAttributeName()
+    {
+        DEFINE_STATIC_LOCAL(QualifiedName, voiceAttr, (nullAtom, "lang", nullAtom));
+        return voiceAttr;
+    }
+
+private:
+    WebVTTElement(const QualifiedName&, Document*);
+    WebVTTElement(WebVTTNodeType, Document*);
+
+    unsigned m_isPastNode : 1;
+    unsigned m_webVTTNodeType : 4;
+    
+    AtomicString m_language;
+};
+
+inline WebVTTElement* toWebVTTElement(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isWebVTTElement());
+    return static_cast<WebVTTElement*>(node);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toWebVTTElement(const WebVTTElement*);
+
+
+} // namespace WebCore
+
diff --git a/Source/core/html/track/WebVTTParser.cpp b/Source/core/html/track/WebVTTParser.cpp
new file mode 100644
index 0000000..1875081
--- /dev/null
+++ b/Source/core/html/track/WebVTTParser.cpp
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/track/WebVTTParser.h"
+
+#include "core/dom/ProcessingInstruction.h"
+#include "core/dom/Text.h"
+#include "core/html/HTMLElement.h"
+#include "core/html/track/WebVTTElement.h"
+#include "core/platform/text/SegmentedString.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+const double secondsPerHour = 3600;
+const double secondsPerMinute = 60;
+const double secondsPerMillisecond = 0.001;
+const double malformedTime = -1;
+const unsigned bomLength = 3;
+const unsigned fileIdentifierLength = 6;
+
+String WebVTTParser::collectDigits(const String& input, unsigned* position)
+{
+    StringBuilder digits;
+    while (*position < input.length() && isASCIIDigit(input[*position]))
+        digits.append(input[(*position)++]);
+    return digits.toString();
+}
+
+String WebVTTParser::collectWord(const String& input, unsigned* position)
+{
+    StringBuilder string;
+    while (*position < input.length() && !isASpace(input[*position]))
+        string.append(input[(*position)++]);
+    return string.toString();
+}
+
+#if ENABLE(WEBVTT_REGIONS)
+float WebVTTParser::parseFloatPercentageValue(const String& value, bool& isValidSetting)
+{
+    // '%' must be present and at the end of the setting value.
+    if (value.find('%', 1) != value.length() - 1) {
+        isValidSetting = false;
+        return 0;
+    }
+
+    unsigned position = 0;
+
+    StringBuilder floatNumberAsString;
+    floatNumberAsString.append(WebVTTParser::collectDigits(value, &position));
+
+    if (value[position] == '.') {
+        floatNumberAsString.append(".");
+        position++;
+
+        floatNumberAsString.append(WebVTTParser::collectDigits(value, &position));
+    }
+    float number = floatNumberAsString.toString().toFloat(&isValidSetting);
+
+    if (isValidSetting && (number <= 0 || number >= 100))
+        isValidSetting = false;
+
+    return number;
+}
+
+FloatPoint WebVTTParser::parseFloatPercentageValuePair(const String& value, char delimiter, bool& isValidSetting)
+{
+    // The delimiter can't be the first or second value because a pair of
+    // percentages (x%,y%) implies that at least the first two characters
+    // are the first percentage value.
+    size_t delimiterOffset = value.find(delimiter, 2);
+    if (delimiterOffset == notFound || delimiterOffset == value.length() - 1) {
+        isValidSetting = false;
+        return FloatPoint(0, 0);
+    }
+
+    bool isFirstValueValid;
+    float firstCoord = parseFloatPercentageValue(value.substring(0, delimiterOffset), isFirstValueValid);
+
+    bool isSecondValueValid;
+    float secondCoord = parseFloatPercentageValue(value.substring(delimiterOffset + 1, value.length() - 1), isSecondValueValid);
+
+    isValidSetting = isFirstValueValid && isSecondValueValid;
+    return FloatPoint(firstCoord, secondCoord);
+}
+#endif
+
+WebVTTParser::WebVTTParser(WebVTTParserClient* client, ScriptExecutionContext* context)
+    : m_scriptExecutionContext(context)
+    , m_state(Initial)
+    , m_currentStartTime(0)
+    , m_currentEndTime(0)
+    , m_tokenizer(WebVTTTokenizer::create())
+    , m_client(client)
+{
+}
+
+void WebVTTParser::getNewCues(Vector<RefPtr<TextTrackCue> >& outputCues)
+{
+    outputCues = m_cuelist;
+    m_cuelist.clear();
+}
+
+#if ENABLE(WEBVTT_REGIONS)
+void WebVTTParser::getNewRegions(Vector<RefPtr<TextTrackRegion> >& outputRegions)
+{
+    outputRegions = m_regionList;
+    m_regionList.clear();
+}
+#endif
+
+void WebVTTParser::parseBytes(const char* data, unsigned length)
+{
+    // 4.8.10.13.3 WHATWG WebVTT Parser algorithm.
+    // 1-3 - Initial setup.
+    unsigned position = 0;
+
+    while (position < length) {
+        String line = collectNextLine(data, length, &position);
+
+        switch (m_state) {
+        case Initial:
+            // Buffer up at least 9 bytes before proceeding with checking for the file identifier.
+            m_identifierData.append(data, length);
+            if (m_identifierData.size() < bomLength + fileIdentifierLength)
+                return;
+
+            // 4-12 - Collect the first line and check for "WEBVTT".
+            if (!hasRequiredFileIdentifier()) {
+                if (m_client)
+                    m_client->fileFailedToParse();
+                return;
+            }
+
+            m_state = Header;
+            m_identifierData.clear();
+            break;
+
+        case Header:
+            // 13-18 - Allow a header (comment area) under the WEBVTT line.
+#if ENABLE(WEBVTT_REGIONS)
+            if (line.isEmpty()) {
+                if (m_client && m_regionList.size())
+                    m_client->newRegionsParsed();
+
+                m_state = Id;
+                break;
+            }
+            collectHeader(line);
+
+            break;
+
+        case Metadata:
+#endif
+            if (line.isEmpty())
+                m_state = Id;
+            break;
+
+        case Id:
+            // 19-29 - Allow any number of line terminators, then initialize new cue values.
+            if (line.isEmpty())
+                break;
+            resetCueValues();
+
+            // 30-39 - Check if this line contains an optional identifier or timing data.
+            m_state = collectCueId(line);
+            break;
+
+        case TimingsAndSettings:
+            // 40 - Collect cue timings and settings.
+            m_state = collectTimingsAndSettings(line);
+            break;
+
+        case CueText:
+            // 41-53 - Collect the cue text, create a cue, and add it to the output.
+            m_state = collectCueText(line, length, position);
+            break;
+
+        case BadCue:
+            // 54-62 - Collect and discard the remaining cue.
+            m_state = ignoreBadCue(line);
+            break;
+        }
+    }
+}
+
+bool WebVTTParser::hasRequiredFileIdentifier()
+{
+    // A WebVTT file identifier consists of an optional BOM character,
+    // the string "WEBVTT" followed by an optional space or tab character,
+    // and any number of characters that are not line terminators ...
+    unsigned position = 0;
+    if (m_identifierData.size() >= bomLength && m_identifierData[0] == '\xEF' && m_identifierData[1] == '\xBB' && m_identifierData[2] == '\xBF')
+        position += bomLength;
+    String line = collectNextLine(m_identifierData.data(), m_identifierData.size(), &position);
+
+    if (line.length() < fileIdentifierLength)
+        return false;
+    if (line.substring(0, fileIdentifierLength) != "WEBVTT")
+        return false;
+    if (line.length() > fileIdentifierLength && line[fileIdentifierLength] != ' ' && line[fileIdentifierLength] != '\t')
+        return false;
+
+    return true;
+}
+
+#if ENABLE(WEBVTT_REGIONS)
+void WebVTTParser::collectHeader(const String& line)
+{
+    // 4.1 Extension of WebVTT header parsing (11 - 15)
+    DEFINE_STATIC_LOCAL(const AtomicString, regionHeaderName, ("Region", AtomicString::ConstructFromLiteral));
+
+    // 15.4 If line contains the character ":" (A U+003A COLON), then set metadata's
+    // name to the substring of line before the first ":" character and
+    // metadata's value to the substring after this character.
+    if (!line.contains(":"))
+        return;
+
+    unsigned colonPosition = line.find(":");
+    m_currentHeaderName = line.substring(0, colonPosition);
+
+    // 15.5 If metadata's name equals "Region":
+    if (m_currentHeaderName == regionHeaderName) {
+        m_currentHeaderValue = line.substring(colonPosition + 1, line.length() - 1);
+        // 15.5.1 - 15.5.8 Region creation: Let region be a new text track region [...]
+        createNewRegion();
+    }
+}
+#endif
+
+WebVTTParser::ParseState WebVTTParser::collectCueId(const String& line)
+{
+    if (line.contains("-->"))
+        return collectTimingsAndSettings(line);
+    m_currentId = line;
+    return TimingsAndSettings;
+}
+
+WebVTTParser::ParseState WebVTTParser::collectTimingsAndSettings(const String& line)
+{
+    // 4.8.10.13.3 Collect WebVTT cue timings and settings.
+    // 1-3 - Let input be the string being parsed and position be a pointer into input
+    unsigned position = 0;
+    skipWhiteSpace(line, &position);
+
+    // 4-5 - Collect a WebVTT timestamp. If that fails, then abort and return failure. Otherwise, let cue's text track cue start time be the collected time.
+    m_currentStartTime = collectTimeStamp(line, &position);
+    if (m_currentStartTime == malformedTime)
+        return BadCue;
+    if (position >= line.length())
+        return BadCue;
+    char nextChar = line[position++];
+    if (nextChar != ' ' && nextChar != '\t')
+        return BadCue;
+    skipWhiteSpace(line, &position);
+
+    // 6-9 - If the next three characters are not "-->", abort and return failure.
+    if (line.find("-->", position) == notFound)
+        return BadCue;
+    position += 3;
+    if (position >= line.length())
+        return BadCue;
+    nextChar = line[position++];
+    if (nextChar != ' ' && nextChar != '\t')
+        return BadCue;
+    skipWhiteSpace(line, &position);
+
+    // 10-11 - Collect a WebVTT timestamp. If that fails, then abort and return failure. Otherwise, let cue's text track cue end time be the collected time.
+    m_currentEndTime = collectTimeStamp(line, &position);
+    if (m_currentEndTime == malformedTime)
+        return BadCue;
+    skipWhiteSpace(line, &position);
+
+    // 12 - Parse the WebVTT settings for the cue (conducted in TextTrackCue).
+    m_currentSettings = line.substring(position, line.length()-1);
+    return CueText;
+}
+
+WebVTTParser::ParseState WebVTTParser::collectCueText(const String& line, unsigned length, unsigned position)
+{
+    if (line.isEmpty()) {
+        createNewCue();
+        return Id;
+    }
+    if (!m_currentContent.isEmpty())
+        m_currentContent.append("\n");
+    m_currentContent.append(line);
+
+    if (position >= length)
+        createNewCue();
+                
+    return CueText;
+}
+
+WebVTTParser::ParseState WebVTTParser::ignoreBadCue(const String& line)
+{
+    if (!line.isEmpty())
+        return BadCue;
+    return Id;
+}
+
+PassRefPtr<DocumentFragment>  WebVTTParser::createDocumentFragmentFromCueText(const String& text)
+{
+    // Cue text processing based on
+    // 4.8.10.13.4 WebVTT cue text parsing rules and
+    // 4.8.10.13.5 WebVTT cue text DOM construction rules.
+
+    if (!text.length())
+        return 0;
+
+    ASSERT(m_scriptExecutionContext->isDocument());
+    Document* document = toDocument(m_scriptExecutionContext);
+    
+    RefPtr<DocumentFragment> fragment = DocumentFragment::create(document);
+    m_currentNode = fragment;
+    m_tokenizer->reset();
+    m_token.clear();
+    
+    m_languageStack.clear();
+    SegmentedString content(text);
+    while (m_tokenizer->nextToken(content, m_token))
+        constructTreeFromToken(document);
+    
+    return fragment.release();
+}
+
+void WebVTTParser::createNewCue()
+{
+    if (!m_currentContent.length())
+        return;
+
+    RefPtr<TextTrackCue> cue = TextTrackCue::create(m_scriptExecutionContext, m_currentStartTime, m_currentEndTime, m_currentContent.toString());
+    cue->setId(m_currentId);
+    cue->setCueSettings(m_currentSettings);
+
+    m_cuelist.append(cue);
+    if (m_client)
+        m_client->newCuesParsed();
+}
+
+void WebVTTParser::resetCueValues()
+{
+    m_currentId = emptyString();
+    m_currentSettings = emptyString();
+    m_currentStartTime = 0;
+    m_currentEndTime = 0;
+    m_currentContent.clear();
+}
+
+#if ENABLE(WEBVTT_REGIONS)
+void WebVTTParser::createNewRegion()
+{
+    if (!m_currentHeaderValue.length())
+        return;
+
+    RefPtr<TextTrackRegion> region = TextTrackRegion::create();
+    region->setRegionSettings(m_currentHeaderValue);
+
+    // 15.5.10 If the text track list of regions regions contains a region
+    // with the same region identifier value as region, remove that region.
+    for (size_t i = 0; i < m_regionList.size(); ++i)
+        if (m_regionList[i]->id() == region->id()) {
+            m_regionList.remove(i);
+            break;
+        }
+
+    m_regionList.append(region);
+}
+#endif
+
+double WebVTTParser::collectTimeStamp(const String& line, unsigned* position)
+{
+    // 4.8.10.13.3 Collect a WebVTT timestamp.
+    // 1-4 - Initial checks, let most significant units be minutes.
+    enum Mode { minutes, hours };
+    Mode mode = minutes;
+    if (*position >= line.length() || !isASCIIDigit(line[*position]))
+        return malformedTime;
+
+    // 5-6 - Collect a sequence of characters that are 0-9.
+    String digits1 = collectDigits(line, position);
+    int value1 = digits1.toInt();
+
+    // 7 - If not 2 characters or value is greater than 59, interpret as hours.
+    if (digits1.length() != 2 || value1 > 59)
+        mode = hours;
+
+    // 8-12 - Collect the next sequence of 0-9 after ':' (must be 2 chars).
+    if (*position >= line.length() || line[(*position)++] != ':')
+        return malformedTime;
+    if (*position >= line.length() || !isASCIIDigit(line[(*position)]))
+        return malformedTime;
+    String digits2 = collectDigits(line, position);
+    int value2 = digits2.toInt();
+    if (digits2.length() != 2) 
+        return malformedTime;
+
+    // 13 - Detect whether this timestamp includes hours.
+    int value3;
+    if (mode == hours || (*position < line.length() && line[*position] == ':')) {
+        if (*position >= line.length() || line[(*position)++] != ':')
+            return malformedTime;
+        if (*position >= line.length() || !isASCIIDigit(line[*position]))
+            return malformedTime;
+        String digits3 = collectDigits(line, position);
+        if (digits3.length() != 2)
+            return malformedTime;
+        value3 = digits3.toInt();
+    } else {
+        value3 = value2;
+        value2 = value1;
+        value1 = 0;
+    }
+
+    // 14-19 - Collect next sequence of 0-9 after '.' (must be 3 chars).
+    if (*position >= line.length() || line[(*position)++] != '.')
+        return malformedTime;
+    if (*position >= line.length() || !isASCIIDigit(line[*position]))
+        return malformedTime;
+    String digits4 = collectDigits(line, position);
+    if (digits4.length() != 3)
+        return malformedTime;
+    int value4 = digits4.toInt();
+    if (value2 > 59 || value3 > 59)
+        return malformedTime;
+
+    // 20-21 - Calculate result.
+    return (value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3 + (value4 * secondsPerMillisecond);
+}
+
+static WebVTTNodeType tokenToNodeType(WebVTTToken& token)
+{
+    switch (token.name().size()) {
+    case 1:
+        if (token.name()[0] == 'c')
+            return WebVTTNodeTypeClass;
+        if (token.name()[0] == 'v')
+            return WebVTTNodeTypeVoice;
+        if (token.name()[0] == 'b')
+            return WebVTTNodeTypeBold;
+        if (token.name()[0] == 'i')
+            return WebVTTNodeTypeItalic;
+        if (token.name()[0] == 'u')
+            return WebVTTNodeTypeUnderline;
+        break;
+    case 2:
+        if (token.name()[0] == 'r' && token.name()[1] == 't')
+            return WebVTTNodeTypeRubyText;
+        break;
+    case 4:
+        if (token.name()[0] == 'r' && token.name()[1] == 'u' && token.name()[2] == 'b' && token.name()[3] == 'y')
+            return WebVTTNodeTypeRuby;
+        if (token.name()[0] == 'l' && token.name()[1] == 'a' && token.name()[2] == 'n' && token.name()[3] == 'g')
+            return WebVTTNodeTypeLanguage;
+        break;
+    }
+    return WebVTTNodeTypeNone;
+}
+
+void WebVTTParser::constructTreeFromToken(Document* document)
+{
+    QualifiedName tagName(nullAtom, AtomicString(m_token.name()), xhtmlNamespaceURI);
+
+    // http://dev.w3.org/html5/webvtt/#webvtt-cue-text-dom-construction-rules
+
+    switch (m_token.type()) {
+    case WebVTTTokenTypes::Character: {
+        String content(m_token.characters()); // FIXME: This should be 8bit if possible.
+        RefPtr<Text> child = Text::create(document, content);
+        m_currentNode->parserAppendChild(child);
+        break;
+    }
+    case WebVTTTokenTypes::StartTag: {
+        RefPtr<WebVTTElement> child;
+        WebVTTNodeType nodeType = tokenToNodeType(m_token);
+        if (nodeType != WebVTTNodeTypeNone)
+            child = WebVTTElement::create(nodeType, document);
+        if (child) {
+            if (m_token.classes().size() > 0)
+                child->setAttribute(classAttr, AtomicString(m_token.classes()));
+
+            if (child->webVTTNodeType() == WebVTTNodeTypeVoice)
+                child->setAttribute(WebVTTElement::voiceAttributeName(), AtomicString(m_token.annotation()));
+            else if (child->webVTTNodeType() == WebVTTNodeTypeLanguage) {
+                m_languageStack.append(AtomicString(m_token.annotation()));
+                child->setAttribute(WebVTTElement::langAttributeName(), m_languageStack.last());
+            }
+            if (!m_languageStack.isEmpty())
+                child->setLanguage(m_languageStack.last());
+            m_currentNode->parserAppendChild(child);
+            m_currentNode = child;
+        }
+        break;
+    }
+    case WebVTTTokenTypes::EndTag: {
+        WebVTTNodeType nodeType = tokenToNodeType(m_token);
+        if (nodeType != WebVTTNodeTypeNone) {
+            if (nodeType == WebVTTNodeTypeLanguage && m_currentNode->isWebVTTElement() && toWebVTTElement(m_currentNode.get())->webVTTNodeType() == WebVTTNodeTypeLanguage)
+                m_languageStack.removeLast();
+            if (m_currentNode->parentNode())
+                m_currentNode = m_currentNode->parentNode();
+        }
+        break;
+    }
+    case WebVTTTokenTypes::TimestampTag: {
+        unsigned position = 0;
+        String charactersString(StringImpl::create8BitIfPossible(m_token.characters()));
+        double time = collectTimeStamp(charactersString, &position);
+        if (time != malformedTime)
+            m_currentNode->parserAppendChild(ProcessingInstruction::create(document, "timestamp", charactersString));
+        break;
+    }
+    default:
+        break;
+    }
+    m_token.clear();
+}
+
+void WebVTTParser::skipWhiteSpace(const String& line, unsigned* position)
+{
+    while (*position < line.length() && isASpace(line[*position]))
+        (*position)++;
+}
+
+void WebVTTParser::skipLineTerminator(const char* data, unsigned length, unsigned* position)
+{
+    if (*position >= length)
+        return;
+    if (data[*position] == '\r')
+        (*position)++;
+    if (*position >= length)
+        return;
+    if (data[*position] == '\n')
+        (*position)++;
+}
+
+String WebVTTParser::collectNextLine(const char* data, unsigned length, unsigned* position)
+{
+    unsigned oldPosition = *position;
+    while (*position < length && data[*position] != '\r' && data[*position] != '\n')
+        (*position)++;
+    String line = String::fromUTF8(data + oldPosition, *position - oldPosition);
+    skipLineTerminator(data, length, position);
+    return line;
+}
+
+}
+
diff --git a/Source/core/html/track/WebVTTParser.h b/Source/core/html/track/WebVTTParser.h
new file mode 100644
index 0000000..8c8d187
--- /dev/null
+++ b/Source/core/html/track/WebVTTParser.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 WebVTTParser_h
+#define WebVTTParser_h
+
+#include "HTMLNames.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/html/track/TextTrackCue.h"
+#include "core/html/track/TextTrackRegion.h"
+#include "core/html/track/WebVTTTokenizer.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+class Document;
+
+class WebVTTParserClient {
+public:
+    virtual ~WebVTTParserClient() { }
+
+    virtual void newCuesParsed() = 0;
+#if ENABLE(WEBVTT_REGIONS)
+    virtual void newRegionsParsed() = 0;
+#endif
+    virtual void fileFailedToParse() = 0;
+};
+
+class WebVTTParser {
+public:
+    virtual ~WebVTTParser() { }
+
+    enum ParseState {
+        Initial,
+        Header,
+#if ENABLE(WEBVTT_REGIONS)
+        Metadata,
+#endif
+        Id,
+        TimingsAndSettings,
+        CueText,
+        BadCue
+    };
+
+    static PassOwnPtr<WebVTTParser> create(WebVTTParserClient* client, ScriptExecutionContext* context)
+    {
+        return adoptPtr(new WebVTTParser(client, context));
+    }
+    
+    static inline bool isRecognizedTag(const AtomicString& tagName)
+    {
+        return tagName == iTag
+            || tagName == bTag
+            || tagName == uTag
+            || tagName == rubyTag
+            || tagName == rtTag;
+    }
+
+    static inline bool isASpace(char c)
+    {
+        // WebVTT space characters are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), U+000A LINE FEED (LF), U+000C FORM FEED (FF), and U+000D CARRIAGE RETURN    (CR).
+        return c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r';
+    }
+    static inline bool isValidSettingDelimiter(char c)
+    {
+        // ... a WebVTT cue consists of zero or more of the following components, in any order, separated from each other by one or more 
+        // U+0020 SPACE characters or U+0009 CHARACTER TABULATION (tab) characters.
+        return c == ' ' || c == '\t';
+    }
+    static String collectDigits(const String&, unsigned*);
+    static String collectWord(const String&, unsigned*);
+
+#if ENABLE(WEBVTT_REGIONS)
+    // Useful functions for parsing percentage settings.
+    static float parseFloatPercentageValue(const String&, bool&);
+    static FloatPoint parseFloatPercentageValuePair(const String&, char, bool&);
+#endif
+
+    // Input data to the parser to parse.
+    void parseBytes(const char* data, unsigned length);
+
+    // Transfers ownership of last parsed cues to caller.
+    void getNewCues(Vector<RefPtr<TextTrackCue> >&);
+#if ENABLE(WEBVTT_REGIONS)
+    void getNewRegions(Vector<RefPtr<TextTrackRegion> >&);
+#endif
+
+    PassRefPtr<DocumentFragment> createDocumentFragmentFromCueText(const String&);
+    double collectTimeStamp(const String&, unsigned*);
+
+protected:
+    WebVTTParser(WebVTTParserClient*, ScriptExecutionContext*);
+
+    ScriptExecutionContext* m_scriptExecutionContext;
+    ParseState m_state;
+
+private:
+    bool hasRequiredFileIdentifier();
+    ParseState collectCueId(const String&);
+    ParseState collectTimingsAndSettings(const String&);
+    ParseState collectCueText(const String&, unsigned length, unsigned);
+    ParseState ignoreBadCue(const String&);
+
+    void createNewCue();
+    void resetCueValues();
+
+#if ENABLE(WEBVTT_REGIONS)
+    void collectHeader(const String&);
+    void createNewRegion();
+#endif
+
+    void skipWhiteSpace(const String&, unsigned*);
+    static void skipLineTerminator(const char* data, unsigned length, unsigned*);
+    static String collectNextLine(const char* data, unsigned length, unsigned*);
+
+    void constructTreeFromToken(Document*);
+
+    String m_currentHeaderName;
+    String m_currentHeaderValue;
+
+    Vector<char> m_identifierData;
+    String m_currentId;
+    double m_currentStartTime;
+    double m_currentEndTime;
+    StringBuilder m_currentContent;
+    String m_currentSettings;
+    
+    WebVTTToken m_token;
+    OwnPtr<WebVTTTokenizer> m_tokenizer;
+
+    RefPtr<ContainerNode> m_currentNode;
+
+    WebVTTParserClient* m_client;
+
+    Vector<AtomicString> m_languageStack;
+    Vector<RefPtr<TextTrackCue> > m_cuelist;
+
+#if ENABLE(WEBVTT_REGIONS)
+    Vector<RefPtr<TextTrackRegion> > m_regionList;
+#endif
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/html/track/WebVTTToken.h b/Source/core/html/track/WebVTTToken.h
new file mode 100644
index 0000000..f867179
--- /dev/null
+++ b/Source/core/html/track/WebVTTToken.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 WebVTTToken_h
+#define WebVTTToken_h
+
+namespace WebCore {
+
+class WebVTTTokenTypes {
+public:
+    enum Type {
+        Uninitialized,
+        Character,
+        StartTag,
+        EndTag,
+        TimestampTag,
+        EndOfFile,
+    };
+};
+
+class WebVTTToken {
+    WTF_MAKE_NONCOPYABLE(WebVTTToken);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    typedef WebVTTTokenTypes Type;
+    typedef WTF::Vector<UChar, 1024> DataVector; // FIXME: Is this too large for WebVTT?
+
+    WebVTTToken() { clear(); }
+
+    void appendToName(UChar character)
+    {
+        ASSERT(m_type == WebVTTTokenTypes::StartTag || m_type == WebVTTTokenTypes::EndTag);
+        ASSERT(character);
+        m_data.append(character);
+    }
+
+    Type::Type type() const { return m_type; }
+
+    const DataVector& name() const
+    {
+        return m_data;
+    }
+
+    const DataVector& characters() const
+    {
+        ASSERT(m_type == Type::Character || m_type == Type::TimestampTag);
+        return m_data;
+    }
+
+    // Starting a character token works slightly differently than starting
+    // other types of tokens because we want to save a per-character branch.
+    void ensureIsCharacterToken()
+    {
+        ASSERT(m_type == Type::Uninitialized || m_type == Type::Character);
+        m_type = Type::Character;
+    }
+
+    void appendToCharacter(char character)
+    {
+        ASSERT(m_type == Type::Character);
+        m_data.append(character);
+    }
+
+    void appendToCharacter(UChar character)
+    {
+        ASSERT(m_type == Type::Character);
+        m_data.append(character);
+    }
+
+    void appendToCharacter(const Vector<LChar, 32>& characters)
+    {
+        ASSERT(m_type == Type::Character);
+        m_data.appendVector(characters);
+    }
+
+    void beginEmptyStartTag()
+    {
+        ASSERT(m_type == Type::Uninitialized);
+        m_type = Type::StartTag;
+        m_data.clear();
+    }
+ 
+    void beginStartTag(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == Type::Uninitialized);
+        m_type = Type::StartTag;
+        m_data.append(character);
+    }
+
+    void beginEndTag(LChar character)
+    {
+        ASSERT(m_type == Type::Uninitialized);
+        m_type = Type::EndTag;
+        m_data.append(character);
+    }
+
+    void beginTimestampTag(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == Type::Uninitialized);
+        m_type = Type::TimestampTag;
+        m_data.append(character);
+    }
+    
+    void appendToTimestamp(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == Type::TimestampTag);
+        m_data.append(character);
+    }
+
+    void appendToClass(UChar character)
+    {
+        appendToStartType(character);
+    }
+
+    void addNewClass()
+    {
+        ASSERT(m_type == Type::StartTag);
+        if (!m_classes.isEmpty())
+            m_classes.append(' ');
+        m_classes.append(m_currentBuffer);
+        m_currentBuffer.clear();
+    }
+    
+    const DataVector& classes() const
+    {
+        return m_classes;
+    }
+
+    void appendToAnnotation(UChar character)
+    {
+        appendToStartType(character);
+    }
+        
+    void addNewAnnotation()
+    {
+        ASSERT(m_type == Type::StartTag);
+        m_annotation.clear();
+        m_annotation.append(m_currentBuffer);
+        m_currentBuffer.clear();
+    }
+    
+    const DataVector& annotation() const
+    {
+        return m_annotation;
+    }
+
+    void makeEndOfFile()
+    {
+        ASSERT(m_type == Type::Uninitialized);
+        m_type = Type::EndOfFile;
+    }
+    
+    void clear()
+    {
+        m_type = Type::Uninitialized;
+        m_data.clear();
+        m_annotation.clear();
+        m_classes.clear();
+        m_currentBuffer.clear();
+    }
+
+private:
+    void appendToStartType(UChar character)
+    {
+        ASSERT(character);
+        ASSERT(m_type == Type::StartTag);
+        m_currentBuffer.append(character);
+    }
+
+    Type::Type m_type;
+    DataVector m_data;
+    DataVector m_annotation;
+    DataVector m_classes;
+    DataVector m_currentBuffer;
+};
+
+}
+
+#endif
diff --git a/Source/core/html/track/WebVTTTokenizer.cpp b/Source/core/html/track/WebVTTTokenizer.cpp
new file mode 100644
index 0000000..f00dfc8
--- /dev/null
+++ b/Source/core/html/track/WebVTTTokenizer.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#include "core/html/track/WebVTTTokenizer.h"
+
+#include "core/xml/parser/MarkupTokenizerInlines.h"
+
+namespace WebCore {
+
+#define WEBVTT_BEGIN_STATE(stateName) BEGIN_STATE(WebVTTTokenizerState, stateName)
+#define WEBVTT_ADVANCE_TO(stateName) ADVANCE_TO(WebVTTTokenizerState, stateName)
+
+WebVTTTokenizer::WebVTTTokenizer()
+    : m_inputStreamPreprocessor(this)
+{
+    reset();
+}
+
+template <typename CharacterType>
+inline bool vectorEqualsString(const Vector<CharacterType, 32>& vector, const String& string)
+{
+    if (vector.size() != string.length())
+        return false;
+
+    if (!string.length())
+        return true;
+
+    return equal(string.impl(), vector.data(), vector.size());
+}
+
+void WebVTTTokenizer::reset()
+{
+    m_state = WebVTTTokenizerState::DataState;
+    m_token = 0;
+    m_buffer.clear();
+}
+    
+bool WebVTTTokenizer::nextToken(SegmentedString& source, WebVTTToken& token)
+{
+    // If we have a token in progress, then we're supposed to be called back
+    // with the same token so we can finish it.
+    ASSERT(!m_token || m_token == &token || token.type() == WebVTTTokenTypes::Uninitialized);
+    m_token = &token;
+
+    if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source))
+        return haveBufferedCharacterToken();
+
+    UChar cc = m_inputStreamPreprocessor.nextInputCharacter();
+
+    // 4.8.10.13.4 WebVTT cue text tokenizer
+    switch (m_state) {
+    WEBVTT_BEGIN_STATE(DataState) {
+        if (cc == '&') {
+            m_buffer.append(static_cast<LChar>(cc));
+            WEBVTT_ADVANCE_TO(EscapeState);
+        } else if (cc == '<') {
+            if (m_token->type() == WebVTTTokenTypes::Uninitialized
+                || vectorEqualsString<UChar>(m_token->characters(), emptyString()))
+                WEBVTT_ADVANCE_TO(TagState);
+            else
+                return emitAndResumeIn(source, WebVTTTokenizerState::TagState);
+        } else if (cc == kEndOfFileMarker)
+            return emitEndOfFile(source);
+        else {
+            bufferCharacter(cc);
+            WEBVTT_ADVANCE_TO(DataState);
+        }
+    }
+    END_STATE()
+
+    WEBVTT_BEGIN_STATE(EscapeState) {
+        if (cc == ';') {
+            if (vectorEqualsString(m_buffer, "&amp"))
+                bufferCharacter('&');
+            else if (vectorEqualsString(m_buffer, "&lt"))
+                bufferCharacter('<');
+            else if (vectorEqualsString(m_buffer, "&gt"))
+                bufferCharacter('>');
+            else {
+                m_buffer.append(static_cast<LChar>(cc));
+                m_token->appendToCharacter(m_buffer);
+            }
+            m_buffer.clear();
+            WEBVTT_ADVANCE_TO(DataState);
+        } else if (isASCIIAlphanumeric(cc)) {
+            m_buffer.append(static_cast<LChar>(cc));
+            WEBVTT_ADVANCE_TO(EscapeState);
+        } else if (cc == kEndOfFileMarker) {
+            m_token->appendToCharacter(m_buffer);
+            return emitEndOfFile(source);
+        } else {
+            if (!vectorEqualsString(m_buffer, "&"))
+                m_token->appendToCharacter(m_buffer);
+            m_buffer.clear();
+            WEBVTT_ADVANCE_TO(DataState);
+        }
+    }
+    END_STATE()
+
+    WEBVTT_BEGIN_STATE(TagState) {
+        if (isTokenizerWhitespace(cc)) {
+            m_token->beginEmptyStartTag();
+            WEBVTT_ADVANCE_TO(StartTagAnnotationState);
+        } else if (cc == '.') {
+            m_token->beginEmptyStartTag();
+            WEBVTT_ADVANCE_TO(StartTagClassState);
+        } else if (cc == '/') {
+            WEBVTT_ADVANCE_TO(EndTagOpenState);
+        } else if (WTF::isASCIIDigit(cc)) {
+            m_token->beginTimestampTag(cc);
+            WEBVTT_ADVANCE_TO(TimestampTagState);
+        } else if (cc == '>' || cc == kEndOfFileMarker) {
+            m_token->beginEmptyStartTag();
+            return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
+        } else {
+            m_token->beginStartTag(cc);
+            WEBVTT_ADVANCE_TO(StartTagState);
+        }
+    }
+    END_STATE()
+
+    WEBVTT_BEGIN_STATE(StartTagState) {
+        if (isTokenizerWhitespace(cc))
+            WEBVTT_ADVANCE_TO(StartTagAnnotationState);
+        else if (cc == '.')
+            WEBVTT_ADVANCE_TO(StartTagClassState);
+        else if (cc == '>' || cc == kEndOfFileMarker)
+            return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
+        else {
+            m_token->appendToName(cc);
+            WEBVTT_ADVANCE_TO(StartTagState);
+        }
+    }
+    END_STATE()
+
+    WEBVTT_BEGIN_STATE(StartTagClassState) {
+        if (isTokenizerWhitespace(cc)) {
+            m_token->addNewClass();
+            WEBVTT_ADVANCE_TO(StartTagAnnotationState);
+        } else if (cc == '.') {
+            m_token->addNewClass();
+            WEBVTT_ADVANCE_TO(StartTagClassState);
+        } else if (cc == '>' || cc == kEndOfFileMarker) {
+            m_token->addNewClass();
+            return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
+        } else {
+            m_token->appendToClass(cc);
+            WEBVTT_ADVANCE_TO(StartTagClassState);
+        }
+
+    }
+    END_STATE()
+
+    WEBVTT_BEGIN_STATE(StartTagAnnotationState) {
+        if (cc == '>' || cc == kEndOfFileMarker) {
+            m_token->addNewAnnotation();
+            return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
+        }
+        m_token->appendToAnnotation(cc);
+        WEBVTT_ADVANCE_TO(StartTagAnnotationState);
+    }
+    END_STATE()
+    
+    WEBVTT_BEGIN_STATE(EndTagOpenState) {
+        if (cc == '>' || cc == kEndOfFileMarker) {
+            m_token->beginEndTag('\0');
+            return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
+        }
+        m_token->beginEndTag(cc);
+        WEBVTT_ADVANCE_TO(EndTagState);
+    }
+    END_STATE()
+
+    WEBVTT_BEGIN_STATE(EndTagState) {
+        if (cc == '>' || cc == kEndOfFileMarker)
+            return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
+        m_token->appendToName(cc);
+        WEBVTT_ADVANCE_TO(EndTagState);
+    }
+    END_STATE()
+
+    WEBVTT_BEGIN_STATE(TimestampTagState) {
+        if (cc == '>' || cc == kEndOfFileMarker)
+            return emitAndResumeIn(source, WebVTTTokenizerState::DataState);
+        m_token->appendToTimestamp(cc);
+        WEBVTT_ADVANCE_TO(TimestampTagState);
+    }
+    END_STATE()
+
+    }
+
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+}
+
diff --git a/Source/core/html/track/WebVTTTokenizer.h b/Source/core/html/track/WebVTTTokenizer.h
new file mode 100644
index 0000000..de1ee0a
--- /dev/null
+++ b/Source/core/html/track/WebVTTTokenizer.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 WebVTTTokenizer_h
+#define WebVTTTokenizer_h
+
+#include "core/html/parser/InputStreamPreprocessor.h"
+#include "core/html/track/WebVTTToken.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebVTTTokenizerState {
+public:
+    enum State {
+        DataState,
+        EscapeState,
+        TagState,
+        StartTagState,
+        StartTagClassState,
+        StartTagAnnotationState,
+        EndTagState,
+        EndTagOpenState,
+        TimestampTagState,
+    };
+};
+
+class WebVTTTokenizer {
+    WTF_MAKE_NONCOPYABLE(WebVTTTokenizer);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static PassOwnPtr<WebVTTTokenizer> create() { return adoptPtr(new WebVTTTokenizer); }
+
+    typedef WebVTTTokenizerState State;
+
+    void reset();
+    
+    bool nextToken(SegmentedString&, WebVTTToken&);
+
+    inline bool haveBufferedCharacterToken()
+    {
+        return m_token->type() == WebVTTToken::Type::Character;
+    }
+
+    inline void bufferCharacter(UChar character)
+    {
+        ASSERT(character != kEndOfFileMarker);
+        m_token->ensureIsCharacterToken();
+        m_token->appendToCharacter(character);
+    }
+
+    inline bool emitAndResumeIn(SegmentedString& source, State::State state)
+    {
+        m_state = state;
+        source.advanceAndUpdateLineNumber();
+        return true;
+    }
+
+    inline bool emitEndOfFile(SegmentedString& source)
+    {
+        if (haveBufferedCharacterToken())
+            return true;
+        m_state = State::DataState;
+        source.advanceAndUpdateLineNumber();
+        m_token->clear();
+        m_token->makeEndOfFile();
+        return true;
+    }
+
+    bool shouldSkipNullCharacters() const { return true; }
+
+private:
+    WebVTTTokenizer();
+
+    // m_token is owned by the caller. If nextToken is not on the stack,
+    // this member might be pointing to unallocated memory.
+    WebVTTToken* m_token;
+    WebVTTTokenizerState::State m_state;
+
+    Vector<LChar, 32> m_buffer;
+
+    // ://www.whatwg.org/specs/web-apps/current-work/#preprocessing-the-input-stream
+    InputStreamPreprocessor<WebVTTTokenizer> m_inputStreamPreprocessor;
+};
+
+}
+
+#endif