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

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

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

Powered by Google App Engine
This is Rietveld 408576698