Pass Attribute by const reference as much as possible.
[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.isOnUpperEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext);
67 }
68
69 bool HTMLMeterElement::supportsFocus() const
70 {
71     return Node::supportsFocus() && !disabled();
72 }
73
74 void HTMLMeterElement::parseAttribute(const 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 double HTMLMeterElement::min() const
83 {
84     double min = 0;
85     parseToDoubleForNumberType(getAttribute(minAttr), &min);
86     return min;
87 }
88
89 void HTMLMeterElement::setMin(double min, ExceptionCode& ec)
90 {
91     if (!isfinite(min)) {
92         ec = NOT_SUPPORTED_ERR;
93         return;
94     }
95     setAttribute(minAttr, String::number(min));
96 }
97
98 double HTMLMeterElement::max() const
99 {
100     double max = std::max(1.0, min());
101     parseToDoubleForNumberType(getAttribute(maxAttr), &max);
102     return std::max(max, min());
103 }
104
105 void HTMLMeterElement::setMax(double max, ExceptionCode& ec)
106 {
107     if (!isfinite(max)) {
108         ec = NOT_SUPPORTED_ERR;
109         return;
110     }
111     setAttribute(maxAttr, String::number(max));
112 }
113
114 double HTMLMeterElement::value() const
115 {
116     double value = 0;
117     parseToDoubleForNumberType(getAttribute(valueAttr), &value);
118     return std::min(std::max(value, min()), max());
119 }
120
121 void HTMLMeterElement::setValue(double value, ExceptionCode& ec)
122 {
123     if (!isfinite(value)) {
124         ec = NOT_SUPPORTED_ERR;
125         return;
126     }
127     setAttribute(valueAttr, String::number(value));
128 }
129
130 double HTMLMeterElement::low() const
131 {
132     double low = min();
133     parseToDoubleForNumberType(getAttribute(lowAttr), &low);
134     return std::min(std::max(low, min()), max());
135 }
136
137 void HTMLMeterElement::setLow(double low, ExceptionCode& ec)
138 {
139     if (!isfinite(low)) {
140         ec = NOT_SUPPORTED_ERR;
141         return;
142     }
143     setAttribute(lowAttr, String::number(low));
144 }
145
146 double HTMLMeterElement::high() const
147 {
148     double high = max();
149     parseToDoubleForNumberType(getAttribute(highAttr), &high);
150     return std::min(std::max(high, low()), max());
151 }
152
153 void HTMLMeterElement::setHigh(double high, ExceptionCode& ec)
154 {
155     if (!isfinite(high)) {
156         ec = NOT_SUPPORTED_ERR;
157         return;
158     }
159     setAttribute(highAttr, String::number(high));
160 }
161
162 double HTMLMeterElement::optimum() const
163 {
164     double optimum = (max() + min()) / 2;
165     parseToDoubleForNumberType(getAttribute(optimumAttr), &optimum);
166     return std::min(std::max(optimum, min()), max());
167 }
168
169 void HTMLMeterElement::setOptimum(double optimum, ExceptionCode& ec)
170 {
171     if (!isfinite(optimum)) {
172         ec = NOT_SUPPORTED_ERR;
173         return;
174     }
175     setAttribute(optimumAttr, String::number(optimum));
176 }
177
178 HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const
179 {
180     double lowValue = low();
181     double highValue = high();
182     double theValue = value();
183     double optimumValue = optimum();
184
185     if (optimumValue < lowValue) {
186         // The optimum range stays under low
187         if (theValue <= lowValue)
188             return GaugeRegionOptimum;
189         if (theValue <= highValue)
190             return GaugeRegionSuboptimal;
191         return GaugeRegionEvenLessGood;
192     }
193     
194     if (highValue < optimumValue) {
195         // The optimum range stays over high
196         if (highValue <= theValue)
197             return GaugeRegionOptimum;
198         if (lowValue <= theValue)
199             return GaugeRegionSuboptimal;
200         return GaugeRegionEvenLessGood;
201     }
202
203     // The optimum range stays between high and low.
204     // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case
205     // because the value is never less or greater than min or max.
206     if (lowValue <= theValue && theValue <= highValue)
207         return GaugeRegionOptimum;
208     return GaugeRegionSuboptimal;
209 }
210
211 double HTMLMeterElement::valueRatio() const
212 {
213     double min = this->min();
214     double max = this->max();
215     double value = this->value();
216
217     if (max <= min)
218         return 0;
219     return (value - min) / (max - min);
220 }
221
222 void HTMLMeterElement::didElementStateChange()
223 {
224     m_value->setWidthPercentage(valueRatio()*100);
225     if (RenderObject* render = renderer())
226         render->updateFromElement();
227 }
228
229 void HTMLMeterElement::createShadowSubtree()
230 {
231     ASSERT(!shadow());
232
233     RefPtr<MeterBarElement> bar = MeterBarElement::create(document());
234     m_value = MeterValueElement::create(document());
235     m_value->setWidthPercentage(0);
236     ExceptionCode ec = 0;
237     bar->appendChild(m_value, ec);
238
239     RefPtr<ShadowRoot> root = ShadowRoot::create(this, ShadowRoot::CreatingUserAgentShadowRoot);
240     root->appendChild(bar, ec);
241 }
242
243 } // namespace
244 #endif