/* * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "RenderTheme.h" #include "Document.h" #include "FrameView.h" #include "GraphicsContext.h" #include "HostWindow.h" #include "NotImplemented.h" #include "RenderView.h" #include <wx/defs.h> #include <wx/dc.h> #include <wx/dcgraph.h> #include <wx/renderer.h> #include <wx/dcclient.h> #include <wx/scrolwin.h> #include <wx/settings.h> namespace WebCore { class RenderThemeWx : public RenderTheme { private: RenderThemeWx() : RenderTheme() { } virtual ~RenderThemeWx(); public: static PassRefPtr<RenderTheme> create(); // A method asking if the theme's controls actually care about redrawing when hovered. virtual bool supportsHover(const RenderStyle*) const { return true; } virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintButton(o, i, r); } virtual void setCheckboxSize(RenderStyle*) const; virtual bool paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintButton(o, i, r); } virtual void setRadioSize(RenderStyle*) const; virtual void adjustRepaintRect(const RenderObject*, IntRect&); virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual int minimumMenuListSize(RenderStyle*) const; virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool isControlStyled(const RenderStyle*, const BorderData&, const FillLayer&, const Color&) const; virtual bool controlSupportsTints(const RenderObject*) const; virtual void systemFont(int propId, FontDescription&) const; virtual Color platformActiveSelectionBackgroundColor() const; virtual Color platformInactiveSelectionBackgroundColor() const; virtual Color platformActiveSelectionForegroundColor() const; virtual Color platformInactiveSelectionForegroundColor() const; virtual int popupInternalPaddingLeft(RenderStyle*) const; virtual int popupInternalPaddingRight(RenderStyle*) const; virtual int popupInternalPaddingTop(RenderStyle*) const; virtual int popupInternalPaddingBottom(RenderStyle*) const; private: void addIntrinsicMargins(RenderStyle*) const; void close(); bool supportsFocus(ControlPart) const; }; // Constants #define MINIMUM_MENU_LIST_SIZE 21 #define POPUP_INTERNAL_PADDING_LEFT 6 #define POPUP_INTERNAL_PADDING_TOP 2 #define POPUP_INTERNAL_PADDING_BOTTOM 2 #ifdef __WXMAC__ #define POPUP_INTERNAL_PADDING_RIGHT 22 #else #define POPUP_INTERNAL_PADDING_RIGHT 20 #endif RenderThemeWx::~RenderThemeWx() { } PassRefPtr<RenderTheme> RenderThemeWx::create() { return adoptRef(new RenderThemeWx()); } PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) { static RenderTheme* rt = RenderThemeWx::create().releaseRef(); return rt; } wxWindow* nativeWindowForRenderObject(RenderObject* o) { FrameView* frameView = o->view()->frameView(); ASSERT(frameView); ASSERT(frameView->hostWindow()); return frameView->hostWindow()->platformPageClient(); } bool RenderThemeWx::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& background, const Color& backgroundColor) const { if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart) return style->border() != border; // Normally CSS can be used to set properties of form controls (such as adding a background bitmap). // However, for this to work RenderThemeWx needs to adjust uncustomized elements (e.g. buttons) to reflect the // changes made by CSS. Since we don't do that right now, the native parts of form elements appear in odd places. // Until we have time to implement that support, we return false here, so that we ignore customizations // and always use the native theme drawing to draw form controls. return false; } void RenderThemeWx::adjustRepaintRect(const RenderObject* o, IntRect& r) { switch (o->style()->appearance()) { case MenulistPart: { r.setWidth(r.width() + 100); break; } default: break; } } bool RenderThemeWx::controlSupportsTints(const RenderObject* o) const { if (!isEnabled(o)) return false; // Checkboxes only have tint when checked. if (o->style()->appearance() == CheckboxPart) return isChecked(o); // For now assume other controls have tint if enabled. return true; } void RenderThemeWx::systemFont(int propId, FontDescription& fontDescription) const { // no-op } void RenderThemeWx::addIntrinsicMargins(RenderStyle* style) const { // Cut out the intrinsic margins completely if we end up using a small font size if (style->fontSize() < 11) return; // Intrinsic margin value. const int m = 2; // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed. if (style->width().isIntrinsicOrAuto()) { if (style->marginLeft().quirk()) style->setMarginLeft(Length(m, Fixed)); if (style->marginRight().quirk()) style->setMarginRight(Length(m, Fixed)); } if (style->height().isAuto()) { if (style->marginTop().quirk()) style->setMarginTop(Length(m, Fixed)); if (style->marginBottom().quirk()) style->setMarginBottom(Length(m, Fixed)); } } void RenderThemeWx::setCheckboxSize(RenderStyle* style) const { // If the width and height are both specified, then we have nothing to do. if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) return; // FIXME: A hard-coded size of 13 is used. This is wrong but necessary for now. It matches Firefox. // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for // the higher DPI. Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's // metrics. if (style->width().isIntrinsicOrAuto()) style->setWidth(Length(13, Fixed)); if (style->height().isAuto()) style->setHeight(Length(13, Fixed)); } void RenderThemeWx::setRadioSize(RenderStyle* style) const { // This is the same as checkboxes. setCheckboxSize(style); } bool RenderThemeWx::supportsFocus(ControlPart part) const { switch (part) { case PushButtonPart: case ButtonPart: case TextFieldPart: return true; default: // No for all others... return false; } } void RenderThemeWx::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const { addIntrinsicMargins(style); } bool RenderThemeWx::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { wxWindow* window = nativeWindowForRenderObject(o); wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); int flags = 0; IntRect rect = r; // On Mac, wxGraphicsContext and wxDC share the same native implementation, // and so transformations are available. // On Win and Linux, however, this is not true and transforms are lost, // so we need to restore them here. #if USE(WXGC) && !defined(__WXMAC__) double xtrans = 0; double ytrans = 0; wxGCDC* gcdc = static_cast<wxGCDC*>(dc); wxGraphicsContext* gc = gcdc->GetGraphicsContext(); gc->GetTransform().TransformPoint(&xtrans, &ytrans); rect.setX(r.x() + (int)xtrans); rect.setY(r.y() + (int)ytrans); #endif if (!isEnabled(o)) flags |= wxCONTROL_DISABLED; ControlPart part = o->style()->appearance(); if (supportsFocus(part) && isFocused(o)) flags |= wxCONTROL_FOCUSED; if (isPressed(o)) flags |= wxCONTROL_PRESSED; if (part == PushButtonPart || part == ButtonPart) wxRendererNative::Get().DrawPushButton(window, *dc, rect, flags); else if(part == RadioPart) { if (isChecked(o)) flags |= wxCONTROL_CHECKED; #if wxCHECK_VERSION(2,9,1) wxRendererNative::Get().DrawRadioBitmap(window, *dc, rect, flags); #elif wxCHECK_VERSION(2,9,0) wxRendererNative::Get().DrawRadioButton(window, *dc, rect, flags); #else wxRenderer_DrawRadioButton(window, *dc, rect, flags); #endif } else if(part == CheckboxPart) { if (isChecked(o)) flags |= wxCONTROL_CHECKED; wxRendererNative::Get().DrawCheckBox(window, *dc, rect, flags); } return false; } void RenderThemeWx::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { } bool RenderThemeWx::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { wxWindow* window = nativeWindowForRenderObject(o); wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); #if wxCHECK_VERSION(2,9,0) wxRendererNative::Get().DrawTextCtrl(window, *dc, r, 0); #else wxRenderer_DrawTextCtrl(window, *dc, r, 0); #endif return false; } int RenderThemeWx::minimumMenuListSize(RenderStyle*) const { return MINIMUM_MENU_LIST_SIZE; } void RenderThemeWx::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { } bool RenderThemeWx::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { wxWindow* window = nativeWindowForRenderObject(o); wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); int flags = 0; if (!isEnabled(o)) flags |= wxCONTROL_DISABLED; if (supportsFocus(o->style()->appearance()) && isFocused(o)) flags |= wxCONTROL_FOCUSED; if (isPressed(o)) flags |= wxCONTROL_PRESSED; #if wxCHECK_VERSION(2,9,0) wxRendererNative::Get().DrawChoice(window, *dc, r, flags); #else wxRenderer_DrawChoice(window, *dc, r, flags); #endif return false; } void RenderThemeWx::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const { notImplemented(); } bool RenderThemeWx::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { wxWindow* window = nativeWindowForRenderObject(o); wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); int flags = 0; if (!isEnabled(o)) flags |= wxCONTROL_DISABLED; if (supportsFocus(o->style()->appearance()) && isFocused(o)) flags |= wxCONTROL_FOCUSED; if (isPressed(o)) flags |= wxCONTROL_PRESSED; wxRendererNative::Get().DrawComboBoxDropButton(window, *dc, r, flags); return false; } Color RenderThemeWx::platformActiveSelectionBackgroundColor() const { return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); } Color RenderThemeWx::platformInactiveSelectionBackgroundColor() const { return wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); } Color RenderThemeWx::platformActiveSelectionForegroundColor() const { // FIXME: Get wx to return the correct value for each platform. #if __WXMAC__ return Color(); #else return Color(255, 255, 255); #endif } Color RenderThemeWx::platformInactiveSelectionForegroundColor() const { #if __WXMAC__ return Color(); #else return Color(255, 255, 255); #endif } int RenderThemeWx::popupInternalPaddingLeft(RenderStyle*) const { return POPUP_INTERNAL_PADDING_LEFT; } int RenderThemeWx::popupInternalPaddingRight(RenderStyle*) const { return POPUP_INTERNAL_PADDING_RIGHT; } int RenderThemeWx::popupInternalPaddingTop(RenderStyle*) const { return POPUP_INTERNAL_PADDING_TOP; } int RenderThemeWx::popupInternalPaddingBottom(RenderStyle*) const { return POPUP_INTERNAL_PADDING_BOTTOM; } }