HTMLMeterElement.cpp (7917B)
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 9 #include "mozilla/dom/HTMLMeterElementBinding.h" 10 11 NS_IMPL_NS_NEW_HTML_ELEMENT(Meter) 12 13 namespace mozilla::dom { 14 15 static const double kDefaultValue = 0.0; 16 static const double kDefaultMin = 0.0; 17 static const double kDefaultMax = 1.0; 18 19 HTMLMeterElement::HTMLMeterElement( 20 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) 21 : nsGenericHTMLElement(std::move(aNodeInfo)) {} 22 23 HTMLMeterElement::~HTMLMeterElement() = default; 24 25 NS_IMPL_ELEMENT_CLONE(HTMLMeterElement) 26 27 static bool IsInterestingAttr(int32_t aNamespaceID, nsAtom* aAttribute) { 28 if (aNamespaceID != kNameSpaceID_None) { 29 return false; 30 } 31 return aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max || 32 aAttribute == nsGkAtoms::min || aAttribute == nsGkAtoms::low || 33 aAttribute == nsGkAtoms::high || aAttribute == nsGkAtoms::optimum; 34 } 35 36 bool HTMLMeterElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, 37 const nsAString& aValue, 38 nsIPrincipal* aMaybeScriptedPrincipal, 39 nsAttrValue& aResult) { 40 if (IsInterestingAttr(aNamespaceID, aAttribute)) { 41 return aResult.ParseDoubleValue(aValue); 42 } 43 return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue, 44 aMaybeScriptedPrincipal, aResult); 45 } 46 47 void HTMLMeterElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, 48 const nsAttrValue* aValue, 49 const nsAttrValue* aOldValue, 50 nsIPrincipal* aSubjectPrincipal, 51 bool aNotify) { 52 if (IsInterestingAttr(aNameSpaceID, aName)) { 53 UpdateOptimumState(aNotify); 54 } 55 nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, aOldValue, 56 aSubjectPrincipal, aNotify); 57 } 58 59 void HTMLMeterElement::UpdateOptimumState(bool aNotify) { 60 AutoStateChangeNotifier notifier(*this, aNotify); 61 RemoveStatesSilently(ElementState::METER_OPTIMUM_STATES); 62 AddStatesSilently(GetOptimumState()); 63 } 64 65 double HTMLMeterElement::Min() const { 66 /** 67 * If the attribute min is defined, the minimum is this value. 68 * Otherwise, the minimum is the default value. 69 */ 70 const nsAttrValue* attrMin = mAttrs.GetAttr(nsGkAtoms::min); 71 if (attrMin && attrMin->Type() == nsAttrValue::eDoubleValue) { 72 return attrMin->GetDoubleValue(); 73 } 74 return kDefaultMin; 75 } 76 77 double HTMLMeterElement::Max() const { 78 /** 79 * If the attribute max is defined, the maximum is this value. 80 * Otherwise, the maximum is the default value. 81 * If the maximum value is less than the minimum value, 82 * the maximum value is the same as the minimum value. 83 */ 84 double max; 85 86 const nsAttrValue* attrMax = mAttrs.GetAttr(nsGkAtoms::max); 87 if (attrMax && attrMax->Type() == nsAttrValue::eDoubleValue) { 88 max = attrMax->GetDoubleValue(); 89 } else { 90 max = kDefaultMax; 91 } 92 93 return std::max(max, Min()); 94 } 95 96 double HTMLMeterElement::Value() const { 97 /** 98 * If the attribute value is defined, the actual value is this value. 99 * Otherwise, the actual value is the default value. 100 * If the actual value is less than the minimum value, 101 * the actual value is the same as the minimum value. 102 * If the actual value is greater than the maximum value, 103 * the actual value is the same as the maximum value. 104 */ 105 double value; 106 107 const nsAttrValue* attrValue = mAttrs.GetAttr(nsGkAtoms::value); 108 if (attrValue && attrValue->Type() == nsAttrValue::eDoubleValue) { 109 value = attrValue->GetDoubleValue(); 110 } else { 111 value = kDefaultValue; 112 } 113 114 double min = Min(); 115 116 if (value <= min) { 117 return min; 118 } 119 120 return std::min(value, Max()); 121 } 122 123 double HTMLMeterElement::Position() const { 124 const double max = Max(); 125 const double min = Min(); 126 const double value = Value(); 127 128 double range = max - min; 129 return range != 0.0 ? (value - min) / range : 1.0; 130 } 131 132 double HTMLMeterElement::Low() const { 133 /** 134 * If the low value is defined, the low value is this value. 135 * Otherwise, the low value is the minimum value. 136 * If the low value is less than the minimum value, 137 * the low value is the same as the minimum value. 138 * If the low value is greater than the maximum value, 139 * the low value is the same as the maximum value. 140 */ 141 142 double min = Min(); 143 144 const nsAttrValue* attrLow = mAttrs.GetAttr(nsGkAtoms::low); 145 if (!attrLow || attrLow->Type() != nsAttrValue::eDoubleValue) { 146 return min; 147 } 148 149 double low = attrLow->GetDoubleValue(); 150 151 if (low <= min) { 152 return min; 153 } 154 155 return std::min(low, Max()); 156 } 157 158 double HTMLMeterElement::High() const { 159 /** 160 * If the high value is defined, the high value is this value. 161 * Otherwise, the high value is the maximum value. 162 * If the high value is less than the low value, 163 * the high value is the same as the low value. 164 * If the high value is greater than the maximum value, 165 * the high value is the same as the maximum value. 166 */ 167 168 double max = Max(); 169 170 const nsAttrValue* attrHigh = mAttrs.GetAttr(nsGkAtoms::high); 171 if (!attrHigh || attrHigh->Type() != nsAttrValue::eDoubleValue) { 172 return max; 173 } 174 175 double high = attrHigh->GetDoubleValue(); 176 177 if (high >= max) { 178 return max; 179 } 180 181 return std::max(high, Low()); 182 } 183 184 double HTMLMeterElement::Optimum() const { 185 /** 186 * If the optimum value is defined, the optimum value is this value. 187 * Otherwise, the optimum value is the midpoint between 188 * the minimum value and the maximum value : 189 * min + (max - min)/2 = (min + max)/2 190 * If the optimum value is less than the minimum value, 191 * the optimum value is the same as the minimum value. 192 * If the optimum value is greater than the maximum value, 193 * the optimum value is the same as the maximum value. 194 */ 195 196 double max = Max(); 197 198 double min = Min(); 199 200 const nsAttrValue* attrOptimum = mAttrs.GetAttr(nsGkAtoms::optimum); 201 if (!attrOptimum || attrOptimum->Type() != nsAttrValue::eDoubleValue) { 202 return (min + max) / 2.0; 203 } 204 205 double optimum = attrOptimum->GetDoubleValue(); 206 207 if (optimum <= min) { 208 return min; 209 } 210 211 return std::min(optimum, max); 212 } 213 214 ElementState HTMLMeterElement::GetOptimumState() const { 215 /* 216 * If the optimum value is in [minimum, low[, 217 * return if the value is in optimal, suboptimal or sub-suboptimal region 218 * 219 * If the optimum value is in [low, high], 220 * return if the value is in optimal or suboptimal region 221 * 222 * If the optimum value is in ]high, maximum], 223 * return if the value is in optimal, suboptimal or sub-suboptimal region 224 */ 225 double value = Value(); 226 double low = Low(); 227 double high = High(); 228 double optimum = Optimum(); 229 230 if (optimum < low) { 231 if (value < low) { 232 return ElementState::OPTIMUM; 233 } 234 if (value <= high) { 235 return ElementState::SUB_OPTIMUM; 236 } 237 return ElementState::SUB_SUB_OPTIMUM; 238 } 239 if (optimum > high) { 240 if (value > high) { 241 return ElementState::OPTIMUM; 242 } 243 if (value >= low) { 244 return ElementState::SUB_OPTIMUM; 245 } 246 return ElementState::SUB_SUB_OPTIMUM; 247 } 248 // optimum in [low, high] 249 if (value >= low && value <= high) { 250 return ElementState::OPTIMUM; 251 } 252 return ElementState::SUB_OPTIMUM; 253 } 254 255 JSObject* HTMLMeterElement::WrapNode(JSContext* aCx, 256 JS::Handle<JSObject*> aGivenProto) { 257 return HTMLMeterElement_Binding::Wrap(aCx, this, aGivenProto); 258 } 259 260 } // namespace mozilla::dom