1 | /** |
2 | * Copyright (C) 2005 Apple 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 | #include "RenderTreeBuilder.h" |
31 | #include "StyleInheritedData.h" |
32 | #include <wtf/IsoMallocInlines.h> |
33 | |
34 | #if PLATFORM(IOS_FAMILY) |
35 | #include "RenderThemeIOS.h" |
36 | #endif |
37 | |
38 | namespace WebCore { |
39 | |
40 | using namespace HTMLNames; |
41 | |
42 | WTF_MAKE_ISO_ALLOCATED_IMPL(RenderButton); |
43 | |
44 | RenderButton::RenderButton(HTMLFormControlElement& element, RenderStyle&& style) |
45 | : RenderFlexibleBox(element, WTFMove(style)) |
46 | { |
47 | } |
48 | |
49 | RenderButton::~RenderButton() = default; |
50 | |
51 | HTMLFormControlElement& RenderButton::formControlElement() const |
52 | { |
53 | return downcast<HTMLFormControlElement>(nodeForNonAnonymous()); |
54 | } |
55 | |
56 | bool RenderButton::canBeSelectionLeaf() const |
57 | { |
58 | return formControlElement().hasEditableStyle(); |
59 | } |
60 | |
61 | bool RenderButton::hasLineIfEmpty() const |
62 | { |
63 | return is<HTMLInputElement>(formControlElement()); |
64 | } |
65 | |
66 | void RenderButton::setInnerRenderer(RenderBlock& innerRenderer) |
67 | { |
68 | ASSERT(!m_inner.get()); |
69 | m_inner = makeWeakPtr(innerRenderer); |
70 | updateAnonymousChildStyle(m_inner->mutableStyle()); |
71 | } |
72 | |
73 | void RenderButton::updateAnonymousChildStyle(RenderStyle& childStyle) const |
74 | { |
75 | childStyle.setFlexGrow(1.0f); |
76 | // min-width: 0; is needed for correct shrinking. |
77 | childStyle.setMinWidth(Length(0, Fixed)); |
78 | // Use margin:auto instead of align-items:center to get safe centering, i.e. |
79 | // when the content overflows, treat it the same as align-items: flex-start. |
80 | childStyle.setMarginTop(Length()); |
81 | childStyle.setMarginBottom(Length()); |
82 | childStyle.setFlexDirection(style().flexDirection()); |
83 | childStyle.setJustifyContent(style().justifyContent()); |
84 | childStyle.setFlexWrap(style().flexWrap()); |
85 | childStyle.setAlignItems(style().alignItems()); |
86 | childStyle.setAlignContent(style().alignContent()); |
87 | } |
88 | |
89 | void RenderButton::updateFromElement() |
90 | { |
91 | // If we're an input element, we may need to change our button text. |
92 | if (is<HTMLInputElement>(formControlElement())) { |
93 | HTMLInputElement& input = downcast<HTMLInputElement>(formControlElement()); |
94 | String value = input.valueWithDefault(); |
95 | setText(value); |
96 | } |
97 | } |
98 | |
99 | void RenderButton::setText(const String& str) |
100 | { |
101 | if (!m_buttonText && str.isEmpty()) |
102 | return; |
103 | |
104 | if (!m_buttonText) { |
105 | auto newButtonText = createRenderer<RenderTextFragment>(document(), str); |
106 | m_buttonText = makeWeakPtr(*newButtonText); |
107 | // FIXME: This mutation should go through the normal RenderTreeBuilder path. |
108 | if (RenderTreeBuilder::current()) |
109 | RenderTreeBuilder::current()->attach(*this, WTFMove(newButtonText)); |
110 | else |
111 | RenderTreeBuilder(*document().renderView()).attach(*this, WTFMove(newButtonText)); |
112 | return; |
113 | } |
114 | |
115 | if (!str.isEmpty()) { |
116 | m_buttonText->setText(str.impl()); |
117 | return; |
118 | } |
119 | if (RenderTreeBuilder::current()) |
120 | RenderTreeBuilder::current()->destroy(*m_buttonText); |
121 | else |
122 | RenderTreeBuilder(*document().renderView()).destroy(*m_buttonText); |
123 | } |
124 | |
125 | String RenderButton::text() const |
126 | { |
127 | if (m_buttonText) |
128 | return m_buttonText->text(); |
129 | return { }; |
130 | } |
131 | |
132 | bool RenderButton::canHaveGeneratedChildren() const |
133 | { |
134 | // Input elements can't have generated children, but button elements can. We'll |
135 | // write the code assuming any other button types that might emerge in the future |
136 | // can also have children. |
137 | return !is<HTMLInputElement>(formControlElement()); |
138 | } |
139 | |
140 | LayoutRect RenderButton::controlClipRect(const LayoutPoint& additionalOffset) const |
141 | { |
142 | // Clip to the padding box to at least give content the extra padding space. |
143 | return LayoutRect(additionalOffset.x() + borderLeft(), additionalOffset.y() + borderTop(), width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom()); |
144 | } |
145 | |
146 | static int synthesizedBaselineFromContentBox(const RenderBox& box, LineDirectionMode direction) |
147 | { |
148 | return direction == HorizontalLine ? box.borderTop() + box.paddingTop() + box.contentHeight() : box.borderRight() + box.paddingRight() + box.contentWidth(); |
149 | } |
150 | |
151 | int RenderButton::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode) const |
152 | { |
153 | // We cannot rely on RenderFlexibleBox::baselinePosition() because of flexboxes have some special behavior |
154 | // regarding baselines that shouldn't apply to buttons. |
155 | int baseline = firstLineBaseline().valueOr(synthesizedBaselineFromContentBox(*this, direction)); |
156 | int marginAscent = direction == HorizontalLine ? marginTop() : marginRight(); |
157 | return baseline + marginAscent; |
158 | } |
159 | |
160 | #if PLATFORM(IOS_FAMILY) |
161 | void RenderButton::layout() |
162 | { |
163 | RenderFlexibleBox::layout(); |
164 | |
165 | // FIXME: We should not be adjusting styles during layout. See <rdar://problem/7675493>. |
166 | RenderThemeIOS::adjustRoundBorderRadius(mutableStyle(), *this); |
167 | } |
168 | #endif |
169 | |
170 | } // namespace WebCore |
171 | |