diff -r 000000000000 -r 4f2f89ce4247 WebCore/rendering/RenderThemeSafari.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/rendering/RenderThemeSafari.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,1215 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderThemeSafari.h" +#include "RenderThemeWin.h" +#include "Settings.h" + +#if USE(SAFARI_THEME) + +#include "CSSValueKeywords.h" +#include "Document.h" +#include "Element.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLInputElement.h" +#include "HTMLMediaElement.h" +#include "HTMLNames.h" +#include "RenderMediaControls.h" +#include "RenderSlider.h" +#include "RenderView.h" +#include "RetainPtr.h" +#include "SoftLinking.h" +#include "cssstyleselector.h" +#include + +using std::min; + +// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeMac. + +namespace WebCore { + +using namespace HTMLNames; +using namespace SafariTheme; + +enum { + topMargin, + rightMargin, + bottomMargin, + leftMargin +}; + +enum { + topPadding, + rightPadding, + bottomPadding, + leftPadding +}; + +PassRefPtr RenderThemeSafari::create() +{ + return adoptRef(new RenderThemeSafari); +} + +PassRefPtr RenderTheme::themeForPage(Page* page) +{ + static RenderTheme* safariTheme = RenderThemeSafari::create().releaseRef(); + static RenderTheme* windowsTheme = RenderThemeWin::create().releaseRef(); + + // FIXME: This is called before Settings has been initialized by WebKit, so will return a + // potentially wrong answer the very first time it's called (see + // ). + if (Settings::shouldPaintNativeControls()) { + RenderTheme::setCustomFocusRingColor(safariTheme->platformFocusRingColor()); + return windowsTheme; // keep the reference of one. + } + return safariTheme; // keep the reference of one. +} + +#ifdef DEBUG_ALL +SOFT_LINK_DEBUG_LIBRARY(SafariTheme) +#else +SOFT_LINK_LIBRARY(SafariTheme) +#endif + +SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state), (part, context, rect, size, state)) +#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 +SOFT_LINK(SafariTheme, STPaintProgressIndicator, void, APIENTRY, (ProgressIndicatorType type, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state, float value), (type, context, rect, size, state, value)) +#endif +SOFT_LINK_OPTIONAL(SafariTheme, STCopyThemeColor, CGColorRef, APIENTRY, (unsigned color, SafariTheme::ThemeControlState)); + +static const unsigned stFocusRingColorID = 4; + +static const unsigned aquaFocusRingColor = 0xFF7DADD9; + +static RGBA32 makeRGBAFromCGColor(CGColorRef color) +{ + const CGFloat* components = CGColorGetComponents(color); + return makeRGBA(255 * components[0], 255 * components[1], 255 * components[2], 255 * components[3]); +} + +ThemeControlState RenderThemeSafari::determineState(RenderObject* o) const +{ + ThemeControlState result = 0; + if (isActive(o)) + result |= SafariTheme::ActiveState; + if (isEnabled(o) && !isReadOnlyControl(o)) + result |= SafariTheme::EnabledState; + if (isPressed(o)) + result |= SafariTheme::PressedState; + if (isChecked(o)) + result |= SafariTheme::CheckedState; + if (isIndeterminate(o)) + result |= SafariTheme::IndeterminateCheckedState; + if (isFocused(o)) + result |= SafariTheme::FocusedState; + if (isDefault(o)) + result |= SafariTheme::DefaultState; + return result; +} + +static NSControlSize controlSizeFromRect(const IntRect& rect, const IntSize sizes[]) +{ + if (sizes[NSRegularControlSize].height() == rect.height()) + return NSRegularControlSize; + else if (sizes[NSMiniControlSize].height() == rect.height()) + return NSMiniControlSize; + + return NSSmallControlSize; +} + +RenderThemeSafari::RenderThemeSafari() +{ +} + +RenderThemeSafari::~RenderThemeSafari() +{ +} + +Color RenderThemeSafari::platformActiveSelectionBackgroundColor() const +{ + return Color(181, 213, 255); +} + +Color RenderThemeSafari::platformInactiveSelectionBackgroundColor() const +{ + return Color(212, 212, 212); +} + +Color RenderThemeSafari::activeListBoxSelectionBackgroundColor() const +{ + // FIXME: This should probably just be a darker version of the platformActiveSelectionBackgroundColor + return Color(56, 117, 215); +} + +Color RenderThemeSafari::platformFocusRingColor() const +{ + static Color focusRingColor; + + if (!focusRingColor.isValid()) { + if (STCopyThemeColorPtr()) { + RetainPtr color(AdoptCF, STCopyThemeColorPtr()(stFocusRingColorID, SafariTheme::ActiveState)); + focusRingColor = makeRGBAFromCGColor(color.get()); + } + if (!focusRingColor.isValid()) + focusRingColor = aquaFocusRingColor; + } + + return focusRingColor; +} + +static float systemFontSizeForControlSize(NSControlSize controlSize) +{ + static float sizes[] = { 13.0f, 11.0f, 9.0f }; + + return sizes[controlSize]; +} + +void RenderThemeSafari::systemFont(int propId, FontDescription& fontDescription) const +{ + static FontDescription systemFont; + static FontDescription smallSystemFont; + static FontDescription menuFont; + static FontDescription labelFont; + static FontDescription miniControlFont; + static FontDescription smallControlFont; + static FontDescription controlFont; + + FontDescription* cachedDesc; + float fontSize = 0; + switch (propId) { + case CSSValueSmallCaption: + cachedDesc = &smallSystemFont; + if (!smallSystemFont.isAbsoluteSize()) + fontSize = systemFontSizeForControlSize(NSSmallControlSize); + break; + case CSSValueMenu: + cachedDesc = &menuFont; + if (!menuFont.isAbsoluteSize()) + fontSize = systemFontSizeForControlSize(NSRegularControlSize); + break; + case CSSValueStatusBar: + cachedDesc = &labelFont; + if (!labelFont.isAbsoluteSize()) + fontSize = 10.0f; + break; + case CSSValueWebkitMiniControl: + cachedDesc = &miniControlFont; + if (!miniControlFont.isAbsoluteSize()) + fontSize = systemFontSizeForControlSize(NSMiniControlSize); + break; + case CSSValueWebkitSmallControl: + cachedDesc = &smallControlFont; + if (!smallControlFont.isAbsoluteSize()) + fontSize = systemFontSizeForControlSize(NSSmallControlSize); + break; + case CSSValueWebkitControl: + cachedDesc = &controlFont; + if (!controlFont.isAbsoluteSize()) + fontSize = systemFontSizeForControlSize(NSRegularControlSize); + break; + default: + cachedDesc = &systemFont; + if (!systemFont.isAbsoluteSize()) + fontSize = 13.0f; + } + + if (fontSize) { + cachedDesc->setIsAbsoluteSize(true); + cachedDesc->setGenericFamily(FontDescription::NoFamily); + cachedDesc->firstFamily().setFamily("Lucida Grande"); + cachedDesc->setSpecifiedSize(fontSize); + cachedDesc->setWeight(FontWeightNormal); + cachedDesc->setItalic(false); + } + fontDescription = *cachedDesc; +} + +bool RenderThemeSafari::isControlStyled(const RenderStyle* style, const BorderData& border, + const FillLayer& background, const Color& backgroundColor) const +{ + // If we didn't find SafariTheme.dll we won't be able to paint any themed controls. + if (!SafariThemeLibrary()) + return true; + + if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) + return style->border() != border; + return RenderTheme::isControlStyled(style, border, background, backgroundColor); +} + +void RenderThemeSafari::adjustRepaintRect(const RenderObject* o, IntRect& r) +{ + NSControlSize controlSize = controlSizeForFont(o->style()); + + switch (o->style()->appearance()) { + case CheckboxPart: { + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + r = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize)); + break; + } + case RadioPart: { + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + r = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize)); + break; + } + case PushButtonPart: + case DefaultButtonPart: + case ButtonPart: { + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + if (r.height() <= buttonSizes()[NSRegularControlSize].height()) + r = inflateRect(r, buttonSizes()[controlSize], buttonMargins(controlSize)); + break; + } + case MenulistPart: { + r = inflateRect(r, popupButtonSizes()[controlSize], popupButtonMargins(controlSize)); + break; + } + default: + break; + } +} + +IntRect RenderThemeSafari::inflateRect(const IntRect& r, const IntSize& size, const int* margins) const +{ + // Only do the inflation if the available width/height are too small. Otherwise try to + // fit the glow/check space into the available box's width/height. + int widthDelta = r.width() - (size.width() + margins[leftMargin] + margins[rightMargin]); + int heightDelta = r.height() - (size.height() + margins[topMargin] + margins[bottomMargin]); + IntRect result(r); + if (widthDelta < 0) { + result.setX(result.x() - margins[leftMargin]); + result.setWidth(result.width() - widthDelta); + } + if (heightDelta < 0) { + result.setY(result.y() - margins[topMargin]); + result.setHeight(result.height() - heightDelta); + } + return result; +} + +int RenderThemeSafari::baselinePosition(const RenderObject* o) const +{ + if (!o->isBox()) + return 0; + + if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) { + const RenderBox* box = toRenderBox(o); + return box->marginTop() + box->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit. + } + + return RenderTheme::baselinePosition(o); +} + +bool RenderThemeSafari::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; +} + +NSControlSize RenderThemeSafari::controlSizeForFont(RenderStyle* style) const +{ + int fontSize = style->fontSize(); + if (fontSize >= 16) + return NSRegularControlSize; + if (fontSize >= 11) + return NSSmallControlSize; + return NSMiniControlSize; +} +/* +void RenderThemeSafari::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize) +{ + NSControlSize size; + if (minSize.width() >= sizes[NSRegularControlSize].width() && + minSize.height() >= sizes[NSRegularControlSize].height()) + size = NSRegularControlSize; + else if (minSize.width() >= sizes[NSSmallControlSize].width() && + minSize.height() >= sizes[NSSmallControlSize].height()) + size = NSSmallControlSize; + else + size = NSMiniControlSize; + if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same. + [cell setControlSize:size]; +} +*/ +IntSize RenderThemeSafari::sizeForFont(RenderStyle* style, const IntSize* sizes) const +{ + return sizes[controlSizeForFont(style)]; +} + +IntSize RenderThemeSafari::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const +{ + return sizes[controlSizeForSystemFont(style)]; +} + +void RenderThemeSafari::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const +{ + // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. + IntSize size = sizeForFont(style, sizes); + if (style->width().isIntrinsicOrAuto() && size.width() > 0) + style->setWidth(Length(size.width(), Fixed)); + if (style->height().isAuto() && size.height() > 0) + style->setHeight(Length(size.height(), Fixed)); +} + +void RenderThemeSafari::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const +{ + FontDescription fontDescription; + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::SerifFamily); + + float fontSize = systemFontSizeForControlSize(controlSize); + fontDescription.firstFamily().setFamily("Lucida Grande"); + fontDescription.setComputedSize(fontSize); + fontDescription.setSpecifiedSize(fontSize); + + // Reset line height + style->setLineHeight(RenderStyle::initialLineHeight()); + + if (style->setFontDescription(fontDescription)) + style->font().update(selector->fontSelector()); +} + +NSControlSize RenderThemeSafari::controlSizeForSystemFont(RenderStyle* style) const +{ + int fontSize = style->fontSize(); + if (fontSize >= 13) + return NSRegularControlSize; + if (fontSize >= 11) + return NSSmallControlSize; + return NSMiniControlSize; +} + +bool RenderThemeSafari::paintCheckbox(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + ASSERT(SafariThemeLibrary()); + + NSControlSize controlSize = controlSizeForFont(o->style()); + + IntRect inflatedRect = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize)); + paintThemePart(SafariTheme::CheckboxPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o)); + + return false; +} + +const IntSize* RenderThemeSafari::checkboxSizes() const +{ + static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) }; + return sizes; +} + +const int* RenderThemeSafari::checkboxMargins(NSControlSize controlSize) const +{ + static const int margins[3][4] = + { + { 2, 2, 2, 2 }, + { 2, 2, 2, 1 }, + { 1, 0, 0, 0 }, + }; + return margins[controlSize]; +} + +void RenderThemeSafari::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; + + // Use the font size to determine the intrinsic width of the control. + setSizeFromFont(style, checkboxSizes()); +} + +bool RenderThemeSafari::paintRadio(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ + ASSERT(SafariThemeLibrary()); + + NSControlSize controlSize = controlSizeForFont(o->style()); + + IntRect inflatedRect = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize)); + paintThemePart(RadioButtonPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o)); + + return false; +} + +const IntSize* RenderThemeSafari::radioSizes() const +{ + static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) }; + return sizes; +} + +const int* RenderThemeSafari::radioMargins(NSControlSize controlSize) const +{ + static const int margins[3][4] = + { + { 1, 2, 2, 2 }, + { 0, 1, 2, 1 }, + { 0, 0, 1, 0 }, + }; + return margins[controlSize]; +} + +void RenderThemeSafari::setRadioSize(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; + + // Use the font size to determine the intrinsic width of the control. + setSizeFromFont(style, radioSizes()); +} + +void RenderThemeSafari::setButtonPaddingFromControlSize(RenderStyle* style, NSControlSize size) const +{ + // Just use 8px. AppKit wants to use 11px for mini buttons, but that padding is just too large + // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is + // by definition constrained, since we select mini only for small cramped environments. + // This also guarantees the HTML4