Node.appendChild(null) / replaceChild(null, null) / removeChild(null) / insertBefore...
[WebKit-https.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 #include "HTMLProgressElement.h"
23
24 #include "ElementIterator.h"
25 #include "EventNames.h"
26 #include "ExceptionCode.h"
27 #include "HTMLNames.h"
28 #include "HTMLParserIdioms.h"
29 #include "ProgressShadowElement.h"
30 #include "RenderProgress.h"
31 #include "ShadowRoot.h"
32
33 namespace WebCore {
34
35 using namespace HTMLNames;
36
37 const double HTMLProgressElement::IndeterminatePosition = -1;
38 const double HTMLProgressElement::InvalidPosition = -2;
39
40 HTMLProgressElement::HTMLProgressElement(const QualifiedName& tagName, Document& document)
41     : LabelableElement(tagName, document)
42     , m_value(0)
43 {
44     ASSERT(hasTagName(progressTag));
45     setHasCustomStyleResolveCallbacks();
46 }
47
48 HTMLProgressElement::~HTMLProgressElement()
49 {
50 }
51
52 Ref<HTMLProgressElement> HTMLProgressElement::create(const QualifiedName& tagName, Document& document)
53 {
54     Ref<HTMLProgressElement> progress = adoptRef(*new HTMLProgressElement(tagName, document));
55     progress->ensureUserAgentShadowRoot();
56     return progress;
57 }
58
59 RenderPtr<RenderElement> HTMLProgressElement::createElementRenderer(Ref<RenderStyle>&& style, const RenderTreePosition&)
60 {
61     if (!style.get().hasAppearance())
62         return RenderElement::createFor(*this, WTF::move(style));
63
64     return createRenderer<RenderProgress>(*this, WTF::move(style));
65 }
66
67 bool HTMLProgressElement::childShouldCreateRenderer(const Node& child) const
68 {
69     return hasShadowRootParent(child) && HTMLElement::childShouldCreateRenderer(child);
70 }
71
72 RenderProgress* HTMLProgressElement::renderProgress() const
73 {
74     if (is<RenderProgress>(renderer()))
75         return downcast<RenderProgress>(renderer());
76     return downcast<RenderProgress>(descendantsOfType<Element>(*userAgentShadowRoot()).first()->renderer());
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::didAttachRenderers()
90 {
91     if (RenderProgress* render = renderProgress())
92         render->updateFromElement();
93 }
94
95 double HTMLProgressElement::value() const
96 {
97     double value = parseToDoubleForNumberType(fastGetAttribute(valueAttr));
98     return !std::isfinite(value) || value < 0 ? 0 : std::min(value, max());
99 }
100
101 void HTMLProgressElement::setValue(double value, ExceptionCode& ec)
102 {
103     if (!std::isfinite(value)) {
104         ec = NOT_SUPPORTED_ERR;
105         return;
106     }
107     setAttribute(valueAttr, AtomicString::number(value >= 0 ? value : 0));
108 }
109
110 double HTMLProgressElement::max() const
111 {
112     double max = parseToDoubleForNumberType(fastGetAttribute(maxAttr));
113     return !std::isfinite(max) || max <= 0 ? 1 : max;
114 }
115
116 void HTMLProgressElement::setMax(double max, ExceptionCode& ec)
117 {
118     if (!std::isfinite(max)) {
119         ec = NOT_SUPPORTED_ERR;
120         return;
121     }
122     setAttribute(maxAttr, AtomicString::number(max > 0 ? max : 1));
123 }
124
125 double HTMLProgressElement::position() const
126 {
127     if (!isDeterminate())
128         return HTMLProgressElement::IndeterminatePosition;
129     return value() / max();
130 }
131
132 bool HTMLProgressElement::isDeterminate() const
133 {
134     return fastHasAttribute(valueAttr);
135 }
136     
137 void HTMLProgressElement::didElementStateChange()
138 {
139     m_value->setWidthPercentage(position() * 100);
140     if (RenderProgress* render = renderProgress()) {
141         bool wasDeterminate = render->isDeterminate();
142         render->updateFromElement();
143         if (wasDeterminate != isDeterminate())
144             setNeedsStyleRecalc();
145     }
146 }
147
148 void HTMLProgressElement::didAddUserAgentShadowRoot(ShadowRoot* root)
149 {
150     ASSERT(!m_value);
151
152     Ref<ProgressInnerElement> inner = ProgressInnerElement::create(document());
153     root->appendChild(inner.copyRef());
154
155     Ref<ProgressBarElement> bar = ProgressBarElement::create(document());
156     Ref<ProgressValueElement> value = ProgressValueElement::create(document());
157     m_value = value.ptr();
158     m_value->setWidthPercentage(HTMLProgressElement::IndeterminatePosition * 100);
159     bar->appendChild(*m_value, ASSERT_NO_EXCEPTION);
160
161     inner->appendChild(WTF::move(bar), ASSERT_NO_EXCEPTION);
162 }
163
164 bool HTMLProgressElement::shouldAppearIndeterminate() const
165 {
166     return !isDeterminate();
167 }
168
169 } // namespace