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 "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/ProgressShadowElement.h"
     34 #include "core/rendering/RenderProgress.h"
     35 
     36 namespace blink {
     37 
     38 using namespace HTMLNames;
     39 
     40 const double HTMLProgressElement::IndeterminatePosition = -1;
     41 const double HTMLProgressElement::InvalidPosition = -2;
     42 
     43 HTMLProgressElement::HTMLProgressElement(Document& document)
     44     : LabelableElement(progressTag, document)
     45     , m_value(nullptr)
     46 {
     47     UseCounter::count(document, UseCounter::ProgressElement);
     48 }
     49 
     50 HTMLProgressElement::~HTMLProgressElement()
     51 {
     52 }
     53 
     54 PassRefPtrWillBeRawPtr<HTMLProgressElement> HTMLProgressElement::create(Document& document)
     55 {
     56     RefPtrWillBeRawPtr<HTMLProgressElement> progress = adoptRefWillBeNoop(new HTMLProgressElement(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 toRenderProgress(renderer());
     73 
     74     RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer();
     75     ASSERT_WITH_SECURITY_IMPLICATION(!renderObject || renderObject->isProgress());
     76     return toRenderProgress(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 = getFloatingPointAttribute(valueAttr);
     99     // Otherwise, if the parsed value was greater than or equal to the maximum
    100     // value, then the current value of the progress bar is the maximum value
    101     // of the progress bar. Otherwise, if parsing the value attribute's value
    102     // resulted in an error, or a number less than or equal to zero, then the
    103     // current value of the progress bar is zero.
    104     return !std::isfinite(value) || value < 0 ? 0 : std::min(value, max());
    105 }
    106 
    107 void HTMLProgressElement::setValue(double value)
    108 {
    109     setFloatingPointAttribute(valueAttr, std::max(value, 0.));
    110 }
    111 
    112 double HTMLProgressElement::max() const
    113 {
    114     double max = getFloatingPointAttribute(maxAttr);
    115     // Otherwise, if the element has no max attribute, or if it has one but
    116     // parsing it resulted in an error, or if the parsed value was less than or
    117     // equal to zero, then the maximum value of the progress bar is 1.0.
    118     return !std::isfinite(max) || max <= 0 ? 1 : max;
    119 }
    120 
    121 void HTMLProgressElement::setMax(double max)
    122 {
    123     // FIXME: The specification says we should ignore the input value if it is inferior or equal to 0.
    124     setFloatingPointAttribute(maxAttr, max > 0 ? max : 1);
    125 }
    126 
    127 double HTMLProgressElement::position() const
    128 {
    129     if (!isDeterminate())
    130         return HTMLProgressElement::IndeterminatePosition;
    131     return value() / max();
    132 }
    133 
    134 bool HTMLProgressElement::isDeterminate() const
    135 {
    136     return fastHasAttribute(valueAttr);
    137 }
    138 
    139 void HTMLProgressElement::didElementStateChange()
    140 {
    141     m_value->setWidthPercentage(position() * 100);
    142     if (RenderProgress* render = renderProgress()) {
    143         bool wasDeterminate = render->isDeterminate();
    144         render->updateFromElement();
    145         if (wasDeterminate != isDeterminate())
    146             pseudoStateChanged(CSSSelector::PseudoIndeterminate);
    147     }
    148 }
    149 
    150 void HTMLProgressElement::didAddUserAgentShadowRoot(ShadowRoot& root)
    151 {
    152     ASSERT(!m_value);
    153 
    154     RefPtrWillBeRawPtr<ProgressInnerElement> inner = ProgressInnerElement::create(document());
    155     inner->setShadowPseudoId(AtomicString("-webkit-progress-inner-element", AtomicString::ConstructFromLiteral));
    156     root.appendChild(inner);
    157 
    158     RefPtrWillBeRawPtr<ProgressBarElement> bar = ProgressBarElement::create(document());
    159     bar->setShadowPseudoId(AtomicString("-webkit-progress-bar", AtomicString::ConstructFromLiteral));
    160     RefPtrWillBeRawPtr<ProgressValueElement> value = ProgressValueElement::create(document());
    161     m_value = value.get();
    162     m_value->setShadowPseudoId(AtomicString("-webkit-progress-value", AtomicString::ConstructFromLiteral));
    163     m_value->setWidthPercentage(HTMLProgressElement::IndeterminatePosition * 100);
    164     bar->appendChild(m_value);
    165 
    166     inner->appendChild(bar);
    167 }
    168 
    169 bool HTMLProgressElement::shouldAppearIndeterminate() const
    170 {
    171     return !isDeterminate();
    172 }
    173 
    174 void HTMLProgressElement::trace(Visitor* visitor)
    175 {
    176     visitor->trace(m_value);
    177     LabelableElement::trace(visitor);
    178 }
    179 
    180 } // namespace
    181