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