Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "ScrollbarThemeChromiumLinux.h"
     33 
     34 #include "PlatformContextSkia.h"
     35 #include "PlatformMouseEvent.h"
     36 #include "RenderTheme.h"
     37 #include "RenderThemeChromiumLinux.h"
     38 #include "Scrollbar.h"
     39 #include "TransformationMatrix.h"
     40 
     41 namespace WebCore {
     42 
     43 ScrollbarTheme* ScrollbarTheme::nativeTheme()
     44 {
     45     static ScrollbarThemeChromiumLinux theme;
     46     return &theme;
     47 }
     48 
     49 int ScrollbarThemeChromiumLinux::scrollbarThickness(ScrollbarControlSize controlSize)
     50 {
     51     return 15;
     52 }
     53 
     54 static void drawVertLine(SkCanvas* canvas, int x, int y1, int y2, const SkPaint& paint)
     55 {
     56     SkIRect skrect;
     57     skrect.set(x, y1, x + 1, y2 + 1);
     58     canvas->drawIRect(skrect, paint);
     59 }
     60 
     61 static void drawHorizLine(SkCanvas* canvas, int x1, int x2, int y, const SkPaint& paint)
     62 {
     63     SkIRect skrect;
     64     skrect.set(x1, y, x2 + 1, y + 1);
     65     canvas->drawIRect(skrect, paint);
     66 }
     67 
     68 static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint)
     69 {
     70     const int right = rect.x() + rect.width() - 1;
     71     const int bottom = rect.y() + rect.height() - 1;
     72     drawHorizLine(canvas, rect.x(), right, rect.y(), paint);
     73     drawVertLine(canvas, right, rect.y(), bottom, paint);
     74     drawHorizLine(canvas, rect.x(), right, bottom, paint);
     75     drawVertLine(canvas, rect.x(), rect.y(), bottom, paint);
     76 }
     77 
     78 static SkScalar clamp(SkScalar value, SkScalar min, SkScalar max)
     79 {
     80     return std::min(std::max(value, min), max);
     81 }
     82 
     83 static SkColor saturateAndBrighten(SkScalar* hsv,
     84                                    SkScalar saturateAmount,
     85                                    SkScalar brightenAmount)
     86 {
     87     SkScalar color[3];
     88     color[0] = hsv[0];
     89     color[1] = clamp(hsv[1] + saturateAmount, 0.0, 1.0);
     90     color[2] = clamp(hsv[2] + brightenAmount, 0.0, 1.0);
     91     return SkHSVToColor(color);
     92 }
     93 
     94 static SkColor outlineColor(SkScalar* hsv1, SkScalar* hsv2)
     95 {
     96     // GTK Theme engines have way too much control over the layout of
     97     // the scrollbar. We might be able to more closely approximate its
     98     // look-and-feel, if we sent whole images instead of just colors
     99     // from the browser to the renderer. But even then, some themes
    100     // would just break.
    101     //
    102     // So, instead, we don't even try to 100% replicate the look of
    103     // the native scrollbar. We render our own version, but we make
    104     // sure to pick colors that blend in nicely with the system GTK
    105     // theme. In most cases, we can just sample a couple of pixels
    106     // from the system scrollbar and use those colors to draw our
    107     // scrollbar.
    108     //
    109     // This works fine for the track color and the overall thumb
    110     // color. But it fails spectacularly for the outline color used
    111     // around the thumb piece.  Not all themes have a clearly defined
    112     // outline. For some of them it is partially transparent, and for
    113     // others the thickness is very unpredictable.
    114     //
    115     // So, instead of trying to approximate the system theme, we
    116     // instead try to compute a reasonable looking choice based on the
    117     // known color of the track and the thumb piece. This is difficult
    118     // when trying to deal both with high- and low-contrast themes,
    119     // and both with positive and inverted themes.
    120     //
    121     // The following code has been tested to look OK with all of the
    122     // default GTK themes.
    123     SkScalar minDiff = clamp((hsv1[1] + hsv2[1]) * 1.2, 0.2, 0.5);
    124     SkScalar diff = clamp(fabs(hsv1[2] - hsv2[2]) / 2, minDiff, 0.5);
    125 
    126     if (hsv1[2] + hsv2[2] > 1.0)
    127         diff = -diff;
    128 
    129     return saturateAndBrighten(hsv2, -0.2, diff);
    130 }
    131 
    132 IntRect ScrollbarThemeChromium::trackRect(Scrollbar* scrollbar, bool)
    133 {
    134     IntSize bs = buttonSize(scrollbar);
    135     int thickness = scrollbarThickness(scrollbar->controlSize());
    136     if (scrollbar->orientation() == HorizontalScrollbar)
    137         return IntRect(scrollbar->x() + bs.width(), scrollbar->y(), scrollbar->width(), thickness);
    138     return IntRect(scrollbar->x(), scrollbar->y() + bs.height(), thickness, scrollbar->height());
    139 }
    140 
    141 void ScrollbarThemeChromiumLinux::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart partType)
    142 {
    143     SkCanvas* const canvas = gc->platformContext()->canvas();
    144     SkPaint paint;
    145     SkIRect skrect;
    146 
    147     skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
    148     SkScalar track_hsv[3];
    149     SkColorToHSV(RenderThemeChromiumLinux::trackColor(), track_hsv);
    150     paint.setColor(saturateAndBrighten(track_hsv, 0, 0));
    151     canvas->drawIRect(skrect, paint);
    152 
    153     SkScalar thumb_hsv[3];
    154     SkColorToHSV(RenderThemeChromiumLinux::thumbInactiveColor(),
    155                  thumb_hsv);
    156 
    157     paint.setColor(outlineColor(track_hsv, thumb_hsv));
    158     drawBox(canvas, rect, paint);
    159 }
    160 
    161 void ScrollbarThemeChromiumLinux::paintButton(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
    162 {
    163     // We don't use buttons
    164 }
    165 
    166 void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect)
    167 {
    168     const bool hovered = scrollbar->hoveredPart() == ThumbPart;
    169     const int midx = rect.x() + rect.width() / 2;
    170     const int midy = rect.y() + rect.height() / 2;
    171     const bool vertical = scrollbar->orientation() == VerticalScrollbar;
    172     SkCanvas* const canvas = gc->platformContext()->canvas();
    173 
    174     SkScalar thumb[3];
    175     SkColorToHSV(hovered
    176                  ? RenderThemeChromiumLinux::thumbActiveColor()
    177                  : RenderThemeChromiumLinux::thumbInactiveColor(),
    178                  thumb);
    179 
    180     SkPaint paint;
    181     paint.setColor(saturateAndBrighten(thumb, 0, 0.02));
    182 
    183     SkIRect skrect;
    184     if (vertical)
    185         skrect.set(rect.x(), rect.y(), midx + 1, rect.y() + rect.height());
    186     else
    187         skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), midy + 1);
    188 
    189     canvas->drawIRect(skrect, paint);
    190 
    191     paint.setColor(saturateAndBrighten(thumb, 0, -0.02));
    192 
    193     if (vertical)
    194         skrect.set(midx + 1, rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
    195     else
    196         skrect.set(rect.x(), midy + 1, rect.x() + rect.width(), rect.y() + rect.height());
    197 
    198     canvas->drawIRect(skrect, paint);
    199 
    200     SkScalar track[3];
    201     SkColorToHSV(RenderThemeChromiumLinux::trackColor(), track);
    202     paint.setColor(outlineColor(track, thumb));
    203     drawBox(canvas, rect, paint);
    204 
    205     if (rect.height() > 10 && rect.width() > 10) {
    206         const int grippyHalfWidth = 2;
    207         const int interGrippyOffset = 3;
    208         if (vertical) {
    209             drawHorizLine(canvas, midx - grippyHalfWidth, midx + grippyHalfWidth, midy - interGrippyOffset, paint);
    210             drawHorizLine(canvas, midx - grippyHalfWidth, midx + grippyHalfWidth, midy,                     paint);
    211             drawHorizLine(canvas, midx - grippyHalfWidth, midx + grippyHalfWidth, midy + interGrippyOffset, paint);
    212         } else {
    213             drawVertLine(canvas, midx - interGrippyOffset, midy - grippyHalfWidth, midy + grippyHalfWidth, paint);
    214             drawVertLine(canvas, midx,                     midy - grippyHalfWidth, midy + grippyHalfWidth, paint);
    215             drawVertLine(canvas, midx + interGrippyOffset, midy - grippyHalfWidth, midy + grippyHalfWidth, paint);
    216         }
    217     }
    218 }
    219 
    220 bool ScrollbarThemeChromiumLinux::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
    221 {
    222     return (evt.shiftKey() && evt.button() == LeftButton) || (evt.button() == MiddleButton);
    223 }
    224 
    225 IntSize ScrollbarThemeChromiumLinux::buttonSize(Scrollbar* scrollbar)
    226 {
    227     // On Linux, we don't use buttons
    228     return IntSize(0, 0);
    229 }
    230 
    231 int ScrollbarThemeChromiumLinux::minimumThumbLength(Scrollbar* scrollbar)
    232 {
    233     // This matches Firefox on Linux.
    234     return 2 * scrollbarThickness(scrollbar->controlSize());
    235 }
    236 
    237 } // namespace WebCore
    238