Home | History | Annotate | Download | only in wx
      1 /*
      2  * Copyright (C) 2007 Kevin Ollivier <kevino (at) 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:
     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.
     57     virtual bool supportsHover(const RenderStyle*) const { return true; }
     58 
     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 
     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 
    128 RenderThemeWx::~RenderThemeWx()
    129 {
    130 }
    131 
    132 PassRefPtr<RenderTheme> RenderThemeWx::create()
    133 {
    134     return adoptRef(new RenderThemeWx());
    135 }
    136 
    137 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
    138 {
    139     static RenderTheme* rt = RenderThemeWx::create().releaseRef();
    140     return rt;
    141 }
    142 
    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 
    152 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 
    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 
    178 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 
    191 void RenderThemeWx::systemFont(int propId, FontDescription& fontDescription) const
    192 {
    193     // no-op
    194 }
    195 
    196 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 
    223 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 
    240 void RenderThemeWx::setRadioSize(RenderStyle* style) const
    241 {
    242     // This is the same as checkboxes.
    243     setCheckboxSize(style);
    244 }
    245 
    246 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 
    258 void RenderThemeWx::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    259 {
    260     addIntrinsicMargins(style);
    261 }
    262 
    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 
    317 void RenderThemeWx::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    318 {
    319 
    320 }
    321 
    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 
    335 int RenderThemeWx::minimumMenuListSize(RenderStyle*) const
    336 {
    337     return MINIMUM_MENU_LIST_SIZE;
    338 }
    339 
    340 void RenderThemeWx::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    341 {
    342 }
    343 
    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 
    368 void RenderThemeWx::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const
    369 {
    370     notImplemented();
    371 }
    372 
    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 
    394 Color RenderThemeWx::platformActiveSelectionBackgroundColor() const
    395 {
    396     return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
    397 }
    398 
    399 Color RenderThemeWx::platformInactiveSelectionBackgroundColor() const
    400 {
    401     return wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
    402 }
    403 
    404 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 
    414 Color RenderThemeWx::platformInactiveSelectionForegroundColor() const
    415 {
    416 #if __WXMAC__
    417     return Color();
    418 #else
    419     return Color(255, 255, 255);
    420 #endif
    421 }
    422 
    423 int RenderThemeWx::popupInternalPaddingLeft(RenderStyle*) const
    424 {
    425     return POPUP_INTERNAL_PADDING_LEFT;
    426 }
    427 
    428 int RenderThemeWx::popupInternalPaddingRight(RenderStyle*) const
    429 {
    430     return POPUP_INTERNAL_PADDING_RIGHT;
    431 }
    432 
    433 int RenderThemeWx::popupInternalPaddingTop(RenderStyle*) const
    434 {
    435     return POPUP_INTERNAL_PADDING_TOP;
    436 }
    437 
    438 int RenderThemeWx::popupInternalPaddingBottom(RenderStyle*) const
    439 {
    440     return POPUP_INTERNAL_PADDING_BOTTOM;
    441 }
    442 
    443 }
    444 
    445