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

Side by Side Diff: ui/views/bubble/bubble_border.cc

Issue 2343913003: Implement Harmony spec for dialog/bubble borders. (Closed)
Patch Set: compile fix Created 4 years, 3 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
« no previous file with comments | « ui/views/bubble/bubble_border.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/bubble/bubble_border.h" 5 #include "ui/views/bubble/bubble_border.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "third_party/skia/include/core/SkDrawLooper.h"
10 #include "third_party/skia/include/core/SkPaint.h" 11 #include "third_party/skia/include/core/SkPaint.h"
11 #include "third_party/skia/include/core/SkPath.h" 12 #include "third_party/skia/include/core/SkPath.h"
13 #include "ui/base/material_design/material_design_controller.h"
12 #include "ui/base/resource/resource_bundle.h" 14 #include "ui/base/resource/resource_bundle.h"
13 #include "ui/gfx/canvas.h" 15 #include "ui/gfx/canvas.h"
14 #include "ui/gfx/geometry/rect.h" 16 #include "ui/gfx/geometry/rect.h"
15 #include "ui/gfx/path.h" 17 #include "ui/gfx/path.h"
18 #include "ui/gfx/scoped_canvas.h"
16 #include "ui/gfx/skia_util.h" 19 #include "ui/gfx/skia_util.h"
17 #include "ui/resources/grit/ui_resources.h" 20 #include "ui/resources/grit/ui_resources.h"
18 #include "ui/views/painter.h" 21 #include "ui/views/painter.h"
19 #include "ui/views/resources/grit/views_resources.h" 22 #include "ui/views/resources/grit/views_resources.h"
20 #include "ui/views/view.h" 23 #include "ui/views/view.h"
21 24
22 namespace views { 25 namespace views {
23 26
24 namespace internal { 27 namespace internal {
25 28
(...skipping 24 matching lines...) Expand all
50 arrow_thickness = top_arrow.height(); 53 arrow_thickness = top_arrow.height();
51 } 54 }
52 } 55 }
53 56
54 BorderImages::~BorderImages() {} 57 BorderImages::~BorderImages() {}
55 58
56 } // namespace internal 59 } // namespace internal
57 60
58 namespace { 61 namespace {
59 62
63 // Blur and offset values for the two shadows drawn around each dialog. The
64 // values are all in dip.
65 const int kSmallShadowVerticalOffset = 2;
66 const int kSmallShadowBlur = 4;
67 const SkColor kSmallShadowColor = SkColorSetA(SK_ColorBLACK, 0x33);
68
69 const int kLargeShadowVerticalOffset = 2;
70 const int kLargeShadowBlur = 6;
71 const SkColor kLargeShadowColor = SkColorSetA(SK_ColorBLACK, 0x1A);
72
73 bool UseMd() {
74 return ui::MaterialDesignController::IsSecondaryUiMaterial();
75 }
76
60 // Bubble border and arrow image resource ids. They don't use the IMAGE_GRID 77 // Bubble border and arrow image resource ids. They don't use the IMAGE_GRID
61 // macro because there is no center image. 78 // macro because there is no center image.
62 const int kNoShadowImages[] = { 79 const int kNoShadowImages[] = {
63 IDR_BUBBLE_TL, IDR_BUBBLE_T, IDR_BUBBLE_TR, 80 IDR_BUBBLE_TL, IDR_BUBBLE_T, IDR_BUBBLE_TR,
64 IDR_BUBBLE_L, 0, IDR_BUBBLE_R, 81 IDR_BUBBLE_L, 0, IDR_BUBBLE_R,
65 IDR_BUBBLE_BL, IDR_BUBBLE_B, IDR_BUBBLE_BR }; 82 IDR_BUBBLE_BL, IDR_BUBBLE_B, IDR_BUBBLE_BR };
66 const int kNoShadowArrows[] = { 83 const int kNoShadowArrows[] = {
67 IDR_BUBBLE_L_ARROW, IDR_BUBBLE_T_ARROW, 84 IDR_BUBBLE_L_ARROW, IDR_BUBBLE_T_ARROW,
68 IDR_BUBBLE_R_ARROW, IDR_BUBBLE_B_ARROW, }; 85 IDR_BUBBLE_R_ARROW, IDR_BUBBLE_B_ARROW, };
69 86
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 } // namespace 153 } // namespace
137 154
138 const int BubbleBorder::kStroke = 1; 155 const int BubbleBorder::kStroke = 1;
139 156
140 BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color) 157 BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
141 : arrow_(arrow), 158 : arrow_(arrow),
142 arrow_offset_(0), 159 arrow_offset_(0),
143 arrow_paint_type_(PAINT_NORMAL), 160 arrow_paint_type_(PAINT_NORMAL),
144 alignment_(ALIGN_ARROW_TO_MID_ANCHOR), 161 alignment_(ALIGN_ARROW_TO_MID_ANCHOR),
145 shadow_(shadow), 162 shadow_(shadow),
163 images_(nullptr),
146 background_color_(color), 164 background_color_(color),
147 use_theme_background_color_(false) { 165 use_theme_background_color_(false) {
148 #if defined(OS_MACOSX) 166 #if defined(OS_MACOSX)
149 // On Mac, use the NO_ASSETS bubble border. WindowServer on Mac is able to 167 // On Mac, use the NO_ASSETS bubble border. WindowServer on Mac is able to
150 // generate drop shadows for dialogs, hence we don't use raster shadows. 168 // generate drop shadows for dialogs, hence we don't use raster shadows.
151 shadow_ = NO_ASSETS; 169 shadow_ = NO_ASSETS;
152 #endif // OS_MACOSX 170 #endif // OS_MACOSX
153 DCHECK(shadow_ < SHADOW_COUNT); 171 DCHECK(shadow_ < SHADOW_COUNT);
154 images_ = GetBorderImages(shadow_); 172 if (UseMd()) {
173 // Harmony bubbles don't use arrows.
174 alignment_ = ALIGN_EDGE_TO_ANCHOR_EDGE;
175 arrow_paint_type_ = PAINT_NONE;
176 } else {
177 images_ = GetBorderImages(shadow_);
178 }
155 } 179 }
156 180
157 BubbleBorder::~BubbleBorder() {} 181 BubbleBorder::~BubbleBorder() {}
158 182
183 void BubbleBorder::set_paint_arrow(ArrowPaintType value) {
184 if (UseMd())
185 return;
186 arrow_paint_type_ = value;
187 }
188
159 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect, 189 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
160 const gfx::Size& contents_size) const { 190 const gfx::Size& contents_size) const {
161 int x = anchor_rect.x(); 191 int x = anchor_rect.x();
162 int y = anchor_rect.y(); 192 int y = anchor_rect.y();
163 int w = anchor_rect.width(); 193 int w = anchor_rect.width();
164 int h = anchor_rect.height(); 194 int h = anchor_rect.height();
165 const gfx::Size size(GetSizeForContentsSize(contents_size)); 195 const gfx::Size size(GetSizeForContentsSize(contents_size));
166 const int arrow_offset = GetArrowOffset(size); 196 const int arrow_offset = GetArrowOffset(size);
167 // |arrow_shift| is necessary to visually align the tip of the bubble arrow 197 // |arrow_shift| is necessary to visually align the tip of the bubble arrow
168 // with the anchor point. This shift is an inverse of the shadow thickness. 198 // with the anchor point. This shift is an inverse of the shadow thickness.
169 int arrow_shift = 199 int arrow_shift = UseMd() ? 0 :
170 images_->arrow_interior_thickness + kStroke - images_->arrow_thickness; 200 images_->arrow_interior_thickness + kStroke - images_->arrow_thickness;
171 // When arrow is painted transparently the visible border of the bubble needs 201 // When arrow is painted transparently the visible border of the bubble needs
172 // to be positioned at the same bounds as when the arrow is shown. 202 // to be positioned at the same bounds as when the arrow is shown.
173 if (arrow_paint_type_ == PAINT_TRANSPARENT) 203 if (arrow_paint_type_ == PAINT_TRANSPARENT)
174 arrow_shift += images_->arrow_interior_thickness; 204 arrow_shift += images_->arrow_interior_thickness;
175 const bool mid_anchor = alignment_ == ALIGN_ARROW_TO_MID_ANCHOR; 205 const bool mid_anchor = alignment_ == ALIGN_ARROW_TO_MID_ANCHOR;
176 206
177 // Calculate the bubble coordinates based on the border and arrow settings. 207 // Calculate the bubble coordinates based on the border and arrow settings.
178 if (is_arrow_on_horizontal(arrow_)) { 208 if (is_arrow_on_horizontal(arrow_)) {
179 if (is_arrow_on_left(arrow_)) { 209 if (is_arrow_on_left(arrow_)) {
(...skipping 19 matching lines...) Expand all
199 } 229 }
200 } else { 230 } else {
201 x += (w - size.width()) / 2; 231 x += (w - size.width()) / 2;
202 y += (arrow_ == NONE) ? h : (h - size.height()) / 2; 232 y += (arrow_ == NONE) ? h : (h - size.height()) / 2;
203 } 233 }
204 234
205 return gfx::Rect(x, y, size.width(), size.height()); 235 return gfx::Rect(x, y, size.width(), size.height());
206 } 236 }
207 237
208 int BubbleBorder::GetBorderThickness() const { 238 int BubbleBorder::GetBorderThickness() const {
209 return images_->border_thickness - images_->border_interior_thickness; 239 // TODO(estade): this shouldn't be called in MD.
240 return UseMd()
241 ? 0
242 : images_->border_thickness - images_->border_interior_thickness;
210 } 243 }
211 244
212 int BubbleBorder::GetBorderCornerRadius() const { 245 int BubbleBorder::GetBorderCornerRadius() const {
213 return images_->corner_radius; 246 return UseMd() ? 3 : images_->corner_radius;
214 } 247 }
215 248
216 int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const { 249 int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const {
250 if (UseMd())
251 return 0;
252
217 const int edge_length = is_arrow_on_horizontal(arrow_) ? 253 const int edge_length = is_arrow_on_horizontal(arrow_) ?
218 border_size.width() : border_size.height(); 254 border_size.width() : border_size.height();
219 if (is_arrow_at_center(arrow_) && arrow_offset_ == 0) 255 if (is_arrow_at_center(arrow_) && arrow_offset_ == 0)
220 return edge_length / 2; 256 return edge_length / 2;
221 257
222 // Calculate the minimum offset to not overlap arrow and corner images. 258 // Calculate the minimum offset to not overlap arrow and corner images.
223 const int min = images_->border_thickness + (images_->arrow_width / 2); 259 const int min = images_->border_thickness + (images_->arrow_width / 2);
224 // Ensure the returned value will not cause image overlap, if possible. 260 // Ensure the returned value will not cause image overlap, if possible.
225 return std::max(min, std::min(arrow_offset_, edge_length - min)); 261 return std::max(min, std::min(arrow_offset_, edge_length - min));
226 } 262 }
227 263
228 bool BubbleBorder::GetArrowPath(const gfx::Rect& view_bounds, 264 bool BubbleBorder::GetArrowPath(const gfx::Rect& view_bounds,
229 gfx::Path* path) const { 265 gfx::Path* path) const {
230 if (!has_arrow(arrow_) || arrow_paint_type_ != PAINT_NORMAL) 266 if (!has_arrow(arrow_) || arrow_paint_type_ != PAINT_NORMAL)
231 return false; 267 return false;
232 268
233 GetArrowPathFromArrowBounds(GetArrowRect(view_bounds), path); 269 GetArrowPathFromArrowBounds(GetArrowRect(view_bounds), path);
234 return true; 270 return true;
235 } 271 }
236 272
237 void BubbleBorder::SetBorderInteriorThickness(int border_interior_thickness) { 273 void BubbleBorder::SetBorderInteriorThickness(int border_interior_thickness) {
238 images_->border_interior_thickness = border_interior_thickness; 274 images_->border_interior_thickness = border_interior_thickness;
239 if (!has_arrow(arrow_) || arrow_paint_type_ != PAINT_NORMAL) 275 if (!has_arrow(arrow_) || arrow_paint_type_ != PAINT_NORMAL)
240 images_->border_thickness = border_interior_thickness; 276 images_->border_thickness = border_interior_thickness;
241 } 277 }
242 278
243 void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) { 279 void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
280 if (UseMd())
281 return PaintMd(view, canvas);
282
244 gfx::Rect bounds(view.GetContentsBounds()); 283 gfx::Rect bounds(view.GetContentsBounds());
245 bounds.Inset(-GetBorderThickness(), -GetBorderThickness()); 284 bounds.Inset(-GetBorderThickness(), -GetBorderThickness());
246 const gfx::Rect arrow_bounds = GetArrowRect(view.GetLocalBounds()); 285 const gfx::Rect arrow_bounds = GetArrowRect(view.GetLocalBounds());
247 if (arrow_bounds.IsEmpty()) { 286 if (arrow_bounds.IsEmpty()) {
248 if (images_->border_painter) 287 if (images_->border_painter)
249 Painter::PaintPainterAt(canvas, images_->border_painter.get(), bounds); 288 Painter::PaintPainterAt(canvas, images_->border_painter.get(), bounds);
250 return; 289 return;
251 } 290 }
252 if (!images_->border_painter) { 291 if (!images_->border_painter) {
253 DrawArrow(canvas, arrow_bounds); 292 DrawArrow(canvas, arrow_bounds);
254 return; 293 return;
255 } 294 }
256 295
257 // Clip the arrow bounds out to avoid painting the overlapping edge area. 296 // Clip the arrow bounds out to avoid painting the overlapping edge area.
258 canvas->Save(); 297 canvas->Save();
259 canvas->ClipRect(arrow_bounds, SkRegion::kDifference_Op); 298 canvas->ClipRect(arrow_bounds, SkRegion::kDifference_Op);
260 Painter::PaintPainterAt(canvas, images_->border_painter.get(), bounds); 299 Painter::PaintPainterAt(canvas, images_->border_painter.get(), bounds);
261 canvas->Restore(); 300 canvas->Restore();
262 301
263 DrawArrow(canvas, arrow_bounds); 302 DrawArrow(canvas, arrow_bounds);
264 } 303 }
265 304
266 gfx::Insets BubbleBorder::GetInsets() const { 305 gfx::Insets BubbleBorder::GetInsets() const {
306 if (UseMd()) {
307 gfx::Insets blur(kLargeShadowBlur);
308 gfx::Insets offset(-kLargeShadowVerticalOffset, 0,
309 kLargeShadowVerticalOffset, 0);
310 return blur + offset;
311 }
312
267 // The insets contain the stroke and shadow pixels outside the bubble fill. 313 // The insets contain the stroke and shadow pixels outside the bubble fill.
268 const int inset = GetBorderThickness(); 314 const int inset = GetBorderThickness();
269 if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_)) 315 if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_))
270 return gfx::Insets(inset); 316 return gfx::Insets(inset);
271 317
272 int first_inset = inset; 318 int first_inset = inset;
273 int second_inset = std::max(inset, images_->arrow_thickness); 319 int second_inset = std::max(inset, images_->arrow_thickness);
274 if (is_arrow_on_horizontal(arrow_) ? 320 if (is_arrow_on_horizontal(arrow_) ?
275 is_arrow_on_top(arrow_) : is_arrow_on_left(arrow_)) 321 is_arrow_on_top(arrow_) : is_arrow_on_left(arrow_))
276 std::swap(first_inset, second_inset); 322 std::swap(first_inset, second_inset);
277 return is_arrow_on_horizontal(arrow_) ? 323 return is_arrow_on_horizontal(arrow_) ?
278 gfx::Insets(first_inset, inset, second_inset, inset) : 324 gfx::Insets(first_inset, inset, second_inset, inset) :
279 gfx::Insets(inset, first_inset, inset, second_inset); 325 gfx::Insets(inset, first_inset, inset, second_inset);
280 } 326 }
281 327
282 gfx::Size BubbleBorder::GetMinimumSize() const { 328 gfx::Size BubbleBorder::GetMinimumSize() const {
283 return GetSizeForContentsSize(gfx::Size()); 329 return GetSizeForContentsSize(gfx::Size());
284 } 330 }
285 331
286 gfx::Size BubbleBorder::GetSizeForContentsSize( 332 gfx::Size BubbleBorder::GetSizeForContentsSize(
287 const gfx::Size& contents_size) const { 333 const gfx::Size& contents_size) const {
288 // Enlarge the contents size by the thickness of the border images. 334 // Enlarge the contents size by the thickness of the border images.
289 gfx::Size size(contents_size); 335 gfx::Size size(contents_size);
290 const gfx::Insets insets = GetInsets(); 336 const gfx::Insets insets = GetInsets();
291 size.Enlarge(insets.width(), insets.height()); 337 size.Enlarge(insets.width(), insets.height());
338 if (UseMd())
339 return size;
292 340
293 // Ensure the bubble is large enough to not overlap border and arrow images. 341 // Ensure the bubble is large enough to not overlap border and arrow images.
294 const int min = 2 * images_->border_thickness; 342 const int min = 2 * images_->border_thickness;
295 // Only take arrow image sizes into account when the bubble tip is shown. 343 // Only take arrow image sizes into account when the bubble tip is shown.
296 if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_)) { 344 if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_)) {
297 size.SetToMax(gfx::Size(min, min)); 345 size.SetToMax(gfx::Size(min, min));
298 return size; 346 return size;
299 } 347 }
300 const int min_with_arrow_width = min + images_->arrow_width; 348 const int min_with_arrow_width = min + images_->arrow_width;
301 const int min_with_arrow_thickness = images_->border_thickness + 349 const int min_with_arrow_thickness = images_->border_thickness +
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 DCHECK_EQ(2 * images_->arrow_interior_thickness, images_->arrow_width); 401 DCHECK_EQ(2 * images_->arrow_interior_thickness, images_->arrow_width);
354 int width = images_->arrow_width; 402 int width = images_->arrow_width;
355 int height = images_->arrow_interior_thickness; 403 int height = images_->arrow_interior_thickness;
356 if (!is_arrow_on_horizontal(arrow_)) 404 if (!is_arrow_on_horizontal(arrow_))
357 std::swap(width, height); 405 std::swap(width, height);
358 return gfx::Rect(origin, gfx::Size(width, height)); 406 return gfx::Rect(origin, gfx::Size(width, height));
359 } 407 }
360 408
361 void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds, 409 void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds,
362 SkPath* path) const { 410 SkPath* path) const {
411 DCHECK(!UseMd());
363 const bool horizontal = is_arrow_on_horizontal(arrow_); 412 const bool horizontal = is_arrow_on_horizontal(arrow_);
364 const int thickness = images_->arrow_interior_thickness; 413 const int thickness = images_->arrow_interior_thickness;
365 float tip_x = horizontal ? arrow_bounds.CenterPoint().x() : 414 float tip_x = horizontal ? arrow_bounds.CenterPoint().x() :
366 is_arrow_on_left(arrow_) ? arrow_bounds.right() - thickness : 415 is_arrow_on_left(arrow_) ? arrow_bounds.right() - thickness :
367 arrow_bounds.x() + thickness; 416 arrow_bounds.x() + thickness;
368 float tip_y = !horizontal ? arrow_bounds.CenterPoint().y() + 0.5f : 417 float tip_y = !horizontal ? arrow_bounds.CenterPoint().y() + 0.5f :
369 is_arrow_on_top(arrow_) ? arrow_bounds.bottom() - thickness : 418 is_arrow_on_top(arrow_) ? arrow_bounds.bottom() - thickness :
370 arrow_bounds.y() + thickness; 419 arrow_bounds.y() + thickness;
371 const bool positive_offset = horizontal ? 420 const bool positive_offset = horizontal ?
372 is_arrow_on_top(arrow_) : is_arrow_on_left(arrow_); 421 is_arrow_on_top(arrow_) : is_arrow_on_left(arrow_);
373 const int offset_to_next_vertex = positive_offset ? 422 const int offset_to_next_vertex = positive_offset ?
374 images_->arrow_interior_thickness : -images_->arrow_interior_thickness; 423 images_->arrow_interior_thickness : -images_->arrow_interior_thickness;
375 424
376 path->incReserve(4); 425 path->incReserve(4);
377 path->moveTo(SkDoubleToScalar(tip_x), SkDoubleToScalar(tip_y)); 426 path->moveTo(SkDoubleToScalar(tip_x), SkDoubleToScalar(tip_y));
378 path->lineTo(SkDoubleToScalar(tip_x + offset_to_next_vertex), 427 path->lineTo(SkDoubleToScalar(tip_x + offset_to_next_vertex),
379 SkDoubleToScalar(tip_y + offset_to_next_vertex)); 428 SkDoubleToScalar(tip_y + offset_to_next_vertex));
380 const int multiplier = horizontal ? 1 : -1; 429 const int multiplier = horizontal ? 1 : -1;
381 path->lineTo(SkDoubleToScalar(tip_x - multiplier * offset_to_next_vertex), 430 path->lineTo(SkDoubleToScalar(tip_x - multiplier * offset_to_next_vertex),
382 SkDoubleToScalar(tip_y + multiplier * offset_to_next_vertex)); 431 SkDoubleToScalar(tip_y + multiplier * offset_to_next_vertex));
383 path->close(); 432 path->close();
384 } 433 }
385 434
386 void BubbleBorder::DrawArrow(gfx::Canvas* canvas, 435 void BubbleBorder::DrawArrow(gfx::Canvas* canvas,
387 const gfx::Rect& arrow_bounds) const { 436 const gfx::Rect& arrow_bounds) const {
437 DCHECK(!UseMd());
388 canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y()); 438 canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y());
389 SkPath path; 439 SkPath path;
390 GetArrowPathFromArrowBounds(arrow_bounds, &path); 440 GetArrowPathFromArrowBounds(arrow_bounds, &path);
391 SkPaint paint; 441 SkPaint paint;
392 paint.setStyle(SkPaint::kFill_Style); 442 paint.setStyle(SkPaint::kFill_Style);
393 paint.setColor(background_color_); 443 paint.setColor(background_color_);
394 444
395 canvas->DrawPath(path, paint); 445 canvas->DrawPath(path, paint);
396 } 446 }
397 447
448 void BubbleBorder::PaintMd(const View& view, gfx::Canvas* canvas) {
449 gfx::ScopedCanvas scoped(canvas);
450
451 SkPaint paint;
452 std::vector<gfx::ShadowValue> shadows;
453 // gfx::ShadowValue counts blur pixels both inside and outside the shape,
454 // whereas these blur values only describe the outside portion, hence they
455 // must be doubled.
456 shadows.emplace_back(gfx::Vector2d(0, kSmallShadowVerticalOffset),
457 2 * kSmallShadowBlur, kSmallShadowColor);
458 shadows.emplace_back(gfx::Vector2d(0, kLargeShadowVerticalOffset),
459 2 * kLargeShadowBlur, kLargeShadowColor);
460 paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows));
461 paint.setColor(SkColorSetA(SK_ColorBLACK, 0x0D));
462 paint.setAntiAlias(true);
463
464 gfx::Rect bounds(view.GetLocalBounds());
465 bounds.Inset(GetInsets());
466 SkRRect r_rect =
467 SkRRect::MakeRectXY(gfx::RectToSkRect(bounds), GetBorderCornerRadius(),
468 GetBorderCornerRadius());
469 // Clip out a round rect so the fill and shadow don't draw over the contents
470 // of the bubble.
471 SkRRect clip_r_rect = r_rect;
472 // Stroke width is a single pixel at any scale factor.
473 const SkScalar one_pixel = SkFloatToScalar(1 / canvas->image_scale());
474 clip_r_rect.inset(one_pixel, one_pixel);
475 canvas->sk_canvas()->clipRRect(clip_r_rect, SkRegion::kDifference_Op,
476 true /*doAntiAlias*/);
477 canvas->sk_canvas()->drawRRect(r_rect, paint);
478 }
479
398 internal::BorderImages* BubbleBorder::GetImagesForTest() const { 480 internal::BorderImages* BubbleBorder::GetImagesForTest() const {
399 return images_; 481 return images_;
400 } 482 }
401 483
402 void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const { 484 void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
403 if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER) 485 if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER)
404 canvas->DrawColor(border_->background_color()); 486 canvas->DrawColor(border_->background_color());
405 487
406 // Fill the contents with a round-rect region to match the border images. 488 // Fill the contents with a round-rect region to match the border images.
407 SkPaint paint; 489 SkPaint paint;
408 paint.setAntiAlias(true); 490 paint.setAntiAlias(true);
409 paint.setStyle(SkPaint::kFill_Style); 491 paint.setStyle(SkPaint::kFill_Style);
410 paint.setColor(border_->background_color()); 492 paint.setColor(border_->background_color());
411 SkPath path; 493 SkPath path;
412 gfx::Rect bounds(view->GetLocalBounds()); 494 gfx::Rect bounds(view->GetLocalBounds());
413 bounds.Inset(border_->GetInsets()); 495 bounds.Inset(border_->GetInsets());
414 496
415 canvas->DrawRoundRect(bounds, border_->GetBorderCornerRadius(), paint); 497 canvas->DrawRoundRect(bounds, border_->GetBorderCornerRadius(), paint);
416 } 498 }
417 499
418 } // namespace views 500 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/bubble/bubble_border.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698