[Forms] The "meter" element should not be a form-associated element.
[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_TAG)
23 #include "HTMLMeterElement.h"
24
25 #include "Attribute.h"
26 #include "EventNames.h"
27 #include "ExceptionCode.h"
28 #include "FormDataList.h"
29 #include "NodeRenderingContext.h"
30 #include "HTMLFormElement.h"
31 #include "HTMLNames.h"
32 #include "HTMLParserIdioms.h"
33 #include "MeterShadowElement.h"
34 #include "RenderMeter.h"
35 #include "ShadowRoot.h"
36 #include <wtf/StdLibExtras.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->createShadowSubtree();
56     return meter;
57 }
58
59 RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle*)
60 {
61     return new (arena) RenderMeter(this);
62 }
63
64 bool HTMLMeterElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
65 {
66     return childContext.isOnEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext);
67 }
68
69 bool HTMLMeterElement::supportsFocus() const
70 {
71     return Node::supportsFocus() && !disabled();
72 }
73
74 void HTMLMeterElement::parseAttribute(Attribute* attribute)
75 {
76     if (attribute->name() == valueAttr || attribute->name() == minAttr || attribute->name() == maxAttr || attribute->name() == lowAttr || attribute->name() == highAttr || attribute->name() == optimumAttr)
77         didElementStateChange();
78     else
79         LabelableElement::parseAttribute(attribute);
80 }
81
82 void HTMLMeterElement::attach()
83 {
84     LabelableElement::attach();
85     didElementStateChange();
86 }
87
88 double HTMLMeterElement::min() const
89 {
90     double min = 0;
91     parseToDoubleForNumberType(getAttribute(minAttr), &min);
92     return min;
93 }
94
95 void HTMLMeterElement::setMin(double min, ExceptionCode& ec)
96 {
97     if (!isfinite(min)) {
98         ec = NOT_SUPPORTED_ERR;
99         return;
100     }
101     setAttribute(minAttr, String::number(min));
102 }
103
104 double HTMLMeterElement::max() const
105 {
106     double max = std::max(1.0, min());
107     parseToDoubleForNumberType(getAttribute(maxAttr), &max);
108     return std::max(max, min());
109 }
110
111 void HTMLMeterElement::setMax(double max, ExceptionCode& ec)
112 {
113     if (!isfinite(max)) {
114         ec = NOT_SUPPORTED_ERR;
115         return;
116     }
117     setAttribute(maxAttr, String::number(max));
118 }
119
120 double HTMLMeterElement::value() const
121 {
122     double value = 0;
123     parseToDoubleForNumberType(getAttribute(valueAttr), &value);
124     return std::min(std::max(value, min()), max());
125 }
126
127 void HTMLMeterElement::setValue(double value, ExceptionCode& ec)
128 {
129     if (!isfinite(value)) {
130         ec = NOT_SUPPORTED_ERR;
131         return;
132     }
133     setAttribute(valueAttr, String::number(value));
134 }
135
136 double HTMLMeterElement::low() const
137 {
138     double low = min();
139     parseToDoubleForNumberType(getAttribute(lowAttr), &low);
140     return std::min(std::max(low, min()), max());
141 }
142
143 void HTMLMeterElement::setLow(double low, ExceptionCode& ec)
144 {
145     if (!isfinite(low)) {
146         ec = NOT_SUPPORTED_ERR;
147         return;
148     }
149     setAttribute(lowAttr, String::number(low));
150 }
151
152 double HTMLMeterElement::high() const
153 {
154     double high = max();
155     parseToDoubleForNumberType(getAttribute(highAttr), &high);
156     return std::min(std::max(high, low()), max());
157 }
158
159 void HTMLMeterElement::setHigh(double high, ExceptionCode& ec)
160 {
161     if (!isfinite(high)) {
162         ec = NOT_SUPPORTED_ERR;
163         return;
164     }
165     setAttribute(highAttr, String::number(high));
166 }
167
168 double HTMLMeterElement::optimum() const
169 {
170     double optimum = (max() + min()) / 2;
171     parseToDoubleForNumberType(getAttribute(optimumAttr), &optimum);
172     return std::min(std::max(optimum, min()), max());
173 }
174
175 void HTMLMeterElement::setOptimum(double optimum, ExceptionCode& ec)
176 {
177     if (!isfinite(optimum)) {
178         ec = NOT_SUPPORTED_ERR;
179         return;
180     }
181     setAttribute(optimumAttr, String::number(optimum));
182 }
183
184 HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const
185 {
186     double lowValue = low();
187     double highValue = high();
188     double theValue = value();
189     double optimumValue = optimum();
190
191     if (optimumValue < lowValue) {
192         // The optimum range stays under low
193         if (theValue <= lowValue)
194             return GaugeRegionOptimum;
195         if (theValue <= highValue)
196             return GaugeRegionSuboptimal;
197         return GaugeRegionEvenLessGood;
198     }
199     
200     if (highValue < optimumValue) {
201         // The optimum range stays over high
202         if (highValue <= theValue)
203             return GaugeRegionOptimum;
204         if (lowValue <= theValue)
205             return GaugeRegionSuboptimal;
206         return GaugeRegionEvenLessGood;
207     }
208
209     // The optimum range stays between high and low.
210     // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case
211     // because the value is never less or greater than min or max.
212     if (lowValue <= theValue && theValue <= highValue)
213         return GaugeRegionOptimum;
214     return GaugeRegionSuboptimal;
215 }
216
217 double HTMLMeterElement::valueRatio() const
218 {
219     double min = this->min();
220     double max = this->max();
221     double value = this->value();
222
223     if (max <= min)
224         return 0;
225     return (value - min) / (max - min);
226 }
227
228 void HTMLMeterElement::didElementStateChange()
229 {
230     m_value->setWidthPercentage(valueRatio()*100);
231     if (RenderObject* render = renderer())
232         render->updateFromElement();
233 }
234
235 void HTMLMeterElement::createShadowSubtree()
236 {
237     ASSERT(!hasShadowRoot());
238
239     RefPtr<MeterBarElement> bar = MeterBarElement::create(document());
240     m_value = MeterValueElement::create(document());
241     ExceptionCode ec = 0;
242     bar->appendChild(m_value, ec);
243
244     RefPtr<ShadowRoot> root = ShadowRoot::create(this, ShadowRoot::CreatingUserAgentShadowRoot);
245     root->appendChild(bar, ec);
246 }
247
248 } // namespace
249 #endif