blob: a53e4291c5e95874ad9dc5575ec8f8b4ebcdb541 [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"
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000022#include "HTMLMeterElement.h"
23
darin@apple.com4e29cb22016-11-14 17:55:57 +000024#if ENABLE(METER_ELEMENT)
25
weinig@apple.comc3608932010-05-19 17:48:06 +000026#include "Attribute.h"
antti@apple.com71ed9352014-01-10 17:45:19 +000027#include "ElementIterator.h"
antti@apple.comb4a1f8c2016-10-13 09:22:38 +000028#include "HTMLDivElement.h"
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000029#include "HTMLFormElement.h"
30#include "HTMLNames.h"
darin@apple.com2f2a9802010-09-13 23:42:02 +000031#include "HTMLParserIdioms.h"
antti@apple.comb4a1f8c2016-10-13 09:22:38 +000032#include "HTMLStyleElement.h"
shinyak@chromium.org037f1cd2012-08-15 09:37:32 +000033#include "Page.h"
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000034#include "RenderMeter.h"
shinyak@chromium.org037f1cd2012-08-15 09:37:32 +000035#include "RenderTheme.h"
tkent@chromium.org553b1722011-04-08 06:03:31 +000036#include "ShadowRoot.h"
antti@apple.comb4a1f8c2016-10-13 09:22:38 +000037#include "UserAgentStyleSheets.h"
fpizlo@apple.com197cd322018-03-17 06:11:00 +000038#include <wtf/IsoMallocInlines.h>
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000039
40namespace WebCore {
41
fpizlo@apple.com197cd322018-03-17 06:11:00 +000042WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLMeterElement);
43
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000044using namespace HTMLNames;
45
weinig@apple.com49178832013-09-15 00:39:29 +000046HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document& document)
commit-queue@webkit.orga3eabcd2012-03-16 01:49:05 +000047 : LabelableElement(tagName, document)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000048{
49 ASSERT(hasTagName(meterTag));
50}
51
dbates@webkit.orgf21f3ae2017-10-19 23:48:45 +000052HTMLMeterElement::~HTMLMeterElement() = default;
morrita@google.comca4194d2011-04-05 02:01:56 +000053
weinig@apple.com02f433a2015-01-06 22:32:48 +000054Ref<HTMLMeterElement> HTMLMeterElement::create(const QualifiedName& tagName, Document& document)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000055{
weinig@apple.com02f433a2015-01-06 22:32:48 +000056 Ref<HTMLMeterElement> meter = adoptRef(*new HTMLMeterElement(tagName, document));
esprehn@chromium.org933723d2013-01-29 07:47:20 +000057 meter->ensureUserAgentShadowRoot();
morrita@google.comca4194d2011-04-05 02:01:56 +000058 return meter;
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000059}
60
antti@apple.com454418f2016-04-25 19:49:23 +000061RenderPtr<RenderElement> HTMLMeterElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000062{
antti@apple.com26b5c582017-05-16 05:35:04 +000063 if (!RenderTheme::singleton().supportsMeter(style.appearance()))
aestes@apple.com13aae082016-01-02 08:03:08 +000064 return RenderElement::createFor(*this, WTFMove(style));
shinyak@chromium.org037f1cd2012-08-15 09:37:32 +000065
aestes@apple.com13aae082016-01-02 08:03:08 +000066 return createRenderer<RenderMeter>(*this, WTFMove(style));
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000067}
68
weinig@apple.comda898c32013-11-11 04:02:09 +000069bool HTMLMeterElement::childShouldCreateRenderer(const Node& child) const
morrita@google.combeaa6642012-02-24 09:59:07 +000070{
antti@apple.comb4a1f8c2016-10-13 09:22:38 +000071 return !is<RenderMeter>(renderer()) && HTMLElement::childShouldCreateRenderer(child);
morrita@google.combeaa6642012-02-24 09:59:07 +000072}
73
darin@apple.com0ce67df2019-06-17 01:48:13 +000074void HTMLMeterElement::parseAttribute(const QualifiedName& name, const AtomString& value)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000075{
akling@apple.com43e9d042012-11-18 16:55:06 +000076 if (name == valueAttr || name == minAttr || name == maxAttr || name == lowAttr || name == highAttr || name == optimumAttr)
morrita@google.comca4194d2011-04-05 02:01:56 +000077 didElementStateChange();
78 else
akling@apple.com43e9d042012-11-18 16:55:06 +000079 LabelableElement::parseAttribute(name, value);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000080}
81
82double HTMLMeterElement::min() const
83{
rniwa@webkit.orge999a052016-07-16 15:21:55 +000084 return parseToDoubleForNumberType(attributeWithoutSynchronization(minAttr), 0);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000085}
86
cdumez@apple.combbe7d9a2016-09-21 23:50:24 +000087void HTMLMeterElement::setMin(double min)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000088{
darin@apple.com0ce67df2019-06-17 01:48:13 +000089 setAttributeWithoutSynchronization(minAttr, AtomString::number(min));
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000090}
91
92double HTMLMeterElement::max() const
93{
rniwa@webkit.orge999a052016-07-16 15:21:55 +000094 return std::max(parseToDoubleForNumberType(attributeWithoutSynchronization(maxAttr), std::max(1.0, min())), min());
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000095}
96
cdumez@apple.combbe7d9a2016-09-21 23:50:24 +000097void HTMLMeterElement::setMax(double max)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +000098{
darin@apple.com0ce67df2019-06-17 01:48:13 +000099 setAttributeWithoutSynchronization(maxAttr, AtomString::number(max));
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000100}
101
102double HTMLMeterElement::value() const
103{
rniwa@webkit.orge999a052016-07-16 15:21:55 +0000104 double value = parseToDoubleForNumberType(attributeWithoutSynchronization(valueAttr), 0);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000105 return std::min(std::max(value, min()), max());
106}
107
cdumez@apple.combbe7d9a2016-09-21 23:50:24 +0000108void HTMLMeterElement::setValue(double value)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000109{
darin@apple.com0ce67df2019-06-17 01:48:13 +0000110 setAttributeWithoutSynchronization(valueAttr, AtomString::number(value));
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000111}
112
113double HTMLMeterElement::low() const
114{
rniwa@webkit.orge999a052016-07-16 15:21:55 +0000115 double low = parseToDoubleForNumberType(attributeWithoutSynchronization(lowAttr), min());
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000116 return std::min(std::max(low, min()), max());
117}
118
cdumez@apple.combbe7d9a2016-09-21 23:50:24 +0000119void HTMLMeterElement::setLow(double low)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000120{
darin@apple.com0ce67df2019-06-17 01:48:13 +0000121 setAttributeWithoutSynchronization(lowAttr, AtomString::number(low));
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000122}
123
124double HTMLMeterElement::high() const
125{
rniwa@webkit.orge999a052016-07-16 15:21:55 +0000126 double high = parseToDoubleForNumberType(attributeWithoutSynchronization(highAttr), max());
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000127 return std::min(std::max(high, low()), max());
128}
129
cdumez@apple.combbe7d9a2016-09-21 23:50:24 +0000130void HTMLMeterElement::setHigh(double high)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000131{
darin@apple.com0ce67df2019-06-17 01:48:13 +0000132 setAttributeWithoutSynchronization(highAttr, AtomString::number(high));
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000133}
134
135double HTMLMeterElement::optimum() const
136{
rniwa@webkit.orge999a052016-07-16 15:21:55 +0000137 double optimum = parseToDoubleForNumberType(attributeWithoutSynchronization(optimumAttr), (max() + min()) / 2);
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000138 return std::min(std::max(optimum, min()), max());
139}
140
cdumez@apple.combbe7d9a2016-09-21 23:50:24 +0000141void HTMLMeterElement::setOptimum(double optimum)
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000142{
darin@apple.com0ce67df2019-06-17 01:48:13 +0000143 setAttributeWithoutSynchronization(optimumAttr, AtomString::number(optimum));
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000144}
145
morrita@google.coma70a8f42010-06-08 06:26:06 +0000146HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const
147{
148 double lowValue = low();
149 double highValue = high();
150 double theValue = value();
151 double optimumValue = optimum();
152
morrita@google.com2611bce2010-10-29 09:47:03 +0000153 if (optimumValue < lowValue) {
morrita@google.coma70a8f42010-06-08 06:26:06 +0000154 // The optimum range stays under low
155 if (theValue <= lowValue)
156 return GaugeRegionOptimum;
157 if (theValue <= highValue)
158 return GaugeRegionSuboptimal;
159 return GaugeRegionEvenLessGood;
160 }
161
morrita@google.com2611bce2010-10-29 09:47:03 +0000162 if (highValue < optimumValue) {
morrita@google.coma70a8f42010-06-08 06:26:06 +0000163 // The optimum range stays over high
164 if (highValue <= theValue)
165 return GaugeRegionOptimum;
166 if (lowValue <= theValue)
167 return GaugeRegionSuboptimal;
168 return GaugeRegionEvenLessGood;
169 }
170
morrita@google.com2611bce2010-10-29 09:47:03 +0000171 // The optimum range stays between high and low.
172 // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case
173 // because the value is never less or greater than min or max.
174 if (lowValue <= theValue && theValue <= highValue)
morrita@google.coma70a8f42010-06-08 06:26:06 +0000175 return GaugeRegionOptimum;
morrita@google.coma70a8f42010-06-08 06:26:06 +0000176 return GaugeRegionSuboptimal;
177}
178
morrita@google.comca4194d2011-04-05 02:01:56 +0000179double HTMLMeterElement::valueRatio() const
180{
181 double min = this->min();
182 double max = this->max();
183 double value = this->value();
184
185 if (max <= min)
186 return 0;
187 return (value - min) / (max - min);
188}
189
antti@apple.comb4a1f8c2016-10-13 09:22:38 +0000190static void setValueClass(HTMLElement& element, HTMLMeterElement::GaugeRegion gaugeRegion)
191{
192 switch (gaugeRegion) {
193 case HTMLMeterElement::GaugeRegionOptimum:
194 element.setAttribute(HTMLNames::classAttr, "optimum");
195 element.setPseudo("-webkit-meter-optimum-value");
196 return;
197 case HTMLMeterElement::GaugeRegionSuboptimal:
198 element.setAttribute(HTMLNames::classAttr, "suboptimum");
199 element.setPseudo("-webkit-meter-suboptimum-value");
200 return;
201 case HTMLMeterElement::GaugeRegionEvenLessGood:
202 element.setAttribute(HTMLNames::classAttr, "even-less-good");
203 element.setPseudo("-webkit-meter-even-less-good-value");
204 return;
205 default:
206 ASSERT_NOT_REACHED();
207 }
208}
209
morrita@google.comca4194d2011-04-05 02:01:56 +0000210void HTMLMeterElement::didElementStateChange()
211{
simon.fraser@apple.com094a8742019-11-13 04:41:17 +0000212 m_value->setInlineStyleProperty(CSSPropertyWidth, valueRatio()*100, CSSUnitType::CSS_PERCENTAGE);
antti@apple.comb4a1f8c2016-10-13 09:22:38 +0000213 setValueClass(*m_value, gaugeRegion());
214
shinyak@chromium.org037f1cd2012-08-15 09:37:32 +0000215 if (RenderMeter* render = renderMeter())
morrita@google.comf1987562011-09-21 05:41:27 +0000216 render->updateFromElement();
morrita@google.comca4194d2011-04-05 02:01:56 +0000217}
218
shinyak@chromium.org037f1cd2012-08-15 09:37:32 +0000219RenderMeter* HTMLMeterElement::renderMeter() const
220{
cdumez@apple.com3abcc792014-10-20 03:42:03 +0000221 if (is<RenderMeter>(renderer()))
222 return downcast<RenderMeter>(renderer());
antti@apple.comb4a1f8c2016-10-13 09:22:38 +0000223 return nullptr;
shinyak@chromium.org037f1cd2012-08-15 09:37:32 +0000224}
225
dbates@webkit.org62df2762017-11-02 04:13:18 +0000226void HTMLMeterElement::didAddUserAgentShadowRoot(ShadowRoot& root)
morrita@google.comca4194d2011-04-05 02:01:56 +0000227{
esprehn@chromium.org933723d2013-01-29 07:47:20 +0000228 ASSERT(!m_value);
shinyak@chromium.org037f1cd2012-08-15 09:37:32 +0000229
antti@apple.comb4a1f8c2016-10-13 09:22:38 +0000230 static NeverDestroyed<String> shadowStyle(meterElementShadowUserAgentStyleSheet, String::ConstructFromLiteral);
231
232 auto style = HTMLStyleElement::create(HTMLNames::styleTag, document(), false);
darin@apple.com4a588ff2016-11-11 20:16:03 +0000233 style->setTextContent(shadowStyle);
dbates@webkit.org62df2762017-11-02 04:13:18 +0000234 root.appendChild(style);
antti@apple.comb4a1f8c2016-10-13 09:22:38 +0000235
236 // Pseudos are set to allow author styling.
237 auto inner = HTMLDivElement::create(document());
238 inner->setIdAttribute("inner");
239 inner->setPseudo("-webkit-meter-inner-element");
dbates@webkit.org62df2762017-11-02 04:13:18 +0000240 root.appendChild(inner);
morrita@google.com6b18c3f2012-02-09 05:46:57 +0000241
antti@apple.comb4a1f8c2016-10-13 09:22:38 +0000242 auto bar = HTMLDivElement::create(document());
243 bar->setIdAttribute("bar");
244 bar->setPseudo("-webkit-meter-bar");
darin@apple.com4a588ff2016-11-11 20:16:03 +0000245 inner->appendChild(bar);
antti@apple.comb4a1f8c2016-10-13 09:22:38 +0000246
247 m_value = HTMLDivElement::create(document());
248 m_value->setIdAttribute("value");
darin@apple.com4a588ff2016-11-11 20:16:03 +0000249 bar->appendChild(*m_value);
morrita@google.com6b18c3f2012-02-09 05:46:57 +0000250
antti@apple.comb4a1f8c2016-10-13 09:22:38 +0000251 didElementStateChange();
morrita@google.comca4194d2011-04-05 02:01:56 +0000252}
253
yael.aharon@nokia.com666f4b82010-05-15 16:41:06 +0000254} // namespace
255#endif