Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(601)

Side by Side Diff: content/shell/renderer/test_runner/WebTestThemeEngineMock.cpp

Issue 110533009: Import TestRunner library into chromium. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updates Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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 // FIXME: This code is largely cloned from WebTestThemeEngineWin.cpp
6 // and WebTestThemeControlWin.cpp. We should delete that code once the
7 // cutover to Aura is final.
8
9 #include "content/shell/renderer/test_runner/WebTestThemeEngineMock.h"
10
11 #include "skia/ext/platform_canvas.h"
12 #include "third_party/WebKit/public/platform/WebRect.h"
13 #include "third_party/WebKit/public/platform/WebSize.h"
14 #include "third_party/skia/include/core/SkRect.h"
15
16 using blink::WebCanvas;
17 using blink::WebColor;
18 using blink::WebRect;
19 using blink::WebThemeEngine;
20
21 namespace WebTestRunner {
22
23 static const SkColor edgeColor = SK_ColorBLACK;
24 static const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6);
25 static const SkColor bgColors[] = {
26 SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled
27 SkColorSetRGB(0x43, 0xf9, 0xff), // Hover (Win's "Hot")
28 SkColorSetRGB(0x89, 0xc4, 0xff), // Normal
29 SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed
30 SkColorSetRGB(0x00, 0xf3, 0xac), // Focused
31 SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly
32 };
33
34
35 blink::WebSize WebTestThemeEngineMock::getSize(WebThemeEngine::Part part)
36 {
37 // FIXME: We use this constant to indicate we are being asked for the size o f
38 // a part that we don't expect to be asked about. We return a garbage value
39 // rather than just asserting because this code doesn't have access to eithe r
40 // WTF or base to raise an assertion or do any logging :(.
41 const blink::WebSize invalidPartSize = blink::WebSize(100, 100);
42
43 switch (part) {
44 case WebThemeEngine::PartScrollbarLeftArrow:
45 return blink::WebSize(17, 15);
46 case WebThemeEngine::PartScrollbarRightArrow:
47 return invalidPartSize;
48 case WebThemeEngine::PartScrollbarUpArrow:
49 return blink::WebSize(15, 17);
50 case WebThemeEngine::PartScrollbarDownArrow:
51 return invalidPartSize;
52 case WebThemeEngine::PartScrollbarHorizontalThumb:
53 return blink::WebSize(15, 15);
54 case WebThemeEngine::PartScrollbarVerticalThumb:
55 return blink::WebSize(15, 15);
56 case WebThemeEngine::PartScrollbarHorizontalTrack:
57 return blink::WebSize(0, 15);
58 case WebThemeEngine::PartScrollbarVerticalTrack:
59 return blink::WebSize(15, 0);
60 case WebThemeEngine::PartCheckbox:
61 case WebThemeEngine::PartRadio:
62 return blink::WebSize(13, 13);
63 case WebThemeEngine::PartSliderThumb:
64 return blink::WebSize(11, 21);
65 case WebThemeEngine::PartInnerSpinButton:
66 return blink::WebSize(15, 8);
67 default:
68 return invalidPartSize;
69 }
70 }
71
72 static SkIRect webRectToSkIRect(const WebRect& webRect)
73 {
74 SkIRect irect;
75 irect.set(webRect.x, webRect.y,
76 webRect.x + webRect.width - 1, webRect.y + webRect.height - 1);
77 return irect;
78 }
79
80 static SkIRect validate(const SkIRect& rect, WebThemeEngine::Part part)
81 {
82 switch (part) {
83 case WebThemeEngine::PartCheckbox:
84 case WebThemeEngine::PartRadio: {
85 SkIRect retval = rect;
86
87 // The maximum width and height is 13.
88 // Center the square in the passed rectangle.
89 const int maxControlSize = 13;
90 int controlSize = std::min(rect.width(), rect.height());
91 controlSize = std::min(controlSize, maxControlSize);
92
93 retval.fLeft = rect.fLeft + (rect.width() / 2) - (controlSize / 2);
94 retval.fRight = retval.fLeft + controlSize - 1;
95 retval.fTop = rect.fTop + (rect.height() / 2) - (controlSize / 2);
96 retval.fBottom = retval.fTop + controlSize - 1;
97
98 return retval;
99 }
100 default:
101 return rect;
102 }
103 }
104
105
106 void box(SkCanvas *canvas, const SkIRect& rect, SkColor fillColor)
107 {
108 SkPaint paint;
109
110 paint.setStyle(SkPaint::kFill_Style);
111 paint.setColor(fillColor);
112 canvas->drawIRect(rect, paint);
113
114 paint.setColor(edgeColor);
115 paint.setStyle(SkPaint::kStroke_Style);
116 canvas->drawIRect(rect, paint);
117 }
118
119 void line(SkCanvas *canvas, int x0, int y0, int x1, int y1, SkColor color)
120 {
121 SkPaint paint;
122 paint.setColor(color);
123 canvas->drawLine(SkIntToScalar(x0), SkIntToScalar(y0),
124 SkIntToScalar(x1), SkIntToScalar(y1), paint);
125 }
126
127 void triangle(SkCanvas *canvas,
128 int x0, int y0,
129 int x1, int y1,
130 int x2, int y2,
131 SkColor color)
132 {
133 SkPath path;
134 SkPaint paint;
135
136 paint.setColor(color);
137 paint.setStyle(SkPaint::kFill_Style);
138 path.incReserve(4);
139 path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0));
140 path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1));
141 path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2));
142 path.close();
143 canvas->drawPath(path, paint);
144
145 paint.setColor(edgeColor);
146 paint.setStyle(SkPaint::kStroke_Style);
147 canvas->drawPath(path, paint);
148 }
149
150 void roundRect(SkCanvas *canvas, SkIRect irect, SkColor color)
151 {
152 SkRect rect;
153 SkScalar radius = SkIntToScalar(5);
154 SkPaint paint;
155
156 rect.set(irect);
157 paint.setColor(color);
158 paint.setStyle(SkPaint::kFill_Style);
159 canvas->drawRoundRect(rect, radius, radius, paint);
160
161 paint.setColor(edgeColor);
162 paint.setStyle(SkPaint::kStroke_Style);
163 canvas->drawRoundRect(rect, radius, radius, paint);
164 }
165
166 void oval(SkCanvas* canvas, SkIRect irect, SkColor color)
167 {
168 SkRect rect;
169 SkPaint paint;
170
171 rect.set(irect);
172 paint.setColor(color);
173 paint.setStyle(SkPaint::kFill_Style);
174 canvas->drawOval(rect, paint);
175
176 paint.setColor(edgeColor);
177 paint.setStyle(SkPaint::kStroke_Style);
178 canvas->drawOval(rect, paint);
179 }
180
181 void circle(SkCanvas *canvas, SkIRect irect, SkScalar radius, SkColor color)
182 {
183 int left = irect.fLeft;
184 int width = irect.width();
185 int height = irect.height();
186 int top = irect.fTop;
187
188 SkScalar cy = SkIntToScalar(top + height / 2);
189 SkScalar cx = SkIntToScalar(left + width / 2);
190 SkPaint paint;
191
192 paint.setColor(color);
193 paint.setStyle(SkPaint::kFill_Style);
194 canvas->drawCircle(cx, cy, radius, paint);
195
196 paint.setColor(edgeColor);
197 paint.setStyle(SkPaint::kStroke_Style);
198 canvas->drawCircle(cx, cy, radius, paint);
199 }
200
201 void nestedBoxes(SkCanvas *canvas,
202 SkIRect irect,
203 int indentLeft,
204 int indentTop,
205 int indentRight,
206 int indentBottom,
207 SkColor outerColor,
208 SkColor innerColor)
209 {
210 SkIRect lirect;
211 box(canvas, irect, outerColor);
212 lirect.set(irect.fLeft + indentLeft,
213 irect.fTop + indentTop,
214 irect.fRight - indentRight,
215 irect.fBottom - indentBottom);
216 box(canvas, lirect, innerColor);
217 }
218
219 void markState(SkCanvas *canvas, SkIRect irect, WebThemeEngine::State state)
220 {
221 int left = irect.fLeft;
222 int right = irect.fRight;
223 int top = irect.fTop;
224 int bottom = irect.fBottom;
225
226 // The length of a triangle side for the corner marks.
227 const int triangleSize = 5;
228
229 switch (state) {
230 case WebThemeEngine::StateDisabled:
231 case WebThemeEngine::StateNormal:
232 // Don't visually mark these states (color is enough).
233 break;
234
235 case WebThemeEngine::StateReadonly: {
236 // The horizontal lines in a read only control are spaced by this amount .
237 const int readOnlyLineOffset = 5;
238
239 // Drawing lines across the control.
240 for (int i = top + readOnlyLineOffset; i < bottom; i += readOnlyLineOffs et)
241 line(canvas, left + 1, i, right - 1, i, readOnlyColor);
242 break;
243 }
244 case WebThemeEngine::StateHover:
245 // Draw a triangle in the upper left corner of the control. (Win's "hot" )
246 triangle(canvas,
247 left, top,
248 left + triangleSize, top,
249 left, top + triangleSize,
250 edgeColor);
251 break;
252
253 case WebThemeEngine::StateFocused:
254 // Draw a triangle in the bottom right corner of the control.
255 triangle(canvas,
256 right, bottom,
257 right - triangleSize, bottom,
258 right, bottom - triangleSize,
259 edgeColor);
260 break;
261
262 case WebThemeEngine::StatePressed:
263 // Draw a triangle in the bottom left corner of the control.
264 triangle(canvas,
265 left, bottom,
266 left, bottom - triangleSize,
267 left + triangleSize, bottom,
268 edgeColor);
269 break;
270
271 default:
272 // FIXME: Should we do something here to indicate that we got an invalid state?
273 // Unfortunately, we can't assert because we don't have access to WTF or base.
274 break;
275 }
276 }
277
278 void WebTestThemeEngineMock::paint(
279 blink::WebCanvas* canvas,
280 WebThemeEngine::Part part,
281 WebThemeEngine::State state,
282 const blink::WebRect& rect,
283 const WebThemeEngine::ExtraParams* extraParams)
284 {
285 SkIRect irect = webRectToSkIRect(rect);
286 SkPaint paint;
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 int halfHeight = irect.height() / 2;
308 int halfWidth = irect.width() / 2;
309 int quarterHeight = irect.height() / 4;
310 int quarterWidth = irect.width() / 4;
311 int left = irect.fLeft;
312 int right = irect.fRight;
313 int top = irect.fTop;
314 int bottom = irect.fBottom;
315
316 switch (part) {
317 case WebThemeEngine::PartScrollbarDownArrow:
318 box(canvas, irect, bgColors[state]);
319 triangle(canvas,
320 left + quarterWidth, top + quarterHeight,
321 right - quarterWidth, top + quarterHeight,
322 left + halfWidth, bottom - quarterHeight,
323 edgeColor);
324 markState(canvas, irect, state);
325 break;
326
327 case WebThemeEngine::PartScrollbarLeftArrow:
328 box(canvas, irect, bgColors[state]);
329 triangle(canvas,
330 right - quarterWidth, top + quarterHeight,
331 right - quarterWidth, bottom - quarterHeight,
332 left + quarterWidth, top + halfHeight,
333 edgeColor);
334 break;
335
336 case WebThemeEngine::PartScrollbarRightArrow:
337 box(canvas, irect, bgColors[state]);
338 triangle(canvas,
339 left + quarterWidth, top + quarterHeight,
340 right - quarterWidth, top + halfHeight,
341 left + quarterWidth, bottom - quarterHeight,
342 edgeColor);
343 break;
344
345 case WebThemeEngine::PartScrollbarUpArrow:
346 box(canvas, irect, bgColors[state]);
347 triangle(canvas,
348 left + quarterWidth, bottom - quarterHeight,
349 left + halfWidth, top + quarterHeight,
350 right - quarterWidth, bottom - quarterHeight,
351 edgeColor);
352 markState(canvas, irect, state);
353 break;
354
355 case WebThemeEngine::PartScrollbarHorizontalThumb: {
356 // Draw a narrower box on top of the outside box.
357 nestedBoxes(canvas, irect, thumbLongIndent, thumbShortIndent,
358 thumbLongIndent, thumbShortIndent,
359 bgColors[state], bgColors[state]);
360 // Draw a horizontal crosshatch for the grip.
361 int longOffset = halfWidth - gripLongIndent;
362 line(canvas,
363 left + gripLongIndent, top + halfHeight,
364 right - gripLongIndent, top + halfHeight,
365 edgeColor);
366 line(canvas,
367 left + longOffset, top + gripShortIndent,
368 left + longOffset, bottom - gripShortIndent,
369 edgeColor);
370 line(canvas,
371 right - longOffset, top + gripShortIndent,
372 right - longOffset, bottom - gripShortIndent,
373 edgeColor);
374 markState(canvas, irect, state);
375 break;
376 }
377
378 case WebThemeEngine::PartScrollbarVerticalThumb: {
379 // Draw a shorter box on top of the outside box.
380 nestedBoxes(canvas, irect, thumbShortIndent, thumbLongIndent,
381 thumbShortIndent, thumbLongIndent,
382 bgColors[state], bgColors[state]);
383 // Draw a vertical crosshatch for the grip.
384 int longOffset = halfHeight - gripLongIndent;
385 line(canvas,
386 left + halfWidth, top + gripLongIndent,
387 left + halfWidth, bottom - gripLongIndent,
388 edgeColor);
389 line(canvas,
390 left + gripShortIndent, top + longOffset,
391 right - gripShortIndent, top + longOffset,
392 edgeColor);
393 line(canvas,
394 left + gripShortIndent, bottom - longOffset,
395 right - gripShortIndent, bottom - longOffset,
396 edgeColor);
397 markState(canvas, irect, state);
398 break;
399 }
400
401 case WebThemeEngine::PartScrollbarHorizontalTrack: {
402 int longOffset = halfHeight - notchLongOffset;
403 int shortOffset = irect.width() - notchShortOffset;
404 if (extraParams->scrollbarTrack.isBack) {
405 // back, notch on left
406 nestedBoxes(canvas, irect, noOffset, longOffset, shortOffset,
407 longOffset, bgColors[state], edgeColor);
408 } else {
409 // forward, notch on right
410 nestedBoxes(canvas, irect, shortOffset, longOffset, noOffset,
411 longOffset, bgColors[state], edgeColor);
412 }
413
414 markState(canvas, irect, state);
415 break;
416 }
417
418 case WebThemeEngine::PartScrollbarVerticalTrack: {
419 int longOffset = halfWidth - notchLongOffset;
420 int shortOffset = irect.height() - notchShortOffset;
421 if (extraParams->scrollbarTrack.isBack) {
422 // back, notch at top
423 nestedBoxes(canvas, irect, longOffset, noOffset, longOffset,
424 shortOffset, bgColors[state], edgeColor);
425 } else {
426 // forward, notch at bottom
427 nestedBoxes(canvas, irect, longOffset, shortOffset, longOffset,
428 noOffset, bgColors[state], edgeColor);
429 }
430
431 markState(canvas, irect, state);
432 break;
433 }
434
435 case WebThemeEngine::PartCheckbox:
436 if (extraParams->button.indeterminate) {
437 nestedBoxes(canvas, irect,
438 checkIndent, halfHeight,
439 checkIndent, halfHeight,
440 bgColors[state], edgeColor);
441 } else if (extraParams->button.checked) {
442 irect = validate(irect, part);
443 nestedBoxes(canvas, irect,
444 checkIndent, checkIndent,
445 checkIndent, checkIndent,
446 bgColors[state], edgeColor);
447 } else {
448 irect = validate(irect, part);
449 box(canvas, irect, bgColors[state]);
450 }
451 break;
452
453 case WebThemeEngine::PartRadio:
454 irect = validate(irect, part);
455 halfHeight = irect.height() / 2;
456 if (extraParams->button.checked) {
457 circle(canvas, irect, SkIntToScalar(halfHeight), bgColors[state]);
458 circle(canvas, irect, SkIntToScalar(halfHeight - checkIndent), edgeC olor);
459 } else {
460 circle(canvas, irect, SkIntToScalar(halfHeight), bgColors[state]);
461 }
462 break;
463
464 case WebThemeEngine::PartButton:
465 roundRect(canvas, irect, bgColors[state]);
466 markState(canvas, irect, state);
467 break;
468
469 case WebThemeEngine::PartTextField:
470 paint.setColor(extraParams->textField.backgroundColor);
471 paint.setStyle(SkPaint::kFill_Style);
472 canvas->drawIRect(irect, paint);
473
474 paint.setColor(edgeColor);
475 paint.setStyle(SkPaint::kStroke_Style);
476 canvas->drawIRect(irect, paint);
477
478 markState(canvas, irect, state);
479 break;
480
481 case WebThemeEngine::PartMenuList:
482 if (extraParams->menuList.fillContentArea) {
483 box(canvas, irect, extraParams->menuList.backgroundColor);
484 } else {
485 SkPaint paint;
486 paint.setColor(edgeColor);
487 paint.setStyle(SkPaint::kStroke_Style);
488 canvas->drawIRect(irect, paint);
489 }
490
491 // clip the drop-down arrow to be inside the select box
492 if (extraParams->menuList.arrowX - 4 > irect.fLeft)
493 irect.fLeft = extraParams->menuList.arrowX - 4;
494 if (extraParams->menuList.arrowX + 12 < irect.fRight)
495 irect.fRight = extraParams->menuList.arrowX + 12;
496
497 irect.fTop = extraParams->menuList.arrowY - (extraParams->menuList.arrow Height) / 2;
498 irect.fBottom = extraParams->menuList.arrowY + (extraParams->menuList.ar rowHeight - 1) / 2;
499 halfWidth = irect.width() / 2;
500 quarterWidth = irect.width() / 4;
501
502 if (state == WebThemeEngine::StateFocused) // FIXME: draw differenty?
503 state = WebThemeEngine::StateNormal;
504 box(canvas, irect, bgColors[state]);
505 triangle(canvas,
506 irect.fLeft + quarterWidth, irect.fTop,
507 irect.fRight - quarterWidth, irect.fTop,
508 irect.fLeft + halfWidth, irect.fBottom,
509 edgeColor);
510
511 break;
512
513 case WebThemeEngine::PartSliderTrack: {
514 SkIRect lirect = irect;
515
516 // Draw a narrow rect for the track plus box hatches on the ends.
517 if (state == WebThemeEngine::StateFocused) // FIXME: draw differently?
518 state = WebThemeEngine::StateNormal;
519 if (extraParams->slider.vertical) {
520 lirect.inset(halfWidth - sliderIndent, noOffset);
521 box(canvas, lirect, bgColors[state]);
522 line(canvas, left, top, right, top, edgeColor);
523 line(canvas, left, bottom, right, bottom, edgeColor);
524 } else {
525 lirect.inset(noOffset, halfHeight - sliderIndent);
526 box(canvas, lirect, bgColors[state]);
527 line(canvas, left, top, left, bottom, edgeColor);
528 line(canvas, right, top, right, bottom, edgeColor);
529 }
530 break;
531 }
532
533 case WebThemeEngine::PartSliderThumb:
534 if (state == WebThemeEngine::StateFocused) // FIXME: draw differently?
535 state = WebThemeEngine::StateNormal;
536 oval(canvas, irect, bgColors[state]);
537 break;
538
539 case WebThemeEngine::PartInnerSpinButton: {
540 // stack half-height up and down arrows on top of each other
541 SkIRect lirect;
542 int halfHeight = rect.height / 2;
543 if (extraParams->innerSpin.readOnly)
544 state = blink::WebThemeEngine::StateDisabled;
545
546 lirect.set(rect.x, rect.y, rect.x + rect.width - 1, rect.y + halfHeight - 1);
547 box(canvas, lirect, bgColors[state]);
548 bottom = lirect.fBottom;
549 quarterHeight = lirect.height() / 4;
550 triangle(canvas,
551 left + quarterWidth, bottom - quarterHeight,
552 right - quarterWidth, bottom - quarterHeight,
553 left + halfWidth, top + quarterHeight,
554 edgeColor);
555
556 lirect.set(rect.x, rect.y + halfHeight, rect.x + rect.width - 1,
557 rect.y + 2 * halfHeight - 1);
558 top = lirect.fTop;
559 bottom = lirect.fBottom;
560 quarterHeight = lirect.height() / 4;
561 box(canvas, lirect, bgColors[state]);
562 triangle(canvas,
563 left + quarterWidth, top + quarterHeight,
564 right - quarterWidth, top + quarterHeight,
565 left + halfWidth, bottom - quarterHeight,
566 edgeColor);
567 markState(canvas, irect, state);
568 break;
569 }
570 case WebThemeEngine::PartProgressBar: {
571 paint.setColor(bgColors[state]);
572 paint.setStyle(SkPaint::kFill_Style);
573 canvas->drawIRect(irect, paint);
574
575 // Emulate clipping
576 SkIRect tofill = irect;
577 if (extraParams->progressBar.determinate) {
578 tofill.set(extraParams->progressBar.valueRectX,
579 extraParams->progressBar.valueRectY,
580 extraParams->progressBar.valueRectX +
581 extraParams->progressBar.valueRectWidth - 1,
582 extraParams->progressBar.valueRectY +
583 extraParams->progressBar.valueRectHeight);
584 }
585
586 tofill.intersect(irect, tofill);
587 paint.setColor(edgeColor);
588 paint.setStyle(SkPaint::kFill_Style);
589 canvas->drawIRect(tofill, paint);
590
591 markState(canvas, irect, state);
592 break;
593 }
594 default:
595 // FIXME: Should we do something here to indicate that we got an invalid part?
596 // Unfortunately, we can't assert because we don't have access to WTF or base.
597 break;
598 }
599 }
600
601 } // namespace WebTestRunner
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698