• 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 // This file implements a simple generic version of the WebThemeEngine,
32 // which is used to draw all the native controls on a web page. We use this
33 // file when running in layout test mode in order to remove any
34 // platform-specific rendering differences due to themes, colors, etc.
35 //
36 
37 #include "config.h"
38 #include "WebThemeControlDRTWin.h"
39 
40 #include "skia/ext/platform_canvas.h"
41 #include "skia/ext/skia_utils_win.h"
42 #include "third_party/skia/include/core/SkPaint.h"
43 #include "third_party/skia/include/core/SkPath.h"
44 #include "third_party/skia/include/core/SkRect.h"
45 
46 #include <wtf/Assertions.h>
47 
48 using namespace std;
49 
50 static const SkColor edgeColor     = SK_ColorBLACK;
51 static const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6);
52 static const SkColor fgColor       = SK_ColorBLACK;
53 static const SkColor bgColors[]    = {
54     SK_ColorBLACK,                   // Unknown
55     SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled
56     SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly
57     SkColorSetRGB(0x89, 0xc4, 0xff), // Normal
58     SkColorSetRGB(0x43, 0xf9, 0xff), // Hot
59     SkColorSetRGB(0x20, 0xf6, 0xcc), // Focused
60     SkColorSetRGB(0x00, 0xf3, 0xac), // Hover
61     SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed
62     SkColorSetRGB(0xcc, 0xcc, 0xcc)  // Indeterminate
63 };
64 
validate(const SkIRect & rect,WebThemeControlDRTWin::Type ctype)65 static SkIRect validate(const SkIRect& rect, WebThemeControlDRTWin::Type ctype)
66 {
67     switch (ctype) {
68     case WebThemeControlDRTWin::UncheckedBoxType:
69     case WebThemeControlDRTWin::CheckedBoxType:
70     case WebThemeControlDRTWin::UncheckedRadioType:
71     case WebThemeControlDRTWin::CheckedRadioType: {
72         SkIRect retval = rect;
73 
74         // The maximum width and height is 13.
75         // Center the square in the passed rectangle.
76         const int maxControlSize = 13;
77         int controlSize = min(rect.width(), rect.height());
78         controlSize = min(controlSize, maxControlSize);
79 
80         retval.fLeft   = rect.fLeft + (rect.width() / 2) - (controlSize / 2);
81         retval.fRight  = retval.fLeft + controlSize - 1;
82         retval.fTop    = rect.fTop + (rect.height() / 2) - (controlSize / 2);
83         retval.fBottom = retval.fTop + controlSize - 1;
84 
85         return retval;
86     }
87 
88     default:
89         return rect;
90     }
91 }
92 
93 // WebThemeControlDRTWin
94 
WebThemeControlDRTWin(SkCanvas * canvas,const SkIRect & irect,Type ctype,State cstate)95 WebThemeControlDRTWin::WebThemeControlDRTWin(SkCanvas* canvas,
96                                              const SkIRect& irect,
97                                              Type ctype,
98                                              State cstate)
99     : m_canvas(canvas)
100     , m_irect(validate(irect, ctype))
101     , m_type(ctype)
102     , m_state(cstate)
103     , m_left(m_irect.fLeft)
104     , m_right(m_irect.fRight)
105     , m_top(m_irect.fTop)
106     , m_bottom(m_irect.fBottom)
107     , m_height(m_irect.height())
108     , m_width(m_irect.width())
109     , m_edgeColor(edgeColor)
110     , m_bgColor(bgColors[cstate])
111     , m_fgColor(fgColor)
112 {
113 }
114 
~WebThemeControlDRTWin()115 WebThemeControlDRTWin::~WebThemeControlDRTWin()
116 {
117 }
118 
box(const SkIRect & rect,SkColor fillColor)119 void WebThemeControlDRTWin::box(const SkIRect& rect, SkColor fillColor)
120 {
121     SkPaint paint;
122 
123     paint.setStyle(SkPaint::kFill_Style);
124     paint.setColor(fillColor);
125     m_canvas->drawIRect(rect, paint);
126 
127     paint.setColor(m_edgeColor);
128     paint.setStyle(SkPaint::kStroke_Style);
129     m_canvas->drawIRect(rect, paint);
130 }
131 
line(int x0,int y0,int x1,int y1,SkColor color)132 void WebThemeControlDRTWin::line(int x0, int y0, int x1, int y1, SkColor color)
133 {
134     SkPaint paint;
135     paint.setColor(color);
136     m_canvas->drawLine(SkIntToScalar(x0), SkIntToScalar(y0),
137                        SkIntToScalar(x1), SkIntToScalar(y1),
138                        paint);
139 }
140 
triangle(int x0,int y0,int x1,int y1,int x2,int y2,SkColor color)141 void WebThemeControlDRTWin::triangle(int x0, int y0,
142                                      int x1, int y1,
143                                      int x2, int y2,
144                                      SkColor color)
145 {
146     SkPath path;
147     SkPaint paint;
148 
149     paint.setColor(color);
150     paint.setStyle(SkPaint::kFill_Style);
151     path.incReserve(4);
152     path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0));
153     path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1));
154     path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2));
155     path.close();
156     m_canvas->drawPath(path, paint);
157 
158     paint.setColor(m_edgeColor);
159     paint.setStyle(SkPaint::kStroke_Style);
160     m_canvas->drawPath(path, paint);
161 }
162 
roundRect(SkColor color)163 void WebThemeControlDRTWin::roundRect(SkColor color)
164 {
165     SkRect rect;
166     SkScalar radius = SkIntToScalar(5);
167     SkPaint paint;
168 
169     rect.set(m_irect);
170     paint.setColor(color);
171     paint.setStyle(SkPaint::kFill_Style);
172     m_canvas->drawRoundRect(rect, radius, radius, paint);
173 
174     paint.setColor(m_edgeColor);
175     paint.setStyle(SkPaint::kStroke_Style);
176     m_canvas->drawRoundRect(rect, radius, radius, paint);
177 }
178 
oval(SkColor color)179 void WebThemeControlDRTWin::oval(SkColor color)
180 {
181     SkRect rect;
182     SkPaint paint;
183 
184     rect.set(m_irect);
185     paint.setColor(color);
186     paint.setStyle(SkPaint::kFill_Style);
187     m_canvas->drawOval(rect, paint);
188 
189     paint.setColor(m_edgeColor);
190     paint.setStyle(SkPaint::kStroke_Style);
191     m_canvas->drawOval(rect, paint);
192 }
193 
circle(SkScalar radius,SkColor color)194 void WebThemeControlDRTWin::circle(SkScalar radius, SkColor color)
195 {
196     SkScalar cy = SkIntToScalar(m_top  + m_height / 2);
197     SkScalar cx = SkIntToScalar(m_left + m_width / 2);
198     SkPaint paint;
199 
200     paint.setColor(color);
201     paint.setStyle(SkPaint::kFill_Style);
202     m_canvas->drawCircle(cx, cy, radius, paint);
203 
204     paint.setColor(m_edgeColor);
205     paint.setStyle(SkPaint::kStroke_Style);
206     m_canvas->drawCircle(cx, cy, radius, paint);
207 }
208 
nestedBoxes(int indentLeft,int indentTop,int indentRight,int indentBottom,SkColor outerColor,SkColor innerColor)209 void WebThemeControlDRTWin::nestedBoxes(int indentLeft,
210                                         int indentTop,
211                                         int indentRight,
212                                         int indentBottom,
213                                         SkColor outerColor,
214                                         SkColor innerColor)
215 {
216     SkIRect lirect;
217     box(m_irect, outerColor);
218     lirect.set(m_irect.fLeft + indentLeft,
219                m_irect.fTop + indentTop,
220                m_irect.fRight - indentRight,
221                m_irect.fBottom - indentBottom);
222     box(lirect, innerColor);
223 }
224 
markState()225 void WebThemeControlDRTWin::markState()
226 {
227     // The horizontal lines in a read only control are spaced by this amount.
228     const int readOnlyLineOffset = 5;
229 
230     // The length of a triangle side for the corner marks.
231     const int triangleSize = 5;
232 
233     switch (m_state) {
234     case UnknownState:
235     case DisabledState:
236     case NormalState:
237         // Don't visually mark these states (color is enough).
238         break;
239     case ReadOnlyState:
240         // Drawing lines across the control.
241         for (int i = m_top + readOnlyLineOffset; i < m_bottom; i += readOnlyLineOffset)
242             line(m_left + 1, i, m_right - 1, i, readOnlyColor);
243         break;
244 
245     case HotState:
246         // Draw a triangle in the upper left corner of the control.
247         triangle(m_left,                 m_top,
248                  m_left + triangleSize,  m_top,
249                  m_left,                 m_top + triangleSize,    m_edgeColor);
250         break;
251 
252     case HoverState:
253         // Draw a triangle in the upper right corner of the control.
254         triangle(m_right,                m_top,
255                  m_right,                m_top + triangleSize,
256                  m_right - triangleSize, m_top,                   m_edgeColor);
257         break;
258 
259     case FocusedState:
260         // Draw a triangle in the bottom right corner of the control.
261         triangle(m_right,                m_bottom,
262                  m_right - triangleSize, m_bottom,
263                  m_right,                m_bottom - triangleSize, m_edgeColor);
264         break;
265 
266     case PressedState:
267         // Draw a triangle in the bottom left corner of the control.
268         triangle(m_left,                 m_bottom,
269                  m_left,                 m_bottom - triangleSize,
270                  m_left + triangleSize,  m_bottom,                m_edgeColor);
271         break;
272 
273     default:
274         ASSERT_NOT_REACHED();
275         CRASH();
276         break;
277     }
278 }
279 
draw()280 void WebThemeControlDRTWin::draw()
281 {
282     int halfWidth = m_width / 2;
283     int halfHeight = m_height / 2;
284     int quarterWidth = m_width / 4;
285     int quarterHeight = m_height / 4;
286 
287     // Indent amounts for the check in a checkbox or radio button.
288     const int checkIndent = 3;
289 
290     // Indent amounts for short and long sides of the scrollbar notches.
291     const int notchLongOffset = 1;
292     const int notchShortOffset = 4;
293     const int noOffset = 0;
294 
295     // Indent amounts for the short and long sides of a scroll thumb box.
296     const int thumbLongIndent = 0;
297     const int thumbShortIndent = 2;
298 
299     // Indents for the crosshatch on a scroll grip.
300     const int gripLongIndent = 3;
301     const int gripShortIndent = 5;
302 
303     // Indents for the the slider track.
304     const int sliderIndent = 2;
305 
306     skia::BeginPlatformPaint(m_canvas);
307 
308     switch (m_type) {
309     case UnknownType:
310         ASSERT_NOT_REACHED();
311         CRASH();
312         break;
313 
314     case TextFieldType:
315         // We render this by hand outside of this function.
316         ASSERT_NOT_REACHED();
317         CRASH();
318         break;
319 
320     case PushButtonType:
321         // push buttons render as a rounded rectangle
322         roundRect(m_bgColor);
323         break;
324 
325     case UncheckedBoxType:
326         // Unchecked boxes are simply plain boxes.
327         box(m_irect, m_bgColor);
328         break;
329 
330     case CheckedBoxType:
331         nestedBoxes(checkIndent, checkIndent, checkIndent, checkIndent, m_bgColor, m_fgColor);
332         break;
333 
334     case IndeterminateCheckboxType:
335         // Indeterminate checkbox is a box containing '-'.
336         nestedBoxes(checkIndent, halfHeight, checkIndent, halfHeight, m_bgColor, m_fgColor);
337         break;
338 
339     case UncheckedRadioType:
340         circle(SkIntToScalar(halfHeight), m_bgColor);
341         break;
342 
343     case CheckedRadioType:
344         circle(SkIntToScalar(halfHeight), m_bgColor);
345         circle(SkIntToScalar(halfHeight - checkIndent), m_fgColor);
346         break;
347 
348     case HorizontalScrollTrackBackType: {
349         // Draw a box with a notch at the left.
350         int longOffset = halfHeight - notchLongOffset;
351         int shortOffset = m_width - notchShortOffset;
352         nestedBoxes(noOffset, longOffset, shortOffset, longOffset, m_bgColor, m_edgeColor);
353         break;
354     }
355 
356     case HorizontalScrollTrackForwardType: {
357         // Draw a box with a notch at the right.
358         int longOffset  = halfHeight - notchLongOffset;
359         int shortOffset = m_width - notchShortOffset;
360         nestedBoxes(shortOffset, longOffset, noOffset, longOffset, m_bgColor, m_fgColor);
361         break;
362     }
363 
364     case VerticalScrollTrackBackType: {
365         // Draw a box with a notch at the top.
366         int longOffset  = halfWidth - notchLongOffset;
367         int shortOffset = m_height - notchShortOffset;
368         nestedBoxes(longOffset, noOffset, longOffset, shortOffset, m_bgColor, m_fgColor);
369         break;
370     }
371 
372     case VerticalScrollTrackForwardType: {
373         // Draw a box with a notch at the bottom.
374         int longOffset  = halfWidth - notchLongOffset;
375         int shortOffset = m_height - notchShortOffset;
376         nestedBoxes(longOffset, shortOffset, longOffset, noOffset, m_bgColor, m_fgColor);
377         break;
378     }
379 
380     case HorizontalScrollThumbType:
381         // Draw a narrower box on top of the outside box.
382         nestedBoxes(thumbLongIndent, thumbShortIndent, thumbLongIndent, thumbShortIndent, m_bgColor, m_bgColor);
383         break;
384 
385     case VerticalScrollThumbType:
386         // Draw a shorter box on top of the outside box.
387         nestedBoxes(thumbShortIndent, thumbLongIndent, thumbShortIndent, thumbLongIndent, m_bgColor, m_bgColor);
388         break;
389 
390     case HorizontalSliderThumbType:
391         // Slider thumbs are ovals.
392         oval(m_bgColor);
393         break;
394 
395     case HorizontalScrollGripType: {
396         // Draw a horizontal crosshatch for the grip.
397         int longOffset = halfWidth - gripLongIndent;
398         line(m_left  + gripLongIndent, m_top    + halfHeight,
399              m_right - gripLongIndent, m_top    + halfHeight,      m_fgColor);
400         line(m_left  + longOffset,     m_top    + gripShortIndent,
401              m_left  + longOffset,     m_bottom - gripShortIndent, m_fgColor);
402         line(m_right - longOffset,     m_top    + gripShortIndent,
403              m_right - longOffset,     m_bottom - gripShortIndent, m_fgColor);
404         break;
405     }
406 
407     case VerticalScrollGripType: {
408         // Draw a vertical crosshatch for the grip.
409         int longOffset = halfHeight - gripLongIndent;
410         line(m_left  + halfWidth,       m_top    + gripLongIndent,
411              m_left  + halfWidth,       m_bottom - gripLongIndent, m_fgColor);
412         line(m_left  + gripShortIndent, m_top    + longOffset,
413              m_right - gripShortIndent, m_top    + longOffset,     m_fgColor);
414         line(m_left  + gripShortIndent, m_bottom - longOffset,
415              m_right - gripShortIndent, m_bottom - longOffset,     m_fgColor);
416         break;
417     }
418 
419     case LeftArrowType:
420         // Draw a left arrow inside a box.
421         box(m_irect, m_bgColor);
422         triangle(m_right - quarterWidth, m_top    + quarterHeight,
423                  m_right - quarterWidth, m_bottom - quarterHeight,
424                  m_left  + quarterWidth, m_top    + halfHeight,    m_fgColor);
425         break;
426 
427     case RightArrowType:
428         // Draw a left arrow inside a box.
429         box(m_irect, m_bgColor);
430         triangle(m_left  + quarterWidth, m_top    + quarterHeight,
431                  m_right - quarterWidth, m_top    + halfHeight,
432                  m_left  + quarterWidth, m_bottom - quarterHeight, m_fgColor);
433         break;
434 
435     case UpArrowType:
436         // Draw an up arrow inside a box.
437         box(m_irect, m_bgColor);
438         triangle(m_left  + quarterWidth, m_bottom - quarterHeight,
439                  m_left  + halfWidth,    m_top    + quarterHeight,
440                  m_right - quarterWidth, m_bottom - quarterHeight, m_fgColor);
441         break;
442 
443     case DownArrowType:
444         // Draw a down arrow inside a box.
445         box(m_irect, m_bgColor);
446         triangle(m_left  + quarterWidth, m_top    + quarterHeight,
447                  m_right - quarterWidth, m_top    + quarterHeight,
448                  m_left  + halfWidth,    m_bottom - quarterHeight, m_fgColor);
449         break;
450 
451     case HorizontalSliderTrackType: {
452         // Draw a narrow rect for the track plus box hatches on the ends.
453         SkIRect lirect;
454         lirect = m_irect;
455         lirect.inset(noOffset, halfHeight - sliderIndent);
456         box(lirect, m_bgColor);
457         line(m_left,  m_top, m_left,  m_bottom, m_edgeColor);
458         line(m_right, m_top, m_right, m_bottom, m_edgeColor);
459         break;
460     }
461 
462     case DropDownButtonType:
463         // Draw a box with a big down arrow on top.
464         box(m_irect, m_bgColor);
465         triangle(m_left  + quarterWidth, m_top,
466                  m_right - quarterWidth, m_top,
467                  m_left  + halfWidth,    m_bottom, m_fgColor);
468         break;
469 
470     default:
471         ASSERT_NOT_REACHED();
472         CRASH();
473         break;
474     }
475 
476     markState();
477     skia::EndPlatformPaint(m_canvas);
478 }
479 
480 // Because rendering a text field is dependent on input
481 // parameters the other controls don't have, we render it directly
482 // rather than trying to overcomplicate draw() further.
drawTextField(bool drawEdges,bool fillContentArea,SkColor color)483 void WebThemeControlDRTWin::drawTextField(bool drawEdges, bool fillContentArea, SkColor color)
484 {
485     SkPaint paint;
486 
487     skia::BeginPlatformPaint(m_canvas);
488     if (fillContentArea) {
489         paint.setColor(color);
490         paint.setStyle(SkPaint::kFill_Style);
491         m_canvas->drawIRect(m_irect, paint);
492     }
493     if (drawEdges) {
494         paint.setColor(m_edgeColor);
495         paint.setStyle(SkPaint::kStroke_Style);
496         m_canvas->drawIRect(m_irect, paint);
497     }
498 
499     markState();
500     skia::EndPlatformPaint(m_canvas);
501 }
502 
drawProgressBar(const SkIRect & fillRect)503 void WebThemeControlDRTWin::drawProgressBar(const SkIRect& fillRect)
504 {
505     SkPaint paint;
506 
507     skia::BeginPlatformPaint(m_canvas);
508     paint.setColor(m_bgColor);
509     paint.setStyle(SkPaint::kFill_Style);
510     m_canvas->drawIRect(m_irect, paint);
511 
512     // Emulate clipping
513     SkIRect tofill;
514     tofill.intersect(m_irect, fillRect);
515     paint.setColor(m_fgColor);
516     paint.setStyle(SkPaint::kFill_Style);
517     m_canvas->drawIRect(tofill, paint);
518 
519     markState();
520     skia::EndPlatformPaint(m_canvas);
521 }
522 
523