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/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/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(const QualifiedName& tagName, Document* document)
     43     : LabelableElement(tagName, document)
     44     , m_value(0)
     45 {
     46     ASSERT(hasTagName(progressTag));
     47     ScriptWrappable::init(this);
     48 }
     49 
     50 HTMLProgressElement::~HTMLProgressElement()
     51 {
     52 }
     53 
     54 PassRefPtr<HTMLProgressElement> HTMLProgressElement::create(const QualifiedName& tagName, Document* document)
     55 {
     56     RefPtr<HTMLProgressElement> progress = adoptRef(new HTMLProgressElement(tagName, document));
     57     progress->ensureUserAgentShadowRoot();
     58     return progress.release();
     59 }
     60 
     61 RenderObject* HTMLProgressElement::createRenderer(RenderStyle* style)
     62 {
     63     if (!style->hasAppearance() || hasAuthorShadowRoot())
     64         return RenderObject::createObject(this, style);
     65 
     66     return new RenderProgress(this);
     67 }
     68 
     69 RenderProgress* HTMLProgressElement::renderProgress() const
     70 {
     71     if (renderer() && renderer()->isProgress())
     72         return static_cast<RenderProgress*>(renderer());
     73 
     74     RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer();
     75     ASSERT_WITH_SECURITY_IMPLICATION(!renderObject || renderObject->isProgress());
     76     return static_cast<RenderProgress*>(renderObject);
     77 }
     78 
     79 void HTMLProgressElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
     80 {
     81     if (name == valueAttr)
     82         didElementStateChange();
     83     else if (name == maxAttr)
     84         didElementStateChange();
     85     else
     86         LabelableElement::parseAttribute(name, value);
     87 }
     88 
     89 void HTMLProgressElement::attach(const AttachContext& context)
     90 {
     91     LabelableElement::attach(context);
     92     if (RenderProgress* render = renderProgress())
     93         render->updateFromElement();
     94 }
     95 
     96 double HTMLProgressElement::value() const
     97 {
     98     double value = parseToDoubleForNumberType(fastGetAttribute(valueAttr));
     99     return !std::isfinite(value) || value < 0 ? 0 : std::min(value, max());
    100 }
    101 
    102 void HTMLProgressElement::setValue(double value, ExceptionState& es)
    103 {
    104     if (!std::isfinite(value)) {
    105         es.throwDOMException(NotSupportedError);
    106         return;
    107     }
    108     setAttribute(valueAttr, String::number(value >= 0 ? value : 0));
    109 }
    110 
    111 double HTMLProgressElement::max() const
    112 {
    113     double max = parseToDoubleForNumberType(getAttribute(maxAttr));
    114     return !std::isfinite(max) || max <= 0 ? 1 : max;
    115 }
    116 
    117 void HTMLProgressElement::setMax(double max, ExceptionState& es)
    118 {
    119     if (!std::isfinite(max)) {
    120         es.throwDOMException(NotSupportedError);
    121         return;
    122     }
    123     setAttribute(maxAttr, String::number(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     root->appendChild(inner);
    155 
    156     RefPtr<ProgressBarElement> bar = ProgressBarElement::create(document());
    157     RefPtr<ProgressValueElement> value = ProgressValueElement::create(document());
    158     m_value = value.get();
    159     m_value->setWidthPercentage(HTMLProgressElement::IndeterminatePosition * 100);
    160     bar->appendChild(m_value, ASSERT_NO_EXCEPTION);
    161 
    162     inner->appendChild(bar, ASSERT_NO_EXCEPTION);
    163 }
    164 
    165 bool HTMLProgressElement::shouldAppearIndeterminate() const
    166 {
    167     return !isDeterminate();
    168 }
    169 
    170 } // namespace
    171