OLD | NEW |
---|---|
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/SkPaint.h" | 10 #include "third_party/skia/include/core/SkPaint.h" |
11 #include "third_party/skia/include/core/SkPath.h" | 11 #include "third_party/skia/include/core/SkPath.h" |
12 #include "ui/base/resource/resource_bundle.h" | 12 #include "ui/base/resource/resource_bundle.h" |
13 #include "ui/gfx/canvas.h" | 13 #include "ui/gfx/canvas.h" |
14 #include "ui/gfx/geometry/rect.h" | 14 #include "ui/gfx/geometry/rect.h" |
15 #include "ui/gfx/path.h" | |
15 #include "ui/gfx/skia_util.h" | 16 #include "ui/gfx/skia_util.h" |
16 #include "ui/resources/grit/ui_resources.h" | 17 #include "ui/resources/grit/ui_resources.h" |
17 #include "ui/views/painter.h" | 18 #include "ui/views/painter.h" |
18 #include "ui/views/resources/grit/views_resources.h" | 19 #include "ui/views/resources/grit/views_resources.h" |
19 #include "ui/views/view.h" | 20 #include "ui/views/view.h" |
20 | 21 |
21 namespace views { | 22 namespace views { |
22 | 23 |
23 namespace internal { | 24 namespace internal { |
24 | 25 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
134 | 135 |
135 } // namespace | 136 } // namespace |
136 | 137 |
137 const int BubbleBorder::kStroke = 1; | 138 const int BubbleBorder::kStroke = 1; |
138 | 139 |
139 BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color) | 140 BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color) |
140 : arrow_(arrow), | 141 : arrow_(arrow), |
141 arrow_offset_(0), | 142 arrow_offset_(0), |
142 arrow_paint_type_(PAINT_NORMAL), | 143 arrow_paint_type_(PAINT_NORMAL), |
143 alignment_(ALIGN_ARROW_TO_MID_ANCHOR), | 144 alignment_(ALIGN_ARROW_TO_MID_ANCHOR), |
144 shadow_(shadow), | |
145 background_color_(color), | 145 background_color_(color), |
146 use_theme_background_color_(false) { | 146 use_theme_background_color_(false) { |
147 DCHECK(shadow < SHADOW_COUNT); | 147 // On Mac, use the NO_ASSETS bubble border. WindowServer on Mac is able to |
tapted
2016/01/28 05:59:22
nit: I think we should have the initializer still,
karandeepb
2016/02/04 03:39:27
Done.
| |
148 images_ = GetBorderImages(shadow); | 148 // generate drop shadows for dialogs, hence we don't use raster shadows. |
149 #if defined(OS_MACOSX) | |
150 shadow_ = NO_ASSETS; | |
151 #else | |
152 shadow_ = shadow; | |
153 #endif // OS_MACOSX | |
154 DCHECK(shadow_ < SHADOW_COUNT); | |
155 images_ = GetBorderImages(shadow_); | |
149 } | 156 } |
150 | 157 |
151 BubbleBorder::~BubbleBorder() {} | 158 BubbleBorder::~BubbleBorder() {} |
152 | 159 |
153 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect, | 160 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect, |
154 const gfx::Size& contents_size) const { | 161 const gfx::Size& contents_size) const { |
155 int x = anchor_rect.x(); | 162 int x = anchor_rect.x(); |
156 int y = anchor_rect.y(); | 163 int y = anchor_rect.y(); |
157 int w = anchor_rect.width(); | 164 int w = anchor_rect.width(); |
158 int h = anchor_rect.height(); | 165 int h = anchor_rect.height(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
204 border_size.width() : border_size.height(); | 211 border_size.width() : border_size.height(); |
205 if (is_arrow_at_center(arrow_) && arrow_offset_ == 0) | 212 if (is_arrow_at_center(arrow_) && arrow_offset_ == 0) |
206 return edge_length / 2; | 213 return edge_length / 2; |
207 | 214 |
208 // Calculate the minimum offset to not overlap arrow and corner images. | 215 // Calculate the minimum offset to not overlap arrow and corner images. |
209 const int min = images_->border_thickness + (images_->arrow_width / 2); | 216 const int min = images_->border_thickness + (images_->arrow_width / 2); |
210 // Ensure the returned value will not cause image overlap, if possible. | 217 // Ensure the returned value will not cause image overlap, if possible. |
211 return std::max(min, std::min(arrow_offset_, edge_length - min)); | 218 return std::max(min, std::min(arrow_offset_, edge_length - min)); |
212 } | 219 } |
213 | 220 |
221 void BubbleBorder::GetArrowMask(const gfx::Rect& view_bounds, | |
222 gfx::Path* mask) const { | |
223 if (!has_arrow(arrow_) || arrow_paint_type_ != PAINT_NORMAL) | |
224 return; | |
225 | |
226 return GetArrowMaskFromArrowBounds(GetArrowRect(view_bounds), mask); | |
227 } | |
228 | |
214 void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) { | 229 void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) { |
215 gfx::Rect bounds(view.GetContentsBounds()); | 230 gfx::Rect bounds(view.GetContentsBounds()); |
216 bounds.Inset(-GetBorderThickness(), -GetBorderThickness()); | 231 bounds.Inset(-GetBorderThickness(), -GetBorderThickness()); |
217 const gfx::Rect arrow_bounds = GetArrowRect(view.GetLocalBounds()); | 232 const gfx::Rect arrow_bounds = GetArrowRect(view.GetLocalBounds()); |
218 if (arrow_bounds.IsEmpty()) { | 233 if (arrow_bounds.IsEmpty()) { |
219 if (images_->border_painter) | 234 if (images_->border_painter) |
220 Painter::PaintPainterAt(canvas, images_->border_painter.get(), bounds); | 235 Painter::PaintPainterAt(canvas, images_->border_painter.get(), bounds); |
221 return; | 236 return; |
222 } | 237 } |
223 if (!images_->border_painter) { | 238 if (!images_->border_painter) { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
321 | 336 |
322 // With no assets, return the size enclosing the path filled in DrawArrow(). | 337 // With no assets, return the size enclosing the path filled in DrawArrow(). |
323 DCHECK_EQ(2 * images_->arrow_interior_thickness, images_->arrow_width); | 338 DCHECK_EQ(2 * images_->arrow_interior_thickness, images_->arrow_width); |
324 int width = images_->arrow_width; | 339 int width = images_->arrow_width; |
325 int height = images_->arrow_interior_thickness; | 340 int height = images_->arrow_interior_thickness; |
326 if (!is_arrow_on_horizontal(arrow_)) | 341 if (!is_arrow_on_horizontal(arrow_)) |
327 std::swap(width, height); | 342 std::swap(width, height); |
328 return gfx::Rect(origin, gfx::Size(width, height)); | 343 return gfx::Rect(origin, gfx::Size(width, height)); |
329 } | 344 } |
330 | 345 |
331 void BubbleBorder::DrawArrow(gfx::Canvas* canvas, | 346 void BubbleBorder::GetArrowMaskFromArrowBounds(const gfx::Rect& arrow_bounds, |
332 const gfx::Rect& arrow_bounds) const { | 347 SkPath* mask) const { |
333 canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y()); | |
334 const bool horizontal = is_arrow_on_horizontal(arrow_); | 348 const bool horizontal = is_arrow_on_horizontal(arrow_); |
335 const int thickness = images_->arrow_interior_thickness; | 349 const int thickness = images_->arrow_interior_thickness; |
336 float tip_x = horizontal ? arrow_bounds.CenterPoint().x() : | 350 float tip_x = horizontal ? arrow_bounds.CenterPoint().x() : |
337 is_arrow_on_left(arrow_) ? arrow_bounds.right() - thickness : | 351 is_arrow_on_left(arrow_) ? arrow_bounds.right() - thickness : |
338 arrow_bounds.x() + thickness; | 352 arrow_bounds.x() + thickness; |
339 float tip_y = !horizontal ? arrow_bounds.CenterPoint().y() + 0.5f : | 353 float tip_y = !horizontal ? arrow_bounds.CenterPoint().y() + 0.5f : |
340 is_arrow_on_top(arrow_) ? arrow_bounds.bottom() - thickness : | 354 is_arrow_on_top(arrow_) ? arrow_bounds.bottom() - thickness : |
341 arrow_bounds.y() + thickness; | 355 arrow_bounds.y() + thickness; |
342 const bool positive_offset = horizontal ? | 356 const bool positive_offset = horizontal ? |
343 is_arrow_on_top(arrow_) : is_arrow_on_left(arrow_); | 357 is_arrow_on_top(arrow_) : is_arrow_on_left(arrow_); |
344 const int offset_to_next_vertex = positive_offset ? | 358 const int offset_to_next_vertex = positive_offset ? |
345 images_->arrow_interior_thickness : -images_->arrow_interior_thickness; | 359 images_->arrow_interior_thickness : -images_->arrow_interior_thickness; |
346 | 360 |
361 mask->incReserve(4); | |
362 mask->moveTo(SkDoubleToScalar(tip_x), SkDoubleToScalar(tip_y)); | |
363 mask->lineTo(SkDoubleToScalar(tip_x + offset_to_next_vertex), | |
364 SkDoubleToScalar(tip_y + offset_to_next_vertex)); | |
365 const int multiplier = horizontal ? 1 : -1; | |
366 mask->lineTo(SkDoubleToScalar(tip_x - multiplier * offset_to_next_vertex), | |
367 SkDoubleToScalar(tip_y + multiplier * offset_to_next_vertex)); | |
368 mask->close(); | |
369 } | |
370 | |
371 void BubbleBorder::DrawArrow(gfx::Canvas* canvas, | |
372 const gfx::Rect& arrow_bounds) const { | |
373 canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y()); | |
347 SkPath path; | 374 SkPath path; |
348 path.incReserve(4); | 375 GetArrowMaskFromArrowBounds(arrow_bounds, &path); |
349 path.moveTo(SkDoubleToScalar(tip_x), SkDoubleToScalar(tip_y)); | |
350 path.lineTo(SkDoubleToScalar(tip_x + offset_to_next_vertex), | |
351 SkDoubleToScalar(tip_y + offset_to_next_vertex)); | |
352 const int multiplier = horizontal ? 1 : -1; | |
353 path.lineTo(SkDoubleToScalar(tip_x - multiplier * offset_to_next_vertex), | |
354 SkDoubleToScalar(tip_y + multiplier * offset_to_next_vertex)); | |
355 path.close(); | |
356 | |
357 SkPaint paint; | 376 SkPaint paint; |
358 paint.setStyle(SkPaint::kFill_Style); | 377 paint.setStyle(SkPaint::kFill_Style); |
359 paint.setColor(background_color_); | 378 paint.setColor(background_color_); |
360 | 379 |
361 canvas->DrawPath(path, paint); | 380 canvas->DrawPath(path, paint); |
362 } | 381 } |
363 | 382 |
364 internal::BorderImages* BubbleBorder::GetImagesForTest() const { | 383 internal::BorderImages* BubbleBorder::GetImagesForTest() const { |
365 return images_; | 384 return images_; |
366 } | 385 } |
367 | 386 |
368 void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const { | 387 void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const { |
369 if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER) | 388 if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER) |
370 canvas->DrawColor(border_->background_color()); | 389 canvas->DrawColor(border_->background_color()); |
371 | 390 |
372 // Fill the contents with a round-rect region to match the border images. | 391 // Fill the contents with a round-rect region to match the border images. |
373 SkPaint paint; | 392 SkPaint paint; |
374 paint.setAntiAlias(true); | 393 paint.setAntiAlias(true); |
375 paint.setStyle(SkPaint::kFill_Style); | 394 paint.setStyle(SkPaint::kFill_Style); |
376 paint.setColor(border_->background_color()); | 395 paint.setColor(border_->background_color()); |
377 SkPath path; | 396 SkPath path; |
378 gfx::Rect bounds(view->GetLocalBounds()); | 397 gfx::Rect bounds(view->GetLocalBounds()); |
379 bounds.Inset(border_->GetInsets()); | 398 bounds.Inset(border_->GetInsets()); |
380 | 399 |
381 canvas->DrawRoundRect(bounds, border_->GetBorderCornerRadius(), paint); | 400 canvas->DrawRoundRect(bounds, border_->GetBorderCornerRadius(), paint); |
382 } | 401 } |
383 | 402 |
384 } // namespace views | 403 } // namespace views |
OLD | NEW |