2009-12-07 Evan Martin <evan@chromium.org>
[WebKit-https.git] / WebCore / platform / chromium / ScrollbarThemeChromiumLinux.cpp
index 64f58c4e6e284b2e95db03ea0f7c1a4966c21cf2..3a1a6521eb9521806ae441a89fe3daf2824cd6af 100644 (file)
@@ -33,6 +33,8 @@
 
 #include "PlatformContextSkia.h"
 #include "PlatformMouseEvent.h"
+#include "RenderTheme.h"
+#include "RenderThemeChromiumLinux.h"
 #include "Scrollbar.h"
 #include "TransformationMatrix.h"
 
@@ -73,6 +75,60 @@ static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint)
     drawVertLine(canvas, rect.x(), rect.y(), bottom, paint);
 }
 
+static SkScalar clamp(SkScalar value, SkScalar min, SkScalar max)
+{
+    return std::min(std::max(value, min), max);
+}
+
+static SkColor saturateAndBrighten(SkScalar* hsv,
+                                   SkScalar saturateAmount,
+                                   SkScalar brightenAmount)
+{
+    SkScalar color[3];
+    color[0] = hsv[0];
+    color[1] = clamp(hsv[1] + saturateAmount, 0.0, 1.0);
+    color[2] = clamp(hsv[2] + brightenAmount, 0.0, 1.0);
+    return SkHSVToColor(color);
+}
+
+static SkColor outlineColor(SkScalar* hsv1, SkScalar* hsv2)
+{
+    // GTK Theme engines have way too much control over the layout of
+    // the scrollbar. We might be able to more closely approximate its
+    // look-and-feel, if we sent whole images instead of just colors
+    // from the browser to the renderer. But even then, some themes
+    // would just break.
+    //
+    // So, instead, we don't even try to 100% replicate the look of
+    // the native scrollbar. We render our own version, but we make
+    // sure to pick colors that blend in nicely with the system GTK
+    // theme. In most cases, we can just sample a couple of pixels
+    // from the system scrollbar and use those colors to draw our
+    // scrollbar.
+    //
+    // This works fine for the track color and the overall thumb
+    // color. But it fails spectacularly for the outline color used
+    // around the thumb piece.  Not all themes have a clearly defined
+    // outline. For some of them it is partially transparent, and for
+    // others the thickness is very unpredictable.
+    //
+    // So, instead of trying to approximate the system theme, we
+    // instead try to compute a reasonable looking choice based on the
+    // known color of the track and the thumb piece. This is difficult
+    // when trying to deal both with high- and low-contrast themes,
+    // and both with positive and inverted themes.
+    //
+    // The following code has been tested to look OK with all of the
+    // default GTK themes.
+    SkScalar minDiff = clamp((hsv1[1] + hsv2[1]) * 1.2, 0.2, 0.5);
+    SkScalar diff = clamp(fabs(hsv1[2] - hsv2[2]) / 2, minDiff, 0.5);
+
+    if (hsv1[2] + hsv2[2] > 1.0)
+        diff = -diff;
+
+    return saturateAndBrighten(hsv2, -0.2, diff);
+}
+
 IntRect ScrollbarThemeChromium::trackRect(Scrollbar* scrollbar, bool)
 {
     IntSize bs = buttonSize(scrollbar);
@@ -89,10 +145,16 @@ void ScrollbarThemeChromiumLinux::paintTrackPiece(GraphicsContext* gc, Scrollbar
     SkIRect skrect;
 
     skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
-    paint.setARGB(0xff, 0xe3, 0xdd, 0xd8);
+    SkScalar track_hsv[3];
+    SkColorToHSV(RenderThemeChromiumLinux::trackColor(), track_hsv);
+    paint.setColor(saturateAndBrighten(track_hsv, 0, 0));
     canvas->drawIRect(skrect, paint);
 
-    paint.setARGB(0xff, 0xc5, 0xba, 0xb0);
+    SkScalar thumb_hsv[3];
+    SkColorToHSV(RenderThemeChromiumLinux::thumbInactiveColor(),
+                 thumb_hsv);
+
+    paint.setColor(outlineColor(track_hsv, thumb_hsv));
     drawBox(canvas, rect, paint);
 }
 
@@ -109,11 +171,14 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr
     const bool vertical = scrollbar->orientation() == VerticalScrollbar;
     SkCanvas* const canvas = gc->platformContext()->canvas();
 
+    SkScalar thumb[3];
+    SkColorToHSV(hovered
+                 ? RenderThemeChromiumLinux::thumbActiveColor()
+                 : RenderThemeChromiumLinux::thumbInactiveColor(),
+                 thumb);
+
     SkPaint paint;
-    if (hovered)
-        paint.setARGB(0xff, 0xff, 0xff, 0xff);
-    else
-        paint.setARGB(0xff, 0xf4, 0xf2, 0xef);
+    paint.setColor(saturateAndBrighten(thumb, 0, 0.02));
 
     SkIRect skrect;
     if (vertical)
@@ -123,10 +188,7 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr
 
     canvas->drawIRect(skrect, paint);
 
-    if (hovered)
-        paint.setARGB(0xff, 0xf4, 0xf2, 0xef);
-    else
-        paint.setARGB(0xff, 0xea, 0xe5, 0xe0);
+    paint.setColor(saturateAndBrighten(thumb, 0, -0.02));
 
     if (vertical)
         skrect.set(midx + 1, rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
@@ -135,11 +197,12 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr
 
     canvas->drawIRect(skrect, paint);
 
-    paint.setARGB(0xff, 0x9d, 0x96, 0x8e);
+    SkScalar track[3];
+    SkColorToHSV(RenderThemeChromiumLinux::trackColor(), track);
+    paint.setColor(outlineColor(track, thumb));
     drawBox(canvas, rect, paint);
 
     if (rect.height() > 10 && rect.width() > 10) {
-        paint.setARGB(0xff, 0x9d, 0x96, 0x8e);
         const int grippyHalfWidth = 2;
         const int interGrippyOffset = 3;
         if (vertical) {