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/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