blob: 3be84e33dfacbc86542429685f07cea50e0783c4 [file] [log] [blame]
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +00001/*
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
weinig@apple.comc3608932010-05-19 17:48:06 +000025#include "Attribute.h"
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000026#include "EventNames.h"
kinuko@chromium.org6d95dee2010-06-07 20:55:00 +000027#include "ExceptionCode.h"
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000028#include "FormDataList.h"
morrita@google.combeaa6642012-02-24 09:59:07 +000029#include "NodeRenderingContext.h"
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000030#include "HTMLFormElement.h"
31#include "HTMLNames.h"
darin@apple.com2f2a9802010-09-13 23:42:02 +000032#include "HTMLParserIdioms.h"
morrita@google.comca4194d2011-04-05 02:01:56 +000033#include "MeterShadowElement.h"
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000034#include "RenderMeter.h"
tkent@chromium.org553b1722011-04-08 06:03:31 +000035#include "ShadowRoot.h"
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000036#include <wtf/StdLibExtras.h>
37
38namespace WebCore {
39
40using namespace HTMLNames;
41
yael.aharon@nokia.com4920c932010-12-01 00:13:33 +000042HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
43 : HTMLFormControlElement(tagName, document, form)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000044{
45 ASSERT(hasTagName(meterTag));
46}
47
morrita@google.comca4194d2011-04-05 02:01:56 +000048HTMLMeterElement::~HTMLMeterElement()
49{
50}
51
yael.aharon@nokia.com4920c932010-12-01 00:13:33 +000052PassRefPtr<HTMLMeterElement> HTMLMeterElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000053{
morrita@google.comca4194d2011-04-05 02:01:56 +000054 RefPtr<HTMLMeterElement> meter = adoptRef(new HTMLMeterElement(tagName, document, form));
55 meter->createShadowSubtree();
56 return meter;
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000057}
58
59RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle*)
60{
61 return new (arena) RenderMeter(this);
62}
63
morrita@google.combeaa6642012-02-24 09:59:07 +000064bool HTMLMeterElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
65{
66 return childContext.isOnEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext);
67}
68
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000069const AtomicString& HTMLMeterElement::formControlType() const
70{
71 DEFINE_STATIC_LOCAL(const AtomicString, meter, ("meter"));
72 return meter;
73}
74
commit-queue@webkit.org12ad3822011-05-16 05:59:46 +000075bool HTMLMeterElement::supportsFocus() const
76{
77 return Node::supportsFocus() && !disabled();
78}
79
kling@webkit.org8a3d4af2012-02-06 02:21:57 +000080void HTMLMeterElement::parseAttribute(Attribute* attribute)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000081{
morrita@google.comca4194d2011-04-05 02:01:56 +000082 if (attribute->name() == valueAttr || attribute->name() == minAttr || attribute->name() == maxAttr || attribute->name() == lowAttr || attribute->name() == highAttr || attribute->name() == optimumAttr)
83 didElementStateChange();
84 else
kling@webkit.org8a3d4af2012-02-06 02:21:57 +000085 HTMLFormControlElement::parseAttribute(attribute);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000086}
87
morrita@google.comb172c47a2010-12-08 04:21:20 +000088void HTMLMeterElement::attach()
89{
90 HTMLFormControlElement::attach();
morrita@google.comca4194d2011-04-05 02:01:56 +000091 didElementStateChange();
morrita@google.comb172c47a2010-12-08 04:21:20 +000092}
93
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000094double HTMLMeterElement::min() const
95{
96 double min = 0;
commit-queue@webkit.org03477c82011-09-02 17:07:51 +000097 parseToDoubleForNumberType(getAttribute(minAttr), &min);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000098 return min;
99}
100
101void HTMLMeterElement::setMin(double min, ExceptionCode& ec)
102{
103 if (!isfinite(min)) {
104 ec = NOT_SUPPORTED_ERR;
105 return;
106 }
107 setAttribute(minAttr, String::number(min));
108}
109
110double HTMLMeterElement::max() const
111{
112 double max = std::max(1.0, min());
commit-queue@webkit.org03477c82011-09-02 17:07:51 +0000113 parseToDoubleForNumberType(getAttribute(maxAttr), &max);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000114 return std::max(max, min());
115}
116
117void HTMLMeterElement::setMax(double max, ExceptionCode& ec)
118{
119 if (!isfinite(max)) {
120 ec = NOT_SUPPORTED_ERR;
121 return;
122 }
123 setAttribute(maxAttr, String::number(max));
124}
125
126double HTMLMeterElement::value() const
127{
128 double value = 0;
commit-queue@webkit.org03477c82011-09-02 17:07:51 +0000129 parseToDoubleForNumberType(getAttribute(valueAttr), &value);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000130 return std::min(std::max(value, min()), max());
131}
132
133void HTMLMeterElement::setValue(double value, ExceptionCode& ec)
134{
135 if (!isfinite(value)) {
136 ec = NOT_SUPPORTED_ERR;
137 return;
138 }
139 setAttribute(valueAttr, String::number(value));
140}
141
142double HTMLMeterElement::low() const
143{
144 double low = min();
commit-queue@webkit.org03477c82011-09-02 17:07:51 +0000145 parseToDoubleForNumberType(getAttribute(lowAttr), &low);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000146 return std::min(std::max(low, min()), max());
147}
148
149void HTMLMeterElement::setLow(double low, ExceptionCode& ec)
150{
151 if (!isfinite(low)) {
152 ec = NOT_SUPPORTED_ERR;
153 return;
154 }
155 setAttribute(lowAttr, String::number(low));
156}
157
158double HTMLMeterElement::high() const
159{
160 double high = max();
commit-queue@webkit.org03477c82011-09-02 17:07:51 +0000161 parseToDoubleForNumberType(getAttribute(highAttr), &high);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000162 return std::min(std::max(high, low()), max());
163}
164
165void HTMLMeterElement::setHigh(double high, ExceptionCode& ec)
166{
167 if (!isfinite(high)) {
168 ec = NOT_SUPPORTED_ERR;
169 return;
170 }
171 setAttribute(highAttr, String::number(high));
172}
173
174double HTMLMeterElement::optimum() const
175{
176 double optimum = (max() + min()) / 2;
commit-queue@webkit.org03477c82011-09-02 17:07:51 +0000177 parseToDoubleForNumberType(getAttribute(optimumAttr), &optimum);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000178 return std::min(std::max(optimum, min()), max());
179}
180
181void HTMLMeterElement::setOptimum(double optimum, ExceptionCode& ec)
182{
183 if (!isfinite(optimum)) {
184 ec = NOT_SUPPORTED_ERR;
185 return;
186 }
187 setAttribute(optimumAttr, String::number(optimum));
188}
189
morrita@google.coma70a8f42010-06-08 06:26:06 +0000190HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const
191{
192 double lowValue = low();
193 double highValue = high();
194 double theValue = value();
195 double optimumValue = optimum();
196
morrita@google.com2611bce2010-10-29 09:47:03 +0000197 if (optimumValue < lowValue) {
morrita@google.coma70a8f42010-06-08 06:26:06 +0000198 // The optimum range stays under low
199 if (theValue <= lowValue)
200 return GaugeRegionOptimum;
201 if (theValue <= highValue)
202 return GaugeRegionSuboptimal;
203 return GaugeRegionEvenLessGood;
204 }
205
morrita@google.com2611bce2010-10-29 09:47:03 +0000206 if (highValue < optimumValue) {
morrita@google.coma70a8f42010-06-08 06:26:06 +0000207 // The optimum range stays over high
208 if (highValue <= theValue)
209 return GaugeRegionOptimum;
210 if (lowValue <= theValue)
211 return GaugeRegionSuboptimal;
212 return GaugeRegionEvenLessGood;
213 }
214
morrita@google.com2611bce2010-10-29 09:47:03 +0000215 // The optimum range stays between high and low.
216 // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case
217 // because the value is never less or greater than min or max.
218 if (lowValue <= theValue && theValue <= highValue)
morrita@google.coma70a8f42010-06-08 06:26:06 +0000219 return GaugeRegionOptimum;
morrita@google.coma70a8f42010-06-08 06:26:06 +0000220 return GaugeRegionSuboptimal;
221}
222
morrita@google.comca4194d2011-04-05 02:01:56 +0000223double HTMLMeterElement::valueRatio() const
224{
225 double min = this->min();
226 double max = this->max();
227 double value = this->value();
228
229 if (max <= min)
230 return 0;
231 return (value - min) / (max - min);
232}
233
234void HTMLMeterElement::didElementStateChange()
235{
236 m_value->setWidthPercentage(valueRatio()*100);
morrita@google.comf1987562011-09-21 05:41:27 +0000237 if (RenderObject* render = renderer())
238 render->updateFromElement();
morrita@google.comca4194d2011-04-05 02:01:56 +0000239}
240
241void HTMLMeterElement::createShadowSubtree()
242{
commit-queue@webkit.org36762182012-02-14 12:48:24 +0000243 ASSERT(!hasShadowRoot());
morrita@google.com6b18c3f2012-02-09 05:46:57 +0000244
morrita@google.comca4194d2011-04-05 02:01:56 +0000245 RefPtr<MeterBarElement> bar = MeterBarElement::create(document());
246 m_value = MeterValueElement::create(document());
247 ExceptionCode ec = 0;
248 bar->appendChild(m_value, ec);
morrita@google.com6b18c3f2012-02-09 05:46:57 +0000249
commit-queue@webkit.org792213f2012-02-09 09:54:04 +0000250 RefPtr<ShadowRoot> root = ShadowRoot::create(this, ShadowRoot::CreatingUserAgentShadowRoot);
morrita@google.com6b18c3f2012-02-09 05:46:57 +0000251 root->appendChild(bar, ec);
morrita@google.comca4194d2011-04-05 02:01:56 +0000252}
253
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000254} // namespace
255#endif