Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2007 Apple Inc.
      3  * Copyright (C) 2007 Alp Toker <alp (at) atoker.com>
      4  * Copyright (C) 2008 Collabora Ltd.
      5  * Copyright (C) 2008, 2009 Google Inc.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * along with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  *
     22  */
     23 
     24 #include "config.h"
     25 #include "core/rendering/RenderThemeChromiumSkia.h"
     26 
     27 #include "UserAgentStyleSheets.h"
     28 #include "core/rendering/PaintInfo.h"
     29 #include "core/rendering/RenderBox.h"
     30 #include "core/rendering/RenderMediaControls.h"
     31 #include "core/rendering/RenderObject.h"
     32 #include "core/rendering/RenderProgress.h"
     33 #include "core/rendering/RenderThemeChromiumFontProvider.h"
     34 #include "platform/LayoutTestSupport.h"
     35 #include "platform/graphics/GraphicsContext.h"
     36 #include "platform/graphics/Image.h"
     37 #include "platform/scroll/ScrollbarTheme.h"
     38 #include "wtf/CurrentTime.h"
     39 #include "wtf/StdLibExtras.h"
     40 
     41 namespace WebCore {
     42 
     43 enum PaddingType {
     44     TopPadding,
     45     RightPadding,
     46     BottomPadding,
     47     LeftPadding
     48 };
     49 
     50 static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 };
     51 
     52 // These values all match Safari/Win.
     53 static const float defaultControlFontPixelSize = 13;
     54 static const float defaultCancelButtonSize = 9;
     55 static const float minCancelButtonSize = 5;
     56 static const float maxCancelButtonSize = 21;
     57 static const float defaultSearchFieldResultsDecorationSize = 13;
     58 static const float minSearchFieldResultsDecorationSize = 9;
     59 static const float maxSearchFieldResultsDecorationSize = 30;
     60 
     61 RenderThemeChromiumSkia::RenderThemeChromiumSkia()
     62 {
     63 }
     64 
     65 RenderThemeChromiumSkia::~RenderThemeChromiumSkia()
     66 {
     67 }
     68 
     69 // Use the Windows style sheets to match their metrics.
     70 String RenderThemeChromiumSkia::extraDefaultStyleSheet()
     71 {
     72     return RenderTheme::extraDefaultStyleSheet() +
     73         String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)) +
     74         String(themeChromiumSkiaUserAgentStyleSheet, sizeof(themeChromiumSkiaUserAgentStyleSheet)) +
     75         String(themeChromiumUserAgentStyleSheet, sizeof(themeChromiumUserAgentStyleSheet));
     76 }
     77 
     78 String RenderThemeChromiumSkia::extraQuirksStyleSheet()
     79 {
     80     return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
     81 }
     82 
     83 bool RenderThemeChromiumSkia::supportsHover(const RenderStyle* style) const
     84 {
     85     return true;
     86 }
     87 
     88 bool RenderThemeChromiumSkia::supportsFocusRing(const RenderStyle* style) const
     89 {
     90     // This causes WebKit to draw the focus rings for us.
     91     return false;
     92 }
     93 
     94 bool RenderThemeChromiumSkia::supportsClosedCaptioning() const
     95 {
     96     return true;
     97 }
     98 
     99 Color RenderThemeChromiumSkia::platformActiveSelectionBackgroundColor() const
    100 {
    101     return Color(0x1e, 0x90, 0xff);
    102 }
    103 
    104 Color RenderThemeChromiumSkia::platformInactiveSelectionBackgroundColor() const
    105 {
    106     return Color(0xc8, 0xc8, 0xc8);
    107 }
    108 
    109 Color RenderThemeChromiumSkia::platformActiveSelectionForegroundColor() const
    110 {
    111     return Color::black;
    112 }
    113 
    114 Color RenderThemeChromiumSkia::platformInactiveSelectionForegroundColor() const
    115 {
    116     return Color(0x32, 0x32, 0x32);
    117 }
    118 
    119 Color RenderThemeChromiumSkia::platformFocusRingColor() const
    120 {
    121     static Color focusRingColor(229, 151, 0, 255);
    122     return focusRingColor;
    123 }
    124 
    125 double RenderThemeChromiumSkia::caretBlinkInterval() const
    126 {
    127     // Disable the blinking caret in layout test mode, as it introduces
    128     // a race condition for the pixel tests. http://b/1198440
    129     if (isRunningLayoutTest())
    130         return 0;
    131 
    132     return caretBlinkIntervalInternal();
    133 }
    134 
    135 void RenderThemeChromiumSkia::systemFont(CSSValueID valueID, FontDescription& fontDescription) const
    136 {
    137     RenderThemeChromiumFontProvider::systemFont(valueID, fontDescription);
    138 }
    139 
    140 int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const
    141 {
    142     return 0;
    143 }
    144 
    145 // These are the default dimensions of radio buttons and checkboxes.
    146 static const int widgetStandardWidth = 13;
    147 static const int widgetStandardHeight = 13;
    148 
    149 // Return a rectangle that has the same center point as |original|, but with a
    150 // size capped at |width| by |height|.
    151 IntRect center(const IntRect& original, int width, int height)
    152 {
    153     width = std::min(original.width(), width);
    154     height = std::min(original.height(), height);
    155     int x = original.x() + (original.width() - width) / 2;
    156     int y = original.y() + (original.height() - height) / 2;
    157 
    158     return IntRect(x, y, width, height);
    159 }
    160 
    161 void RenderThemeChromiumSkia::setCheckboxSize(RenderStyle* style) const
    162 {
    163     // If the width and height are both specified, then we have nothing to do.
    164     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
    165         return;
    166 
    167     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary
    168     // for now.  It matches Firefox.  At different DPI settings on Windows,
    169     // querying the theme gives you a larger size that accounts for the higher
    170     // DPI.  Until our entire engine honors a DPI setting other than 96, we
    171     // can't rely on the theme's metrics.
    172     const IntSize size(widgetStandardWidth, widgetStandardHeight);
    173     setSizeIfAuto(style, size);
    174 }
    175 
    176 void RenderThemeChromiumSkia::setRadioSize(RenderStyle* style) const
    177 {
    178     // Use same sizing for radio box as checkbox.
    179     setCheckboxSize(style);
    180 }
    181 
    182 void RenderThemeChromiumSkia::adjustButtonStyle(RenderStyle* style, Element*) const
    183 {
    184     if (style->appearance() == PushButtonPart) {
    185         // Ignore line-height.
    186         style->setLineHeight(RenderStyle::initialLineHeight());
    187     }
    188 }
    189 
    190 bool RenderThemeChromiumSkia::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
    191 {
    192     return paintTextField(o, i, r);
    193 }
    194 
    195 void RenderThemeChromiumSkia::adjustSearchFieldStyle(RenderStyle* style, Element*) const
    196 {
    197      // Ignore line-height.
    198      style->setLineHeight(RenderStyle::initialLineHeight());
    199 }
    200 
    201 bool RenderThemeChromiumSkia::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& r)
    202 {
    203     return paintTextField(o, i, r);
    204 }
    205 
    206 void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(RenderStyle* style, Element*) const
    207 {
    208     // Scale the button size based on the font size
    209     float fontScale = style->fontSize() / defaultControlFontPixelSize;
    210     int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
    211     style->setWidth(Length(cancelButtonSize, Fixed));
    212     style->setHeight(Length(cancelButtonSize, Fixed));
    213 }
    214 
    215 IntRect RenderThemeChromiumSkia::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, LayoutRect partRect, const IntRect& localOffset) const
    216 {
    217     // Compute an offset between the part renderer and the input renderer.
    218     LayoutSize offsetFromInputRenderer = -partRenderer->offsetFromAncestorContainer(inputRenderer);
    219     // Move the rect into partRenderer's coords.
    220     partRect.move(offsetFromInputRenderer);
    221     // Account for the local drawing offset.
    222     partRect.move(localOffset.x(), localOffset.y());
    223 
    224     return pixelSnappedIntRect(partRect);
    225 }
    226 
    227 bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* cancelButtonObject, const PaintInfo& paintInfo, const IntRect& r)
    228 {
    229     // Get the renderer of <input> element.
    230     Node* input = cancelButtonObject->node()->shadowHost();
    231     RenderObject* baseRenderer = input ? input->renderer() : cancelButtonObject;
    232     if (!baseRenderer->isBox())
    233         return false;
    234     RenderBox* inputRenderBox = toRenderBox(baseRenderer);
    235     LayoutRect inputContentBox = inputRenderBox->contentBoxRect();
    236 
    237     // Make sure the scaled button stays square and will fit in its parent's box.
    238     LayoutUnit cancelButtonSize = std::min(inputContentBox.width(), std::min<LayoutUnit>(inputContentBox.height(), r.height()));
    239     // Calculate cancel button's coordinates relative to the input element.
    240     // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
    241     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
    242     LayoutRect cancelButtonRect(cancelButtonObject->offsetFromAncestorContainer(inputRenderBox).width(),
    243                                 inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2,
    244                                 cancelButtonSize, cancelButtonSize);
    245     IntRect paintingRect = convertToPaintingRect(inputRenderBox, cancelButtonObject, cancelButtonRect, r);
    246 
    247     DEFINE_STATIC_REF(Image, cancelImage, (Image::loadPlatformResource("searchCancel")));
    248     DEFINE_STATIC_REF(Image, cancelPressedImage, (Image::loadPlatformResource("searchCancelPressed")));
    249     paintInfo.context->drawImage(isPressed(cancelButtonObject) ? cancelPressedImage : cancelImage, paintingRect);
    250     return false;
    251 }
    252 
    253 void RenderThemeChromiumSkia::adjustSearchFieldDecorationStyle(RenderStyle* style, Element*) const
    254 {
    255     IntSize emptySize(1, 11);
    256     style->setWidth(Length(emptySize.width(), Fixed));
    257     style->setHeight(Length(emptySize.height(), Fixed));
    258 }
    259 
    260 void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(RenderStyle* style, Element*) const
    261 {
    262     // Scale the decoration size based on the font size
    263     float fontScale = style->fontSize() / defaultControlFontPixelSize;
    264     int magnifierSize = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
    265                                          maxSearchFieldResultsDecorationSize));
    266     style->setWidth(Length(magnifierSize, Fixed));
    267     style->setHeight(Length(magnifierSize, Fixed));
    268 }
    269 
    270 bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* magnifierObject, const PaintInfo& paintInfo, const IntRect& r)
    271 {
    272     // Get the renderer of <input> element.
    273     Node* input = magnifierObject->node()->shadowHost();
    274     RenderObject* baseRenderer = input ? input->renderer() : magnifierObject;
    275     if (!baseRenderer->isBox())
    276         return false;
    277     RenderBox* inputRenderBox = toRenderBox(baseRenderer);
    278     LayoutRect inputContentBox = inputRenderBox->contentBoxRect();
    279 
    280     // Make sure the scaled decoration stays square and will fit in its parent's box.
    281     LayoutUnit magnifierSize = std::min(inputContentBox.width(), std::min<LayoutUnit>(inputContentBox.height(), r.height()));
    282     // Calculate decoration's coordinates relative to the input element.
    283     // Center the decoration vertically.  Round up though, so if it has to be one pixel off-center, it will
    284     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
    285     LayoutRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(),
    286                              inputContentBox.y() + (inputContentBox.height() - magnifierSize + 1) / 2,
    287                              magnifierSize, magnifierSize);
    288     IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r);
    289 
    290     DEFINE_STATIC_REF(Image, magnifierImage, (Image::loadPlatformResource("searchMagnifier")));
    291     paintInfo.context->drawImage(magnifierImage, paintingRect);
    292     return false;
    293 }
    294 
    295 bool RenderThemeChromiumSkia::paintMediaSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
    296 {
    297     return RenderMediaControls::paintMediaControlsPart(MediaSlider, object, paintInfo, rect);
    298 }
    299 
    300 bool RenderThemeChromiumSkia::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
    301 {
    302     return RenderMediaControls::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect);
    303 }
    304 
    305 void RenderThemeChromiumSkia::adjustSliderThumbSize(RenderStyle* style, Element*) const
    306 {
    307     RenderMediaControls::adjustMediaSliderThumbSize(style);
    308 }
    309 
    310 bool RenderThemeChromiumSkia::paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
    311 {
    312     return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect);
    313 }
    314 
    315 bool RenderThemeChromiumSkia::paintMediaToggleClosedCaptionsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
    316 {
    317     return RenderMediaControls::paintMediaControlsPart(MediaShowClosedCaptionsButton, o, paintInfo, r);
    318 }
    319 
    320 bool RenderThemeChromiumSkia::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
    321 {
    322     return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
    323 }
    324 
    325 bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
    326 {
    327     return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
    328 }
    329 
    330 bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
    331 {
    332     return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
    333 }
    334 
    335 String RenderThemeChromiumSkia::formatMediaControlsTime(float time) const
    336 {
    337     return RenderMediaControls::formatMediaControlsTime(time);
    338 }
    339 
    340 String RenderThemeChromiumSkia::formatMediaControlsCurrentTime(float currentTime, float duration) const
    341 {
    342     return RenderMediaControls::formatMediaControlsCurrentTime(currentTime, duration);
    343 }
    344 
    345 bool RenderThemeChromiumSkia::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
    346 {
    347     return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, object, paintInfo, rect);
    348 }
    349 
    350 void RenderThemeChromiumSkia::adjustMenuListStyle(RenderStyle* style, WebCore::Element*) const
    351 {
    352     // Height is locked to auto on all browsers.
    353     style->setLineHeight(RenderStyle::initialLineHeight());
    354 }
    355 
    356 void RenderThemeChromiumSkia::adjustMenuListButtonStyle(RenderStyle* style, Element* e) const
    357 {
    358     adjustMenuListStyle(style, e);
    359 }
    360 
    361 // Used to paint styled menulists (i.e. with a non-default border)
    362 bool RenderThemeChromiumSkia::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
    363 {
    364     return paintMenuList(o, i, rect);
    365 }
    366 
    367 int RenderThemeChromiumSkia::popupInternalPaddingLeft(RenderStyle* style) const
    368 {
    369     return menuListInternalPadding(style, LeftPadding);
    370 }
    371 
    372 int RenderThemeChromiumSkia::popupInternalPaddingRight(RenderStyle* style) const
    373 {
    374     return menuListInternalPadding(style, RightPadding);
    375 }
    376 
    377 int RenderThemeChromiumSkia::popupInternalPaddingTop(RenderStyle* style) const
    378 {
    379     return menuListInternalPadding(style, TopPadding);
    380 }
    381 
    382 int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) const
    383 {
    384     return menuListInternalPadding(style, BottomPadding);
    385 }
    386 
    387 // static
    388 void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize)
    389 {
    390     RenderThemeChromiumFontProvider::setDefaultFontSize(fontSize);
    391 }
    392 
    393 double RenderThemeChromiumSkia::caretBlinkIntervalInternal() const
    394 {
    395     return RenderTheme::caretBlinkInterval();
    396 }
    397 
    398 int RenderThemeChromiumSkia::menuListArrowPadding() const
    399 {
    400     return ScrollbarTheme::theme()->scrollbarThickness();
    401 }
    402 
    403 int RenderThemeChromiumSkia::menuListInternalPadding(RenderStyle* style, int paddingType) const
    404 {
    405     // This internal padding is in addition to the user-supplied padding.
    406     // Matches the FF behavior.
    407     int padding = styledMenuListInternalPadding[paddingType];
    408 
    409     // Reserve the space for right arrow here. The rest of the padding is
    410     // set by adjustMenuListStyle, since PopMenuWin.cpp uses the padding from
    411     // RenderMenuList to lay out the individual items in the popup.
    412     // If the MenuList actually has appearance "NoAppearance", then that means
    413     // we don't draw a button, so don't reserve space for it.
    414     const int barType = style->direction() == LTR ? RightPadding : LeftPadding;
    415     if (paddingType == barType && style->appearance() != NoControlPart)
    416         padding += menuListArrowPadding();
    417 
    418     return padding;
    419 }
    420 
    421 bool RenderThemeChromiumSkia::shouldShowPlaceholderWhenFocused() const
    422 {
    423     return true;
    424 }
    425 
    426 //
    427 // Following values are come from default of GTK+
    428 //
    429 static const int progressActivityBlocks = 5;
    430 static const int progressAnimationFrames = 10;
    431 static const double progressAnimationInterval = 0.125;
    432 
    433 IntRect RenderThemeChromiumSkia::determinateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
    434 {
    435     int dx = rect.width() * renderProgress->position();
    436     return IntRect(rect.x(), rect.y(), dx, rect.height());
    437 }
    438 
    439 IntRect RenderThemeChromiumSkia::indeterminateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
    440 {
    441 
    442     int valueWidth = rect.width() / progressActivityBlocks;
    443     int movableWidth = rect.width() - valueWidth;
    444     if (movableWidth <= 0)
    445         return IntRect();
    446 
    447     double progress = renderProgress->animationProgress();
    448     if (progress < 0.5)
    449         return IntRect(rect.x() + progress * 2 * movableWidth, rect.y(), valueWidth, rect.height());
    450     return IntRect(rect.x() + (1.0 - progress) * 2 * movableWidth, rect.y(), valueWidth, rect.height());
    451 }
    452 
    453 double RenderThemeChromiumSkia::animationRepeatIntervalForProgressBar(RenderProgress*) const
    454 {
    455     return progressAnimationInterval;
    456 }
    457 
    458 double RenderThemeChromiumSkia::animationDurationForProgressBar(RenderProgress* renderProgress) const
    459 {
    460     return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth
    461 }
    462 
    463 IntRect RenderThemeChromiumSkia::progressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
    464 {
    465     return renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, rect) : indeterminateProgressValueRectFor(renderProgress, rect);
    466 }
    467 
    468 RenderThemeChromiumSkia::DirectionFlippingScope::DirectionFlippingScope(RenderObject* renderer, const PaintInfo& paintInfo, const IntRect& rect)
    469     : m_needsFlipping(!renderer->style()->isLeftToRightDirection())
    470     , m_paintInfo(paintInfo)
    471 {
    472     if (!m_needsFlipping)
    473         return;
    474     m_paintInfo.context->save();
    475     m_paintInfo.context->translate(2 * rect.x() + rect.width(), 0);
    476     m_paintInfo.context->scale(FloatSize(-1, 1));
    477 }
    478 
    479 RenderThemeChromiumSkia::DirectionFlippingScope::~DirectionFlippingScope()
    480 {
    481     if (!m_needsFlipping)
    482         return;
    483     m_paintInfo.context->restore();
    484 }
    485 
    486 } // namespace WebCore
    487