1 /*
2 * Copyright 2006, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "RenderThemeAndroid.h"
28
29 #include "Color.h"
30 #include "Element.h"
31 #include "GraphicsContext.h"
32 #include "PlatformGraphicsContext.h"
33 #include "RenderSkinAndroid.h"
34 #include "RenderSkinButton.h"
35 #include "RenderSkinCombo.h"
36 #include "RenderSkinRadio.h"
37 #include "SkCanvas.h"
38
39 namespace WebCore {
40
41 const int MAX_COMBO_HEIGHT = 20;
42
43 // Add a constant amount of padding to the textsize to get the final height
44 // of buttons, so that our button images are large enough to properly fit
45 // the text.
46 const int BUTTON_PADDING = 18;
47
48 // Add padding to the fontSize of ListBoxes to get their maximum sizes.
49 // Listboxes often have a specified size. Since we change them into
50 // dropdowns, we want a much smaller height, which encompasses the text.
51 const int LISTBOX_PADDING = 5;
52
53 // This is the color of selection in a textfield. It was obtained by checking
54 // the color of selection in TextViews in the system.
55 const RGBA32 SELECTION_COLOR = makeRGB(255, 146, 0);
56
getCanvasFromInfo(const RenderObject::PaintInfo & info)57 static SkCanvas* getCanvasFromInfo(const RenderObject::PaintInfo& info)
58 {
59 return info.context->platformContext()->mCanvas;
60 }
61
theme()62 RenderTheme* theme()
63 {
64 static RenderThemeAndroid androidTheme;
65 return &androidTheme;
66 }
67
themeForPage(Page * page)68 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
69 {
70 RefPtr<RenderThemeAndroid> androidTheme = new RenderThemeAndroid();
71 return androidTheme.release();
72 }
73
RenderThemeAndroid()74 RenderThemeAndroid::RenderThemeAndroid()
75 {
76 }
77
~RenderThemeAndroid()78 RenderThemeAndroid::~RenderThemeAndroid()
79 {
80 }
81
close()82 void RenderThemeAndroid::close()
83 {
84 }
85
stateChanged(RenderObject * obj,ControlState state) const86 bool RenderThemeAndroid::stateChanged(RenderObject* obj, ControlState state) const
87 {
88 if (CheckedState == state) {
89 obj->repaint();
90 return true;
91 }
92 return false;
93 }
94
platformActiveSelectionBackgroundColor() const95 Color RenderThemeAndroid::platformActiveSelectionBackgroundColor() const
96 {
97 return Color(SELECTION_COLOR);
98 }
99
platformInactiveSelectionBackgroundColor() const100 Color RenderThemeAndroid::platformInactiveSelectionBackgroundColor() const
101 {
102 return Color(Color::transparent);
103 }
104
platformActiveSelectionForegroundColor() const105 Color RenderThemeAndroid::platformActiveSelectionForegroundColor() const
106 {
107 return Color::black;
108 }
109
platformInactiveSelectionForegroundColor() const110 Color RenderThemeAndroid::platformInactiveSelectionForegroundColor() const
111 {
112 return Color::black;
113 }
114
platformTextSearchHighlightColor() const115 Color RenderThemeAndroid::platformTextSearchHighlightColor() const
116 {
117 return Color(Color::transparent);
118 }
119
baselinePosition(const RenderObject * obj) const120 int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const
121 {
122 // From the description of this function in RenderTheme.h:
123 // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline
124 // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of
125 // controls that need to do this.
126 //
127 // Our checkboxes and radio buttons need to be offset to line up properly.
128 return RenderTheme::baselinePosition(obj) - 2;
129 }
130
addIntrinsicMargins(RenderStyle * style) const131 void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const
132 {
133 // Cut out the intrinsic margins completely if we end up using a small font size
134 if (style->fontSize() < 11)
135 return;
136
137 // Intrinsic margin value.
138 const int m = 2;
139
140 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
141 if (style->width().isIntrinsicOrAuto()) {
142 if (style->marginLeft().quirk())
143 style->setMarginLeft(Length(m, Fixed));
144 if (style->marginRight().quirk())
145 style->setMarginRight(Length(m, Fixed));
146 }
147
148 if (style->height().isAuto()) {
149 if (style->marginTop().quirk())
150 style->setMarginTop(Length(m, Fixed));
151 if (style->marginBottom().quirk())
152 style->setMarginBottom(Length(m, Fixed));
153 }
154 }
155
supportsFocus(ControlPart appearance)156 bool RenderThemeAndroid::supportsFocus(ControlPart appearance)
157 {
158 switch (appearance) {
159 case PushButtonPart:
160 case ButtonPart:
161 case TextFieldPart:
162 return true;
163 default:
164 return false;
165 }
166
167 return false;
168 }
169
adjustButtonStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const170 void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
171 {
172 // Padding code is taken from RenderThemeSafari.cpp
173 // It makes sure we have enough space for the button text.
174 const int padding = 8;
175 style->setPaddingLeft(Length(padding, Fixed));
176 style->setPaddingRight(Length(padding, Fixed));
177 style->setMinHeight(Length(style->fontSize() + BUTTON_PADDING, Fixed));
178 }
179
paintCheckbox(RenderObject * obj,const RenderObject::PaintInfo & info,const IntRect & rect)180 bool RenderThemeAndroid::paintCheckbox(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
181 {
182 RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, true);
183 return false;
184 }
185
paintButton(RenderObject * obj,const RenderObject::PaintInfo & info,const IntRect & rect)186 bool RenderThemeAndroid::paintButton(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
187 {
188 // If it is a disabled button, simply paint it to the master picture.
189 Node* node = obj->node();
190 Element* formControlElement = static_cast<Element*>(node);
191 if (formControlElement && !formControlElement->isEnabledFormControl())
192 RenderSkinButton::Draw(getCanvasFromInfo(info), rect, RenderSkinAndroid::kDisabled);
193 else
194 // Store all the important information in the platform context.
195 info.context->platformContext()->storeButtonInfo(node, rect);
196
197 // We always return false so we do not request to be redrawn.
198 return false;
199 }
200
paintRadio(RenderObject * obj,const RenderObject::PaintInfo & info,const IntRect & rect)201 bool RenderThemeAndroid::paintRadio(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
202 {
203 RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, false);
204 return false;
205 }
206
setCheckboxSize(RenderStyle * style) const207 void RenderThemeAndroid::setCheckboxSize(RenderStyle* style) const
208 {
209 style->setWidth(Length(19, Fixed));
210 style->setHeight(Length(19, Fixed));
211 }
212
setRadioSize(RenderStyle * style) const213 void RenderThemeAndroid::setRadioSize(RenderStyle* style) const
214 {
215 // This is the same as checkboxes.
216 setCheckboxSize(style);
217 }
218
adjustTextFieldStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const219 void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
220 {
221 addIntrinsicMargins(style);
222 }
223
paintTextField(RenderObject *,const RenderObject::PaintInfo &,const IntRect &)224 bool RenderThemeAndroid::paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&)
225 {
226 return true;
227 }
228
adjustTextAreaStyle(CSSStyleSelector *,RenderStyle * style,WebCore::Element *) const229 void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const
230 {
231 addIntrinsicMargins(style);
232 }
233
paintTextArea(RenderObject * obj,const RenderObject::PaintInfo & info,const IntRect & rect)234 bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
235 {
236 if (obj->isMenuList())
237 return paintCombo(obj, info, rect);
238 return true;
239 }
240
adjustSearchFieldStyle(CSSStyleSelector *,RenderStyle * style,Element *) const241 void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
242 {
243 addIntrinsicMargins(style);
244 }
245
paintSearchField(RenderObject *,const RenderObject::PaintInfo &,const IntRect &)246 bool RenderThemeAndroid::paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&)
247 {
248 return true;
249 }
250
adjustListboxStyle(CSSStyleSelector *,RenderStyle * style,Element *) const251 void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
252 {
253 style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
254 style->setMaxHeight(Length(style->fontSize() + LISTBOX_PADDING, Fixed));
255 addIntrinsicMargins(style);
256 }
257
adjustMenuListStyleCommon(RenderStyle * style,Element * e)258 static void adjustMenuListStyleCommon(RenderStyle* style, Element* e)
259 {
260 // Added to make room for our arrow.
261 style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
262 // Code copied from RenderThemeMac.mm
263 // Makes sure that the text shows up on our treatment
264 bool isEnabled = true;
265 if (e)
266 isEnabled = e->isEnabledFormControl();
267 style->setColor(isEnabled ? Color::black : Color::darkGray);
268 }
269
adjustMenuListStyle(CSSStyleSelector *,RenderStyle * style,Element * e) const270 void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
271 {
272 adjustMenuListStyleCommon(style, e);
273 addIntrinsicMargins(style);
274 }
275
paintCombo(RenderObject * obj,const RenderObject::PaintInfo & info,const IntRect & rect)276 bool RenderThemeAndroid::paintCombo(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
277 {
278 if (obj->style() && !obj->style()->backgroundColor().alpha())
279 return true;
280 Node* node = obj->node();
281 int height = rect.height();
282 int y = rect.y();
283 // If the combo box is too large, leave it at its max height, and center it.
284 if (height > MAX_COMBO_HEIGHT) {
285 y += (height - MAX_COMBO_HEIGHT) >> 1;
286 height = MAX_COMBO_HEIGHT;
287 }
288 return RenderSkinCombo::Draw(getCanvasFromInfo(info), node, rect.x(), y,
289 rect.width(), height);
290 }
291
paintMenuList(RenderObject * obj,const RenderObject::PaintInfo & info,const IntRect & rect)292 bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
293 {
294 return paintCombo(obj, info, rect);
295 }
296
adjustMenuListButtonStyle(CSSStyleSelector *,RenderStyle * style,Element * e) const297 void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
298 {
299 // Copied from RenderThemeSafari.
300 const float baseFontSize = 11.0f;
301 const int baseBorderRadius = 5;
302 float fontScale = style->fontSize() / baseFontSize;
303
304 style->resetPadding();
305 style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
306
307 const int minHeight = 15;
308 style->setMinHeight(Length(minHeight, Fixed));
309
310 style->setLineHeight(RenderStyle::initialLineHeight());
311 // Found these padding numbers by trial and error.
312 const int padding = 4;
313 style->setPaddingTop(Length(padding, Fixed));
314 style->setPaddingLeft(Length(padding, Fixed));
315 adjustMenuListStyleCommon(style, e);
316 }
317
paintMenuListButton(RenderObject * obj,const RenderObject::PaintInfo & info,const IntRect & rect)318 bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect)
319 {
320 return paintCombo(obj, info, rect);
321 }
322
supportsFocusRing(const RenderStyle * style) const323 bool RenderThemeAndroid::supportsFocusRing(const RenderStyle* style) const
324 {
325 return style->opacity() > 0
326 && style->hasAppearance()
327 && style->appearance() != TextFieldPart
328 && style->appearance() != SearchFieldPart
329 && style->appearance() != TextAreaPart
330 && style->appearance() != CheckboxPart
331 && style->appearance() != RadioPart
332 && style->appearance() != PushButtonPart
333 && style->appearance() != SquareButtonPart
334 && style->appearance() != ButtonPart
335 && style->appearance() != ButtonBevelPart
336 && style->appearance() != MenulistPart
337 && style->appearance() != MenulistButtonPart;
338 }
339
340 } // namespace WebCore
341