1 /*
2 * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
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 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. 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 APPLE COMPUTER, INC. ``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 "RenderTheme.h"
28
29 #include "Document.h"
30 #include "FrameView.h"
31 #include "GraphicsContext.h"
32 #include "HostWindow.h"
33 #include "NotImplemented.h"
34 #include "PaintInfo.h"
35 #include "RenderView.h"
36
37 #include <wx/defs.h>
38
39 #include <wx/dc.h>
40 #include <wx/dcgraph.h>
41 #include <wx/renderer.h>
42 #include <wx/dcclient.h>
43 #include <wx/scrolwin.h>
44 #include <wx/settings.h>
45
46 namespace WebCore {
47
48 class RenderThemeWx : public RenderTheme {
49 private:
RenderThemeWx()50 RenderThemeWx() : RenderTheme() { }
51 virtual ~RenderThemeWx();
52
53 public:
54 static PassRefPtr<RenderTheme> create();
55
56 // A method asking if the theme's controls actually care about redrawing when hovered.
supportsHover(const RenderStyle *) const57 virtual bool supportsHover(const RenderStyle*) const { return true; }
58
paintCheckbox(RenderObject * o,const PaintInfo & i,const IntRect & r)59 virtual bool paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
60 {
61 return paintButton(o, i, r);
62 }
63
64 virtual void setCheckboxSize(RenderStyle*) const;
65
paintRadio(RenderObject * o,const PaintInfo & i,const IntRect & r)66 virtual bool paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
67 {
68 return paintButton(o, i, r);
69 }
70
71 virtual void setRadioSize(RenderStyle*) const;
72
73 virtual void adjustRepaintRect(const RenderObject*, IntRect&);
74
75 virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
76 virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&);
77
78 virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
79 virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&);
80
81 virtual int minimumMenuListSize(RenderStyle*) const;
82
83 virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
84 virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&);
85
86 virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
87 virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&);
88
89 virtual bool isControlStyled(const RenderStyle*, const BorderData&,
90 const FillLayer&, const Color&) const;
91
92 virtual bool controlSupportsTints(const RenderObject*) const;
93
94 virtual void systemFont(int propId, FontDescription&) const;
95
96 virtual Color platformActiveSelectionBackgroundColor() const;
97 virtual Color platformInactiveSelectionBackgroundColor() const;
98
99 virtual Color platformActiveSelectionForegroundColor() const;
100 virtual Color platformInactiveSelectionForegroundColor() const;
101
102 virtual int popupInternalPaddingLeft(RenderStyle*) const;
103 virtual int popupInternalPaddingRight(RenderStyle*) const;
104 virtual int popupInternalPaddingTop(RenderStyle*) const;
105 virtual int popupInternalPaddingBottom(RenderStyle*) const;
106
107 private:
108 void addIntrinsicMargins(RenderStyle*) const;
109 void close();
110
111 bool supportsFocus(ControlPart) const;
112 };
113
114
115 // Constants
116
117 #define MINIMUM_MENU_LIST_SIZE 21
118 #define POPUP_INTERNAL_PADDING_LEFT 6
119 #define POPUP_INTERNAL_PADDING_TOP 2
120 #define POPUP_INTERNAL_PADDING_BOTTOM 2
121
122 #ifdef __WXMAC__
123 #define POPUP_INTERNAL_PADDING_RIGHT 22
124 #else
125 #define POPUP_INTERNAL_PADDING_RIGHT 20
126 #endif
127
~RenderThemeWx()128 RenderThemeWx::~RenderThemeWx()
129 {
130 }
131
create()132 PassRefPtr<RenderTheme> RenderThemeWx::create()
133 {
134 return adoptRef(new RenderThemeWx());
135 }
136
themeForPage(Page * page)137 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
138 {
139 static RenderTheme* rt = RenderThemeWx::create().releaseRef();
140 return rt;
141 }
142
nativeWindowForRenderObject(RenderObject * o)143 wxWindow* nativeWindowForRenderObject(RenderObject* o)
144 {
145 FrameView* frameView = o->view()->frameView();
146 ASSERT(frameView);
147 ASSERT(frameView->hostWindow());
148 return frameView->hostWindow()->platformPageClient();
149 }
150
151
isControlStyled(const RenderStyle * style,const BorderData & border,const FillLayer & background,const Color & backgroundColor) const152 bool RenderThemeWx::isControlStyled(const RenderStyle* style, const BorderData& border,
153 const FillLayer& background, const Color& backgroundColor) const
154 {
155 if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart)
156 return style->border() != border;
157
158 // Normally CSS can be used to set properties of form controls (such as adding a background bitmap).
159 // However, for this to work RenderThemeWx needs to adjust uncustomized elements (e.g. buttons) to reflect the
160 // changes made by CSS. Since we don't do that right now, the native parts of form elements appear in odd places.
161 // Until we have time to implement that support, we return false here, so that we ignore customizations
162 // and always use the native theme drawing to draw form controls.
163 return false;
164 }
165
adjustRepaintRect(const RenderObject * o,IntRect & r)166 void RenderThemeWx::adjustRepaintRect(const RenderObject* o, IntRect& r)
167 {
168 switch (o->style()->appearance()) {
169 case MenulistPart: {
170 r.setWidth(r.width() + 100);
171 break;
172 }
173 default:
174 break;
175 }
176 }
177
controlSupportsTints(const RenderObject * o) const178 bool RenderThemeWx::controlSupportsTints(const RenderObject* o) const
179 {
180 if (!isEnabled(o))
181 return false;
182
183 // Checkboxes only have tint when checked.
184 if (o->style()->appearance() == CheckboxPart)
185 return isChecked(o);
186
187 // For now assume other controls have tint if enabled.
188 return true;
189 }
190
systemFont(int propId,FontDescription & fontDescription) const191 void RenderThemeWx::systemFont(int propId, FontDescription& fontDescription) const
192 {
193 // no-op
194 }
195
addIntrinsicMargins(RenderStyle * style) const196 void RenderThemeWx::addIntrinsicMargins(RenderStyle* style) const
197 {
198 // Cut out the intrinsic margins completely if we end up using a small font size
199 if (style->fontSize() < 11)
200 return;
201
202 // Intrinsic margin value.
203 const int m = 2;
204
205 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
206 if (style->width().isIntrinsicOrAuto()) {
207 if (style->marginLeft().quirk())
208 style->setMarginLeft(Length(m, Fixed));
209
210 if (style->marginRight().quirk())
211 style->setMarginRight(Length(m, Fixed));
212 }
213
214 if (style->height().isAuto()) {
215 if (style->marginTop().quirk())
216 style->setMarginTop(Length(m, Fixed));
217
218 if (style->marginBottom().quirk())
219 style->setMarginBottom(Length(m, Fixed));
220 }
221 }
222
setCheckboxSize(RenderStyle * style) const223 void RenderThemeWx::setCheckboxSize(RenderStyle* style) const
224 {
225 // If the width and height are both specified, then we have nothing to do.
226 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
227 return;
228
229 // FIXME: A hard-coded size of 13 is used. This is wrong but necessary for now. It matches Firefox.
230 // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
231 // the higher DPI. Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
232 // metrics.
233 if (style->width().isIntrinsicOrAuto())
234 style->setWidth(Length(13, Fixed));
235
236 if (style->height().isAuto())
237 style->setHeight(Length(13, Fixed));
238 }
239
setRadioSize(RenderStyle * style) const240 void RenderThemeWx::setRadioSize(RenderStyle* style) const
241 {
242 // This is the same as checkboxes.
243 setCheckboxSize(style);
244 }
245
supportsFocus(ControlPart part) const246 bool RenderThemeWx::supportsFocus(ControlPart part) const
247 {
248 switch (part) {
249 case PushButtonPart:
250 case ButtonPart:
251 case TextFieldPart:
252 return true;
253 default: // No for all others...
254 return false;
255 }
256 }
257
adjustButtonStyle(CSSStyleSelector * selector,RenderStyle * style,Element * e) const258 void RenderThemeWx::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
259 {
260 addIntrinsicMargins(style);
261 }
262
paintButton(RenderObject * o,const PaintInfo & i,const IntRect & r)263 bool RenderThemeWx::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
264 {
265 wxWindow* window = nativeWindowForRenderObject(o);
266 wxDC* dc = static_cast<wxDC*>(i.context->platformContext());
267 int flags = 0;
268
269 IntRect rect = r;
270
271 // On Mac, wxGraphicsContext and wxDC share the same native implementation,
272 // and so transformations are available.
273 // On Win and Linux, however, this is not true and transforms are lost,
274 // so we need to restore them here.
275 #if USE(WXGC) && !defined(__WXMAC__)
276 double xtrans = 0;
277 double ytrans = 0;
278
279 wxGCDC* gcdc = static_cast<wxGCDC*>(dc);
280 wxGraphicsContext* gc = gcdc->GetGraphicsContext();
281 gc->GetTransform().TransformPoint(&xtrans, &ytrans);
282 rect.setX(r.x() + (int)xtrans);
283 rect.setY(r.y() + (int)ytrans);
284 #endif
285
286 if (!isEnabled(o))
287 flags |= wxCONTROL_DISABLED;
288
289 ControlPart part = o->style()->appearance();
290 if (supportsFocus(part) && isFocused(o))
291 flags |= wxCONTROL_FOCUSED;
292
293 if (isPressed(o))
294 flags |= wxCONTROL_PRESSED;
295
296 if (part == PushButtonPart || part == ButtonPart)
297 wxRendererNative::Get().DrawPushButton(window, *dc, rect, flags);
298 else if(part == RadioPart) {
299 if (isChecked(o))
300 flags |= wxCONTROL_CHECKED;
301 #if wxCHECK_VERSION(2,9,1)
302 wxRendererNative::Get().DrawRadioBitmap(window, *dc, rect, flags);
303 #elif wxCHECK_VERSION(2,9,0)
304 wxRendererNative::Get().DrawRadioButton(window, *dc, rect, flags);
305 #else
306 wxRenderer_DrawRadioButton(window, *dc, rect, flags);
307 #endif
308 }
309 else if(part == CheckboxPart) {
310 if (isChecked(o))
311 flags |= wxCONTROL_CHECKED;
312 wxRendererNative::Get().DrawCheckBox(window, *dc, rect, flags);
313 }
314 return false;
315 }
316
adjustTextFieldStyle(CSSStyleSelector *,RenderStyle * style,Element *) const317 void RenderThemeWx::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
318 {
319
320 }
321
paintTextField(RenderObject * o,const PaintInfo & i,const IntRect & r)322 bool RenderThemeWx::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
323 {
324 wxWindow* window = nativeWindowForRenderObject(o);
325 wxDC* dc = static_cast<wxDC*>(i.context->platformContext());
326 #if wxCHECK_VERSION(2,9,0)
327 wxRendererNative::Get().DrawTextCtrl(window, *dc, r, 0);
328 #else
329 wxRenderer_DrawTextCtrl(window, *dc, r, 0);
330 #endif
331
332 return false;
333 }
334
minimumMenuListSize(RenderStyle *) const335 int RenderThemeWx::minimumMenuListSize(RenderStyle*) const
336 {
337 return MINIMUM_MENU_LIST_SIZE;
338 }
339
adjustMenuListStyle(CSSStyleSelector *,RenderStyle * style,Element *) const340 void RenderThemeWx::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
341 {
342 }
343
paintMenuList(RenderObject * o,const PaintInfo & i,const IntRect & r)344 bool RenderThemeWx::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
345 {
346 wxWindow* window = nativeWindowForRenderObject(o);
347 wxDC* dc = static_cast<wxDC*>(i.context->platformContext());
348
349 int flags = 0;
350 if (!isEnabled(o))
351 flags |= wxCONTROL_DISABLED;
352
353 if (supportsFocus(o->style()->appearance()) && isFocused(o))
354 flags |= wxCONTROL_FOCUSED;
355
356 if (isPressed(o))
357 flags |= wxCONTROL_PRESSED;
358
359 #if wxCHECK_VERSION(2,9,0)
360 wxRendererNative::Get().DrawChoice(window, *dc, r, flags);
361 #else
362 wxRenderer_DrawChoice(window, *dc, r, flags);
363 #endif
364
365 return false;
366 }
367
adjustMenuListButtonStyle(CSSStyleSelector *,RenderStyle *,Element *) const368 void RenderThemeWx::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const
369 {
370 notImplemented();
371 }
372
paintMenuListButton(RenderObject * o,const PaintInfo & i,const IntRect & r)373 bool RenderThemeWx::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
374 {
375 wxWindow* window = nativeWindowForRenderObject(o);
376 wxDC* dc = static_cast<wxDC*>(i.context->platformContext());
377
378 int flags = 0;
379 if (!isEnabled(o))
380 flags |= wxCONTROL_DISABLED;
381
382 if (supportsFocus(o->style()->appearance()) && isFocused(o))
383 flags |= wxCONTROL_FOCUSED;
384
385 if (isPressed(o))
386 flags |= wxCONTROL_PRESSED;
387
388 wxRendererNative::Get().DrawComboBoxDropButton(window, *dc, r, flags);
389
390 return false;
391 }
392
393
platformActiveSelectionBackgroundColor() const394 Color RenderThemeWx::platformActiveSelectionBackgroundColor() const
395 {
396 return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
397 }
398
platformInactiveSelectionBackgroundColor() const399 Color RenderThemeWx::platformInactiveSelectionBackgroundColor() const
400 {
401 return wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
402 }
403
platformActiveSelectionForegroundColor() const404 Color RenderThemeWx::platformActiveSelectionForegroundColor() const
405 {
406 // FIXME: Get wx to return the correct value for each platform.
407 #if __WXMAC__
408 return Color();
409 #else
410 return Color(255, 255, 255);
411 #endif
412 }
413
platformInactiveSelectionForegroundColor() const414 Color RenderThemeWx::platformInactiveSelectionForegroundColor() const
415 {
416 #if __WXMAC__
417 return Color();
418 #else
419 return Color(255, 255, 255);
420 #endif
421 }
422
popupInternalPaddingLeft(RenderStyle *) const423 int RenderThemeWx::popupInternalPaddingLeft(RenderStyle*) const
424 {
425 return POPUP_INTERNAL_PADDING_LEFT;
426 }
427
popupInternalPaddingRight(RenderStyle *) const428 int RenderThemeWx::popupInternalPaddingRight(RenderStyle*) const
429 {
430 return POPUP_INTERNAL_PADDING_RIGHT;
431 }
432
popupInternalPaddingTop(RenderStyle *) const433 int RenderThemeWx::popupInternalPaddingTop(RenderStyle*) const
434 {
435 return POPUP_INTERNAL_PADDING_TOP;
436 }
437
popupInternalPaddingBottom(RenderStyle *) const438 int RenderThemeWx::popupInternalPaddingBottom(RenderStyle*) const
439 {
440 return POPUP_INTERNAL_PADDING_BOTTOM;
441 }
442
443 }
444
445