OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // This file implements a simple generic version of the WebKitThemeEngine, | |
6 // which is used to draw all the native controls on a web page. We use this | |
7 // file when running in layout test mode in order to remove any | |
8 // platform-specific rendering differences due to themes, colors, etc. | |
9 // | |
10 | |
11 #include "webkit/tools/test_shell/test_shell_webthemecontrol.h" | |
12 | |
13 #include "base/logging.h" | |
14 #include "skia/ext/platform_canvas.h" | |
15 #include "skia/ext/skia_utils_win.h" | |
16 #include "third_party/skia/include/core/SkPaint.h" | |
17 #include "third_party/skia/include/core/SkPath.h" | |
18 | |
19 namespace TestShellWebTheme { | |
20 | |
21 const SkColor kEdgeColor = SK_ColorBLACK; | |
22 const SkColor kReadOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6); | |
23 const SkColor kFgColor = SK_ColorBLACK; | |
24 | |
25 const SkColor kBgColors[] = { | |
26 SK_ColorBLACK, // Unknown | |
27 SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled | |
28 SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly | |
29 SkColorSetRGB(0x89, 0xc4, 0xff), // Normal | |
30 SkColorSetRGB(0x43, 0xf9, 0xff), // Hot | |
31 SkColorSetRGB(0x20, 0xf6, 0xcc), // Focused | |
32 SkColorSetRGB(0x00, 0xf3, 0xac), // Hover | |
33 SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed | |
34 SkColorSetRGB(0xcc, 0xcc, 0xcc) // Indeterminate | |
35 }; | |
36 | |
37 SkIRect Validate(const SkIRect& rect, Control::Type ctype) { | |
38 SkIRect retval = rect; | |
39 if (ctype == Control::kUncheckedBox_Type || | |
40 ctype == Control::kCheckedBox_Type || | |
41 ctype == Control::kUncheckedRadio_Type || | |
42 ctype == Control::kCheckedRadio_Type) { | |
43 // The maximum width and height is 13. Center the square in the passed | |
44 // rectangle. | |
45 const int kMaxControlSize = 13; | |
46 int control_size = std::min(rect.width(), rect.height()); | |
47 control_size = std::min(control_size, kMaxControlSize); | |
48 | |
49 retval.fLeft = rect.fLeft + (rect.width() / 2) - (control_size / 2); | |
50 retval.fRight = retval.fLeft + control_size - 1; | |
51 retval.fTop = rect.fTop + (rect.height() / 2) - (control_size / 2); | |
52 retval.fBottom = retval.fTop + control_size - 1; | |
53 } | |
54 return retval; | |
55 } | |
56 | |
57 Control::Control(SkCanvas* canvas, const SkIRect& irect, | |
58 Type ctype, State cstate) | |
59 : canvas_(canvas), | |
60 irect_(Validate(irect, ctype)), | |
61 type_(ctype), | |
62 state_(cstate), | |
63 left_(irect_.fLeft), | |
64 right_(irect_.fRight), | |
65 top_(irect_.fTop), | |
66 bottom_(irect_.fBottom), | |
67 height_(irect_.height()), | |
68 width_(irect_.width()), | |
69 edge_color_(kEdgeColor), | |
70 bg_color_(kBgColors[cstate]), | |
71 fg_color_(kFgColor) { | |
72 } | |
73 | |
74 Control::~Control() { | |
75 } | |
76 | |
77 void Control::box(const SkIRect& rect, SkColor fill_color) { | |
78 SkPaint paint; | |
79 | |
80 paint.setStyle(SkPaint::kFill_Style); | |
81 paint.setColor(fill_color); | |
82 canvas_->drawIRect(rect, paint); | |
83 | |
84 paint.setColor(edge_color_); | |
85 paint.setStyle(SkPaint::kStroke_Style); | |
86 canvas_->drawIRect(rect, paint); | |
87 } | |
88 | |
89 void Control::line(int x0, int y0, int x1, int y1, SkColor color) { | |
90 SkPaint paint; | |
91 paint.setColor(color); | |
92 canvas_->drawLine(SkIntToScalar(x0), SkIntToScalar(y0), | |
93 SkIntToScalar(x1), SkIntToScalar(y1), | |
94 paint); | |
95 } | |
96 | |
97 void Control::triangle(int x0, int y0, | |
98 int x1, int y1, | |
99 int x2, int y2, | |
100 SkColor color) { | |
101 SkPath path; | |
102 SkPaint paint; | |
103 | |
104 paint.setColor(color); | |
105 paint.setStyle(SkPaint::kFill_Style); | |
106 path.incReserve(4); | |
107 path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0)); | |
108 path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1)); | |
109 path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2)); | |
110 path.close(); | |
111 canvas_->drawPath(path, paint); | |
112 | |
113 paint.setColor(edge_color_); | |
114 paint.setStyle(SkPaint::kStroke_Style); | |
115 canvas_->drawPath(path, paint); | |
116 } | |
117 | |
118 void Control::roundRect(SkColor color) { | |
119 SkRect rect; | |
120 SkScalar radius = SkIntToScalar(5); | |
121 SkPaint paint; | |
122 | |
123 rect.set(irect_); | |
124 paint.setColor(color); | |
125 paint.setStyle(SkPaint::kFill_Style); | |
126 canvas_->drawRoundRect(rect, radius, radius, paint); | |
127 | |
128 paint.setColor(edge_color_); | |
129 paint.setStyle(SkPaint::kStroke_Style); | |
130 canvas_->drawRoundRect(rect, radius, radius, paint); | |
131 } | |
132 | |
133 void Control::oval(SkColor color) { | |
134 SkRect rect; | |
135 SkPaint paint; | |
136 | |
137 rect.set(irect_); | |
138 paint.setColor(color); | |
139 paint.setStyle(SkPaint::kFill_Style); | |
140 canvas_->drawOval(rect, paint); | |
141 | |
142 paint.setColor(edge_color_); | |
143 paint.setStyle(SkPaint::kStroke_Style); | |
144 canvas_->drawOval(rect, paint); | |
145 } | |
146 | |
147 void Control::circle(SkScalar radius, SkColor color) { | |
148 SkScalar cy = SkIntToScalar(top_ + height_ / 2); | |
149 SkScalar cx = SkIntToScalar(left_ + width_ / 2); | |
150 SkPaint paint; | |
151 | |
152 paint.setColor(color); | |
153 paint.setStyle(SkPaint::kFill_Style); | |
154 canvas_->drawCircle(cx, cy, radius, paint); | |
155 | |
156 paint.setColor(edge_color_); | |
157 paint.setStyle(SkPaint::kStroke_Style); | |
158 canvas_->drawCircle(cx, cy, radius, paint); | |
159 } | |
160 | |
161 void Control::nested_boxes(int indent_left, int indent_top, | |
162 int indent_right, int indent_bottom, | |
163 SkColor outer_color, SkColor inner_color) { | |
164 SkIRect lirect; | |
165 box(irect_, outer_color); | |
166 lirect.set(irect_.fLeft + indent_left, irect_.fTop + indent_top, | |
167 irect_.fRight - indent_right, irect_.fBottom - indent_bottom); | |
168 box(lirect, inner_color); | |
169 } | |
170 | |
171 | |
172 void Control::markState() { | |
173 // The horizontal lines in a read only control are spaced by this amount. | |
174 const int kReadOnlyLineOffset = 5; | |
175 | |
176 // The length of a triangle side for the corner marks. | |
177 const int kTriangleSize = 5; | |
178 | |
179 switch (state_) { | |
180 case kUnknown_State: // FALLTHROUGH | |
181 case kDisabled_State: // FALLTHROUGH | |
182 case kNormal_State: | |
183 // Don't visually mark these states (color is enough). | |
184 break; | |
185 case kReadOnly_State: | |
186 // Drawing lines across the control. | |
187 for (int i = top_ + kReadOnlyLineOffset; i < bottom_ ; | |
188 i += kReadOnlyLineOffset) { | |
189 line(left_ + 1, i, right_ - 1, i, kReadOnlyColor); | |
190 } | |
191 break; | |
192 case kHot_State: | |
193 // Draw a triangle in the upper left corner of the control. | |
194 triangle(left_, top_, | |
195 left_ + kTriangleSize, top_, | |
196 left_, top_ + kTriangleSize, edge_color_); | |
197 break; | |
198 case kHover_State: | |
199 // Draw a triangle in the upper right corner of the control. | |
200 triangle(right_, top_, | |
201 right_, top_ + kTriangleSize, | |
202 right_ - kTriangleSize, top_, edge_color_); | |
203 break; | |
204 case kFocused_State: | |
205 // Draw a triangle in the bottom right corner of the control. | |
206 triangle(right_, bottom_, | |
207 right_ - kTriangleSize, bottom_, | |
208 right_, bottom_ - kTriangleSize, edge_color_); | |
209 break; | |
210 case kPressed_State: | |
211 // Draw a triangle in the bottom left corner of the control. | |
212 triangle(left_, bottom_, | |
213 left_, bottom_ - kTriangleSize, | |
214 left_ + kTriangleSize, bottom_, edge_color_); | |
215 break; | |
216 default: | |
217 NOTREACHED(); | |
218 break; | |
219 } | |
220 } | |
221 | |
222 void Control::draw() { | |
223 int half_width = width_ / 2; | |
224 int half_height = height_ / 2; | |
225 int quarter_width = width_ / 4; | |
226 int quarter_height = height_ / 4; | |
227 | |
228 // Indent amounts for the check in a checkbox or radio button. | |
229 const int kCheckIndent = 3; | |
230 | |
231 // Indent amounts for short and long sides of the scrollbar notches. | |
232 const int kNotchLongOffset = 1; | |
233 const int kNotchShortOffset = 4; | |
234 const int kNoOffset = 0; | |
235 int short_offset; | |
236 int long_offset; | |
237 | |
238 // Indent amounts for the short and long sides of a scroll thumb box. | |
239 const int kThumbLongIndent = 0; | |
240 const int kThumbShortIndent = 2; | |
241 | |
242 // Indents for the crosshatch on a scroll grip. | |
243 const int kGripLongIndent = 3; | |
244 const int kGripShortIndent = 5; | |
245 | |
246 // Indents for the the slider track. | |
247 const int kSliderIndent = 2; | |
248 | |
249 skia::ScopedPlatformPaint scoped_platform_paint(canvas_); | |
250 switch (type_) { | |
251 case kUnknown_Type: | |
252 NOTREACHED(); | |
253 break; | |
254 case kTextField_Type: | |
255 // We render this by hand outside of this function. | |
256 NOTREACHED(); | |
257 break; | |
258 case kPushButton_Type: | |
259 // push buttons render as a rounded rectangle | |
260 roundRect(bg_color_); | |
261 break; | |
262 case kUncheckedBox_Type: | |
263 // Unchecked boxes are simply plain boxes. | |
264 box(irect_, bg_color_); | |
265 break; | |
266 case kCheckedBox_Type: | |
267 nested_boxes(kCheckIndent, kCheckIndent, kCheckIndent, kCheckIndent, | |
268 bg_color_, fg_color_); | |
269 break; | |
270 case kIndeterminateCheckBox_Type: | |
271 // Indeterminate checkbox is a box containing '-'. | |
272 nested_boxes(kCheckIndent, height_ / 2, kCheckIndent, height_ / 2, | |
273 bg_color_, fg_color_); | |
274 break; | |
275 case kUncheckedRadio_Type: | |
276 circle(SkIntToScalar(half_height), bg_color_); | |
277 break; | |
278 case kCheckedRadio_Type: | |
279 circle(SkIntToScalar(half_height), bg_color_); | |
280 circle(SkIntToScalar(half_height - kCheckIndent), fg_color_); | |
281 break; | |
282 case kHorizontalScrollTrackBack_Type: | |
283 // Draw a box with a notch at the left. | |
284 long_offset = half_height - kNotchLongOffset; | |
285 short_offset = width_ - kNotchShortOffset; | |
286 nested_boxes(kNoOffset, long_offset, short_offset, long_offset, | |
287 bg_color_, edge_color_); | |
288 break; | |
289 case kHorizontalScrollTrackForward_Type: | |
290 // Draw a box with a notch at the right. | |
291 long_offset = half_height - kNotchLongOffset; | |
292 short_offset = width_ - kNotchShortOffset; | |
293 nested_boxes(short_offset, long_offset, kNoOffset, long_offset, | |
294 bg_color_, fg_color_); | |
295 break; | |
296 case kVerticalScrollTrackBack_Type: | |
297 // Draw a box with a notch at the top. | |
298 long_offset = half_width - kNotchLongOffset; | |
299 short_offset = height_ - kNotchShortOffset; | |
300 nested_boxes(long_offset, kNoOffset, long_offset, short_offset, | |
301 bg_color_, fg_color_); | |
302 break; | |
303 case kVerticalScrollTrackForward_Type: | |
304 // Draw a box with a notch at the bottom. | |
305 long_offset = half_width - kNotchLongOffset; | |
306 short_offset = height_ - kNotchShortOffset; | |
307 nested_boxes(long_offset, short_offset, long_offset, kNoOffset, | |
308 bg_color_, fg_color_); | |
309 break; | |
310 case kHorizontalScrollThumb_Type: | |
311 // Draw a narrower box on top of the outside box. | |
312 nested_boxes(kThumbLongIndent, kThumbShortIndent, kThumbLongIndent, | |
313 kThumbShortIndent, bg_color_, bg_color_); | |
314 break; | |
315 case kVerticalScrollThumb_Type: | |
316 // Draw a shorter box on top of the outside box. | |
317 nested_boxes(kThumbShortIndent, kThumbLongIndent, kThumbShortIndent, | |
318 kThumbLongIndent, bg_color_, bg_color_); | |
319 break; | |
320 case kHorizontalSliderThumb_Type: | |
321 // Slider thumbs are ovals. | |
322 oval(bg_color_); | |
323 break; | |
324 case kHorizontalScrollGrip_Type: | |
325 // Draw a horizontal crosshatch for the grip. | |
326 long_offset = half_width - kGripLongIndent; | |
327 line(left_ + kGripLongIndent, top_ + half_height, | |
328 right_ - kGripLongIndent, top_ + half_height, fg_color_); | |
329 line(left_ + long_offset, top_ + kGripShortIndent, | |
330 left_ + long_offset, bottom_ - kGripShortIndent, fg_color_); | |
331 line(right_ - long_offset, top_ + kGripShortIndent, | |
332 right_ - long_offset, bottom_ - kGripShortIndent, fg_color_); | |
333 break; | |
334 case kVerticalScrollGrip_Type: | |
335 // Draw a vertical crosshatch for the grip. | |
336 long_offset = half_height - kGripLongIndent; | |
337 line(left_ + half_width, top_ + kGripLongIndent, | |
338 left_ + half_width, bottom_ - kGripLongIndent, fg_color_); | |
339 line(left_ + kGripShortIndent, top_ + long_offset, | |
340 right_ - kGripShortIndent, top_ + long_offset, fg_color_); | |
341 line(left_ + kGripShortIndent, bottom_ - long_offset, | |
342 right_ - kGripShortIndent, bottom_ - long_offset, fg_color_); | |
343 break; | |
344 case kLeftArrow_Type: | |
345 // Draw a left arrow inside a box. | |
346 box(irect_, bg_color_); | |
347 triangle(right_ - quarter_width, top_ + quarter_height, | |
348 right_ - quarter_width, bottom_ - quarter_height, | |
349 left_ + quarter_width, top_ + half_height, fg_color_); | |
350 break; | |
351 case kRightArrow_Type: | |
352 // Draw a left arrow inside a box. | |
353 box(irect_, bg_color_); | |
354 triangle(left_ + quarter_width, top_ + quarter_height, | |
355 right_ - quarter_width, top_ + half_height, | |
356 left_ + quarter_width, bottom_ - quarter_height, fg_color_); | |
357 break; | |
358 case kUpArrow_Type: | |
359 // Draw an up arrow inside a box. | |
360 box(irect_, bg_color_); | |
361 triangle(left_ + quarter_width, bottom_ - quarter_height, | |
362 left_ + half_width, top_ + quarter_height, | |
363 right_ - quarter_width, bottom_ - quarter_height, fg_color_); | |
364 break; | |
365 case kDownArrow_Type: | |
366 // Draw a down arrow inside a box. | |
367 box(irect_, bg_color_); | |
368 triangle(left_ + quarter_width, top_ + quarter_height, | |
369 right_ - quarter_width, top_ + quarter_height, | |
370 left_ + half_width, bottom_ - quarter_height, fg_color_); | |
371 break; | |
372 case kHorizontalSliderTrack_Type: | |
373 // Draw a narrow rect for the track plus box hatches on the ends. | |
374 SkIRect lirect; | |
375 lirect = irect_; | |
376 lirect.inset(kNoOffset, half_height - kSliderIndent); | |
377 box(lirect, bg_color_); | |
378 line(left_, top_, left_, bottom_, edge_color_); | |
379 line(right_, top_, right_, bottom_, edge_color_); | |
380 break; | |
381 case kDropDownButton_Type: | |
382 // Draw a box with a big down arrow on top. | |
383 box(irect_, bg_color_); | |
384 triangle(left_ + quarter_width, top_, | |
385 right_ - quarter_width, top_, | |
386 left_ + half_width, bottom_, fg_color_); | |
387 break; | |
388 default: | |
389 NOTREACHED(); | |
390 break; | |
391 } | |
392 | |
393 markState(); | |
394 } | |
395 | |
396 // Because rendering a text field is dependent on input | |
397 // parameters the other controls don't have, we render it directly | |
398 // rather than trying to overcomplicate draw() further. | |
399 void Control::drawTextField(bool draw_edges, bool fill_content_area, | |
400 SkColor color) { | |
401 SkPaint paint; | |
402 | |
403 skia::ScopedPlatformPaint scoped_platform_paint(canvas_); | |
404 if (fill_content_area) { | |
405 paint.setColor(color); | |
406 paint.setStyle(SkPaint::kFill_Style); | |
407 canvas_->drawIRect(irect_, paint); | |
408 } | |
409 if (draw_edges) { | |
410 paint.setColor(edge_color_); | |
411 paint.setStyle(SkPaint::kStroke_Style); | |
412 canvas_->drawIRect(irect_, paint); | |
413 } | |
414 | |
415 markState(); | |
416 } | |
417 | |
418 void | |
419 Control::drawProgressBar(const SkIRect& fill_rect) { | |
420 SkPaint paint; | |
421 | |
422 skia::ScopedPlatformPaint scoped_platform_paint(canvas_); | |
423 paint.setColor(bg_color_); | |
424 paint.setStyle(SkPaint::kFill_Style); | |
425 canvas_->drawIRect(irect_, paint); | |
426 | |
427 // Emulate clipping | |
428 SkIRect tofill; | |
429 tofill.intersect(irect_, fill_rect); | |
430 paint.setColor(fg_color_); | |
431 paint.setStyle(SkPaint::kFill_Style); | |
432 canvas_->drawIRect(tofill, paint); | |
433 | |
434 markState(); | |
435 } | |
436 | |
437 } // namespace TestShellWebTheme | |
438 | |
OLD | NEW |