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

Side by Side Diff: ui/base/native_theme/native_theme_base.cc

Issue 10387121: Revert 136996 - ui: Move NativeTheme files into ui/base/native_theme/ directory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 7 months 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
« no previous file with comments | « ui/base/native_theme/native_theme_base.h ('k') | ui/base/native_theme/native_theme_gtk.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 #include "ui/base/native_theme/native_theme_base.h"
6
7 #include <limits>
8
9 #include "base/logging.h"
10 #include "grit/gfx_resources.h"
11 #include "third_party/skia/include/effects/SkGradientShader.h"
12 #include "ui/base/resource/resource_bundle.h"
13 #include "ui/gfx/color_utils.h"
14 #include "ui/gfx/rect.h"
15 #include "ui/gfx/size.h"
16
17 namespace {
18
19 // These are the default dimensions of radio buttons and checkboxes.
20 const int kCheckboxAndRadioWidth = 13;
21 const int kCheckboxAndRadioHeight = 13;
22
23 // These sizes match the sizes in Chromium Win.
24 const int kSliderThumbWidth = 11;
25 const int kSliderThumbHeight = 21;
26
27 const SkColor kSliderTrackBackgroundColor =
28 SkColorSetRGB(0xe3, 0xdd, 0xd8);
29 const SkColor kSliderThumbLightGrey = SkColorSetRGB(0xf4, 0xf2, 0xef);
30 const SkColor kSliderThumbDarkGrey = SkColorSetRGB(0xea, 0xe5, 0xe0);
31 const SkColor kSliderThumbBorderDarkGrey =
32 SkColorSetRGB(0x9d, 0x96, 0x8e);
33
34 const SkColor kMenuPopupBackgroundColor = SkColorSetRGB(210, 225, 246);
35
36 const unsigned int kDefaultScrollbarWidth = 15;
37 const unsigned int kDefaultScrollbarButtonLength = 14;
38
39 // Get lightness adjusted color.
40 SkColor BrightenColor(const color_utils::HSL& hsl, SkAlpha alpha,
41 double lightness_amount) {
42 color_utils::HSL adjusted = hsl;
43 adjusted.l += lightness_amount;
44 if (adjusted.l > 1.0)
45 adjusted.l = 1.0;
46 if (adjusted.l < 0.0)
47 adjusted.l = 0.0;
48
49 return color_utils::HSLToSkColor(adjusted, alpha);
50 }
51
52 } // namespace
53
54 namespace ui {
55
56 gfx::Size NativeThemeBase::GetPartSize(Part part,
57 State state,
58 const ExtraParams& extra) const {
59 switch (part) {
60 // Please keep these in the order of NativeTheme::Part.
61 case kCheckbox:
62 return gfx::Size(kCheckboxAndRadioWidth, kCheckboxAndRadioHeight);
63 case kInnerSpinButton:
64 return gfx::Size(scrollbar_width_, 0);
65 case kMenuList:
66 return gfx::Size(); // No default size.
67 case kMenuCheck:
68 case kMenuCheckBackground:
69 case kMenuPopupArrow:
70 NOTIMPLEMENTED();
71 break;
72 case kMenuPopupBackground:
73 return gfx::Size(); // No default size.
74 case kMenuPopupGutter:
75 case kMenuPopupSeparator:
76 NOTIMPLEMENTED();
77 break;
78 case kMenuItemBackground:
79 case kProgressBar:
80 case kPushButton:
81 return gfx::Size(); // No default size.
82 case kRadio:
83 return gfx::Size(kCheckboxAndRadioWidth, kCheckboxAndRadioHeight);
84 case kScrollbarDownArrow:
85 case kScrollbarUpArrow:
86 return gfx::Size(scrollbar_width_, scrollbar_button_length_);
87 case kScrollbarLeftArrow:
88 case kScrollbarRightArrow:
89 return gfx::Size(scrollbar_button_length_, scrollbar_width_);
90 case kScrollbarHorizontalThumb:
91 // This matches Firefox on Linux.
92 return gfx::Size(2 * scrollbar_width_, scrollbar_width_);
93 case kScrollbarVerticalThumb:
94 // This matches Firefox on Linux.
95 return gfx::Size(scrollbar_width_, 2 * scrollbar_width_);
96 case kScrollbarHorizontalTrack:
97 return gfx::Size(0, scrollbar_width_);
98 case kScrollbarVerticalTrack:
99 return gfx::Size(scrollbar_width_, 0);
100 case kScrollbarHorizontalGripper:
101 case kScrollbarVerticalGripper:
102 NOTIMPLEMENTED();
103 break;
104 case kSliderTrack:
105 return gfx::Size(); // No default size.
106 case kSliderThumb:
107 // These sizes match the sizes in Chromium Win.
108 return gfx::Size(kSliderThumbWidth, kSliderThumbHeight);
109 case kTabPanelBackground:
110 NOTIMPLEMENTED();
111 break;
112 case kTextField:
113 return gfx::Size(); // No default size.
114 case kTrackbarThumb:
115 case kTrackbarTrack:
116 case kWindowResizeGripper:
117 NOTIMPLEMENTED();
118 break;
119 default:
120 NOTREACHED() << "Unknown theme part: " << part;
121 break;
122 }
123 return gfx::Size();
124 }
125
126 void NativeThemeBase::Paint(SkCanvas* canvas,
127 Part part,
128 State state,
129 const gfx::Rect& rect,
130 const ExtraParams& extra) const {
131 switch (part) {
132 // Please keep these in the order of NativeTheme::Part.
133 case kCheckbox:
134 PaintCheckbox(canvas, state, rect, extra.button);
135 break;
136 case kInnerSpinButton:
137 PaintInnerSpinButton(canvas, state, rect, extra.inner_spin);
138 break;
139 case kMenuList:
140 PaintMenuList(canvas, state, rect, extra.menu_list);
141 break;
142 case kMenuCheck:
143 case kMenuCheckBackground:
144 case kMenuPopupArrow:
145 NOTIMPLEMENTED();
146 break;
147 case kMenuPopupBackground:
148 PaintMenuPopupBackground(canvas, rect.size());
149 break;
150 case kMenuPopupGutter:
151 case kMenuPopupSeparator:
152 NOTIMPLEMENTED();
153 break;
154 case kMenuItemBackground:
155 PaintMenuItemBackground(canvas, state, rect, extra.menu_list);
156 break;
157 case kProgressBar:
158 PaintProgressBar(canvas, state, rect, extra.progress_bar);
159 break;
160 case kPushButton:
161 PaintButton(canvas, state, rect, extra.button);
162 break;
163 case kRadio:
164 PaintRadio(canvas, state, rect, extra.button);
165 break;
166 case kScrollbarDownArrow:
167 case kScrollbarUpArrow:
168 case kScrollbarLeftArrow:
169 case kScrollbarRightArrow:
170 PaintArrowButton(canvas, rect, part, state);
171 break;
172 case kScrollbarHorizontalThumb:
173 case kScrollbarVerticalThumb:
174 PaintScrollbarThumb(canvas, part, state, rect);
175 break;
176 case kScrollbarHorizontalTrack:
177 case kScrollbarVerticalTrack:
178 PaintScrollbarTrack(canvas, part, state, extra.scrollbar_track, rect);
179 break;
180 case kScrollbarHorizontalGripper:
181 case kScrollbarVerticalGripper:
182 NOTIMPLEMENTED();
183 break;
184 case kSliderTrack:
185 PaintSliderTrack(canvas, state, rect, extra.slider);
186 break;
187 case kSliderThumb:
188 PaintSliderThumb(canvas, state, rect, extra.slider);
189 break;
190 case kTabPanelBackground:
191 NOTIMPLEMENTED();
192 break;
193 case kTextField:
194 PaintTextField(canvas, state, rect, extra.text_field);
195 break;
196 case kTrackbarThumb:
197 case kTrackbarTrack:
198 case kWindowResizeGripper:
199 NOTIMPLEMENTED();
200 break;
201 default:
202 NOTREACHED() << "Unknown theme part: " << part;
203 break;
204 }
205 }
206
207 NativeThemeBase::NativeThemeBase()
208 : scrollbar_width_(kDefaultScrollbarWidth),
209 scrollbar_button_length_(kDefaultScrollbarButtonLength) {
210 }
211
212 NativeThemeBase::~NativeThemeBase() {
213 }
214
215 void NativeThemeBase::PaintArrowButton(
216 SkCanvas* canvas,
217 const gfx::Rect& rect, Part direction, State state) const {
218 int widthMiddle, lengthMiddle;
219 SkPaint paint;
220 if (direction == kScrollbarUpArrow || direction == kScrollbarDownArrow) {
221 widthMiddle = rect.width() / 2 + 1;
222 lengthMiddle = rect.height() / 2 + 1;
223 } else {
224 lengthMiddle = rect.width() / 2 + 1;
225 widthMiddle = rect.height() / 2 + 1;
226 }
227
228 // Calculate button color.
229 SkScalar trackHSV[3];
230 SkColorToHSV(track_color_, trackHSV);
231 SkColor buttonColor = SaturateAndBrighten(trackHSV, 0, 0.2f);
232 SkColor backgroundColor = buttonColor;
233 if (state == kPressed) {
234 SkScalar buttonHSV[3];
235 SkColorToHSV(buttonColor, buttonHSV);
236 buttonColor = SaturateAndBrighten(buttonHSV, 0, -0.1f);
237 } else if (state == kHovered) {
238 SkScalar buttonHSV[3];
239 SkColorToHSV(buttonColor, buttonHSV);
240 buttonColor = SaturateAndBrighten(buttonHSV, 0, 0.05f);
241 }
242
243 SkIRect skrect;
244 skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y()
245 + rect.height());
246 // Paint the background (the area visible behind the rounded corners).
247 paint.setColor(backgroundColor);
248 canvas->drawIRect(skrect, paint);
249
250 // Paint the button's outline and fill the middle
251 SkPath outline;
252 switch (direction) {
253 case kScrollbarUpArrow:
254 outline.moveTo(rect.x() + 0.5, rect.y() + rect.height() + 0.5);
255 outline.rLineTo(0, -(rect.height() - 2));
256 outline.rLineTo(2, -2);
257 outline.rLineTo(rect.width() - 5, 0);
258 outline.rLineTo(2, 2);
259 outline.rLineTo(0, rect.height() - 2);
260 break;
261 case kScrollbarDownArrow:
262 outline.moveTo(rect.x() + 0.5, rect.y() - 0.5);
263 outline.rLineTo(0, rect.height() - 2);
264 outline.rLineTo(2, 2);
265 outline.rLineTo(rect.width() - 5, 0);
266 outline.rLineTo(2, -2);
267 outline.rLineTo(0, -(rect.height() - 2));
268 break;
269 case kScrollbarRightArrow:
270 outline.moveTo(rect.x() - 0.5, rect.y() + 0.5);
271 outline.rLineTo(rect.width() - 2, 0);
272 outline.rLineTo(2, 2);
273 outline.rLineTo(0, rect.height() - 5);
274 outline.rLineTo(-2, 2);
275 outline.rLineTo(-(rect.width() - 2), 0);
276 break;
277 case kScrollbarLeftArrow:
278 outline.moveTo(rect.x() + rect.width() + 0.5, rect.y() + 0.5);
279 outline.rLineTo(-(rect.width() - 2), 0);
280 outline.rLineTo(-2, 2);
281 outline.rLineTo(0, rect.height() - 5);
282 outline.rLineTo(2, 2);
283 outline.rLineTo(rect.width() - 2, 0);
284 break;
285 default:
286 break;
287 }
288 outline.close();
289
290 paint.setStyle(SkPaint::kFill_Style);
291 paint.setColor(buttonColor);
292 canvas->drawPath(outline, paint);
293
294 paint.setAntiAlias(true);
295 paint.setStyle(SkPaint::kStroke_Style);
296 SkScalar thumbHSV[3];
297 SkColorToHSV(thumb_inactive_color_, thumbHSV);
298 paint.setColor(OutlineColor(trackHSV, thumbHSV));
299 canvas->drawPath(outline, paint);
300
301 // If the button is disabled or read-only, the arrow is drawn with the
302 // outline color.
303 if (state != kDisabled)
304 paint.setColor(SK_ColorBLACK);
305
306 paint.setAntiAlias(false);
307 paint.setStyle(SkPaint::kFill_Style);
308
309 SkPath path;
310 // The constants in this block of code are hand-tailored to produce good
311 // looking arrows without anti-aliasing.
312 switch (direction) {
313 case kScrollbarUpArrow:
314 path.moveTo(rect.x() + widthMiddle - 4, rect.y() + lengthMiddle + 2);
315 path.rLineTo(7, 0);
316 path.rLineTo(-4, -4);
317 break;
318 case kScrollbarDownArrow:
319 path.moveTo(rect.x() + widthMiddle - 4, rect.y() + lengthMiddle - 3);
320 path.rLineTo(7, 0);
321 path.rLineTo(-4, 4);
322 break;
323 case kScrollbarRightArrow:
324 path.moveTo(rect.x() + lengthMiddle - 3, rect.y() + widthMiddle - 4);
325 path.rLineTo(0, 7);
326 path.rLineTo(4, -4);
327 break;
328 case kScrollbarLeftArrow:
329 path.moveTo(rect.x() + lengthMiddle + 1, rect.y() + widthMiddle - 5);
330 path.rLineTo(0, 9);
331 path.rLineTo(-4, -4);
332 break;
333 default:
334 break;
335 }
336 path.close();
337
338 canvas->drawPath(path, paint);
339 }
340
341 void NativeThemeBase::PaintScrollbarTrack(SkCanvas* canvas,
342 Part part,
343 State state,
344 const ScrollbarTrackExtraParams& extra_params,
345 const gfx::Rect& rect) const {
346 SkPaint paint;
347 SkIRect skrect;
348
349 skrect.set(rect.x(), rect.y(), rect.right(), rect.bottom());
350 SkScalar track_hsv[3];
351 SkColorToHSV(track_color_, track_hsv);
352 paint.setColor(SaturateAndBrighten(track_hsv, 0, 0));
353 canvas->drawIRect(skrect, paint);
354
355 SkScalar thumb_hsv[3];
356 SkColorToHSV(thumb_inactive_color_, thumb_hsv);
357
358 paint.setColor(OutlineColor(track_hsv, thumb_hsv));
359 DrawBox(canvas, rect, paint);
360 }
361
362 void NativeThemeBase::PaintScrollbarThumb(SkCanvas* canvas,
363 Part part,
364 State state,
365 const gfx::Rect& rect) const {
366 const bool hovered = state == kHovered;
367 const int midx = rect.x() + rect.width() / 2;
368 const int midy = rect.y() + rect.height() / 2;
369 const bool vertical = part == kScrollbarVerticalThumb;
370
371 SkScalar thumb[3];
372 SkColorToHSV(hovered ? thumb_active_color_ : thumb_inactive_color_, thumb);
373
374 SkPaint paint;
375 paint.setColor(SaturateAndBrighten(thumb, 0, 0.02f));
376
377 SkIRect skrect;
378 if (vertical)
379 skrect.set(rect.x(), rect.y(), midx + 1, rect.y() + rect.height());
380 else
381 skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), midy + 1);
382
383 canvas->drawIRect(skrect, paint);
384
385 paint.setColor(SaturateAndBrighten(thumb, 0, -0.02f));
386
387 if (vertical) {
388 skrect.set(
389 midx + 1, rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
390 } else {
391 skrect.set(
392 rect.x(), midy + 1, rect.x() + rect.width(), rect.y() + rect.height());
393 }
394
395 canvas->drawIRect(skrect, paint);
396
397 SkScalar track[3];
398 SkColorToHSV(track_color_, track);
399 paint.setColor(OutlineColor(track, thumb));
400 DrawBox(canvas, rect, paint);
401
402 if (rect.height() > 10 && rect.width() > 10) {
403 const int grippy_half_width = 2;
404 const int inter_grippy_offset = 3;
405 if (vertical) {
406 DrawHorizLine(canvas,
407 midx - grippy_half_width,
408 midx + grippy_half_width,
409 midy - inter_grippy_offset,
410 paint);
411 DrawHorizLine(canvas,
412 midx - grippy_half_width,
413 midx + grippy_half_width,
414 midy,
415 paint);
416 DrawHorizLine(canvas,
417 midx - grippy_half_width,
418 midx + grippy_half_width,
419 midy + inter_grippy_offset,
420 paint);
421 } else {
422 DrawVertLine(canvas,
423 midx - inter_grippy_offset,
424 midy - grippy_half_width,
425 midy + grippy_half_width,
426 paint);
427 DrawVertLine(canvas,
428 midx,
429 midy - grippy_half_width,
430 midy + grippy_half_width,
431 paint);
432 DrawVertLine(canvas,
433 midx + inter_grippy_offset,
434 midy - grippy_half_width,
435 midy + grippy_half_width,
436 paint);
437 }
438 }
439 }
440
441 void NativeThemeBase::PaintCheckbox(SkCanvas* canvas,
442 State state,
443 const gfx::Rect& rect,
444 const ButtonExtraParams& button) const {
445 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
446 SkBitmap* image = NULL;
447 if (button.indeterminate) {
448 image = state == kDisabled ?
449 rb.GetBitmapNamed(IDR_CHECKBOX_DISABLED_INDETERMINATE) :
450 rb.GetBitmapNamed(IDR_CHECKBOX_INDETERMINATE);
451 } else if (button.checked) {
452 image = state == kDisabled ?
453 rb.GetBitmapNamed(IDR_CHECKBOX_DISABLED_ON) :
454 rb.GetBitmapNamed(IDR_CHECKBOX_ON);
455 } else {
456 image = state == kDisabled ?
457 rb.GetBitmapNamed(IDR_CHECKBOX_DISABLED_OFF) :
458 rb.GetBitmapNamed(IDR_CHECKBOX_OFF);
459 }
460
461 gfx::Rect bounds = rect.Center(gfx::Size(image->width(), image->height()));
462 DrawBitmapInt(canvas, *image, 0, 0, image->width(), image->height(),
463 bounds.x(), bounds.y(), bounds.width(), bounds.height());
464 }
465
466 void NativeThemeBase::PaintRadio(SkCanvas* canvas,
467 State state,
468 const gfx::Rect& rect,
469 const ButtonExtraParams& button) const {
470 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
471 SkBitmap* image = NULL;
472 if (state == kDisabled) {
473 image = button.checked ?
474 rb.GetBitmapNamed(IDR_RADIO_DISABLED_ON) :
475 rb.GetBitmapNamed(IDR_RADIO_DISABLED_OFF);
476 } else {
477 image = button.checked ?
478 rb.GetBitmapNamed(IDR_RADIO_ON) :
479 rb.GetBitmapNamed(IDR_RADIO_OFF);
480 }
481
482 gfx::Rect bounds = rect.Center(gfx::Size(image->width(), image->height()));
483 DrawBitmapInt(canvas, *image, 0, 0, image->width(), image->height(),
484 bounds.x(), bounds.y(), bounds.width(), bounds.height());
485 }
486
487 void NativeThemeBase::PaintButton(SkCanvas* canvas,
488 State state,
489 const gfx::Rect& rect,
490 const ButtonExtraParams& button) const {
491 SkPaint paint;
492 const int kRight = rect.right();
493 const int kBottom = rect.bottom();
494 SkRect skrect = SkRect::MakeLTRB(rect.x(), rect.y(), kRight, kBottom);
495 SkColor base_color = button.background_color;
496
497 color_utils::HSL base_hsl;
498 color_utils::SkColorToHSL(base_color, &base_hsl);
499
500 // Our standard gradient is from 0xdd to 0xf8. This is the amount of
501 // increased luminance between those values.
502 SkColor light_color(BrightenColor(base_hsl, SkColorGetA(base_color), 0.105));
503
504 // If the button is too small, fallback to drawing a single, solid color
505 if (rect.width() < 5 || rect.height() < 5) {
506 paint.setColor(base_color);
507 canvas->drawRect(skrect, paint);
508 return;
509 }
510
511 paint.setColor(SK_ColorBLACK);
512 const int kLightEnd = state == kPressed ? 1 : 0;
513 const int kDarkEnd = !kLightEnd;
514 SkPoint gradient_bounds[2];
515 gradient_bounds[kLightEnd].iset(rect.x(), rect.y());
516 gradient_bounds[kDarkEnd].iset(rect.x(), kBottom - 1);
517 SkColor colors[2];
518 colors[0] = light_color;
519 colors[1] = base_color;
520
521 SkShader* shader = SkGradientShader::CreateLinear(
522 gradient_bounds, colors, NULL, 2, SkShader::kClamp_TileMode, NULL);
523 paint.setStyle(SkPaint::kFill_Style);
524 paint.setAntiAlias(true);
525 paint.setShader(shader);
526 shader->unref();
527
528 canvas->drawRoundRect(skrect, SkIntToScalar(1), SkIntToScalar(1), paint);
529 paint.setShader(NULL);
530
531 if (button.has_border) {
532 const int kBorderAlpha = state == kHovered ? 0x80 : 0x55;
533 paint.setStyle(SkPaint::kStroke_Style);
534 paint.setStrokeWidth(SkIntToScalar(1));
535 paint.setARGB(kBorderAlpha, 0, 0, 0);
536 skrect.inset(SkFloatToScalar(.5f), SkFloatToScalar(.5f));
537 canvas->drawRoundRect(skrect, SkIntToScalar(1), SkIntToScalar(1), paint);
538 }
539 }
540
541 void NativeThemeBase::PaintTextField(SkCanvas* canvas,
542 State state,
543 const gfx::Rect& rect,
544 const TextFieldExtraParams& text) const {
545 // The following drawing code simulates the user-agent css border for
546 // text area and text input so that we do not break layout tests. Once we
547 // have decided the desired looks, we should update the code here and
548 // the layout test expectations.
549 SkRect bounds;
550 bounds.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1);
551
552 SkPaint fill_paint;
553 fill_paint.setStyle(SkPaint::kFill_Style);
554 fill_paint.setColor(text.background_color);
555 canvas->drawRect(bounds, fill_paint);
556
557 if (text.is_text_area) {
558 // Draw text area border: 1px solid black
559 SkPaint stroke_paint;
560 fill_paint.setStyle(SkPaint::kStroke_Style);
561 fill_paint.setColor(SK_ColorBLACK);
562 canvas->drawRect(bounds, fill_paint);
563 } else {
564 // Draw text input and listbox inset border
565 // Text Input: 2px inset #eee
566 // Listbox: 1px inset #808080
567 const SkColor kLightColor = text.is_listbox ?
568 SkColorSetRGB(0x80, 0x80, 0x80) : SkColorSetRGB(0xee, 0xee, 0xee);
569 const SkColor kDarkColor = text.is_listbox ?
570 SkColorSetRGB(0x2c, 0x2c, 0x2c) : SkColorSetRGB(0x9a, 0x9a, 0x9a);
571 const int kBorderWidth = text.is_listbox ? 1 : 2;
572
573 SkPaint dark_paint;
574 dark_paint.setAntiAlias(true);
575 dark_paint.setStyle(SkPaint::kFill_Style);
576 dark_paint.setColor(kDarkColor);
577
578 SkPaint light_paint;
579 light_paint.setAntiAlias(true);
580 light_paint.setStyle(SkPaint::kFill_Style);
581 light_paint.setColor(kLightColor);
582
583 int left = rect.x();
584 int top = rect.y();
585 int right = rect.right();
586 int bottom = rect.bottom();
587
588 SkPath path;
589 path.incReserve(4);
590
591 // Top
592 path.moveTo(SkIntToScalar(left), SkIntToScalar(top));
593 path.lineTo(SkIntToScalar(left + kBorderWidth),
594 SkIntToScalar(top + kBorderWidth));
595 path.lineTo(SkIntToScalar(right - kBorderWidth),
596 SkIntToScalar(top + kBorderWidth));
597 path.lineTo(SkIntToScalar(right), SkIntToScalar(top));
598 canvas->drawPath(path, dark_paint);
599
600 // Bottom
601 path.reset();
602 path.moveTo(SkIntToScalar(left + kBorderWidth),
603 SkIntToScalar(bottom - kBorderWidth));
604 path.lineTo(SkIntToScalar(left), SkIntToScalar(bottom));
605 path.lineTo(SkIntToScalar(right), SkIntToScalar(bottom));
606 path.lineTo(SkIntToScalar(right - kBorderWidth),
607 SkIntToScalar(bottom - kBorderWidth));
608 canvas->drawPath(path, light_paint);
609
610 // Left
611 path.reset();
612 path.moveTo(SkIntToScalar(left), SkIntToScalar(top));
613 path.lineTo(SkIntToScalar(left), SkIntToScalar(bottom));
614 path.lineTo(SkIntToScalar(left + kBorderWidth),
615 SkIntToScalar(bottom - kBorderWidth));
616 path.lineTo(SkIntToScalar(left + kBorderWidth),
617 SkIntToScalar(top + kBorderWidth));
618 canvas->drawPath(path, dark_paint);
619
620 // Right
621 path.reset();
622 path.moveTo(SkIntToScalar(right - kBorderWidth),
623 SkIntToScalar(top + kBorderWidth));
624 path.lineTo(SkIntToScalar(right - kBorderWidth), SkIntToScalar(bottom));
625 path.lineTo(SkIntToScalar(right), SkIntToScalar(bottom));
626 path.lineTo(SkIntToScalar(right), SkIntToScalar(top));
627 canvas->drawPath(path, light_paint);
628 }
629 }
630
631 void NativeThemeBase::PaintMenuList(
632 SkCanvas* canvas,
633 State state,
634 const gfx::Rect& rect,
635 const MenuListExtraParams& menu_list) const {
636 // If a border radius is specified, we let the WebCore paint the background
637 // and the border of the control.
638 if (!menu_list.has_border_radius) {
639 ButtonExtraParams button = { 0 };
640 button.background_color = menu_list.background_color;
641 button.has_border = menu_list.has_border;
642 PaintButton(canvas, state, rect, button);
643 }
644
645 SkPaint paint;
646 paint.setColor(SK_ColorBLACK);
647 paint.setAntiAlias(true);
648 paint.setStyle(SkPaint::kFill_Style);
649
650 SkPath path;
651 path.moveTo(menu_list.arrow_x, menu_list.arrow_y - 3);
652 path.rLineTo(6, 0);
653 path.rLineTo(-3, 6);
654 path.close();
655 canvas->drawPath(path, paint);
656 }
657
658 void NativeThemeBase::PaintMenuPopupBackground(SkCanvas* canvas,
659 const gfx::Size& size) const {
660 canvas->drawColor(kMenuPopupBackgroundColor, SkXfermode::kSrc_Mode);
661 }
662
663 void NativeThemeBase::PaintMenuItemBackground(
664 SkCanvas* canvas,
665 State state,
666 const gfx::Rect& rect,
667 const MenuListExtraParams& menu_list) const {
668 // By default don't draw anything over the normal background.
669 }
670
671 void NativeThemeBase::PaintSliderTrack(SkCanvas* canvas,
672 State state,
673 const gfx::Rect& rect,
674 const SliderExtraParams& slider) const {
675 const int kMidX = rect.x() + rect.width() / 2;
676 const int kMidY = rect.y() + rect.height() / 2;
677
678 SkPaint paint;
679 paint.setColor(kSliderTrackBackgroundColor);
680
681 SkRect skrect;
682 if (slider.vertical) {
683 skrect.set(std::max(rect.x(), kMidX - 2),
684 rect.y(),
685 std::min(rect.right(), kMidX + 2),
686 rect.bottom());
687 } else {
688 skrect.set(rect.x(),
689 std::max(rect.y(), kMidY - 2),
690 rect.right(),
691 std::min(rect.bottom(), kMidY + 2));
692 }
693 canvas->drawRect(skrect, paint);
694 }
695
696 void NativeThemeBase::PaintSliderThumb(SkCanvas* canvas,
697 State state,
698 const gfx::Rect& rect,
699 const SliderExtraParams& slider) const {
700 const bool hovered = (state == kHovered) || slider.in_drag;
701 const int kMidX = rect.x() + rect.width() / 2;
702 const int kMidY = rect.y() + rect.height() / 2;
703
704 SkPaint paint;
705 paint.setColor(hovered ? SK_ColorWHITE : kSliderThumbLightGrey);
706
707 SkIRect skrect;
708 if (slider.vertical)
709 skrect.set(rect.x(), rect.y(), kMidX + 1, rect.bottom());
710 else
711 skrect.set(rect.x(), rect.y(), rect.right(), kMidY + 1);
712
713 canvas->drawIRect(skrect, paint);
714
715 paint.setColor(hovered ? kSliderThumbLightGrey : kSliderThumbDarkGrey);
716
717 if (slider.vertical)
718 skrect.set(kMidX + 1, rect.y(), rect.right(), rect.bottom());
719 else
720 skrect.set(rect.x(), kMidY + 1, rect.right(), rect.bottom());
721
722 canvas->drawIRect(skrect, paint);
723
724 paint.setColor(kSliderThumbBorderDarkGrey);
725 DrawBox(canvas, rect, paint);
726
727 if (rect.height() > 10 && rect.width() > 10) {
728 DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY, paint);
729 DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY - 3, paint);
730 DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY + 3, paint);
731 }
732 }
733
734 void NativeThemeBase::PaintInnerSpinButton(SkCanvas* canvas,
735 State state,
736 const gfx::Rect& rect,
737 const InnerSpinButtonExtraParams& spin_button) const {
738 if (spin_button.read_only)
739 state = kDisabled;
740
741 State north_state = state;
742 State south_state = state;
743 if (spin_button.spin_up)
744 south_state = south_state != kDisabled ? kNormal : kDisabled;
745 else
746 north_state = north_state != kDisabled ? kNormal : kDisabled;
747
748 gfx::Rect half = rect;
749 half.set_height(rect.height() / 2);
750 PaintArrowButton(canvas, half, kScrollbarUpArrow, north_state);
751
752 half.set_y(rect.y() + rect.height() / 2);
753 PaintArrowButton(canvas, half, kScrollbarDownArrow, south_state);
754 }
755
756 void NativeThemeBase::PaintProgressBar(SkCanvas* canvas,
757 State state,
758 const gfx::Rect& rect,
759 const ProgressBarExtraParams& progress_bar) const {
760 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
761 SkBitmap* bar_image = rb.GetBitmapNamed(IDR_PROGRESS_BAR);
762 SkBitmap* left_border_image = rb.GetBitmapNamed(IDR_PROGRESS_BORDER_LEFT);
763 SkBitmap* right_border_image = rb.GetBitmapNamed(IDR_PROGRESS_BORDER_RIGHT);
764
765 double tile_scale = static_cast<double>(rect.height()) /
766 bar_image->height();
767
768 int new_tile_width = static_cast<int>(bar_image->width() * tile_scale);
769 double tile_scale_x = static_cast<double>(new_tile_width) /
770 bar_image->width();
771
772 DrawTiledImage(canvas, *bar_image, 0, 0, tile_scale_x, tile_scale,
773 rect.x(), rect.y(), rect.width(), rect.height());
774
775 if (progress_bar.value_rect_width) {
776 SkBitmap* value_image = rb.GetBitmapNamed(IDR_PROGRESS_VALUE);
777
778 new_tile_width = static_cast<int>(value_image->width() * tile_scale);
779 tile_scale_x = static_cast<double>(new_tile_width) /
780 value_image->width();
781
782 DrawTiledImage(canvas, *value_image, 0, 0, tile_scale_x, tile_scale,
783 progress_bar.value_rect_x,
784 progress_bar.value_rect_y,
785 progress_bar.value_rect_width,
786 progress_bar.value_rect_height);
787 }
788
789 int dest_left_border_width = static_cast<int>(left_border_image->width() *
790 tile_scale);
791 SkRect dest_rect;
792 dest_rect.iset(rect.x(), rect.y(), rect.x() + dest_left_border_width,
793 rect.bottom());
794 canvas->drawBitmapRect(*left_border_image, NULL, dest_rect);
795
796 int dest_right_border_width = static_cast<int>(right_border_image->width() *
797 tile_scale);
798 dest_rect.iset(rect.right() - dest_right_border_width, rect.y(), rect.right(),
799 rect.bottom());
800 canvas->drawBitmapRect(*right_border_image, NULL, dest_rect);
801 }
802
803 bool NativeThemeBase::IntersectsClipRectInt(SkCanvas* canvas,
804 int x, int y, int w, int h) const {
805 SkRect clip;
806 return canvas->getClipBounds(&clip) &&
807 clip.intersect(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w),
808 SkIntToScalar(y + h));
809 }
810
811 void NativeThemeBase::DrawBitmapInt(
812 SkCanvas* canvas, const SkBitmap& bitmap,
813 int src_x, int src_y, int src_w, int src_h,
814 int dest_x, int dest_y, int dest_w, int dest_h) const {
815 DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
816 src_y + src_h < std::numeric_limits<int16_t>::max());
817 if (src_w <= 0 || src_h <= 0 || dest_w <= 0 || dest_h <= 0) {
818 NOTREACHED() << "Attempting to draw bitmap to/from an empty rect!";
819 return;
820 }
821
822 if (!IntersectsClipRectInt(canvas, dest_x, dest_y, dest_w, dest_h))
823 return;
824
825 SkRect dest_rect = { SkIntToScalar(dest_x),
826 SkIntToScalar(dest_y),
827 SkIntToScalar(dest_x + dest_w),
828 SkIntToScalar(dest_y + dest_h) };
829
830 if (src_w == dest_w && src_h == dest_h) {
831 // Workaround for apparent bug in Skia that causes image to occasionally
832 // shift.
833 SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
834 canvas->drawBitmapRect(bitmap, &src_rect, dest_rect);
835 return;
836 }
837
838 // Make a bitmap shader that contains the bitmap we want to draw. This is
839 // basically what SkCanvas.drawBitmap does internally, but it gives us
840 // more control over quality and will use the mipmap in the source image if
841 // it has one, whereas drawBitmap won't.
842 SkShader* shader = SkShader::CreateBitmapShader(bitmap,
843 SkShader::kRepeat_TileMode,
844 SkShader::kRepeat_TileMode);
845 SkMatrix shader_scale;
846 shader_scale.setScale(SkFloatToScalar(static_cast<float>(dest_w) / src_w),
847 SkFloatToScalar(static_cast<float>(dest_h) / src_h));
848 shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
849 shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
850 shader->setLocalMatrix(shader_scale);
851
852 // The rect will be filled by the bitmap.
853 SkPaint p;
854 p.setFilterBitmap(true);
855 p.setShader(shader);
856 shader->unref();
857 canvas->drawRect(dest_rect, p);
858 }
859
860 void NativeThemeBase::DrawTiledImage(SkCanvas* canvas,
861 const SkBitmap& bitmap,
862 int src_x, int src_y, double tile_scale_x, double tile_scale_y,
863 int dest_x, int dest_y, int w, int h) const {
864 SkShader* shader = SkShader::CreateBitmapShader(bitmap,
865 SkShader::kRepeat_TileMode,
866 SkShader::kRepeat_TileMode);
867 if (tile_scale_x != 1.0 || tile_scale_y != 1.0) {
868 SkMatrix shader_scale;
869 shader_scale.setScale(SkDoubleToScalar(tile_scale_x),
870 SkDoubleToScalar(tile_scale_y));
871 shader->setLocalMatrix(shader_scale);
872 }
873
874 SkPaint paint;
875 paint.setShader(shader);
876 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
877
878 // CreateBitmapShader returns a Shader with a reference count of one, we
879 // need to unref after paint takes ownership of the shader.
880 shader->unref();
881 canvas->save();
882 canvas->translate(SkIntToScalar(dest_x - src_x),
883 SkIntToScalar(dest_y - src_y));
884 canvas->clipRect(SkRect::MakeXYWH(src_x, src_y, w, h));
885 canvas->drawPaint(paint);
886 canvas->restore();
887 }
888
889 SkColor NativeThemeBase::SaturateAndBrighten(SkScalar* hsv,
890 SkScalar saturate_amount,
891 SkScalar brighten_amount) const {
892 SkScalar color[3];
893 color[0] = hsv[0];
894 color[1] = Clamp(hsv[1] + saturate_amount, 0.0, 1.0);
895 color[2] = Clamp(hsv[2] + brighten_amount, 0.0, 1.0);
896 return SkHSVToColor(color);
897 }
898
899 void NativeThemeBase::DrawVertLine(SkCanvas* canvas,
900 int x,
901 int y1,
902 int y2,
903 const SkPaint& paint) const {
904 SkIRect skrect;
905 skrect.set(x, y1, x + 1, y2 + 1);
906 canvas->drawIRect(skrect, paint);
907 }
908
909 void NativeThemeBase::DrawHorizLine(SkCanvas* canvas,
910 int x1,
911 int x2,
912 int y,
913 const SkPaint& paint) const {
914 SkIRect skrect;
915 skrect.set(x1, y, x2 + 1, y + 1);
916 canvas->drawIRect(skrect, paint);
917 }
918
919 void NativeThemeBase::DrawBox(SkCanvas* canvas,
920 const gfx::Rect& rect,
921 const SkPaint& paint) const {
922 const int right = rect.x() + rect.width() - 1;
923 const int bottom = rect.y() + rect.height() - 1;
924 DrawHorizLine(canvas, rect.x(), right, rect.y(), paint);
925 DrawVertLine(canvas, right, rect.y(), bottom, paint);
926 DrawHorizLine(canvas, rect.x(), right, bottom, paint);
927 DrawVertLine(canvas, rect.x(), rect.y(), bottom, paint);
928 }
929
930 SkScalar NativeThemeBase::Clamp(SkScalar value,
931 SkScalar min,
932 SkScalar max) const {
933 return std::min(std::max(value, min), max);
934 }
935
936 SkColor NativeThemeBase::OutlineColor(SkScalar* hsv1, SkScalar* hsv2) const {
937 // GTK Theme engines have way too much control over the layout of
938 // the scrollbar. We might be able to more closely approximate its
939 // look-and-feel, if we sent whole images instead of just colors
940 // from the browser to the renderer. But even then, some themes
941 // would just break.
942 //
943 // So, instead, we don't even try to 100% replicate the look of
944 // the native scrollbar. We render our own version, but we make
945 // sure to pick colors that blend in nicely with the system GTK
946 // theme. In most cases, we can just sample a couple of pixels
947 // from the system scrollbar and use those colors to draw our
948 // scrollbar.
949 //
950 // This works fine for the track color and the overall thumb
951 // color. But it fails spectacularly for the outline color used
952 // around the thumb piece. Not all themes have a clearly defined
953 // outline. For some of them it is partially transparent, and for
954 // others the thickness is very unpredictable.
955 //
956 // So, instead of trying to approximate the system theme, we
957 // instead try to compute a reasonable looking choice based on the
958 // known color of the track and the thumb piece. This is difficult
959 // when trying to deal both with high- and low-contrast themes,
960 // and both with positive and inverted themes.
961 //
962 // The following code has been tested to look OK with all of the
963 // default GTK themes.
964 SkScalar min_diff = Clamp((hsv1[1] + hsv2[1]) * 1.2f, 0.28f, 0.5f);
965 SkScalar diff = Clamp(fabs(hsv1[2] - hsv2[2]) / 2, min_diff, 0.5f);
966
967 if (hsv1[2] + hsv2[2] > 1.0)
968 diff = -diff;
969
970 return SaturateAndBrighten(hsv2, -0.2f, diff);
971 }
972
973 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/native_theme/native_theme_base.h ('k') | ui/base/native_theme/native_theme_gtk.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698