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