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