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

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

Issue 2439793002: Harmony - Draw bubble/dialog borders just outside the content area (Closed)
Patch Set: s/px/dip Created 4 years, 2 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 | « no previous file | 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/SkDrawLooper.h"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 arrow_thickness = top_arrow.height(); 53 arrow_thickness = top_arrow.height();
54 } 54 }
55 } 55 }
56 56
57 BorderImages::~BorderImages() {} 57 BorderImages::~BorderImages() {}
58 58
59 } // namespace internal 59 } // namespace internal
60 60
61 namespace { 61 namespace {
62 62
63 // The border is stroked at 1px, but for the purposes of reserving space we have
64 // to deal in dip coordinates, so round up to 1dip.
65 const int kBorderThicknessDip = 1;
66 const int kBorderStrokeThicknessPx = 1;
67
63 // Blur and offset values for the two shadows drawn around each dialog. The 68 // Blur and offset values for the two shadows drawn around each dialog. The
64 // values are all in dip. 69 // values are all in dip.
65 const int kSmallShadowVerticalOffset = 2; 70 const int kSmallShadowVerticalOffset = 2;
66 const int kSmallShadowBlur = 4; 71 const int kSmallShadowBlur = 4;
67 const SkColor kSmallShadowColor = SkColorSetA(SK_ColorBLACK, 0x33); 72 const SkColor kSmallShadowColor = SkColorSetA(SK_ColorBLACK, 0x33);
68 73
69 const int kLargeShadowVerticalOffset = 2; 74 const int kLargeShadowVerticalOffset = 2;
70 const int kLargeShadowBlur = 6; 75 const int kLargeShadowBlur = 6;
71 const SkColor kLargeShadowColor = SkColorSetA(SK_ColorBLACK, 0x1A); 76 const SkColor kLargeShadowColor = SkColorSetA(SK_ColorBLACK, 0x1A);
72 77
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 } 209 }
205 210
206 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect, 211 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
207 const gfx::Size& contents_size) const { 212 const gfx::Size& contents_size) const {
208 // In MD, there are no arrows, so positioning logic is significantly simpler. 213 // In MD, there are no arrows, so positioning logic is significantly simpler.
209 // TODO(estade): handle more anchor positions. 214 // TODO(estade): handle more anchor positions.
210 if (UseMd() && 215 if (UseMd() &&
211 (arrow_ == TOP_RIGHT || arrow_ == TOP_LEFT || arrow_ == BOTTOM_CENTER || 216 (arrow_ == TOP_RIGHT || arrow_ == TOP_LEFT || arrow_ == BOTTOM_CENTER ||
212 arrow_ == LEFT_CENTER || arrow_ == RIGHT_CENTER)) { 217 arrow_ == LEFT_CENTER || arrow_ == RIGHT_CENTER)) {
213 gfx::Rect contents_bounds(contents_size); 218 gfx::Rect contents_bounds(contents_size);
219 // Apply the border part of the inset before calculating coordinates because
220 // the border should align with the anchor's border. For the purposes of
221 // positioning, the border is rounded up to a dip, which may mean we have
222 // misalignment in scale factors greater than 1.
223 // TODO(estade): when it becomes possible to provide px bounds instead of
224 // dip bounds, fix this.
225 const gfx::Insets border_insets = gfx::Insets(kBorderThicknessDip);
226 const gfx::Insets shadow_insets = GetInsets() - border_insets;
227 contents_bounds.Inset(-border_insets);
214 if (arrow_ == TOP_RIGHT) { 228 if (arrow_ == TOP_RIGHT) {
215 contents_bounds += 229 contents_bounds +=
216 anchor_rect.bottom_right() - contents_bounds.top_right(); 230 anchor_rect.bottom_right() - contents_bounds.top_right();
217 } else if (arrow_ == TOP_LEFT) { 231 } else if (arrow_ == TOP_LEFT) {
218 contents_bounds += 232 contents_bounds +=
219 anchor_rect.bottom_left() - contents_bounds.origin(); 233 anchor_rect.bottom_left() - contents_bounds.origin();
220 } else if (arrow_ == BOTTOM_CENTER) { 234 } else if (arrow_ == BOTTOM_CENTER) {
221 contents_bounds += CenterTop(anchor_rect) - CenterBottom(contents_bounds); 235 contents_bounds += CenterTop(anchor_rect) - CenterBottom(contents_bounds);
222 } else if (arrow_ == LEFT_CENTER) { 236 } else if (arrow_ == LEFT_CENTER) {
223 contents_bounds += RightCenter(anchor_rect) - LeftCenter(contents_bounds); 237 contents_bounds += RightCenter(anchor_rect) - LeftCenter(contents_bounds);
224 } else if (arrow_ == RIGHT_CENTER) { 238 } else if (arrow_ == RIGHT_CENTER) {
225 contents_bounds += LeftCenter(anchor_rect) - RightCenter(contents_bounds); 239 contents_bounds += LeftCenter(anchor_rect) - RightCenter(contents_bounds);
226 } 240 }
227 contents_bounds.Inset(-GetInsets()); 241 contents_bounds.Inset(-shadow_insets);
228 // |arrow_offset_| is used to adjust bubbles that would normally be 242 // |arrow_offset_| is used to adjust bubbles that would normally be
229 // partially offscreen. 243 // partially offscreen.
230 contents_bounds += gfx::Vector2d(-arrow_offset_, 0); 244 contents_bounds += gfx::Vector2d(-arrow_offset_, 0);
231 return contents_bounds; 245 return contents_bounds;
232 } 246 }
233 247
234 int x = anchor_rect.x(); 248 int x = anchor_rect.x();
235 int y = anchor_rect.y(); 249 int y = anchor_rect.y();
236 int w = anchor_rect.width(); 250 int w = anchor_rect.width();
237 int h = anchor_rect.height(); 251 int h = anchor_rect.height();
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 canvas->Restore(); 359 canvas->Restore();
346 360
347 DrawArrow(canvas, arrow_bounds); 361 DrawArrow(canvas, arrow_bounds);
348 } 362 }
349 363
350 gfx::Insets BubbleBorder::GetInsets() const { 364 gfx::Insets BubbleBorder::GetInsets() const {
351 if (UseMd()) { 365 if (UseMd()) {
352 gfx::Insets blur(kLargeShadowBlur); 366 gfx::Insets blur(kLargeShadowBlur);
353 gfx::Insets offset(-kLargeShadowVerticalOffset, 0, 367 gfx::Insets offset(-kLargeShadowVerticalOffset, 0,
354 kLargeShadowVerticalOffset, 0); 368 kLargeShadowVerticalOffset, 0);
369 gfx::Insets border(kBorderThicknessDip);
355 return blur + offset; 370 return blur + offset;
356 } 371 }
357 372
358 // The insets contain the stroke and shadow pixels outside the bubble fill. 373 // The insets contain the stroke and shadow pixels outside the bubble fill.
359 const int inset = GetBorderThickness(); 374 const int inset = GetBorderThickness();
360 if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_)) 375 if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_))
361 return gfx::Insets(inset); 376 return gfx::Insets(inset);
362 377
363 int first_inset = inset; 378 int first_inset = inset;
364 int second_inset = std::max(inset, images_->arrow_thickness); 379 int second_inset = std::max(inset, images_->arrow_thickness);
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 // whereas these blur values only describe the outside portion, hence they 514 // whereas these blur values only describe the outside portion, hence they
500 // must be doubled. 515 // must be doubled.
501 shadows.emplace_back(gfx::Vector2d(0, kSmallShadowVerticalOffset), 516 shadows.emplace_back(gfx::Vector2d(0, kSmallShadowVerticalOffset),
502 2 * kSmallShadowBlur, kSmallShadowColor); 517 2 * kSmallShadowBlur, kSmallShadowColor);
503 shadows.emplace_back(gfx::Vector2d(0, kLargeShadowVerticalOffset), 518 shadows.emplace_back(gfx::Vector2d(0, kLargeShadowVerticalOffset),
504 2 * kLargeShadowBlur, kLargeShadowColor); 519 2 * kLargeShadowBlur, kLargeShadowColor);
505 paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows)); 520 paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows));
506 paint.setColor(SkColorSetA(SK_ColorBLACK, 0x26)); 521 paint.setColor(SkColorSetA(SK_ColorBLACK, 0x26));
507 paint.setAntiAlias(true); 522 paint.setAntiAlias(true);
508 523
509 gfx::Rect bounds(view.GetLocalBounds()); 524 gfx::RectF bounds(view.GetLocalBounds());
510 bounds.Inset(GetInsets()); 525 bounds.Inset(GetInsets());
511 SkRRect r_rect =
512 SkRRect::MakeRectXY(gfx::RectToSkRect(bounds), GetBorderCornerRadius(),
513 GetBorderCornerRadius());
514 // Clip out a round rect so the fill and shadow don't draw over the contents 526 // Clip out a round rect so the fill and shadow don't draw over the contents
515 // of the bubble. 527 // of the bubble.
516 SkRRect clip_r_rect = r_rect; 528 SkRRect clip_r_rect =
517 // Stroke width is a single pixel at any scale factor. 529 SkRRect::MakeRectXY(gfx::RectFToSkRect(bounds), GetBorderCornerRadius(),
518 const SkScalar one_pixel = SkFloatToScalar(1 / canvas->image_scale()); 530 GetBorderCornerRadius());
519 clip_r_rect.inset(one_pixel, one_pixel);
520 canvas->sk_canvas()->clipRRect(clip_r_rect, SkRegion::kDifference_Op, 531 canvas->sk_canvas()->clipRRect(clip_r_rect, SkRegion::kDifference_Op,
521 true /*doAntiAlias*/); 532 true /*doAntiAlias*/);
533
534 // The border is drawn outside the content area.
535 SkRRect r_rect = clip_r_rect;
536 const SkScalar one_pixel =
537 SkFloatToScalar(kBorderStrokeThicknessPx / canvas->image_scale());
538 r_rect.inset(-one_pixel, -one_pixel);
522 canvas->sk_canvas()->drawRRect(r_rect, paint); 539 canvas->sk_canvas()->drawRRect(r_rect, paint);
523 } 540 }
524 541
525 internal::BorderImages* BubbleBorder::GetImagesForTest() const { 542 internal::BorderImages* BubbleBorder::GetImagesForTest() const {
526 return images_; 543 return images_;
527 } 544 }
528 545
529 void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const { 546 void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
530 if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER) 547 if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER)
531 canvas->DrawColor(border_->background_color()); 548 canvas->DrawColor(border_->background_color());
532 549
533 // Fill the contents with a round-rect region to match the border images. 550 // Fill the contents with a round-rect region to match the border images.
534 SkPaint paint; 551 SkPaint paint;
535 paint.setAntiAlias(true); 552 paint.setAntiAlias(true);
536 paint.setStyle(SkPaint::kFill_Style); 553 paint.setStyle(SkPaint::kFill_Style);
537 paint.setColor(border_->background_color()); 554 paint.setColor(border_->background_color());
538 SkPath path; 555 SkPath path;
539 gfx::RectF bounds(view->GetLocalBounds()); 556 gfx::RectF bounds(view->GetLocalBounds());
540 bounds.Inset(gfx::InsetsF(border_->GetInsets())); 557 bounds.Inset(gfx::InsetsF(border_->GetInsets()));
541 if (UseMd()) {
542 // The border is 1px at all scale factors. Leave room for it. It's partially
543 // transparent, so we don't want to draw any background underneath it.
544 const SkScalar one_pixel = SkFloatToScalar(1 / canvas->image_scale());
545 bounds.Inset(gfx::InsetsF(one_pixel));
546 }
547 558
548 canvas->DrawRoundRect(bounds, border_->GetBorderCornerRadius(), paint); 559 canvas->DrawRoundRect(bounds, border_->GetBorderCornerRadius(), paint);
549 } 560 }
550 561
551 } // namespace views 562 } // namespace views
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698