1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "HTMLMeterElement.h"
8 #include "mozilla/EventStates.h"
9 #include "mozilla/dom/HTMLMeterElementBinding.h"
10
11 NS_IMPL_NS_NEW_HTML_ELEMENT(Meter)
12
13 namespace mozilla::dom {
14
15 const double HTMLMeterElement::kDefaultValue = 0.0;
16 const double HTMLMeterElement::kDefaultMin = 0.0;
17 const double HTMLMeterElement::kDefaultMax = 1.0;
18
HTMLMeterElement(already_AddRefed<mozilla::dom::NodeInfo> && aNodeInfo)19 HTMLMeterElement::HTMLMeterElement(
20 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
21 : nsGenericHTMLElement(std::move(aNodeInfo)) {}
22
23 HTMLMeterElement::~HTMLMeterElement() = default;
24
NS_IMPL_ELEMENT_CLONE(HTMLMeterElement)25 NS_IMPL_ELEMENT_CLONE(HTMLMeterElement)
26
27 EventStates HTMLMeterElement::IntrinsicState() const {
28 EventStates state = nsGenericHTMLElement::IntrinsicState();
29
30 state |= GetOptimumState();
31
32 return state;
33 }
34
ParseAttribute(int32_t aNamespaceID,nsAtom * aAttribute,const nsAString & aValue,nsIPrincipal * aMaybeScriptedPrincipal,nsAttrValue & aResult)35 bool HTMLMeterElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
36 const nsAString& aValue,
37 nsIPrincipal* aMaybeScriptedPrincipal,
38 nsAttrValue& aResult) {
39 if (aNamespaceID == kNameSpaceID_None) {
40 if (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max ||
41 aAttribute == nsGkAtoms::min || aAttribute == nsGkAtoms::low ||
42 aAttribute == nsGkAtoms::high || aAttribute == nsGkAtoms::optimum) {
43 return aResult.ParseDoubleValue(aValue);
44 }
45 }
46
47 return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
48 aMaybeScriptedPrincipal, aResult);
49 }
50
51 /*
52 * Value getters :
53 * const getters used by XPCOM methods and by IntrinsicState
54 */
55
Min() const56 double HTMLMeterElement::Min() const {
57 /**
58 * If the attribute min is defined, the minimum is this value.
59 * Otherwise, the minimum is the default value.
60 */
61 const nsAttrValue* attrMin = mAttrs.GetAttr(nsGkAtoms::min);
62 if (attrMin && attrMin->Type() == nsAttrValue::eDoubleValue) {
63 return attrMin->GetDoubleValue();
64 }
65 return kDefaultMin;
66 }
67
Max() const68 double HTMLMeterElement::Max() const {
69 /**
70 * If the attribute max is defined, the maximum is this value.
71 * Otherwise, the maximum is the default value.
72 * If the maximum value is less than the minimum value,
73 * the maximum value is the same as the minimum value.
74 */
75 double max;
76
77 const nsAttrValue* attrMax = mAttrs.GetAttr(nsGkAtoms::max);
78 if (attrMax && attrMax->Type() == nsAttrValue::eDoubleValue) {
79 max = attrMax->GetDoubleValue();
80 } else {
81 max = kDefaultMax;
82 }
83
84 return std::max(max, Min());
85 }
86
Value() const87 double HTMLMeterElement::Value() const {
88 /**
89 * If the attribute value is defined, the actual value is this value.
90 * Otherwise, the actual value is the default value.
91 * If the actual value is less than the minimum value,
92 * the actual value is the same as the minimum value.
93 * If the actual value is greater than the maximum value,
94 * the actual value is the same as the maximum value.
95 */
96 double value;
97
98 const nsAttrValue* attrValue = mAttrs.GetAttr(nsGkAtoms::value);
99 if (attrValue && attrValue->Type() == nsAttrValue::eDoubleValue) {
100 value = attrValue->GetDoubleValue();
101 } else {
102 value = kDefaultValue;
103 }
104
105 double min = Min();
106
107 if (value <= min) {
108 return min;
109 }
110
111 return std::min(value, Max());
112 }
113
Position() const114 double HTMLMeterElement::Position() const {
115 const double max = Max();
116 const double min = Min();
117 const double value = Value();
118
119 double range = max - min;
120 return range != 0.0 ? (value - min) / range : 1.0;
121 }
122
Low() const123 double HTMLMeterElement::Low() const {
124 /**
125 * If the low value is defined, the low value is this value.
126 * Otherwise, the low value is the minimum value.
127 * If the low value is less than the minimum value,
128 * the low value is the same as the minimum value.
129 * If the low value is greater than the maximum value,
130 * the low value is the same as the maximum value.
131 */
132
133 double min = Min();
134
135 const nsAttrValue* attrLow = mAttrs.GetAttr(nsGkAtoms::low);
136 if (!attrLow || attrLow->Type() != nsAttrValue::eDoubleValue) {
137 return min;
138 }
139
140 double low = attrLow->GetDoubleValue();
141
142 if (low <= min) {
143 return min;
144 }
145
146 return std::min(low, Max());
147 }
148
High() const149 double HTMLMeterElement::High() const {
150 /**
151 * If the high value is defined, the high value is this value.
152 * Otherwise, the high value is the maximum value.
153 * If the high value is less than the low value,
154 * the high value is the same as the low value.
155 * If the high value is greater than the maximum value,
156 * the high value is the same as the maximum value.
157 */
158
159 double max = Max();
160
161 const nsAttrValue* attrHigh = mAttrs.GetAttr(nsGkAtoms::high);
162 if (!attrHigh || attrHigh->Type() != nsAttrValue::eDoubleValue) {
163 return max;
164 }
165
166 double high = attrHigh->GetDoubleValue();
167
168 if (high >= max) {
169 return max;
170 }
171
172 return std::max(high, Low());
173 }
174
Optimum() const175 double HTMLMeterElement::Optimum() const {
176 /**
177 * If the optimum value is defined, the optimum value is this value.
178 * Otherwise, the optimum value is the midpoint between
179 * the minimum value and the maximum value :
180 * min + (max - min)/2 = (min + max)/2
181 * If the optimum value is less than the minimum value,
182 * the optimum value is the same as the minimum value.
183 * If the optimum value is greater than the maximum value,
184 * the optimum value is the same as the maximum value.
185 */
186
187 double max = Max();
188
189 double min = Min();
190
191 const nsAttrValue* attrOptimum = mAttrs.GetAttr(nsGkAtoms::optimum);
192 if (!attrOptimum || attrOptimum->Type() != nsAttrValue::eDoubleValue) {
193 return (min + max) / 2.0;
194 }
195
196 double optimum = attrOptimum->GetDoubleValue();
197
198 if (optimum <= min) {
199 return min;
200 }
201
202 return std::min(optimum, max);
203 }
204
GetOptimumState() const205 EventStates HTMLMeterElement::GetOptimumState() const {
206 /*
207 * If the optimum value is in [minimum, low[,
208 * return if the value is in optimal, suboptimal or sub-suboptimal region
209 *
210 * If the optimum value is in [low, high],
211 * return if the value is in optimal or suboptimal region
212 *
213 * If the optimum value is in ]high, maximum],
214 * return if the value is in optimal, suboptimal or sub-suboptimal region
215 */
216 double value = Value();
217 double low = Low();
218 double high = High();
219 double optimum = Optimum();
220
221 if (optimum < low) {
222 if (value < low) {
223 return NS_EVENT_STATE_OPTIMUM;
224 }
225 if (value <= high) {
226 return NS_EVENT_STATE_SUB_OPTIMUM;
227 }
228 return NS_EVENT_STATE_SUB_SUB_OPTIMUM;
229 }
230 if (optimum > high) {
231 if (value > high) {
232 return NS_EVENT_STATE_OPTIMUM;
233 }
234 if (value >= low) {
235 return NS_EVENT_STATE_SUB_OPTIMUM;
236 }
237 return NS_EVENT_STATE_SUB_SUB_OPTIMUM;
238 }
239 // optimum in [low, high]
240 if (value >= low && value <= high) {
241 return NS_EVENT_STATE_OPTIMUM;
242 }
243 return NS_EVENT_STATE_SUB_OPTIMUM;
244 }
245
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)246 JSObject* HTMLMeterElement::WrapNode(JSContext* aCx,
247 JS::Handle<JSObject*> aGivenProto) {
248 return HTMLMeterElement_Binding::Wrap(aCx, this, aGivenProto);
249 }
250
251 } // namespace mozilla::dom
252