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,