• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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