Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (C) 2010 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 "PlatformThemeChromiumGtk.h"
     33 
     34 namespace WebCore {
     35 
     36 unsigned PlatformThemeChromiumGtk::s_thumbInactiveColor = 0xeaeaea;
     37 unsigned PlatformThemeChromiumGtk::s_thumbActiveColor = 0xf4f4f4;
     38 unsigned PlatformThemeChromiumGtk::s_trackColor = 0xd3d3d3;
     39 
     40 void PlatformThemeChromiumGtk::setScrollbarColors(
     41     SkColor inactiveColor, SkColor activeColor, SkColor trackColor)
     42 {
     43     s_thumbInactiveColor = inactiveColor;
     44     s_thumbActiveColor = activeColor;
     45     s_trackColor = trackColor;
     46 }
     47 
     48 static SkScalar clamp(SkScalar value, SkScalar min, SkScalar max)
     49 {
     50     return std::min(std::max(value, min), max);
     51 }
     52 
     53 SkColor PlatformThemeChromiumGtk::saturateAndBrighten(const SkScalar hsv[3], SkScalar saturateAmount, SkScalar brightenAmount)
     54 {
     55     SkScalar color[3];
     56     color[0] = hsv[0];
     57     color[1] = clamp(hsv[1] + saturateAmount, 0.0, 1.0);
     58     color[2] = clamp(hsv[2] + brightenAmount, 0.0, 1.0);
     59     return SkHSVToColor(color);
     60 }
     61 
     62 SkColor PlatformThemeChromiumGtk::outlineColor(const SkScalar hsv1[3], const SkScalar hsv2[3])
     63 {
     64     // GTK Theme engines have way too much control over the layout of
     65     // the scrollbar. We might be able to more closely approximate its
     66     // look-and-feel, if we sent whole images instead of just colors
     67     // from the browser to the renderer. But even then, some themes
     68     // would just break.
     69     //
     70     // So, instead, we don't even try to 100% replicate the look of
     71     // the native scrollbar. We render our own version, but we make
     72     // sure to pick colors that blend in nicely with the system GTK
     73     // theme. In most cases, we can just sample a couple of pixels
     74     // from the system scrollbar and use those colors to draw our
     75     // scrollbar.
     76     //
     77     // This works fine for the track color and the overall thumb
     78     // color. But it fails spectacularly for the outline color used
     79     // around the thumb piece.  Not all themes have a clearly defined
     80     // outline. For some of them it is partially transparent, and for
     81     // others the thickness is very unpredictable.
     82     //
     83     // So, instead of trying to approximate the system theme, we
     84     // instead try to compute a reasonable looking choice based on the
     85     // known color of the track and the thumb piece. This is difficult
     86     // when trying to deal both with high- and low-contrast themes,
     87     // and both with positive and inverted themes.
     88     //
     89     // The following code has been tested to look OK with all of the
     90     // default GTK themes.
     91     SkScalar minDiff = clamp((hsv1[1] + hsv2[1]) * 1.2, 0.28, 0.5);
     92     SkScalar diff = clamp(fabs(hsv1[2] - hsv2[2]) / 2, minDiff, 0.5);
     93 
     94     if (hsv1[2] + hsv2[2] > 1.0)
     95         diff = -diff;
     96 
     97     return saturateAndBrighten(hsv2, -0.2, diff);
     98 }
     99 
    100 void PlatformThemeChromiumGtk::paintArrowButton(GraphicsContext* gc, const IntRect& rect, ArrowDirection direction, ControlStates states)
    101 {
    102     SkCanvas* const canvas = gc->platformContext()->canvas();
    103     int widthMiddle, lengthMiddle;
    104     SkPaint paint;
    105     if (direction == North || direction == South) {
    106         widthMiddle = rect.width() / 2 + 1;
    107         lengthMiddle = rect.height() / 2 + 1;
    108     } else {
    109         lengthMiddle = rect.width() / 2 + 1;
    110         widthMiddle = rect.height() / 2 + 1;
    111     }
    112 
    113     // Calculate button color.
    114     SkScalar trackHSV[3];
    115     SkColorToHSV(trackColor(), trackHSV);
    116     SkColor buttonColor = saturateAndBrighten(trackHSV, 0, 0.2);
    117     SkColor backgroundColor = buttonColor;
    118     if (states & PressedState) {
    119         SkScalar buttonHSV[3];
    120         SkColorToHSV(buttonColor, buttonHSV);
    121         buttonColor = saturateAndBrighten(buttonHSV, 0, -0.1);
    122     } else if (states & HoverState) {
    123         SkScalar buttonHSV[3];
    124         SkColorToHSV(buttonColor, buttonHSV);
    125         buttonColor = saturateAndBrighten(buttonHSV, 0, 0.05);
    126     }
    127 
    128     SkIRect skrect;
    129     skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
    130     // Paint the background (the area visible behind the rounded corners).
    131     paint.setColor(backgroundColor);
    132     canvas->drawIRect(skrect, paint);
    133 
    134     // Paint the button's outline and fill the middle
    135     SkPath outline;
    136     switch (direction) {
    137     case North:
    138         outline.moveTo(rect.x() + 0.5, rect.y() + rect.height() + 0.5);
    139         outline.rLineTo(0, -(rect.height() - 2));
    140         outline.rLineTo(2, -2);
    141         outline.rLineTo(rect.width() - 5, 0);
    142         outline.rLineTo(2, 2);
    143         outline.rLineTo(0, rect.height() - 2);
    144         break;
    145     case South:
    146         outline.moveTo(rect.x() + 0.5, rect.y() - 0.5);
    147         outline.rLineTo(0, rect.height() - 2);
    148         outline.rLineTo(2, 2);
    149         outline.rLineTo(rect.width() - 5, 0);
    150         outline.rLineTo(2, -2);
    151         outline.rLineTo(0, -(rect.height() - 2));
    152         break;
    153     case East:
    154         outline.moveTo(rect.x() - 0.5, rect.y() + 0.5);
    155         outline.rLineTo(rect.width() - 2, 0);
    156         outline.rLineTo(2, 2);
    157         outline.rLineTo(0, rect.height() - 5);
    158         outline.rLineTo(-2, 2);
    159         outline.rLineTo(-(rect.width() - 2), 0);
    160         break;
    161     case West:
    162         outline.moveTo(rect.x() + rect.width() + 0.5, rect.y() + 0.5);
    163         outline.rLineTo(-(rect.width() - 2), 0);
    164         outline.rLineTo(-2, 2);
    165         outline.rLineTo(0, rect.height() - 5);
    166         outline.rLineTo(2, 2);
    167         outline.rLineTo(rect.width() - 2, 0);
    168         break;
    169     }
    170     outline.close();
    171 
    172     paint.setStyle(SkPaint::kFill_Style);
    173     paint.setColor(buttonColor);
    174     canvas->drawPath(outline, paint);
    175 
    176     paint.setAntiAlias(true);
    177     paint.setStyle(SkPaint::kStroke_Style);
    178     SkScalar thumbHSV[3];
    179     SkColorToHSV(thumbInactiveColor(), thumbHSV);
    180     paint.setColor(outlineColor(trackHSV, thumbHSV));
    181     canvas->drawPath(outline, paint);
    182 
    183     // If the button is disabled or read-only, the arrow is drawn with the outline color.
    184     if (states & EnabledState && !(states & ReadOnlyState))
    185         paint.setColor(SK_ColorBLACK);
    186 
    187     paint.setAntiAlias(false);
    188     paint.setStyle(SkPaint::kFill_Style);
    189 
    190     SkPath path;
    191     // The constants in this block of code are hand-tailored to produce good
    192     // looking arrows without anti-aliasing.
    193     switch (direction) {
    194     case North:
    195         path.moveTo(rect.x() + widthMiddle - 4, rect.y() + lengthMiddle + 2);
    196         path.rLineTo(7, 0);
    197         path.rLineTo(-4, -4);
    198         break;
    199     case South:
    200         path.moveTo(rect.x() + widthMiddle - 4, rect.y() + lengthMiddle - 3);
    201         path.rLineTo(7, 0);
    202         path.rLineTo(-4, 4);
    203         break;
    204     case East:
    205         path.moveTo(rect.x() + lengthMiddle - 3, rect.y() + widthMiddle - 4);
    206         path.rLineTo(0, 7);
    207         path.rLineTo(4, -4);
    208         break;
    209     case West:
    210         path.moveTo(rect.x() + lengthMiddle + 1, rect.y() + widthMiddle - 5);
    211         path.rLineTo(0, 9);
    212         path.rLineTo(-4, -4);
    213         break;
    214     }
    215     path.close();
    216 
    217     canvas->drawPath(path, paint);
    218 }
    219 
    220 } // namespace WebCore
    221 
    222