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