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_TAG)
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 "RenderMeter.h"
34 #include "ShadowRoot.h"
35 #include <wtf/StdLibExtras.h>
36
37 namespace WebCore {
38
39 using namespace HTMLNames;
40
HTMLMeterElement(const QualifiedName & tagName,Document * document,HTMLFormElement * form)41 HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
42 : HTMLFormControlElement(tagName, document, form)
43 {
44 ASSERT(hasTagName(meterTag));
45 }
46
~HTMLMeterElement()47 HTMLMeterElement::~HTMLMeterElement()
48 {
49 }
50
create(const QualifiedName & tagName,Document * document,HTMLFormElement * form)51 PassRefPtr<HTMLMeterElement> HTMLMeterElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
52 {
53 RefPtr<HTMLMeterElement> meter = adoptRef(new HTMLMeterElement(tagName, document, form));
54 meter->createShadowSubtree();
55 return meter;
56 }
57
createRenderer(RenderArena * arena,RenderStyle *)58 RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle*)
59 {
60 return new (arena) RenderMeter(this);
61 }
62
formControlType() const63 const AtomicString& HTMLMeterElement::formControlType() const
64 {
65 DEFINE_STATIC_LOCAL(const AtomicString, meter, ("meter"));
66 return meter;
67 }
68
parseMappedAttribute(Attribute * attribute)69 void HTMLMeterElement::parseMappedAttribute(Attribute* attribute)
70 {
71 if (attribute->name() == valueAttr || attribute->name() == minAttr || attribute->name() == maxAttr || attribute->name() == lowAttr || attribute->name() == highAttr || attribute->name() == optimumAttr)
72 didElementStateChange();
73 else
74 HTMLFormControlElement::parseMappedAttribute(attribute);
75 }
76
attach()77 void HTMLMeterElement::attach()
78 {
79 HTMLFormControlElement::attach();
80 didElementStateChange();
81 }
82
min() const83 double HTMLMeterElement::min() const
84 {
85 double min = 0;
86 parseToDoubleForNumberType(getAttribute(minAttr), &min);
87 return min;
88 }
89
setMin(double min,ExceptionCode & ec)90 void HTMLMeterElement::setMin(double min, ExceptionCode& ec)
91 {
92 if (!isfinite(min)) {
93 ec = NOT_SUPPORTED_ERR;
94 return;
95 }
96 setAttribute(minAttr, String::number(min));
97 }
98
max() const99 double HTMLMeterElement::max() const
100 {
101 double max = std::max(1.0, min());
102 parseToDoubleForNumberType(getAttribute(maxAttr), &max);
103 return std::max(max, min());
104 }
105
setMax(double max,ExceptionCode & ec)106 void HTMLMeterElement::setMax(double max, ExceptionCode& ec)
107 {
108 if (!isfinite(max)) {
109 ec = NOT_SUPPORTED_ERR;
110 return;
111 }
112 setAttribute(maxAttr, String::number(max));
113 }
114
value() const115 double HTMLMeterElement::value() const
116 {
117 double value = 0;
118 parseToDoubleForNumberType(getAttribute(valueAttr), &value);
119 return std::min(std::max(value, min()), max());
120 }
121
setValue(double value,ExceptionCode & ec)122 void HTMLMeterElement::setValue(double value, ExceptionCode& ec)
123 {
124 if (!isfinite(value)) {
125 ec = NOT_SUPPORTED_ERR;
126 return;
127 }
128 setAttribute(valueAttr, String::number(value));
129 }
130
low() const131 double HTMLMeterElement::low() const
132 {
133 double low = min();
134 parseToDoubleForNumberType(getAttribute(lowAttr), &low);
135 return std::min(std::max(low, min()), max());
136 }
137
setLow(double low,ExceptionCode & ec)138 void HTMLMeterElement::setLow(double low, ExceptionCode& ec)
139 {
140 if (!isfinite(low)) {
141 ec = NOT_SUPPORTED_ERR;
142 return;
143 }
144 setAttribute(lowAttr, String::number(low));
145 }
146
high() const147 double HTMLMeterElement::high() const
148 {
149 double high = max();
150 parseToDoubleForNumberType(getAttribute(highAttr), &high);
151 return std::min(std::max(high, low()), max());
152 }
153
setHigh(double high,ExceptionCode & ec)154 void HTMLMeterElement::setHigh(double high, ExceptionCode& ec)
155 {
156 if (!isfinite(high)) {
157 ec = NOT_SUPPORTED_ERR;
158 return;
159 }
160 setAttribute(highAttr, String::number(high));
161 }
162
optimum() const163 double HTMLMeterElement::optimum() const
164 {
165 double optimum = (max() + min()) / 2;
166 parseToDoubleForNumberType(getAttribute(optimumAttr), &optimum);
167 return std::min(std::max(optimum, min()), max());
168 }
169
setOptimum(double optimum,ExceptionCode & ec)170 void HTMLMeterElement::setOptimum(double optimum, ExceptionCode& ec)
171 {
172 if (!isfinite(optimum)) {
173 ec = NOT_SUPPORTED_ERR;
174 return;
175 }
176 setAttribute(optimumAttr, String::number(optimum));
177 }
178
gaugeRegion() const179 HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const
180 {
181 double lowValue = low();
182 double highValue = high();
183 double theValue = value();
184 double optimumValue = optimum();
185
186 if (optimumValue < lowValue) {
187 // The optimum range stays under low
188 if (theValue <= lowValue)
189 return GaugeRegionOptimum;
190 if (theValue <= highValue)
191 return GaugeRegionSuboptimal;
192 return GaugeRegionEvenLessGood;
193 }
194
195 if (highValue < optimumValue) {
196 // The optimum range stays over high
197 if (highValue <= theValue)
198 return GaugeRegionOptimum;
199 if (lowValue <= theValue)
200 return GaugeRegionSuboptimal;
201 return GaugeRegionEvenLessGood;
202 }
203
204 // The optimum range stays between high and low.
205 // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case
206 // because the value is never less or greater than min or max.
207 if (lowValue <= theValue && theValue <= highValue)
208 return GaugeRegionOptimum;
209 return GaugeRegionSuboptimal;
210 }
211
valueRatio() const212 double HTMLMeterElement::valueRatio() const
213 {
214 double min = this->min();
215 double max = this->max();
216 double value = this->value();
217
218 if (max <= min)
219 return 0;
220 return (value - min) / (max - min);
221 }
222
didElementStateChange()223 void HTMLMeterElement::didElementStateChange()
224 {
225 m_value->setWidthPercentage(valueRatio()*100);
226 }
227
createShadowSubtree()228 void HTMLMeterElement::createShadowSubtree()
229 {
230 RefPtr<MeterBarElement> bar = MeterBarElement::create(document());
231 m_value = MeterValueElement::create(document());
232 ExceptionCode ec = 0;
233 bar->appendChild(m_value, ec);
234 ensureShadowRoot()->appendChild(bar, ec);
235 }
236
237 } // namespace
238 #endif
239