<https://webkit.org/b/120071> Replace NodeRenderingContext with Node* as childShouldC...
[WebKit-https.git] / Source / WebCore / html / HTMLMeterElement.cpp
1 /*
2  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #include "config.h"
22 #if ENABLE(METER_ELEMENT)
23 #include "HTMLMeterElement.h"
24
25 #include "Attribute.h"
26 #include "EventNames.h"
27 #include "ExceptionCode.h"
28 #include "FormDataList.h"
29 #include "HTMLFormElement.h"
30 #include "HTMLNames.h"
31 #include "HTMLParserIdioms.h"
32 #include "MeterShadowElement.h"
33 #include "Page.h"
34 #include "RenderMeter.h"
35 #include "RenderTheme.h"
36 #include "ShadowRoot.h"
37
38 namespace WebCore {
39
40 using namespace HTMLNames;
41
42 HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document)
43     : LabelableElement(tagName, document)
44 {
45     ASSERT(hasTagName(meterTag));
46 }
47
48 HTMLMeterElement::~HTMLMeterElement()
49 {
50 }
51
52 PassRefPtr<HTMLMeterElement> HTMLMeterElement::create(const QualifiedName& tagName, Document* document)
53 {
54     RefPtr<HTMLMeterElement> meter = adoptRef(new HTMLMeterElement(tagName, document));
55     meter->ensureUserAgentShadowRoot();
56     return meter;
57 }
58
59 RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle* style)
60 {
61     if (hasAuthorShadowRoot() || !document()->page()->theme()->supportsMeter(style->appearance()))
62         return RenderObject::createObject(this, style);
63
64     return new (arena) RenderMeter(this);
65 }
66
67 bool HTMLMeterElement::childShouldCreateRenderer(const Node* child) const
68 {
69     return hasShadowRootParent(child) && HTMLElement::childShouldCreateRenderer(child);
70 }
71
72 void HTMLMeterElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
73 {
74     if (name == valueAttr || name == minAttr || name == maxAttr || name == lowAttr || name == highAttr || name == optimumAttr)
75         didElementStateChange();
76     else
77         LabelableElement::parseAttribute(name, value);
78 }
79
80 double HTMLMeterElement::min() const
81 {
82     return parseToDoubleForNumberType(getAttribute(minAttr), 0);
83 }
84
85 void HTMLMeterElement::setMin(double min, ExceptionCode& ec)
86 {
87     if (!std::isfinite(min)) {
88         ec = NOT_SUPPORTED_ERR;
89         return;
90     }
91     setAttribute(minAttr, String::number(min));
92 }
93
94 double HTMLMeterElement::max() const
95 {
96     return std::max(parseToDoubleForNumberType(getAttribute(maxAttr), std::max(1.0, min())), min());
97 }
98
99 void HTMLMeterElement::setMax(double max, ExceptionCode& ec)
100 {
101     if (!std::isfinite(max)) {
102         ec = NOT_SUPPORTED_ERR;
103         return;
104     }
105     setAttribute(maxAttr, String::number(max));
106 }
107
108 double HTMLMeterElement::value() const
109 {
110     double value = parseToDoubleForNumberType(getAttribute(valueAttr), 0);
111     return std::min(std::max(value, min()), max());
112 }
113
114 void HTMLMeterElement::setValue(double value, ExceptionCode& ec)
115 {
116     if (!std::isfinite(value)) {
117         ec = NOT_SUPPORTED_ERR;
118         return;
119     }
120     setAttribute(valueAttr, String::number(value));
121 }
122
123 double HTMLMeterElement::low() const
124 {
125     double low = parseToDoubleForNumberType(getAttribute(lowAttr), min());
126     return std::min(std::max(low, min()), max());
127 }
128
129 void HTMLMeterElement::setLow(double low, ExceptionCode& ec)
130 {
131     if (!std::isfinite(low)) {
132         ec = NOT_SUPPORTED_ERR;
133         return;
134     }
135     setAttribute(lowAttr, String::number(low));
136 }
137
138 double HTMLMeterElement::high() const
139 {
140     double high = parseToDoubleForNumberType(getAttribute(highAttr), max());
141     return std::min(std::max(high, low()), max());
142 }
143
144 void HTMLMeterElement::setHigh(double high, ExceptionCode& ec)
145 {
146     if (!std::isfinite(high)) {
147         ec = NOT_SUPPORTED_ERR;
148         return;
149     }
150     setAttribute(highAttr, String::number(high));
151 }
152
153 double HTMLMeterElement::optimum() const
154 {
155     double optimum = parseToDoubleForNumberType(getAttribute(optimumAttr), (max() + min()) / 2);
156     return std::min(std::max(optimum, min()), max());
157 }
158
159 void HTMLMeterElement::setOptimum(double optimum, ExceptionCode& ec)
160 {
161     if (!std::isfinite(optimum)) {
162         ec = NOT_SUPPORTED_ERR;
163         return;
164     }
165     setAttribute(optimumAttr, String::number(optimum));
166 }
167
168 HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const
169 {
170     double lowValue = low();
171     double highValue = high();
172     double theValue = value();
173     double optimumValue = optimum();
174
175     if (optimumValue < lowValue) {
176         // The optimum range stays under low
177         if (theValue <= lowValue)
178             return GaugeRegionOptimum;
179         if (theValue <= highValue)
180             return GaugeRegionSuboptimal;
181         return GaugeRegionEvenLessGood;
182     }
183     
184     if (highValue < optimumValue) {
185         // The optimum range stays over high
186         if (highValue <= theValue)
187             return GaugeRegionOptimum;
188         if (lowValue <= theValue)
189             return GaugeRegionSuboptimal;
190         return GaugeRegionEvenLessGood;
191     }
192
193     // The optimum range stays between high and low.
194     // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case
195     // because the value is never less or greater than min or max.
196     if (lowValue <= theValue && theValue <= highValue)
197         return GaugeRegionOptimum;
198     return GaugeRegionSuboptimal;
199 }
200
201 double HTMLMeterElement::valueRatio() const
202 {
203     double min = this->min();
204     double max = this->max();
205     double value = this->value();
206
207     if (max <= min)
208         return 0;
209     return (value - min) / (max - min);
210 }
211
212 void HTMLMeterElement::didElementStateChange()
213 {
214     m_value->setWidthPercentage(valueRatio()*100);
215     m_value->updatePseudo();
216     if (RenderMeter* render = renderMeter())
217         render->updateFromElement();
218 }
219
220 RenderMeter* HTMLMeterElement::renderMeter() const
221 {
222     if (renderer() && renderer()->isMeter())
223         return static_cast<RenderMeter*>(renderer());
224
225     RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer();
226     ASSERT(!renderObject || renderObject->isMeter());
227     return static_cast<RenderMeter*>(renderObject);
228 }
229
230 void HTMLMeterElement::didAddUserAgentShadowRoot(ShadowRoot* root)
231 {
232     ASSERT(!m_value);
233
234     RefPtr<MeterInnerElement> inner = MeterInnerElement::create(document());
235     root->appendChild(inner);
236
237     RefPtr<MeterBarElement> bar = MeterBarElement::create(document());
238     m_value = MeterValueElement::create(document());
239     m_value->setWidthPercentage(0);
240     m_value->updatePseudo();
241     bar->appendChild(m_value, ASSERT_NO_EXCEPTION);
242
243     inner->appendChild(bar, ASSERT_NO_EXCEPTION);
244 }
245
246 } // namespace
247 #endif