• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2005 Apple Computer, Inc.
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 "RenderButton.h"
23 
24 #include "Document.h"
25 #include "GraphicsContext.h"
26 #include "HTMLInputElement.h"
27 #include "HTMLNames.h"
28 #include "RenderTextFragment.h"
29 #include "RenderTheme.h"
30 
31 #if ENABLE(WML)
32 #include "WMLDoElement.h"
33 #include "WMLNames.h"
34 #endif
35 
36 namespace WebCore {
37 
38 using namespace HTMLNames;
39 
RenderButton(Node * node)40 RenderButton::RenderButton(Node* node)
41     : RenderFlexibleBox(node)
42     , m_buttonText(0)
43     , m_inner(0)
44     , m_default(false)
45 {
46 }
47 
~RenderButton()48 RenderButton::~RenderButton()
49 {
50 }
51 
addChild(RenderObject * newChild,RenderObject * beforeChild)52 void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild)
53 {
54     if (!m_inner) {
55         // Create an anonymous block.
56         ASSERT(!firstChild());
57         bool isFlexibleBox = style()->display() == BOX || style()->display() == INLINE_BOX;
58         m_inner = createAnonymousBlock(isFlexibleBox);
59         setupInnerStyle(m_inner->style());
60         RenderFlexibleBox::addChild(m_inner);
61     }
62 
63     m_inner->addChild(newChild, beforeChild);
64 }
65 
removeChild(RenderObject * oldChild)66 void RenderButton::removeChild(RenderObject* oldChild)
67 {
68     if (oldChild == m_inner || !m_inner) {
69         RenderFlexibleBox::removeChild(oldChild);
70         m_inner = 0;
71     } else
72         m_inner->removeChild(oldChild);
73 }
74 
styleWillChange(StyleDifference diff,const RenderStyle * newStyle)75 void RenderButton::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
76 {
77     if (m_inner) {
78         // RenderBlock::setStyle is going to apply a new style to the inner block, which
79         // will have the initial box flex value, 0. The current value is 1, because we set
80         // it right below. Here we change it back to 0 to avoid getting a spurious layout hint
81         // because of the difference.
82         m_inner->style()->setBoxFlex(0);
83     }
84     RenderBlock::styleWillChange(diff, newStyle);
85 }
86 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)87 void RenderButton::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
88 {
89     RenderBlock::styleDidChange(diff, oldStyle);
90 
91     if (m_buttonText)
92         m_buttonText->setStyle(style());
93     if (m_inner) // RenderBlock handled updating the anonymous block's style.
94         setupInnerStyle(m_inner->style());
95 
96     if (!m_default && theme()->isDefault(this)) {
97         if (!m_timer)
98             m_timer.set(new Timer<RenderButton>(this, &RenderButton::timerFired));
99         m_timer->startRepeating(0.03);
100         m_default = true;
101     } else if (m_default && !theme()->isDefault(this)) {
102         m_default = false;
103         m_timer.clear();
104     }
105 }
106 
setupInnerStyle(RenderStyle * innerStyle)107 void RenderButton::setupInnerStyle(RenderStyle* innerStyle)
108 {
109     ASSERT(innerStyle->refCount() == 1);
110     // RenderBlock::createAnonymousBlock creates a new RenderStyle, so this is
111     // safe to modify.
112     innerStyle->setBoxFlex(1.0f);
113     innerStyle->setBoxOrient(style()->boxOrient());
114 }
115 
updateFromElement()116 void RenderButton::updateFromElement()
117 {
118     // If we're an input element, we may need to change our button text.
119     if (node()->hasTagName(inputTag)) {
120         HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
121         String value = input->valueWithDefault();
122         setText(value);
123     }
124 
125 
126 #if ENABLE(WML)
127     else if (node()->hasTagName(WMLNames::doTag)) {
128         WMLDoElement* doElement = static_cast<WMLDoElement*>(node());
129 
130         String value = doElement->label();
131         if (value.isEmpty())
132             value = doElement->name();
133 
134         setText(value);
135     }
136 #endif
137 }
138 
canHaveChildren() const139 bool RenderButton::canHaveChildren() const
140 {
141     // Input elements can't have children, but button elements can.  We'll
142     // write the code assuming any other button types that might emerge in the future
143     // can also have children.
144     return !node()->hasTagName(inputTag);
145 }
146 
setText(const String & str)147 void RenderButton::setText(const String& str)
148 {
149     if (str.isEmpty()) {
150         if (m_buttonText) {
151             m_buttonText->destroy();
152             m_buttonText = 0;
153         }
154     } else {
155         if (m_buttonText)
156             m_buttonText->setText(str.impl());
157         else {
158             m_buttonText = new (renderArena()) RenderTextFragment(document(), str.impl());
159             m_buttonText->setStyle(style());
160             addChild(m_buttonText);
161         }
162     }
163 }
164 
text() const165 String RenderButton::text() const
166 {
167     return m_buttonText ? m_buttonText->text() : 0;
168 }
169 
updateBeforeAfterContent(PseudoId type)170 void RenderButton::updateBeforeAfterContent(PseudoId type)
171 {
172     if (m_inner)
173         m_inner->children()->updateBeforeAfterContent(m_inner, type, this);
174     else
175         children()->updateBeforeAfterContent(this, type);
176 }
177 
controlClipRect(int tx,int ty) const178 IntRect RenderButton::controlClipRect(int tx, int ty) const
179 {
180     // Clip to the padding box to at least give content the extra padding space.
181     return IntRect(tx + borderLeft(), ty + borderTop(), width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom());
182 }
183 
timerFired(Timer<RenderButton> *)184 void RenderButton::timerFired(Timer<RenderButton>*)
185 {
186     // FIXME Bug 25110: Ideally we would stop our timer when our Document
187     // enters the page cache. But we currently have no way of being notified
188     // when that happens, so we'll just ignore the timer firing as long as
189     // we're in the cache.
190     if (document()->inPageCache())
191         return;
192 
193     repaint();
194 }
195 
196 } // namespace WebCore
197