7824fa86bf7e789c5bc8278f7233a021424029fc
[WebKit.git] / Source / WebCore / html / HTMLProgressElement.cpp
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(PROGRESS_TAG)
23 #include "HTMLProgressElement.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 "RenderProgress.h"
33 #include "ShadowElement.h"
34 #include <wtf/StdLibExtras.h>
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
40 class ProgressBarValueElement : public ShadowBlockElement {
41 public:
42     ProgressBarValueElement(HTMLElement* shadowParent) 
43         : ShadowBlockElement(shadowParent)
44     {
45     }
46
47     virtual const AtomicString& shadowPseudoId() const
48     {
49         DEFINE_STATIC_LOCAL(AtomicString, pseudId, ("-webkit-progress-bar-value"));
50         return pseudId;
51     }
52
53     virtual void detach()
54     {
55         // Instead of using setShadowHost() like ShadowBlockElement does,
56         // this class uses setShadowRoot() to unlink mutual shadow-host references.
57         // Note that ShadowBlockElement::detach() should be removed when the
58         // shadow model transition is over. (Bug 53417)
59         if (Element* host = shadowHost())
60             host->setShadowRoot(0);
61         ShadowBlockElement::setShadowHost(0);
62     }
63
64     static PassRefPtr<ProgressBarValueElement> create(HTMLElement* shadowParent)
65     {
66         return adoptRef(new ProgressBarValueElement(shadowParent));
67     }
68
69 };
70
71 HTMLProgressElement::HTMLProgressElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
72     : HTMLFormControlElement(tagName, document, form)
73 {
74     ASSERT(hasTagName(progressTag));
75 }
76
77 PassRefPtr<HTMLProgressElement> HTMLProgressElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
78 {
79     return adoptRef(new HTMLProgressElement(tagName, document, form));
80 }
81
82 RenderObject* HTMLProgressElement::createRenderer(RenderArena* arena, RenderStyle*)
83 {
84     return new (arena) RenderProgress(this);
85 }
86
87 const AtomicString& HTMLProgressElement::formControlType() const
88 {
89     DEFINE_STATIC_LOCAL(const AtomicString, progress, ("progress"));
90     return progress;
91 }
92
93 void HTMLProgressElement::parseMappedAttribute(Attribute* attribute)
94 {
95     if (attribute->name() == valueAttr)
96         didElementStateChange();
97     else if (attribute->name() == maxAttr)
98         didElementStateChange();
99     else
100         HTMLFormControlElement::parseMappedAttribute(attribute);
101 }
102
103 void HTMLProgressElement::attach()
104 {
105     createShadowSubtreeIfNeeded();
106     HTMLFormControlElement::attach();
107     didElementStateChange();
108 }
109
110 double HTMLProgressElement::value() const
111 {
112     const AtomicString& valueString = getAttribute(valueAttr);
113     double value;
114     bool ok = parseToDoubleForNumberType(valueString, &value);
115     if (!ok || value < 0)
116         return valueString.isNull() ? 1 : 0;
117     return (value > max()) ? max() : value;
118 }
119
120 void HTMLProgressElement::setValue(double value, ExceptionCode& ec)
121 {
122     if (!isfinite(value)) {
123         ec = NOT_SUPPORTED_ERR;
124         return;
125     }
126     setAttribute(valueAttr, String::number(value >= 0 ? value : 0));
127 }
128
129 double HTMLProgressElement::max() const
130 {
131     double max;
132     bool ok = parseToDoubleForNumberType(getAttribute(maxAttr), &max);
133     if (!ok || max <= 0)
134         return 1;
135     return max;
136 }
137
138 void HTMLProgressElement::setMax(double max, ExceptionCode& ec)
139 {
140     if (!isfinite(max)) {
141         ec = NOT_SUPPORTED_ERR;
142         return;
143     }
144     setAttribute(maxAttr, String::number(max > 0 ? max : 1));
145 }
146
147 double HTMLProgressElement::position() const
148 {
149     if (!hasAttribute(valueAttr))
150         return -1;
151     return value() / max();
152 }
153
154 ShadowBlockElement* HTMLProgressElement::valuePart()
155 {
156     return static_cast<ShadowBlockElement*>(shadowRoot());
157 }
158
159 void HTMLProgressElement::didElementStateChange()
160 {
161     if (renderer())
162         renderer()->updateFromElement();
163 }
164
165 void HTMLProgressElement::createShadowSubtreeIfNeeded()
166 {
167     if (shadowRoot())
168         return;
169     setShadowRoot(ProgressBarValueElement::create(this).get());
170 }
171
172 } // namespace
173 #endif