Stop placing std::isfinite and std::signbit inside the global scope
[WebKit.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 "NodeRenderingContext.h"
30 #include "HTMLFormElement.h"
31 #include "HTMLNames.h"
32 #include "HTMLParserIdioms.h"
33 #include "MeterShadowElement.h"
34 #include "Page.h"
35 #include "RenderMeter.h"
36 #include "RenderTheme.h"
37 #include "ShadowRoot.h"
38 #include <wtf/StdLibExtras.h>
39
40 namespace WebCore {
41
42 using namespace HTMLNames;
43
44 HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document)
45     : LabelableElement(tagName, document)
46 {
47     ASSERT(hasTagName(meterTag));
48 }
49
50 HTMLMeterElement::~HTMLMeterElement()
51 {
52 }
53
54 PassRefPtr<HTMLMeterElement> HTMLMeterElement::create(const QualifiedName& tagName, Document* document)
55 {
56     RefPtr<HTMLMeterElement> meter = adoptRef(new HTMLMeterElement(tagName, document));
57     meter->ensureUserAgentShadowRoot();
58     return meter;
59 }
60
61 RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle* style)
62 {
63     if (hasAuthorShadowRoot() || !document()->page()->theme()->supportsMeter(style->appearance()))
64         return RenderObject::createObject(this, style);
65
66     return new (arena) RenderMeter(this);
67 }
68
69 bool HTMLMeterElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
70 {
71     return childContext.isOnUpperEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext);
72 }
73
74 bool HTMLMeterElement::supportsFocus() const
75 {
76     return HTMLElement::supportsFocus() && !disabled();
77 }
78
79 void HTMLMeterElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
80 {
81     if (name == valueAttr || name == minAttr || name == maxAttr || name == lowAttr || name == highAttr || name == optimumAttr)
82         didElementStateChange();
83     else
84         LabelableElement::parseAttribute(name, value);
85 }
86
87 double HTMLMeterElement::min() const
88 {
89     return parseToDoubleForNumberType(getAttribute(minAttr), 0);
90 }
91
92 void HTMLMeterElement::setMin(double min, ExceptionCode& ec)
93 {
94     if (!std::isfinite(min)) {
95         ec = NOT_SUPPORTED_ERR;
96         return;
97     }
98     setAttribute(minAttr, String::number(min));
99 }
100
101 double HTMLMeterElement::max() const
102 {
103     return std::max(parseToDoubleForNumberType(getAttribute(maxAttr), std::max(1.0, min())), min());
104 }
105
106 void HTMLMeterElement::setMax(double max, ExceptionCode& ec)
107 {
108     if (!std::isfinite(max)) {
109         ec = NOT_SUPPORTED_ERR;
110         return;
111     }
112     setAttribute(maxAttr, String::number(max));
113 }
114
115 double HTMLMeterElement::value() const
116 {
117     double value = parseToDoubleForNumberType(getAttribute(valueAttr), 0);
118     return std::min(std::max(value, min()), max());
119 }
120
121 void HTMLMeterElement::setValue(double value, ExceptionCode& ec)
122 {
123     if (!std::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 = parseToDoubleForNumberType(getAttribute(lowAttr), min());
133     return std::min(std::max(low, min()), max());
134 }
135
136 void HTMLMeterElement::setLow(double low, ExceptionCode& ec)
137 {
138     if (!std::isfinite(low)) {
139         ec = NOT_SUPPORTED_ERR;
140         return;
141     }
142     setAttribute(lowAttr, String::number(low));
143 }
144
145 double HTMLMeterElement::high() const
146 {
147     double high = parseToDoubleForNumberType(getAttribute(highAttr), max());
148     return std::min(std::max(high, low()), max());
149 }
150
151 void HTMLMeterElement::setHigh(double high, ExceptionCode& ec)
152 {
153     if (!std::isfinite(high)) {
154         ec = NOT_SUPPORTED_ERR;
155         return;
156     }
157     setAttribute(highAttr, String::number(high));
158 }
159
160 double HTMLMeterElement::optimum() const
161 {
162     double optimum = parseToDoubleForNumberType(getAttribute(optimumAttr), (max() + min()) / 2);
163     return std::min(std::max(optimum, min()), max());
164 }
165
166 void HTMLMeterElement::setOptimum(double optimum, ExceptionCode& ec)
167 {
168     if (!std::isfinite(optimum)) {
169         ec = NOT_SUPPORTED_ERR;
170         return;
171     }
172     setAttribute(optimumAttr, String::number(optimum));
173 }
174
175 HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const
176 {
177     double lowValue = low();
178     double highValue = high();
179     double theValue = value();
180     double optimumValue = optimum();
181
182     if (optimumValue < lowValue) {
183         // The optimum range stays under low
184         if (theValue <= lowValue)
185             return GaugeRegionOptimum;
186         if (theValue <= highValue)
187             return GaugeRegionSuboptimal;
188         return GaugeRegionEvenLessGood;
189     }
190     
191     if (highValue < optimumValue) {
192         // The optimum range stays over high
193         if (highValue <= theValue)
194             return GaugeRegionOptimum;
195         if (lowValue <= theValue)
196             return GaugeRegionSuboptimal;
197         return GaugeRegionEvenLessGood;
198     }
199
200     // The optimum range stays between high and low.
201     // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case
202     // because the value is never less or greater than min or max.
203     if (lowValue <= theValue && theValue <= highValue)
204         return GaugeRegionOptimum;
205     return GaugeRegionSuboptimal;
206 }
207
208 double HTMLMeterElement::valueRatio() const
209 {
210     double min = this->min();
211     double max = this->max();
212     double value = this->value();
213
214     if (max <= min)
215         return 0;
216     return (value - min) / (max - min);
217 }
218
219 void HTMLMeterElement::didElementStateChange()
220 {
221     m_value->setWidthPercentage(valueRatio()*100);
222     m_value->updatePseudo();
223     if (RenderMeter* render = renderMeter())
224         render->updateFromElement();
225 }
226
227 RenderMeter* HTMLMeterElement::renderMeter() const
228 {
229     if (renderer() && renderer()->isMeter())
230         return static_cast<RenderMeter*>(renderer());
231
232     RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer();
233     ASSERT(!renderObject || renderObject->isMeter());
234     return static_cast<RenderMeter*>(renderObject);
235 }
236
237 void HTMLMeterElement::didAddUserAgentShadowRoot(ShadowRoot* root)
238 {
239     ASSERT(!m_value);
240
241     RefPtr<MeterInnerElement> inner = MeterInnerElement::create(document());
242     root->appendChild(inner);
243
244     RefPtr<MeterBarElement> bar = MeterBarElement::create(document());
245     m_value = MeterValueElement::create(document());
246     m_value->setWidthPercentage(0);
247     m_value->updatePseudo();
248     bar->appendChild(m_value, ASSERT_NO_EXCEPTION);
249
250     inner->appendChild(bar, ASSERT_NO_EXCEPTION);
251 }
252
253 } // namespace
254 #endif