• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setScrollbarColors(SkColor inactiveColor,SkColor activeColor,SkColor trackColor)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 
clamp(SkScalar value,SkScalar min,SkScalar max)48 static SkScalar clamp(SkScalar value, SkScalar min, SkScalar max)
49 {
50     return std::min(std::max(value, min), max);
51 }
52 
saturateAndBrighten(const SkScalar hsv[3],SkScalar saturateAmount,SkScalar brightenAmount)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 
outlineColor(const SkScalar hsv1[3],const SkScalar hsv2[3])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 
paintArrowButton(GraphicsContext * gc,const IntRect & rect,ArrowDirection direction,ControlStates states)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