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 36namespace WebCore { 37 38using namespace HTMLNames; 39 40RenderButton::RenderButton(Node* node) 41 : RenderFlexibleBox(node) 42 , m_buttonText(0) 43 , m_inner(0) 44 , m_default(false) 45{ 46} 47 48void 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 62void 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 71void 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 83void 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 104void 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 innerStyle->setPaddingTop(Length(theme()->buttonInternalPaddingTop(), Fixed)); 113 innerStyle->setPaddingRight(Length(theme()->buttonInternalPaddingRight(), Fixed)); 114 innerStyle->setPaddingBottom(Length(theme()->buttonInternalPaddingBottom(), Fixed)); 115 innerStyle->setPaddingLeft(Length(theme()->buttonInternalPaddingLeft(), Fixed)); 116} 117 118void RenderButton::updateFromElement() 119{ 120 // If we're an input element, we may need to change our button text. 121 if (node()->hasTagName(inputTag)) { 122 HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); 123 String value = input->valueWithDefault(); 124 setText(value); 125 } 126 127 128#if ENABLE(WML) 129 else if (node()->hasTagName(WMLNames::doTag)) { 130 WMLDoElement* doElement = static_cast<WMLDoElement*>(node()); 131 132 String value = doElement->label(); 133 if (value.isEmpty()) 134 value = doElement->name(); 135 136 setText(value); 137 } 138#endif 139} 140 141bool RenderButton::canHaveChildren() const 142{ 143 // Input elements can't have children, but button elements can. We'll 144 // write the code assuming any other button types that might emerge in the future 145 // can also have children. 146 return !node()->hasTagName(inputTag); 147} 148 149void RenderButton::setText(const String& str) 150{ 151 if (str.isEmpty()) { 152 if (m_buttonText) { 153 m_buttonText->destroy(); 154 m_buttonText = 0; 155 } 156 } else { 157 if (m_buttonText) 158 m_buttonText->setText(str.impl()); 159 else { 160 m_buttonText = new (renderArena()) RenderTextFragment(document(), str.impl()); 161 m_buttonText->setStyle(style()); 162 addChild(m_buttonText); 163 } 164 } 165} 166 167String RenderButton::text() const 168{ 169 return m_buttonText ? m_buttonText->text() : 0; 170} 171 172void RenderButton::updateBeforeAfterContent(PseudoId type) 173{ 174 if (m_inner) 175 m_inner->children()->updateBeforeAfterContent(m_inner, type, this); 176 else 177 children()->updateBeforeAfterContent(this, type); 178} 179 180IntRect RenderButton::controlClipRect(int tx, int ty) const 181{ 182 // Clip to the padding box to at least give content the extra padding space. 183 return IntRect(tx + borderLeft(), ty + borderTop(), width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom()); 184} 185 186void RenderButton::timerFired(Timer<RenderButton>*) 187{ 188 // FIXME Bug 25110: Ideally we would stop our timer when our Document 189 // enters the page cache. But we currently have no way of being notified 190 // when that happens, so we'll just ignore the timer firing as long as 191 // we're in the cache. 192 if (document()->inPageCache()) 193 return; 194 195 repaint(); 196} 197 198} // namespace WebCore 199