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 #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