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

Side by Side Diff: ui/gfx/native_theme_android.cc

Issue 10310136: ui: Move NativeTheme files into ui/base/native_theme/ directory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix win 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/gfx/native_theme_android.h ('k') | ui/gfx/native_theme_aura.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/gfx/native_theme_android.h"
6
7 #include <limits>
8
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "grit/gfx_resources.h"
12 #include "third_party/skia/include/effects/SkGradientShader.h"
13 #include "ui/base/resource/resource_bundle.h"
14 #include "ui/gfx/color_utils.h"
15 #include "ui/gfx/rect.h"
16 #include "ui/gfx/size.h"
17
18 namespace gfx {
19
20 static const unsigned int kButtonLength = 14;
21 static const unsigned int kScrollbarWidth = 15;
22 static const unsigned int kThumbInactiveColor = 0xeaeaea;
23 static const unsigned int kTrackColor= 0xd3d3d3;
24
25 // These are the default dimensions of radio buttons and checkboxes.
26 static const int kCheckboxAndRadioWidth = 13;
27 static const int kCheckboxAndRadioHeight = 13;
28
29 // These sizes match the sizes in Chromium Win.
30 static const int kSliderThumbWidth = 11;
31 static const int kSliderThumbHeight = 21;
32
33 static const SkColor kSliderTrackBackgroundColor =
34 SkColorSetRGB(0xe3, 0xdd, 0xd8);
35 static const SkColor kSliderThumbLightGrey = SkColorSetRGB(0xf4, 0xf2, 0xef);
36 static const SkColor kSliderThumbDarkGrey = SkColorSetRGB(0xea, 0xe5, 0xe0);
37 static const SkColor kSliderThumbBorderDarkGrey =
38 SkColorSetRGB(0x9d, 0x96, 0x8e);
39
40 // Get lightness adjusted color.
41 static SkColor BrightenColor(const color_utils::HSL& hsl,
42 SkAlpha alpha,
43 double lightness_amount) {
44 color_utils::HSL adjusted = hsl;
45 adjusted.l += lightness_amount;
46 if (adjusted.l > 1.0)
47 adjusted.l = 1.0;
48 if (adjusted.l < 0.0)
49 adjusted.l = 0.0;
50
51 return color_utils::HSLToSkColor(adjusted, alpha);
52 }
53
54 // static
55 const NativeTheme* NativeTheme::instance() {
56 return NativeThemeAndroid::instance();
57 }
58
59 // static
60 const NativeThemeAndroid* NativeThemeAndroid::instance() {
61 CR_DEFINE_STATIC_LOCAL(NativeThemeAndroid, s_native_theme, ());
62 return &s_native_theme;
63 }
64
65 gfx::Size NativeThemeAndroid::GetPartSize(Part part,
66 State state,
67 const ExtraParams& extra) const {
68 switch (part) {
69 case kScrollbarDownArrow:
70 case kScrollbarUpArrow:
71 return gfx::Size(kScrollbarWidth, kButtonLength);
72 case kScrollbarLeftArrow:
73 case kScrollbarRightArrow:
74 return gfx::Size(kButtonLength, kScrollbarWidth);
75 case kCheckbox:
76 case kRadio:
77 return gfx::Size(kCheckboxAndRadioWidth, kCheckboxAndRadioHeight);
78 case kSliderThumb:
79 // These sizes match the sizes in Chromium Win.
80 return gfx::Size(kSliderThumbWidth, kSliderThumbHeight);
81 case kInnerSpinButton:
82 return gfx::Size(kScrollbarWidth, 0);
83 case kPushButton:
84 case kTextField:
85 case kMenuList:
86 case kSliderTrack:
87 case kProgressBar:
88 return gfx::Size(); // No default size.
89 default:
90 NOTREACHED();
91 }
92 return gfx::Size();
93 }
94
95 void NativeThemeAndroid::Paint(SkCanvas* canvas,
96 Part part,
97 State state,
98 const gfx::Rect& rect,
99 const ExtraParams& extra) const {
100 switch (part) {
101 case kScrollbarDownArrow:
102 case kScrollbarUpArrow:
103 case kScrollbarLeftArrow:
104 case kScrollbarRightArrow:
105 PaintArrowButton(canvas, rect, part, state);
106 break;
107 case kCheckbox:
108 PaintCheckbox(canvas, state, rect, extra.button);
109 break;
110 case kRadio:
111 PaintRadio(canvas, state, rect, extra.button);
112 break;
113 case kPushButton:
114 PaintButton(canvas, state, rect, extra.button);
115 break;
116 case kTextField:
117 PaintTextField(canvas, state, rect, extra.text_field);
118 break;
119 case kMenuList:
120 PaintMenuList(canvas, state, rect, extra.menu_list);
121 break;
122 case kSliderTrack:
123 PaintSliderTrack(canvas, state, rect, extra.slider);
124 break;
125 case kSliderThumb:
126 PaintSliderThumb(canvas, state, rect, extra.slider);
127 break;
128 case kInnerSpinButton:
129 PaintInnerSpinButton(canvas, state, rect, extra.inner_spin);
130 break;
131 case kProgressBar:
132 PaintProgressBar(canvas, state, rect, extra.progress_bar);
133 break;
134 default:
135 NOTREACHED();
136 }
137 }
138
139 SkColor NativeThemeAndroid::GetSystemColor(ColorId color_id) const {
140 NOTIMPLEMENTED();
141 return SK_ColorBLACK;
142 }
143
144 NativeThemeAndroid::NativeThemeAndroid() {
145 }
146
147 NativeThemeAndroid::~NativeThemeAndroid() {
148 }
149
150 void NativeThemeAndroid::PaintArrowButton(SkCanvas* canvas,
151 const gfx::Rect& rect,
152 Part direction,
153 State state) const {
154 int widthMiddle;
155 int lengthMiddle;
156 SkPaint paint;
157 if (direction == kScrollbarUpArrow || direction == kScrollbarDownArrow) {
158 widthMiddle = rect.width() / 2 + 1;
159 lengthMiddle = rect.height() / 2 + 1;
160 } else {
161 lengthMiddle = rect.width() / 2 + 1;
162 widthMiddle = rect.height() / 2 + 1;
163 }
164
165 // Calculate button color.
166 SkScalar trackHSV[3];
167 SkColorToHSV(kTrackColor, trackHSV);
168 SkColor buttonColor = SaturateAndBrighten(trackHSV, 0, 0.2);
169 SkColor backgroundColor = buttonColor;
170 if (state == kPressed) {
171 SkScalar buttonHSV[3];
172 SkColorToHSV(buttonColor, buttonHSV);
173 buttonColor = SaturateAndBrighten(buttonHSV, 0, -0.1);
174 } else if (state == kHovered) {
175 SkScalar buttonHSV[3];
176 SkColorToHSV(buttonColor, buttonHSV);
177 buttonColor = SaturateAndBrighten(buttonHSV, 0, 0.05);
178 }
179
180 SkIRect skrect;
181 skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y()
182 + rect.height());
183 // Paint the background (the area visible behind the rounded corners).
184 paint.setColor(backgroundColor);
185 canvas->drawIRect(skrect, paint);
186
187 // Paint the button's outline and fill the middle
188 SkPath outline;
189 switch (direction) {
190 case kScrollbarUpArrow:
191 outline.moveTo(rect.x() + 0.5, rect.y() + rect.height() + 0.5);
192 outline.rLineTo(0, -(rect.height() - 2));
193 outline.rLineTo(2, -2);
194 outline.rLineTo(rect.width() - 5, 0);
195 outline.rLineTo(2, 2);
196 outline.rLineTo(0, rect.height() - 2);
197 break;
198 case kScrollbarDownArrow:
199 outline.moveTo(rect.x() + 0.5, rect.y() - 0.5);
200 outline.rLineTo(0, rect.height() - 2);
201 outline.rLineTo(2, 2);
202 outline.rLineTo(rect.width() - 5, 0);
203 outline.rLineTo(2, -2);
204 outline.rLineTo(0, -(rect.height() - 2));
205 break;
206 case kScrollbarRightArrow:
207 outline.moveTo(rect.x() - 0.5, rect.y() + 0.5);
208 outline.rLineTo(rect.width() - 2, 0);
209 outline.rLineTo(2, 2);
210 outline.rLineTo(0, rect.height() - 5);
211 outline.rLineTo(-2, 2);
212 outline.rLineTo(-(rect.width() - 2), 0);
213 break;
214 case kScrollbarLeftArrow:
215 outline.moveTo(rect.x() + rect.width() + 0.5, rect.y() + 0.5);
216 outline.rLineTo(-(rect.width() - 2), 0);
217 outline.rLineTo(-2, 2);
218 outline.rLineTo(0, rect.height() - 5);
219 outline.rLineTo(2, 2);
220 outline.rLineTo(rect.width() - 2, 0);
221 break;
222 default:
223 break;
224 }
225 outline.close();
226
227 paint.setStyle(SkPaint::kFill_Style);
228 paint.setColor(buttonColor);
229 canvas->drawPath(outline, paint);
230
231 paint.setAntiAlias(true);
232 paint.setStyle(SkPaint::kStroke_Style);
233 SkScalar thumbHSV[3];
234 SkColorToHSV(kThumbInactiveColor, thumbHSV);
235 paint.setColor(OutlineColor(trackHSV, thumbHSV));
236 canvas->drawPath(outline, paint);
237
238 // If the button is disabled or read-only, the arrow is drawn with the
239 // outline color.
240 if (state != kDisabled)
241 paint.setColor(SK_ColorBLACK);
242
243 paint.setAntiAlias(false);
244 paint.setStyle(SkPaint::kFill_Style);
245
246 SkPath path;
247 // The constants in this block of code are hand-tailored to produce good
248 // looking arrows without anti-aliasing.
249 switch (direction) {
250 case kScrollbarUpArrow:
251 path.moveTo(rect.x() + widthMiddle - 4, rect.y() + lengthMiddle + 2);
252 path.rLineTo(7, 0);
253 path.rLineTo(-4, -4);
254 break;
255 case kScrollbarDownArrow:
256 path.moveTo(rect.x() + widthMiddle - 4, rect.y() + lengthMiddle - 3);
257 path.rLineTo(7, 0);
258 path.rLineTo(-4, 4);
259 break;
260 case kScrollbarRightArrow:
261 path.moveTo(rect.x() + lengthMiddle - 3, rect.y() + widthMiddle - 4);
262 path.rLineTo(0, 7);
263 path.rLineTo(4, -4);
264 break;
265 case kScrollbarLeftArrow:
266 path.moveTo(rect.x() + lengthMiddle + 1, rect.y() + widthMiddle - 5);
267 path.rLineTo(0, 9);
268 path.rLineTo(-4, -4);
269 break;
270 default:
271 break;
272 }
273 path.close();
274
275 canvas->drawPath(path, paint);
276 }
277
278 void NativeThemeAndroid::PaintCheckbox(SkCanvas* canvas,
279 State state,
280 const gfx::Rect& rect,
281 const ButtonExtraParams& button) const {
282 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
283 SkBitmap* image = NULL;
284 if (button.indeterminate) {
285 image = state == kDisabled ?
286 rb.GetBitmapNamed(IDR_CHECKBOX_DISABLED_INDETERMINATE) :
287 rb.GetBitmapNamed(IDR_CHECKBOX_INDETERMINATE);
288 } else if (button.checked) {
289 image = state == kDisabled ?
290 rb.GetBitmapNamed(IDR_CHECKBOX_DISABLED_ON) :
291 rb.GetBitmapNamed(IDR_CHECKBOX_ON);
292 } else {
293 image = state == kDisabled ?
294 rb.GetBitmapNamed(IDR_CHECKBOX_DISABLED_OFF) :
295 rb.GetBitmapNamed(IDR_CHECKBOX_OFF);
296 }
297
298 gfx::Rect bounds = rect.Center(gfx::Size(image->width(), image->height()));
299 DrawBitmapInt(canvas, *image, 0, 0, image->width(), image->height(),
300 bounds.x(), bounds.y(), bounds.width(), bounds.height());
301 }
302
303 void NativeThemeAndroid::PaintRadio(SkCanvas* canvas,
304 State state,
305 const gfx::Rect& rect,
306 const ButtonExtraParams& button) const {
307 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
308 SkBitmap* image = NULL;
309 if (state == kDisabled) {
310 image = button.checked ?
311 rb.GetBitmapNamed(IDR_RADIO_DISABLED_ON) :
312 rb.GetBitmapNamed(IDR_RADIO_DISABLED_OFF);
313 } else {
314 image = button.checked ?
315 rb.GetBitmapNamed(IDR_RADIO_ON) :
316 rb.GetBitmapNamed(IDR_RADIO_OFF);
317 }
318
319 gfx::Rect bounds = rect.Center(gfx::Size(image->width(), image->height()));
320 DrawBitmapInt(canvas, *image, 0, 0, image->width(), image->height(),
321 bounds.x(), bounds.y(), bounds.width(), bounds.height());
322 }
323
324 void NativeThemeAndroid::PaintButton(SkCanvas* canvas,
325 State state,
326 const gfx::Rect& rect,
327 const ButtonExtraParams& button) const {
328 SkPaint paint;
329 SkRect skrect;
330 int kRight = rect.right();
331 int kBottom = rect.bottom();
332 SkColor base_color = button.background_color;
333
334 color_utils::HSL base_hsl;
335 color_utils::SkColorToHSL(base_color, &base_hsl);
336
337 // Our standard gradient is from 0xdd to 0xf8. This is the amount of
338 // increased luminance between those values.
339 SkColor light_color(BrightenColor(base_hsl, SkColorGetA(base_color), 0.105));
340
341 // If the button is too small, fallback to drawing a single, solid color
342 if (rect.width() < 5 || rect.height() < 5) {
343 paint.setColor(base_color);
344 skrect.set(rect.x(), rect.y(), kRight, kBottom);
345 canvas->drawRect(skrect, paint);
346 return;
347 }
348
349 if (button.has_border) {
350 int kBorderAlpha = state == kHovered ? 0x80 : 0x55;
351 paint.setARGB(kBorderAlpha, 0, 0, 0);
352 canvas->drawLine(rect.x() + 1, rect.y(), kRight - 1, rect.y(), paint);
353 canvas->drawLine(kRight - 1, rect.y() + 1, kRight - 1, kBottom - 1, paint);
354 canvas->drawLine(rect.x() + 1, kBottom - 1, kRight - 1, kBottom - 1, paint);
355 canvas->drawLine(rect.x(), rect.y() + 1, rect.x(), kBottom - 1, paint);
356 }
357
358 paint.setColor(SK_ColorBLACK);
359 int kLightEnd = state == kPressed ? 1 : 0;
360 int kDarkEnd = !kLightEnd;
361 SkPoint gradient_bounds[2];
362 gradient_bounds[kLightEnd].iset(rect.x(), rect.y());
363 gradient_bounds[kDarkEnd].iset(rect.x(), kBottom - 1);
364 SkColor colors[2];
365 colors[0] = light_color;
366 colors[1] = base_color;
367
368 SkShader* shader = SkGradientShader::CreateLinear(
369 gradient_bounds, colors, NULL, 2, SkShader::kClamp_TileMode, NULL);
370 paint.setStyle(SkPaint::kFill_Style);
371 paint.setShader(shader);
372 shader->unref();
373
374 if (button.has_border) {
375 skrect.set(rect.x() + 1, rect.y() + 1, kRight - 1, kBottom - 1);
376 } else {
377 skrect.set(rect.x(), rect.y(), kRight, kBottom);
378 }
379 canvas->drawRect(skrect, paint);
380 paint.setShader(NULL);
381
382 if (button.has_border) {
383 paint.setColor(BrightenColor(base_hsl, SkColorGetA(base_color), -0.0588));
384 canvas->drawPoint(rect.x() + 1, rect.y() + 1, paint);
385 canvas->drawPoint(kRight - 2, rect.y() + 1, paint);
386 canvas->drawPoint(rect.x() + 1, kBottom - 2, paint);
387 canvas->drawPoint(kRight - 2, kBottom - 2, paint);
388 }
389 }
390
391 void NativeThemeAndroid::PaintTextField(
392 SkCanvas* canvas,
393 State state,
394 const gfx::Rect& rect,
395 const TextFieldExtraParams& text) const {
396 // The following drawing code simulates the user-agent css border for
397 // text area and text input so that we do not break layout tests. Once we
398 // have decided the desired looks, we should update the code here and
399 // the layout test expectations.
400 SkRect bounds;
401 bounds.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1);
402
403 SkPaint fill_paint;
404 fill_paint.setStyle(SkPaint::kFill_Style);
405 fill_paint.setColor(text.background_color);
406 canvas->drawRect(bounds, fill_paint);
407
408 if (text.is_text_area) {
409 // Draw text area border: 1px solid black
410 SkPaint stroke_paint;
411 fill_paint.setStyle(SkPaint::kStroke_Style);
412 fill_paint.setColor(SK_ColorBLACK);
413 canvas->drawRect(bounds, fill_paint);
414 } else {
415 // Draw text input and listbox inset border
416 // Text Input: 2px inset #eee
417 // Listbox: 1px inset #808080
418 SkColor kLightColor = text.is_listbox ?
419 SkColorSetRGB(0x80, 0x80, 0x80) : SkColorSetRGB(0xee, 0xee, 0xee);
420 SkColor kDarkColor = text.is_listbox ?
421 SkColorSetRGB(0x2c, 0x2c, 0x2c) : SkColorSetRGB(0x9a, 0x9a, 0x9a);
422 int kBorderWidth = text.is_listbox ? 1 : 2;
423
424 SkPaint dark_paint;
425 dark_paint.setAntiAlias(true);
426 dark_paint.setStyle(SkPaint::kFill_Style);
427 dark_paint.setColor(kDarkColor);
428
429 SkPaint light_paint;
430 light_paint.setAntiAlias(true);
431 light_paint.setStyle(SkPaint::kFill_Style);
432 light_paint.setColor(kLightColor);
433
434 int left = rect.x();
435 int top = rect.y();
436 int right = rect.right();
437 int bottom = rect.bottom();
438
439 SkPath path;
440 path.incReserve(4);
441
442 // Top
443 path.moveTo(SkIntToScalar(left), SkIntToScalar(top));
444 path.lineTo(SkIntToScalar(left + kBorderWidth),
445 SkIntToScalar(top + kBorderWidth));
446 path.lineTo(SkIntToScalar(right - kBorderWidth),
447 SkIntToScalar(top + kBorderWidth));
448 path.lineTo(SkIntToScalar(right), SkIntToScalar(top));
449 canvas->drawPath(path, dark_paint);
450
451 // Bottom
452 path.reset();
453 path.moveTo(SkIntToScalar(left + kBorderWidth),
454 SkIntToScalar(bottom - kBorderWidth));
455 path.lineTo(SkIntToScalar(left), SkIntToScalar(bottom));
456 path.lineTo(SkIntToScalar(right), SkIntToScalar(bottom));
457 path.lineTo(SkIntToScalar(right - kBorderWidth),
458 SkIntToScalar(bottom - kBorderWidth));
459 canvas->drawPath(path, light_paint);
460
461 // Left
462 path.reset();
463 path.moveTo(SkIntToScalar(left), SkIntToScalar(top));
464 path.lineTo(SkIntToScalar(left), SkIntToScalar(bottom));
465 path.lineTo(SkIntToScalar(left + kBorderWidth),
466 SkIntToScalar(bottom - kBorderWidth));
467 path.lineTo(SkIntToScalar(left + kBorderWidth),
468 SkIntToScalar(top + kBorderWidth));
469 canvas->drawPath(path, dark_paint);
470
471 // Right
472 path.reset();
473 path.moveTo(SkIntToScalar(right - kBorderWidth),
474 SkIntToScalar(top + kBorderWidth));
475 path.lineTo(SkIntToScalar(right - kBorderWidth), SkIntToScalar(bottom));
476 path.lineTo(SkIntToScalar(right), SkIntToScalar(bottom));
477 path.lineTo(SkIntToScalar(right), SkIntToScalar(top));
478 canvas->drawPath(path, light_paint);
479 }
480 }
481
482 void NativeThemeAndroid::PaintMenuList(
483 SkCanvas* canvas,
484 State state,
485 const gfx::Rect& rect,
486 const MenuListExtraParams& menu_list) const {
487 // If a border radius is specified, we let the WebCore paint the background
488 // and the border of the control.
489 if (!menu_list.has_border_radius) {
490 ButtonExtraParams button = { 0 };
491 button.background_color = menu_list.background_color;
492 button.has_border = menu_list.has_border;
493 PaintButton(canvas, state, rect, button);
494 }
495
496 SkPaint paint;
497 paint.setColor(SK_ColorBLACK);
498 paint.setAntiAlias(true);
499 paint.setStyle(SkPaint::kFill_Style);
500
501 SkPath path;
502 path.moveTo(menu_list.arrow_x, menu_list.arrow_y - 3);
503 path.rLineTo(6, 0);
504 path.rLineTo(-3, 6);
505 path.close();
506 canvas->drawPath(path, paint);
507 }
508
509 void NativeThemeAndroid::PaintSliderTrack(
510 SkCanvas* canvas,
511 State state,
512 const gfx::Rect& rect,
513 const SliderExtraParams& slider) const {
514 int kMidX = rect.x() + rect.width() / 2;
515 int kMidY = rect.y() + rect.height() / 2;
516
517 SkPaint paint;
518 paint.setColor(kSliderTrackBackgroundColor);
519
520 SkRect skrect;
521 if (slider.vertical) {
522 skrect.set(std::max(rect.x(), kMidX - 2),
523 rect.y(),
524 std::min(rect.right(), kMidX + 2),
525 rect.bottom());
526 } else {
527 skrect.set(rect.x(),
528 std::max(rect.y(), kMidY - 2),
529 rect.right(),
530 std::min(rect.bottom(), kMidY + 2));
531 }
532 canvas->drawRect(skrect, paint);
533 }
534
535 void NativeThemeAndroid::PaintSliderThumb(
536 SkCanvas* canvas,
537 State state,
538 const gfx::Rect& rect,
539 const SliderExtraParams& slider) const {
540 bool hovered = (state == kHovered) || slider.in_drag;
541 int kMidX = rect.x() + rect.width() / 2;
542 int kMidY = rect.y() + rect.height() / 2;
543
544 SkPaint paint;
545 paint.setColor(hovered ? SK_ColorWHITE : kSliderThumbLightGrey);
546
547 SkIRect skrect;
548 if (slider.vertical)
549 skrect.set(rect.x(), rect.y(), kMidX + 1, rect.bottom());
550 else
551 skrect.set(rect.x(), rect.y(), rect.right(), kMidY + 1);
552
553 canvas->drawIRect(skrect, paint);
554
555 paint.setColor(hovered ? kSliderThumbLightGrey : kSliderThumbDarkGrey);
556
557 if (slider.vertical)
558 skrect.set(kMidX + 1, rect.y(), rect.right(), rect.bottom());
559 else
560 skrect.set(rect.x(), kMidY + 1, rect.right(), rect.bottom());
561
562 canvas->drawIRect(skrect, paint);
563
564 paint.setColor(kSliderThumbBorderDarkGrey);
565 DrawBox(canvas, rect, paint);
566
567 if (rect.height() > 10 && rect.width() > 10) {
568 DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY, paint);
569 DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY - 3, paint);
570 DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY + 3, paint);
571 }
572 }
573
574 void NativeThemeAndroid::PaintInnerSpinButton(
575 SkCanvas* canvas,
576 State state,
577 const gfx::Rect& rect,
578 const InnerSpinButtonExtraParams& spin_button) const {
579 if (spin_button.read_only)
580 state = kDisabled;
581
582 State north_state = state;
583 State south_state = state;
584 if (spin_button.spin_up)
585 south_state = south_state != kDisabled ? kNormal : kDisabled;
586 else
587 north_state = north_state != kDisabled ? kNormal : kDisabled;
588
589 gfx::Rect half = rect;
590 half.set_height(rect.height() / 2);
591 PaintArrowButton(canvas, half, kScrollbarUpArrow, north_state);
592
593 half.set_y(rect.y() + rect.height() / 2);
594 PaintArrowButton(canvas, half, kScrollbarDownArrow, south_state);
595 }
596
597 void NativeThemeAndroid::PaintProgressBar(
598 SkCanvas* canvas,
599 State state,
600 const gfx::Rect& rect,
601 const ProgressBarExtraParams& progress_bar) const {
602 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
603 SkBitmap* bar_image = rb.GetBitmapNamed(IDR_PROGRESS_BAR);
604 SkBitmap* left_border_image = rb.GetBitmapNamed(IDR_PROGRESS_BORDER_LEFT);
605 SkBitmap* right_border_image = rb.GetBitmapNamed(IDR_PROGRESS_BORDER_RIGHT);
606
607 double tile_scale = static_cast<double>(rect.height()) /
608 bar_image->height();
609
610 int new_tile_width = static_cast<int>(bar_image->width() * tile_scale);
611 double tile_scale_x = static_cast<double>(new_tile_width) /
612 bar_image->width();
613
614 DrawTiledImage(canvas, *bar_image, 0, 0, tile_scale_x, tile_scale,
615 rect.x(), rect.y(), rect.width(), rect.height());
616
617 if (progress_bar.value_rect_width) {
618 SkBitmap* value_image = rb.GetBitmapNamed(IDR_PROGRESS_VALUE);
619
620 new_tile_width = static_cast<int>(value_image->width() * tile_scale);
621 tile_scale_x = static_cast<double>(new_tile_width) /
622 value_image->width();
623
624 DrawTiledImage(canvas, *value_image, 0, 0, tile_scale_x, tile_scale,
625 progress_bar.value_rect_x,
626 progress_bar.value_rect_y,
627 progress_bar.value_rect_width,
628 progress_bar.value_rect_height);
629 }
630
631 int dest_left_border_width = static_cast<int>(left_border_image->width() *
632 tile_scale);
633 SkRect dest_rect;
634 dest_rect.iset(rect.x(), rect.y(), rect.x() + dest_left_border_width,
635 rect.bottom());
636 canvas->drawBitmapRect(*left_border_image, NULL, dest_rect);
637
638 int dest_right_border_width = static_cast<int>(right_border_image->width() *
639 tile_scale);
640 dest_rect.iset(rect.right() - dest_right_border_width, rect.y(), rect.right(),
641 rect.bottom());
642 canvas->drawBitmapRect(*right_border_image, NULL, dest_rect);
643 }
644
645 bool NativeThemeAndroid::IntersectsClipRectInt(SkCanvas* canvas,
646 int x,
647 int y,
648 int w,
649 int h) const {
650 SkRect clip;
651 return canvas->getClipBounds(&clip) &&
652 clip.intersect(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w),
653 SkIntToScalar(y + h));
654 }
655
656 void NativeThemeAndroid::DrawBitmapInt(SkCanvas* canvas,
657 const SkBitmap& bitmap,
658 int src_x,
659 int src_y,
660 int src_w,
661 int src_h,
662 int dest_x,
663 int dest_y,
664 int dest_w,
665 int dest_h) const {
666 DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
667 src_y + src_h < std::numeric_limits<int16_t>::max());
668 if (src_w <= 0 || src_h <= 0 || dest_w <= 0 || dest_h <= 0) {
669 NOTREACHED() << "Attempting to draw bitmap to/from an empty rect!";
670 return;
671 }
672
673 if (!IntersectsClipRectInt(canvas, dest_x, dest_y, dest_w, dest_h))
674 return;
675
676 SkRect dest_rect = { SkIntToScalar(dest_x),
677 SkIntToScalar(dest_y),
678 SkIntToScalar(dest_x + dest_w),
679 SkIntToScalar(dest_y + dest_h) };
680
681 if (src_w == dest_w && src_h == dest_h) {
682 // Workaround for apparent bug in Skia that causes image to occasionally
683 // shift.
684 SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
685 canvas->drawBitmapRect(bitmap, &src_rect, dest_rect);
686 return;
687 }
688
689 // Make a bitmap shader that contains the bitmap we want to draw. This is
690 // basically what SkCanvas.drawBitmap does internally, but it gives us
691 // more control over quality and will use the mipmap in the source image if
692 // it has one, whereas drawBitmap won't.
693 SkShader* shader = SkShader::CreateBitmapShader(bitmap,
694 SkShader::kRepeat_TileMode,
695 SkShader::kRepeat_TileMode);
696 SkMatrix shader_scale;
697 shader_scale.setScale(SkFloatToScalar(static_cast<float>(dest_w) / src_w),
698 SkFloatToScalar(static_cast<float>(dest_h) / src_h));
699 shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
700 shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
701 shader->setLocalMatrix(shader_scale);
702
703 // The rect will be filled by the bitmap.
704 SkPaint p;
705 p.setFilterBitmap(true);
706 p.setShader(shader);
707 shader->unref();
708 canvas->drawRect(dest_rect, p);
709 }
710
711 void NativeThemeAndroid::DrawTiledImage(SkCanvas* canvas,
712 const SkBitmap& bitmap,
713 int src_x,
714 int src_y,
715 double tile_scale_x,
716 double tile_scale_y,
717 int dest_x,
718 int dest_y,
719 int w,
720 int h) const {
721 SkShader* shader = SkShader::CreateBitmapShader(bitmap,
722 SkShader::kRepeat_TileMode,
723 SkShader::kRepeat_TileMode);
724 if (tile_scale_x != 1.0 || tile_scale_y != 1.0) {
725 SkMatrix shader_scale;
726 shader_scale.setScale(SkDoubleToScalar(tile_scale_x),
727 SkDoubleToScalar(tile_scale_y));
728 shader->setLocalMatrix(shader_scale);
729 }
730
731 SkPaint paint;
732 paint.setShader(shader);
733 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
734
735 // CreateBitmapShader returns a Shader with a reference count of one, we
736 // need to unref after paint takes ownership of the shader.
737 shader->unref();
738 canvas->save();
739 canvas->translate(SkIntToScalar(dest_x - src_x),
740 SkIntToScalar(dest_y - src_y));
741 canvas->clipRect(SkRect::MakeXYWH(src_x, src_y, w, h));
742 canvas->drawPaint(paint);
743 canvas->restore();
744 }
745
746 SkColor NativeThemeAndroid::SaturateAndBrighten(
747 SkScalar* hsv,
748 SkScalar saturate_amount,
749 SkScalar brighten_amount) const {
750 SkScalar color[3];
751 color[0] = hsv[0];
752 color[1] = Clamp(hsv[1] + saturate_amount, 0.0, 1.0);
753 color[2] = Clamp(hsv[2] + brighten_amount, 0.0, 1.0);
754 return SkHSVToColor(color);
755 }
756
757 SkScalar NativeThemeAndroid::Clamp(SkScalar value,
758 SkScalar min,
759 SkScalar max) const {
760 return std::min(std::max(value, min), max);
761 }
762
763 void NativeThemeAndroid::DrawVertLine(SkCanvas* canvas,
764 int x,
765 int y1,
766 int y2,
767 const SkPaint& paint) const {
768 SkIRect skrect;
769 skrect.set(x, y1, x + 1, y2 + 1);
770 canvas->drawIRect(skrect, paint);
771 }
772
773 void NativeThemeAndroid::DrawHorizLine(SkCanvas* canvas,
774 int x1,
775 int x2,
776 int y,
777 const SkPaint& paint) const {
778 SkIRect skrect;
779 skrect.set(x1, y, x2 + 1, y + 1);
780 canvas->drawIRect(skrect, paint);
781 }
782
783 void NativeThemeAndroid::DrawBox(SkCanvas* canvas,
784 const gfx::Rect& rect,
785 const SkPaint& paint) const {
786 int right = rect.x() + rect.width() - 1;
787 int bottom = rect.y() + rect.height() - 1;
788 DrawHorizLine(canvas, rect.x(), right, rect.y(), paint);
789 DrawVertLine(canvas, right, rect.y(), bottom, paint);
790 DrawHorizLine(canvas, rect.x(), right, bottom, paint);
791 DrawVertLine(canvas, rect.x(), rect.y(), bottom, paint);
792 }
793
794 SkColor NativeThemeAndroid::OutlineColor(SkScalar* hsv1, SkScalar* hsv2) const {
795 SkScalar min_diff = Clamp((hsv1[1] + hsv2[1]) * 1.2, 0.28, 0.5);
796 SkScalar diff = Clamp(fabs(hsv1[2] - hsv2[2]) / 2, min_diff, 0.5);
797
798 if (hsv1[2] + hsv2[2] > 1.0)
799 diff = -diff;
800
801 return SaturateAndBrighten(hsv2, -0.2, diff);
802 }
803
804 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/native_theme_android.h ('k') | ui/gfx/native_theme_aura.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698