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 #if ENABLE(METER_TAG) 23 #include "HTMLMeterElement.h" 24 25 #include "Attribute.h" 26 #include "EventNames.h" 27 #include "ExceptionCode.h" 28 #include "FormDataList.h" 29 #include "HTMLFormElement.h" 30 #include "HTMLNames.h" 31 #include "HTMLParserIdioms.h" 32 #include "MeterShadowElement.h" 33 #include "RenderMeter.h" 34 #include "ShadowRoot.h" 35 #include <wtf/StdLibExtras.h> 36 37 namespace WebCore { 38 39 using namespace HTMLNames; 40 41 HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form) 42 : HTMLFormControlElement(tagName, document, form) 43 { 44 ASSERT(hasTagName(meterTag)); 45 } 46 47 HTMLMeterElement::~HTMLMeterElement() 48 { 49 } 50 51 PassRefPtr<HTMLMeterElement> HTMLMeterElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form) 52 { 53 RefPtr<HTMLMeterElement> meter = adoptRef(new HTMLMeterElement(tagName, document, form)); 54 meter->createShadowSubtree(); 55 return meter; 56 } 57 58 RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle*) 59 { 60 return new (arena) RenderMeter(this); 61 } 62 63 const AtomicString& HTMLMeterElement::formControlType() const 64 { 65 DEFINE_STATIC_LOCAL(const AtomicString, meter, ("meter")); 66 return meter; 67 } 68 69 void HTMLMeterElement::parseMappedAttribute(Attribute* attribute) 70 { 71 if (attribute->name() == valueAttr || attribute->name() == minAttr || attribute->name() == maxAttr || attribute->name() == lowAttr || attribute->name() == highAttr || attribute->name() == optimumAttr) 72 didElementStateChange(); 73 else 74 HTMLFormControlElement::parseMappedAttribute(attribute); 75 } 76 77 void HTMLMeterElement::attach() 78 { 79 HTMLFormControlElement::attach(); 80 didElementStateChange(); 81 } 82 83 double HTMLMeterElement::min() const 84 { 85 double min = 0; 86 parseToDoubleForNumberType(getAttribute(minAttr), &min); 87 return min; 88 } 89 90 void HTMLMeterElement::setMin(double min, ExceptionCode& ec) 91 { 92 if (!isfinite(min)) { 93 ec = NOT_SUPPORTED_ERR; 94 return; 95 } 96 setAttribute(minAttr, String::number(min)); 97 } 98 99 double HTMLMeterElement::max() const 100 { 101 double max = std::max(1.0, min()); 102 parseToDoubleForNumberType(getAttribute(maxAttr), &max); 103 return std::max(max, min()); 104 } 105 106 void HTMLMeterElement::setMax(double max, ExceptionCode& ec) 107 { 108 if (!isfinite(max)) { 109 ec = NOT_SUPPORTED_ERR; 110 return; 111 } 112 setAttribute(maxAttr, String::number(max)); 113 } 114 115 double HTMLMeterElement::value() const 116 { 117 double value = 0; 118 parseToDoubleForNumberType(getAttribute(valueAttr), &value); 119 return std::min(std::max(value, min()), max()); 120 } 121 122 void HTMLMeterElement::setValue(double value, ExceptionCode& ec) 123 { 124 if (!isfinite(value)) { 125 ec = NOT_SUPPORTED_ERR; 126 return; 127 } 128 setAttribute(valueAttr, String::number(value)); 129 } 130 131 double HTMLMeterElement::low() const 132 { 133 double low = min(); 134 parseToDoubleForNumberType(getAttribute(lowAttr), &low); 135 return std::min(std::max(low, min()), max()); 136 } 137 138 void HTMLMeterElement::setLow(double low, ExceptionCode& ec) 139 { 140 if (!isfinite(low)) { 141 ec = NOT_SUPPORTED_ERR; 142 return; 143 } 144 setAttribute(lowAttr, String::number(low)); 145 } 146 147 double HTMLMeterElement::high() const 148 { 149 double high = max(); 150 parseToDoubleForNumberType(getAttribute(highAttr), &high); 151 return std::min(std::max(high, low()), max()); 152 } 153 154 void HTMLMeterElement::setHigh(double high, ExceptionCode& ec) 155 { 156 if (!isfinite(high)) { 157 ec = NOT_SUPPORTED_ERR; 158 return; 159 } 160 setAttribute(highAttr, String::number(high)); 161 } 162 163 double HTMLMeterElement::optimum() const 164 { 165 double optimum = (max() + min()) / 2; 166 parseToDoubleForNumberType(getAttribute(optimumAttr), &optimum); 167 return std::min(std::max(optimum, min()), max()); 168 } 169 170 void HTMLMeterElement::setOptimum(double optimum, ExceptionCode& ec) 171 { 172 if (!isfinite(optimum)) { 173 ec = NOT_SUPPORTED_ERR; 174 return; 175 } 176 setAttribute(optimumAttr, String::number(optimum)); 177 } 178 179 HTMLMeterElement::GaugeRegion HTMLMeterElement::gaugeRegion() const 180 { 181 double lowValue = low(); 182 double highValue = high(); 183 double theValue = value(); 184 double optimumValue = optimum(); 185 186 if (optimumValue < lowValue) { 187 // The optimum range stays under low 188 if (theValue <= lowValue) 189 return GaugeRegionOptimum; 190 if (theValue <= highValue) 191 return GaugeRegionSuboptimal; 192 return GaugeRegionEvenLessGood; 193 } 194 195 if (highValue < optimumValue) { 196 // The optimum range stays over high 197 if (highValue <= theValue) 198 return GaugeRegionOptimum; 199 if (lowValue <= theValue) 200 return GaugeRegionSuboptimal; 201 return GaugeRegionEvenLessGood; 202 } 203 204 // The optimum range stays between high and low. 205 // According to the standard, <meter> never show GaugeRegionEvenLessGood in this case 206 // because the value is never less or greater than min or max. 207 if (lowValue <= theValue && theValue <= highValue) 208 return GaugeRegionOptimum; 209 return GaugeRegionSuboptimal; 210 } 211 212 double HTMLMeterElement::valueRatio() const 213 { 214 double min = this->min(); 215 double max = this->max(); 216 double value = this->value(); 217 218 if (max <= min) 219 return 0; 220 return (value - min) / (max - min); 221 } 222 223 void HTMLMeterElement::didElementStateChange() 224 { 225 m_value->setWidthPercentage(valueRatio()*100); 226 } 227 228 void HTMLMeterElement::createShadowSubtree() 229 { 230 RefPtr<MeterBarElement> bar = MeterBarElement::create(document()); 231 m_value = MeterValueElement::create(document()); 232 ExceptionCode ec = 0; 233 bar->appendChild(m_value, ec); 234 ensureShadowRoot()->appendChild(bar, ec); 235 } 236 237 } // namespace 238 #endif 239