Home | History | Annotate | Download | only in html
      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 
     37 namespace WebCore {
     38 
     39 using namespace HTMLNames;
     40 
     41 HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document)
     42     : LabelableElement(tagName, document)
     43 {
     44     ASSERT(hasTagName(meterTag));
     45     ScriptWrappable::init(this);
     46 }
     47 
     48 HTMLMeterElement::~HTMLMeterElement()
     49 {
     50 }
     51 
     52 PassRefPtr<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 
     59 RenderObject* 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 
     67 void 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 
     75 double HTMLMeterElement::min() const
     76 {
     77     return parseToDoubleForNumberType(getAttribute(minAttr), 0);
     78 }
     79 
     80 void 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 
     89 double HTMLMeterElement::max() const
     90 {
     91     return std::max(parseToDoubleForNumberType(getAttribute(maxAttr), std::max(1.0, min())), min());
     92 }
     93 
     94 void 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 
    103 double HTMLMeterElement::value() const
    104 {
    105     double value = parseToDoubleForNumberType(getAttribute(valueAttr), 0);
    106     return std::min(std::max(value, min()), max());
    107 }
    108 
    109 void 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 
    118 double HTMLMeterElement::low() const
    119 {
    120     double low = parseToDoubleForNumberType(getAttribute(lowAttr), min());
    121     return std::min(std::max(low, min()), max());
    122 }
    123 
    124 void 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 
    133 double HTMLMeterElement::high() const
    134 {
    135     double high = parseToDoubleForNumberType(getAttribute(highAttr), max());
    136     return std::min(std::max(high, low()), max());
    137 }
    138 
    139 void 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 
    148 double HTMLMeterElement::optimum() const
    149 {
    150     double optimum = parseToDoubleForNumberType(getAttribute(optimumAttr), (max() + min()) / 2);
    151     return std::min(std::max(optimum, min()), max());
    152 }
    153 
    154 void 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 
    163 HTMLMeterElement::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 
    196 double 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 
    207 void HTMLMeterElement::didElementStateChange()
    208 {
    209     m_value->setWidthPercentage(valueRatio()*100);
    210     m_value->updatePseudo();
    211     if (RenderMeter* render = renderMeter())
    212         render->updateFromElement();
    213 }
    214 
    215 RenderMeter* 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 
    225 void 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