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