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