Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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
23 #include "core/html/HTMLMeterElement.h"
24
25 #include "HTMLNames.h"
26 #include "bindings/v8/ExceptionMessages.h"
27 #include "bindings/v8/ExceptionState.h"
28 #include "bindings/v8/ExceptionStatePlaceholder.h"
29 #include "core/dom/ExceptionCode.h"
30 #include "core/dom/shadow/ShadowRoot.h"
31 #include "core/html/parser/HTMLParserIdioms.h"
32 #include "core/html/shadow/MeterShadowElement.h"
33 #include "core/rendering/RenderMeter.h"
34 #include "core/rendering/RenderTheme.h"
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
40 HTMLMeterElement::HTMLMeterElement(Document& document)
41     : LabelableElement(meterTag, document)
42 {
43     ScriptWrappable::init(this);
44 }
45
46 HTMLMeterElement::~HTMLMeterElement()
47 {
48 }
49
50 PassRefPtrWillBeRawPtr<HTMLMeterElement> HTMLMeterElement::create(Document& document)
51 {
52     RefPtrWillBeRawPtr<HTMLMeterElement> meter = adoptRefWillBeRefCountedGarbageCollected(new HTMLMeterElement(document));
53     meter->ensureUserAgentShadowRoot();
54     return meter.release();
55 }
56
57 RenderObject* HTMLMeterElement::createRenderer(RenderStyle* style)
58 {
59     if (hasAuthorShadowRoot() || !RenderTheme::theme().supportsMeter(style->appearance()))
60         return RenderObject::createObject(this, style);
61
62     return new RenderMeter(this);
63 }
64
65 void HTMLMeterElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
66 {
67     if (name == valueAttr || name == minAttr || name == maxAttr || name == lowAttr || name == highAttr || name == optimumAttr)
68         didElementStateChange();
69     else
70         LabelableElement::parseAttribute(name, value);
71 }
72
73 double HTMLMeterElement::value() const
74 {
75     double value = getFloatingPointAttribute(valueAttr, 0);
76     return std::min(std::max(value, min()), max());
77 }
78
79 void HTMLMeterElement::setValue(double value)
80 {
81     setFloatingPointAttribute(valueAttr, value);
82 }
83
84 double HTMLMeterElement::min() const
85 {
86     return getFloatingPointAttribute(minAttr, 0);
87 }
88
89 void HTMLMeterElement::setMin(double min)
90 {
91     setFloatingPointAttribute(minAttr, min);
92 }
93
94 double HTMLMeterElement::max() const
95 {
96     return std::max(getFloatingPointAttribute(maxAttr, std::max(1.0, min())), min());
97 }
98
99 void HTMLMeterElement::setMax(double max)
100 {
101     setFloatingPointAttribute(maxAttr, max);
102 }
103
104 double HTMLMeterElement::low() const
105 {
106     double low = getFloatingPointAttribute(lowAttr, min());
107     return std::min(std::max(low, min()), max());
108 }
109
110 void HTMLMeterElement::setLow(double low)
111 {
112     setFloatingPointAttribute(lowAttr, low);
113 }
114
115 double HTMLMeterElement::high() const
116 {
117     double high = getFloatingPointAttribute(highAttr, max());
118     return std::min(std::max(high, low()), max());
119 }
120
121 void HTMLMeterElement::setHigh(double high)
122 {
123     setFloatingPointAttribute(highAttr, high);
124 }
125
126 double HTMLMeterElement::optimum() const
127 {
128     double optimum = getFloatingPointAttribute(optimumAttr, (max() + min()) / 2);
129     return std::min(std::max(optimum, min()), max());
130 }
131
132 void HTMLMeterElement::setOptimum(double optimum)
133 {
134     setFloatingPointAttribute(optimumAttr, optimum);
135 }
136
137 HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const
138 {
139     double lowValue = low();
140     double highValue = high();
141     double theValue = value();
142     double optimumValue = optimum();
143
144     if (optimumValue < lowValue) {
145         // The optimum range stays under low
146         if (theValue <= lowValue)
147             return GaugeRegionOptimum;
148         if (theValue <= highValue)
149             return GaugeRegionSuboptimal;
150         return GaugeRegionEvenLessGood;
151     }
152
153     if (highValue < optimumValue) {
154         // The optimum range stays over high
155         if (highValue <= theValue)
156             return GaugeRegionOptimum;
157         if (lowValue <= theValue)
158             return GaugeRegionSuboptimal;
159         return GaugeRegionEvenLessGood;
160     }
161
162     // The optimum range stays between high and low.
163     // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case
164     // because the value is never less or greater than min or max.
165     if (lowValue <= theValue && theValue <= highValue)
166         return GaugeRegionOptimum;
167     return GaugeRegionSuboptimal;
168 }
169
170 double HTMLMeterElement::valueRatio() const
171 {
172     double min = this->min();
173     double max = this->max();
174     double value = this->value();
175
176     if (max <= min)
177         return 0;
178     return (value - min) / (max - min);
179 }
180
181 void HTMLMeterElement::didElementStateChange()
182 {
183     m_value->setWidthPercentage(valueRatio()*100);
184     m_value->updatePseudo();
185     if (RenderMeter* render = renderMeter())
186         render->updateFromElement();
187 }
188
189 RenderMeter* HTMLMeterElement::renderMeter() const
190 {
191     if (renderer() && renderer()->isMeter())
192         return toRenderMeter(renderer());
193
194     RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer();
195     return toRenderMeter(renderObject);
196 }
197
198 void HTMLMeterElement::didAddUserAgentShadowRoot(ShadowRoot& root)
199 {
200     ASSERT(!m_value);
201
202     RefPtr<MeterInnerElement> inner = MeterInnerElement::create(document());
203     root.appendChild(inner);
204
205     RefPtr<MeterBarElement> bar = MeterBarElement::create(document());
206     m_value = MeterValueElement::create(document());
207     m_value->setWidthPercentage(0);
208     m_value->updatePseudo();
209     bar->appendChild(m_value);
210
211     inner->appendChild(bar);
212 }
213
214 void HTMLMeterElement::trace(Visitor* visitor)
215 {
216     visitor->trace(m_value);
217     LabelableElement::trace(visitor);
218 }
219
220 } // namespace