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/HTMLProgressElement.h"
     24 
     25 #include "HTMLNames.h"
     26 #include "bindings/v8/ExceptionMessages.h"
     27 #include "bindings/v8/ExceptionState.h"
     28 #include "bindings/v8/ExceptionStatePlaceholder.h"
     29 #include "core/dom/ExceptionCode.h"
     30 #include "core/dom/shadow/ShadowRoot.h"
     31 #include "core/html/parser/HTMLParserIdioms.h"
     32 #include "core/html/shadow/ProgressShadowElement.h"
     33 #include "core/rendering/RenderProgress.h"
     34 
     35 namespace WebCore {
     36 
     37 using namespace HTMLNames;
     38 
     39 const double HTMLProgressElement::IndeterminatePosition = -1;
     40 const double HTMLProgressElement::InvalidPosition = -2;
     41 
     42 HTMLProgressElement::HTMLProgressElement(Document& document)
     43     : LabelableElement(progressTag, document)
     44     , m_value(0)
     45 {
     46     ScriptWrappable::init(this);
     47 }
     48 
     49 HTMLProgressElement::~HTMLProgressElement()
     50 {
     51 }
     52 
     53 PassRefPtr<HTMLProgressElement> HTMLProgressElement::create(Document& document)
     54 {
     55     RefPtr<HTMLProgressElement> progress = adoptRef(new HTMLProgressElement(document));
     56     progress->ensureUserAgentShadowRoot();
     57     return progress.release();
     58 }
     59 
     60 RenderObject* HTMLProgressElement::createRenderer(RenderStyle* style)
     61 {
     62     if (!style->hasAppearance() || hasAuthorShadowRoot())
     63         return RenderObject::createObject(this, style);
     64 
     65     return new RenderProgress(this);
     66 }
     67 
     68 RenderProgress* HTMLProgressElement::renderProgress() const
     69 {
     70     if (renderer() && renderer()->isProgress())
     71         return toRenderProgress(renderer());
     72 
     73     RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer();
     74     ASSERT_WITH_SECURITY_IMPLICATION(!renderObject || renderObject->isProgress());
     75     return toRenderProgress(renderObject);
     76 }
     77 
     78 void HTMLProgressElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
     79 {
     80     if (name == valueAttr)
     81         didElementStateChange();
     82     else if (name == maxAttr)
     83         didElementStateChange();
     84     else
     85         LabelableElement::parseAttribute(name, value);
     86 }
     87 
     88 void HTMLProgressElement::attach(const AttachContext& context)
     89 {
     90     LabelableElement::attach(context);
     91     if (RenderProgress* render = renderProgress())
     92         render->updateFromElement();
     93 }
     94 
     95 double HTMLProgressElement::value() const
     96 {
     97     double value = getFloatingPointAttribute(valueAttr);
     98     return !std::isfinite(value) || value < 0 ? 0 : std::min(value, max());
     99 }
    100 
    101 void HTMLProgressElement::setValue(double value, ExceptionState& exceptionState)
    102 {
    103     if (!std::isfinite(value)) {
    104         exceptionState.throwDOMException(NotSupportedError, ExceptionMessages::notAFiniteNumber(value));
    105         return;
    106     }
    107     setFloatingPointAttribute(valueAttr, std::max(value, 0.));
    108 }
    109 
    110 double HTMLProgressElement::max() const
    111 {
    112     double max = getFloatingPointAttribute(maxAttr);
    113     return !std::isfinite(max) || max <= 0 ? 1 : max;
    114 }
    115 
    116 void HTMLProgressElement::setMax(double max, ExceptionState& exceptionState)
    117 {
    118     if (!std::isfinite(max)) {
    119         exceptionState.throwDOMException(NotSupportedError, ExceptionMessages::notAFiniteNumber(max));
    120         return;
    121     }
    122     // FIXME: The specification says we should ignore the input value if it is inferior or equal to 0.
    123     setFloatingPointAttribute(maxAttr, max > 0 ? max : 1);
    124 }
    125 
    126 double HTMLProgressElement::position() const
    127 {
    128     if (!isDeterminate())
    129         return HTMLProgressElement::IndeterminatePosition;
    130     return value() / max();
    131 }
    132 
    133 bool HTMLProgressElement::isDeterminate() const
    134 {
    135     return fastHasAttribute(valueAttr);
    136 }
    137 
    138 void HTMLProgressElement::didElementStateChange()
    139 {
    140     m_value->setWidthPercentage(position() * 100);
    141     if (RenderProgress* render = renderProgress()) {
    142         bool wasDeterminate = render->isDeterminate();
    143         render->updateFromElement();
    144         if (wasDeterminate != isDeterminate())
    145             didAffectSelector(AffectedSelectorIndeterminate);
    146     }
    147 }
    148 
    149 void HTMLProgressElement::didAddUserAgentShadowRoot(ShadowRoot& root)
    150 {
    151     ASSERT(!m_value);
    152 
    153     RefPtr<ProgressInnerElement> inner = ProgressInnerElement::create(document());
    154     inner->setPseudo(AtomicString("-webkit-progress-inner-element", AtomicString::ConstructFromLiteral));
    155     root.appendChild(inner);
    156 
    157     RefPtr<ProgressBarElement> bar = ProgressBarElement::create(document());
    158     bar->setPseudo(AtomicString("-webkit-progress-bar", AtomicString::ConstructFromLiteral));
    159     RefPtr<ProgressValueElement> value = ProgressValueElement::create(document());
    160     m_value = value.get();
    161     m_value->setPseudo(AtomicString("-webkit-progress-value", AtomicString::ConstructFromLiteral));
    162     m_value->setWidthPercentage(HTMLProgressElement::IndeterminatePosition * 100);
    163     bar->appendChild(m_value);
    164 
    165     inner->appendChild(bar);
    166 }
    167 
    168 bool HTMLProgressElement::shouldAppearIndeterminate() const
    169 {
    170     return !isDeterminate();
    171 }
    172 
    173 } // namespace
    174