AuthorShadowDOM for meter element
https://bugs.webkit.org/show_bug.cgi?id=91970

Reviewed by Hajime Morita.

Source/WebCore:

We add support for AuthorShadowDOM for a meter element.

According to the Shadow DOM spec, a meter element should behave like having a UserAgentShadowRoot and
an element in UserAgentShadowRoot draws a real 'meter' bar. In this patch, we change the inner structure
of a meter element so that we can distribute an element having RenderMeter to AuthorShadowDOM.

Before this patch, a meter element has the following inner structure.

    <meter>--UserAgentShadowRoot -- -- -- -- -- -- -- -- -- -- AuthorShadowRoot
                       |
                       +-- MeterBarElement
                       |
                       +-- MeterValueElement

After this patch, a meter element will have the following inner structure.

    <meter>--UserAgentShadowRoot -- -- -- -- -- -- -- -- -- -- AuthorShadowRoot
                       |
                       +-- MeterInnerElement
                                   |
                                   +-- MeterBarElement
                                   |
                                   +-- MeterValueElement

However, if RenderTheme supports rendering meter, MeterInnerElement will not create a renderer
unless an AuthorShadowDOM is attached to it so that we can keep the current rendering style.

Tests: fast/dom/shadow/shadowdom-for-meter-dynamic.html
       fast/dom/shadow/shadowdom-for-meter-multiple.html
       fast/dom/shadow/shadowdom-for-meter-with-style.html
       fast/dom/shadow/shadowdom-for-meter-without-appearance.html
       fast/dom/shadow/shadowdom-for-meter-without-shadow-element.html
       fast/dom/shadow/shadowdom-for-meter.html

* css/html.css:
(meter): Changed the display type. inline-box is not supported WebKit. inline-block is true.
(meter::-webkit-meter-inner-element):
* html/HTMLMeterElement.cpp:
(WebCore::HTMLMeterElement::HTMLMeterElement):
(WebCore::HTMLMeterElement::createRenderer):
(WebCore):
(WebCore::HTMLMeterElement::attach): Added didElementStateChange.
(WebCore::HTMLMeterElement::didElementStateChange):
(WebCore::HTMLMeterElement::willAddAuthorShadowRoot):
(WebCore::HTMLMeterElement::renderMeter):
(WebCore::HTMLMeterElement::createShadowSubtree):
* html/HTMLMeterElement.h:
(WebCore):
(WebCore::HTMLMeterElement::hasAuthorShadowRoot):
(HTMLMeterElement):
(WebCore::isHTMLMeterElement):
(WebCore::toHTMLMeterElement):
* html/shadow/MeterShadowElement.cpp:
(WebCore::MeterShadowElement::meterElement):
(WebCore::MeterShadowElement::rendererIsNeeded):
(WebCore):
(WebCore::MeterInnerElement::MeterInnerElement): We introduce a new element having RenderMeter
so that we can distribute an element having RenderMeter to AuthorShadowDOM.
(WebCore::MeterInnerElement::rendererIsNeeded): Different from a progress element, meter element will not be
rendered using a theme. So we don't need to check the style appearance.
(WebCore::MeterInnerElement::createRenderer):
(WebCore::MeterInnerElement::shadowPseudoId):
* html/shadow/MeterShadowElement.h:
(WebCore):
(MeterInnerElement):
(WebCore::MeterInnerElement::create):
* rendering/RenderMeter.cpp:
(WebCore::RenderMeter::RenderMeter):
(WebCore::RenderMeter::meterElement):
(WebCore):
(WebCore::RenderMeter::valueRatio):
* rendering/RenderMeter.h:
(RenderMeter):
* rendering/RenderThemeMac.mm:
(WebCore::RenderThemeMac::levelIndicatorFor):

LayoutTests:

Contains the following tests:
  (1) meter element with AuthorShadowDOM
  (2) meter element with multiple AuthorShadowDOM with a shadow element
  (3) meter element with multiple AuthorShadowDOM without a shadow element
  (4) meter element with AuthorShadowDOM with dynamic value update
  (5) meter element with AuthorShadowDOM with style
  (6) meter element with AuthorShadowDOM with -webkit-appearance: none

* fast/dom/HTMLMeterElement/meter-clone-expected.txt:
* fast/dom/HTMLMeterElement/meter-clone.html:
* fast/dom/HTMLMeterElement/meter-element-markup-expected.txt:
* fast/dom/shadow/resources/replaced-element-styles.css:
(.meter-like):
(.meter-inner-element-like):
* fast/dom/shadow/shadowdom-for-meter-dynamic-expected.html: Added.
* fast/dom/shadow/shadowdom-for-meter-dynamic.html: Added.
* fast/dom/shadow/shadowdom-for-meter-expected.html: Added.
* fast/dom/shadow/shadowdom-for-meter-multiple-expected.html: Added.
* fast/dom/shadow/shadowdom-for-meter-multiple.html: Added.
* fast/dom/shadow/shadowdom-for-meter-with-style-expected.html: Added.
* fast/dom/shadow/shadowdom-for-meter-with-style.html: Added.
* fast/dom/shadow/shadowdom-for-meter-without-appearance-expected.html: Added.
* fast/dom/shadow/shadowdom-for-meter-without-appearance.html: Added.
* fast/dom/shadow/shadowdom-for-meter-without-shadow-element-expected.html: Added.
* fast/dom/shadow/shadowdom-for-meter-without-shadow-element.html: Added.
* fast/dom/shadow/shadowdom-for-meter.html: Added.
* platform/chromium-win/fast/dom/HTMLMeterElement/meter-appearances-capacity-expected.txt:
* platform/chromium-win/fast/dom/HTMLMeterElement/meter-appearances-rating-relevancy-expected.txt:
* platform/chromium-win/fast/dom/HTMLMeterElement/meter-boundary-values-expected.txt:
* platform/chromium-win/fast/dom/HTMLMeterElement/meter-element-expected.txt:
* platform/chromium-win/fast/dom/HTMLMeterElement/meter-element-repaint-on-update-value-expected.txt:
* platform/chromium-win/fast/dom/HTMLMeterElement/meter-optimums-expected.txt:
* platform/chromium-win/fast/dom/HTMLMeterElement/meter-styles-changing-pseudo-expected.txt:
* platform/chromium-win/fast/dom/HTMLMeterElement/meter-styles-expected.txt:
* platform/chromium-win/fast/dom/HTMLMeterElement/meter-writing-mode-expected.txt:
* platform/mac/TestExpectations:


git-svn-id: svn://svn.chromium.org/blink/trunk@125659 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 0ae5995..c98d283 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,86 @@
+2012-08-15  Shinya Kawanaka  <shinyak@chromium.org>
+
+        AuthorShadowDOM for meter element
+        https://bugs.webkit.org/show_bug.cgi?id=91970
+
+        Reviewed by Hajime Morita.
+
+        We add support for AuthorShadowDOM for a meter element.
+
+        According to the Shadow DOM spec, a meter element should behave like having a UserAgentShadowRoot and
+        an element in UserAgentShadowRoot draws a real 'meter' bar. In this patch, we change the inner structure
+        of a meter element so that we can distribute an element having RenderMeter to AuthorShadowDOM.
+
+        Before this patch, a meter element has the following inner structure.
+
+            <meter>--UserAgentShadowRoot -- -- -- -- -- -- -- -- -- -- AuthorShadowRoot
+                               |
+                               +-- MeterBarElement
+                               |
+                               +-- MeterValueElement
+
+        After this patch, a meter element will have the following inner structure.
+
+            <meter>--UserAgentShadowRoot -- -- -- -- -- -- -- -- -- -- AuthorShadowRoot
+                               |
+                               +-- MeterInnerElement
+                                           |
+                                           +-- MeterBarElement
+                                           |
+                                           +-- MeterValueElement
+
+        However, if RenderTheme supports rendering meter, MeterInnerElement will not create a renderer
+        unless an AuthorShadowDOM is attached to it so that we can keep the current rendering style.
+
+        Tests: fast/dom/shadow/shadowdom-for-meter-dynamic.html
+               fast/dom/shadow/shadowdom-for-meter-multiple.html
+               fast/dom/shadow/shadowdom-for-meter-with-style.html
+               fast/dom/shadow/shadowdom-for-meter-without-appearance.html
+               fast/dom/shadow/shadowdom-for-meter-without-shadow-element.html
+               fast/dom/shadow/shadowdom-for-meter.html
+
+        * css/html.css:
+        (meter): Changed the display type. inline-box is not supported WebKit. inline-block is true.
+        (meter::-webkit-meter-inner-element):
+        * html/HTMLMeterElement.cpp:
+        (WebCore::HTMLMeterElement::HTMLMeterElement):
+        (WebCore::HTMLMeterElement::createRenderer):
+        (WebCore):
+        (WebCore::HTMLMeterElement::attach): Added didElementStateChange.
+        (WebCore::HTMLMeterElement::didElementStateChange):
+        (WebCore::HTMLMeterElement::willAddAuthorShadowRoot):
+        (WebCore::HTMLMeterElement::renderMeter):
+        (WebCore::HTMLMeterElement::createShadowSubtree):
+        * html/HTMLMeterElement.h:
+        (WebCore):
+        (WebCore::HTMLMeterElement::hasAuthorShadowRoot):
+        (HTMLMeterElement):
+        (WebCore::isHTMLMeterElement):
+        (WebCore::toHTMLMeterElement):
+        * html/shadow/MeterShadowElement.cpp:
+        (WebCore::MeterShadowElement::meterElement):
+        (WebCore::MeterShadowElement::rendererIsNeeded):
+        (WebCore):
+        (WebCore::MeterInnerElement::MeterInnerElement): We introduce a new element having RenderMeter
+        so that we can distribute an element having RenderMeter to AuthorShadowDOM.
+        (WebCore::MeterInnerElement::rendererIsNeeded): Different from a progress element, meter element will not be
+        rendered using a theme. So we don't need to check the style appearance.
+        (WebCore::MeterInnerElement::createRenderer):
+        (WebCore::MeterInnerElement::shadowPseudoId):
+        * html/shadow/MeterShadowElement.h:
+        (WebCore):
+        (MeterInnerElement):
+        (WebCore::MeterInnerElement::create):
+        * rendering/RenderMeter.cpp:
+        (WebCore::RenderMeter::RenderMeter):
+        (WebCore::RenderMeter::meterElement):
+        (WebCore):
+        (WebCore::RenderMeter::valueRatio):
+        * rendering/RenderMeter.h:
+        (RenderMeter):
+        * rendering/RenderThemeMac.mm:
+        (WebCore::RenderThemeMac::levelIndicatorFor):
+
 2012-08-15  Adam Barth  <abarth@webkit.org>
 
         [Chromium] fast/dom/Window/dom-access-from-closure-window.html is flaky on Linux
diff --git a/Source/WebCore/css/html.css b/Source/WebCore/css/html.css
index 43b65a1..0ab746d 100644
--- a/Source/WebCore/css/html.css
+++ b/Source/WebCore/css/html.css
@@ -894,12 +894,20 @@
 meter {
     -webkit-appearance: meter;
     -webkit-box-sizing: border-box;
-    display: inline-box;
+    display: inline-block;
     height: 1em;
     width: 5em;
     vertical-align: -0.2em;
 }
 
+meter::-webkit-meter-inner-element {
+    -webkit-appearance: inherit;
+    -webkit-box-sizing: inherit;
+    -webkit-user-modify: read-only !important;
+    height: 100%;
+    width: 100%;
+}
+
 meter::-webkit-meter-bar {
     background: -webkit-gradient(linear, left top, left bottom, from(#ddd), to(#ddd), color-stop(0.20, #eee), color-stop(0.45, #ccc), color-stop(0.55, #ccc));
     height: 100%;
diff --git a/Source/WebCore/html/HTMLMeterElement.cpp b/Source/WebCore/html/HTMLMeterElement.cpp
index 290de5b..dbf46c1 100644
--- a/Source/WebCore/html/HTMLMeterElement.cpp
+++ b/Source/WebCore/html/HTMLMeterElement.cpp
@@ -31,7 +31,9 @@
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
 #include "MeterShadowElement.h"
+#include "Page.h"
 #include "RenderMeter.h"
+#include "RenderTheme.h"
 #include "ShadowRoot.h"
 #include <wtf/StdLibExtras.h>
 
@@ -41,6 +43,7 @@
 
 HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document)
     : LabelableElement(tagName, document)
+    , m_hasAuthorShadowRoot(false)
 {
     ASSERT(hasTagName(meterTag));
 }
@@ -56,8 +59,11 @@
     return meter;
 }
 
-RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle*)
+RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle* style)
 {
+    if (hasAuthorShadowRoot() || !document()->page()->theme()->supportsMeter(style->appearance()))
+        return RenderObject::createObject(this, style);
+
     return new (arena) RenderMeter(this);
 }
 
@@ -79,6 +85,12 @@
         LabelableElement::parseAttribute(attribute);
 }
 
+void HTMLMeterElement::attach()
+{
+    m_value->setWidthPercentage(valueRatio()*100);
+    LabelableElement::attach();
+}
+
 double HTMLMeterElement::min() const
 {
     return parseToDoubleForNumberType(getAttribute(minAttr), 0);
@@ -214,22 +226,40 @@
 void HTMLMeterElement::didElementStateChange()
 {
     m_value->setWidthPercentage(valueRatio()*100);
-    if (RenderObject* render = renderer())
+    if (RenderMeter* render = renderMeter())
         render->updateFromElement();
 }
 
+void HTMLMeterElement::willAddAuthorShadowRoot()
+{
+    m_hasAuthorShadowRoot = true;
+}
+
+RenderMeter* HTMLMeterElement::renderMeter() const
+{
+    if (renderer() && renderer()->isMeter())
+        return static_cast<RenderMeter*>(renderer());
+
+    RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer();
+    ASSERT(!renderObject || renderObject->isMeter());
+    return static_cast<RenderMeter*>(renderObject);
+}
+
 void HTMLMeterElement::createShadowSubtree()
 {
-    ASSERT(!shadow());
+    ASSERT(!userAgentShadowRoot());
+           
+    RefPtr<ShadowRoot> root = ShadowRoot::create(this, ShadowRoot::UserAgentShadowRoot, ASSERT_NO_EXCEPTION);
+
+    RefPtr<MeterInnerElement> inner = MeterInnerElement::create(document());
+    root->appendChild(inner);
 
     RefPtr<MeterBarElement> bar = MeterBarElement::create(document());
     m_value = MeterValueElement::create(document());
     m_value->setWidthPercentage(0);
-    ExceptionCode ec = 0;
-    bar->appendChild(m_value, ec);
+    bar->appendChild(m_value, ASSERT_NO_EXCEPTION);
 
-    RefPtr<ShadowRoot> root = ShadowRoot::create(this, ShadowRoot::UserAgentShadowRoot);
-    root->appendChild(bar, ec);
+    inner->appendChild(bar, ASSERT_NO_EXCEPTION);
 }
 
 } // namespace
diff --git a/Source/WebCore/html/HTMLMeterElement.h b/Source/WebCore/html/HTMLMeterElement.h
index 1883091..8e63c64 100644
--- a/Source/WebCore/html/HTMLMeterElement.h
+++ b/Source/WebCore/html/HTMLMeterElement.h
@@ -27,6 +27,7 @@
 namespace WebCore {
 
 class MeterValueElement;
+class RenderMeter;
 
 class HTMLMeterElement : public LabelableElement {
 public:
@@ -38,6 +39,8 @@
         GaugeRegionEvenLessGood
     };
 
+    bool hasAuthorShadowRoot() const { return m_hasAuthorShadowRoot; }
+
     double min() const;
     void setMin(double, ExceptionCode&);
 
@@ -65,6 +68,9 @@
     HTMLMeterElement(const QualifiedName&, Document*);
     virtual ~HTMLMeterElement();
 
+    virtual void willAddAuthorShadowRoot() OVERRIDE;
+    RenderMeter* renderMeter() const;
+
     virtual bool supportLabels() const OVERRIDE { return true; }
 
     virtual bool supportsFocus() const;
@@ -74,12 +80,26 @@
     virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const OVERRIDE;
     virtual void parseAttribute(const Attribute&) OVERRIDE;
 
+    virtual void attach() OVERRIDE;
+
     void didElementStateChange();
     void createShadowSubtree();
 
     RefPtr<MeterValueElement> m_value;
+    bool m_hasAuthorShadowRoot;
 };
 
+inline bool isHTMLMeterElement(Node* node)
+{
+    return node->hasTagName(HTMLNames::meterTag);
+}
+
+inline HTMLMeterElement* toHTMLMeterElement(Node* node)
+{
+    ASSERT(!node || isHTMLMeterElement(node));
+    return static_cast<HTMLMeterElement*>(node);
+}
+
 } // namespace
 
 #endif
diff --git a/Source/WebCore/html/shadow/MeterShadowElement.cpp b/Source/WebCore/html/shadow/MeterShadowElement.cpp
index 3101bd1..441f013 100644
--- a/Source/WebCore/html/shadow/MeterShadowElement.cpp
+++ b/Source/WebCore/html/shadow/MeterShadowElement.cpp
@@ -37,6 +37,7 @@
 #include "HTMLNames.h"
 #include "RenderMeter.h"
 #include "RenderTheme.h"
+#include "ShadowRoot.h"
 #include "StylePropertySet.h"
 
 namespace WebCore {
@@ -50,15 +51,38 @@
 
 HTMLMeterElement* MeterShadowElement::meterElement() const
 {
-    Element* element = shadowHost();
-    ASSERT(!element || element->hasTagName(meterTag));
-    return static_cast<HTMLMeterElement*>(element);
+    return toHTMLMeterElement(shadowHost());
 }
 
 bool MeterShadowElement::rendererIsNeeded(const NodeRenderingContext& context)
 {
-    RenderMeter* meterRenderer = toRenderMeter(meterElement()->renderer());
-    return meterRenderer && !meterRenderer->theme()->supportsMeter(meterRenderer->style()->appearance()) && HTMLDivElement::rendererIsNeeded(context);
+    RenderObject* render = meterElement()->renderer();
+    return render && !render->theme()->supportsMeter(render->style()->appearance()) && HTMLDivElement::rendererIsNeeded(context);
+}
+
+MeterInnerElement::MeterInnerElement(Document* document)
+    : MeterShadowElement(document)
+{
+}
+
+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& MeterInnerElement::shadowPseudoId() const
+{
+    DEFINE_STATIC_LOCAL(AtomicString, pseudId, ("-webkit-meter-inner-element"));
+    return pseudId;
 }
 
 const AtomicString& MeterBarElement::shadowPseudoId() const
@@ -67,7 +91,6 @@
     return pseudId;
 }
 
-
 const AtomicString& MeterValueElement::shadowPseudoId() const
 {
     DEFINE_STATIC_LOCAL(AtomicString, optimumPseudId, ("-webkit-meter-optimum-value"));
diff --git a/Source/WebCore/html/shadow/MeterShadowElement.h b/Source/WebCore/html/shadow/MeterShadowElement.h
index 6b8bf62..b67e0c1 100644
--- a/Source/WebCore/html/shadow/MeterShadowElement.h
+++ b/Source/WebCore/html/shadow/MeterShadowElement.h
@@ -38,6 +38,7 @@
 namespace WebCore {
 
 class HTMLMeterElement;
+class RenderMeter;
 
 class MeterShadowElement : public HTMLDivElement {
 public:
@@ -48,6 +49,22 @@
     virtual bool rendererIsNeeded(const NodeRenderingContext&);
 };
 
+class MeterInnerElement : public MeterShadowElement {
+public:
+    MeterInnerElement(Document*);
+    static PassRefPtr<MeterInnerElement> create(Document*);
+
+private:
+    virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE;
+    virtual const AtomicString& shadowPseudoId() const OVERRIDE;
+};
+
+inline PassRefPtr<MeterInnerElement> MeterInnerElement::create(Document* document)
+{
+    return adoptRef(new MeterInnerElement(document));
+}
+
 class MeterBarElement : public MeterShadowElement {
 public:
     MeterBarElement(Document* document) 
@@ -64,7 +81,6 @@
     return adoptRef(new MeterBarElement(document));
 }
 
-
 class MeterValueElement : public MeterShadowElement {
 public:
     MeterValueElement(Document* document) 
diff --git a/Source/WebCore/rendering/RenderMeter.cpp b/Source/WebCore/rendering/RenderMeter.cpp
index 93b0172..497bef9 100644
--- a/Source/WebCore/rendering/RenderMeter.cpp
+++ b/Source/WebCore/rendering/RenderMeter.cpp
@@ -32,7 +32,7 @@
 
 using namespace HTMLNames;
 
-RenderMeter::RenderMeter(HTMLMeterElement* element)
+RenderMeter::RenderMeter(HTMLElement* element)
     : RenderBlock(element)
 {
 }
@@ -41,6 +41,17 @@
 {
 }
 
+HTMLMeterElement* RenderMeter::meterElement() const
+{
+    ASSERT(node());
+
+    if (isHTMLMeterElement(node()))
+        return toHTMLMeterElement(node());
+
+    ASSERT(node()->shadowHost());
+    return toHTMLMeterElement(node()->shadowHost());
+}
+
 void RenderMeter::computeLogicalWidth()
 {
     RenderBox::computeLogicalWidth();
@@ -55,7 +66,7 @@
 
 double RenderMeter::valueRatio() const
 {
-    return static_cast<HTMLMeterElement*>(node())->valueRatio();
+    return meterElement()->valueRatio();
 }
 
 void RenderMeter::updateFromElement()
diff --git a/Source/WebCore/rendering/RenderMeter.h b/Source/WebCore/rendering/RenderMeter.h
index 7306cae..34909ee 100644
--- a/Source/WebCore/rendering/RenderMeter.h
+++ b/Source/WebCore/rendering/RenderMeter.h
@@ -32,17 +32,19 @@
 
 class RenderMeter : public RenderBlock {
 public:
-    RenderMeter(HTMLMeterElement*);
+    RenderMeter(HTMLElement*);
     virtual ~RenderMeter();
 
-private:
+    HTMLMeterElement* meterElement() const;
+    virtual void updateFromElement();
+
+private:    
     virtual void computeLogicalWidth();
     virtual void computeLogicalHeight();
 
     virtual const char* renderName() const { return "RenderMeter"; }
     virtual bool isMeter() const { return true; }
     virtual bool requiresForcedStyleRecalcPropagation() const { return true; }
-    virtual void updateFromElement();
 
     double valueRatio() const;
 };
diff --git a/Source/WebCore/rendering/RenderThemeMac.mm b/Source/WebCore/rendering/RenderThemeMac.mm
index 25b03b7..0bc9804 100644
--- a/Source/WebCore/rendering/RenderThemeMac.mm
+++ b/Source/WebCore/rendering/RenderThemeMac.mm
@@ -926,7 +926,7 @@
         m_levelIndicator.adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
     NSLevelIndicatorCell* cell = m_levelIndicator.get();
 
-    HTMLMeterElement* element = static_cast<HTMLMeterElement*>(renderMeter->node());
+    HTMLMeterElement* element = renderMeter->meterElement();
     double value = element->value();
 
     // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,