| 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> // for std::max | 7 #include <algorithm> // for std::max |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "grit/ui_resources.h" | 10 #include "grit/ui_resources.h" |
| 11 #include "ui/base/resource/resource_bundle.h" | 11 #include "ui/base/resource/resource_bundle.h" |
| 12 #include "ui/gfx/canvas.h" | 12 #include "ui/gfx/canvas.h" |
| 13 #include "ui/gfx/image/image_skia.h" | 13 #include "ui/gfx/image/image_skia.h" |
| 14 #include "ui/gfx/skia_util.h" | 14 #include "ui/gfx/skia_util.h" |
| 15 | 15 |
| 16 namespace { |
| 17 |
| 18 // Stroke size in pixels of borders in image assets. |
| 19 const int kBorderStrokeSize = 1; |
| 20 |
| 21 // Border image resource ids. |
| 22 const int kShadowImages[] = { |
| 23 IDR_BUBBLE_SHADOW_L, |
| 24 IDR_BUBBLE_SHADOW_TL, |
| 25 IDR_BUBBLE_SHADOW_T, |
| 26 IDR_BUBBLE_SHADOW_TR, |
| 27 IDR_BUBBLE_SHADOW_R, |
| 28 IDR_BUBBLE_SHADOW_BR, |
| 29 IDR_BUBBLE_SHADOW_B, |
| 30 IDR_BUBBLE_SHADOW_BL, |
| 31 }; |
| 32 |
| 33 const int kNoShadowImages[] = { |
| 34 IDR_BUBBLE_L, |
| 35 IDR_BUBBLE_TL, |
| 36 IDR_BUBBLE_T, |
| 37 IDR_BUBBLE_TR, |
| 38 IDR_BUBBLE_R, |
| 39 IDR_BUBBLE_BR, |
| 40 IDR_BUBBLE_B, |
| 41 IDR_BUBBLE_BL, |
| 42 IDR_BUBBLE_L_ARROW, |
| 43 IDR_BUBBLE_T_ARROW, |
| 44 IDR_BUBBLE_R_ARROW, |
| 45 IDR_BUBBLE_B_ARROW, |
| 46 }; |
| 47 |
| 48 const int kBigShadowImages[] = { |
| 49 IDR_WINDOW_BUBBLE_SHADOW_BIG_LEFT, |
| 50 IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_LEFT, |
| 51 IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP, |
| 52 IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_RIGHT, |
| 53 IDR_WINDOW_BUBBLE_SHADOW_BIG_RIGHT, |
| 54 IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_RIGHT, |
| 55 IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM, |
| 56 IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_LEFT, |
| 57 IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_LEFT, |
| 58 IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_TOP, |
| 59 IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_RIGHT, |
| 60 IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_BOTTOM, |
| 61 }; |
| 62 |
| 63 const int kSmallShadowImages[] = { |
| 64 IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT, |
| 65 IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT, |
| 66 IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP, |
| 67 IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT, |
| 68 IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT, |
| 69 IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT, |
| 70 IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM, |
| 71 IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT, |
| 72 IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_LEFT, |
| 73 IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_TOP, |
| 74 IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_RIGHT, |
| 75 IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_BOTTOM, |
| 76 }; |
| 77 |
| 78 } // namespace |
| 79 |
| 16 namespace views { | 80 namespace views { |
| 17 | 81 |
| 18 struct BubbleBorder::BorderImages { | 82 struct BubbleBorder::BorderImages { |
| 19 BorderImages() | 83 BorderImages(const int image_ids[], |
| 20 : left(NULL), | 84 size_t image_ids_size, |
| 21 top_left(NULL), | 85 int arrow_interior_height, |
| 22 top(NULL), | 86 int border_thickness, |
| 23 top_right(NULL), | 87 int corner_radius) |
| 24 right(NULL), | 88 : arrow_interior_height(arrow_interior_height), |
| 25 bottom_right(NULL), | 89 border_thickness(border_thickness), |
| 26 bottom(NULL), | 90 corner_radius(corner_radius) { |
| 27 bottom_left(NULL), | 91 // Only two possible sizes of image ids array. |
| 28 left_arrow(NULL), | 92 DCHECK(image_ids_size == 12 || image_ids_size == 8); |
| 29 top_arrow(NULL), | 93 |
| 30 right_arrow(NULL), | 94 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 31 bottom_arrow(NULL), | 95 |
| 32 border_thickness(0) { | 96 left = *rb.GetImageSkiaNamed(image_ids[0]); |
| 97 top_left = *rb.GetImageSkiaNamed(image_ids[1]); |
| 98 top = *rb.GetImageSkiaNamed(image_ids[2]); |
| 99 top_right = *rb.GetImageSkiaNamed(image_ids[3]); |
| 100 right = *rb.GetImageSkiaNamed(image_ids[4]); |
| 101 bottom_right = *rb.GetImageSkiaNamed(image_ids[5]); |
| 102 bottom = *rb.GetImageSkiaNamed(image_ids[6]); |
| 103 bottom_left = *rb.GetImageSkiaNamed(image_ids[7]); |
| 104 |
| 105 if (image_ids_size > 8) { |
| 106 left_arrow = *rb.GetImageSkiaNamed(image_ids[8]); |
| 107 top_arrow = *rb.GetImageSkiaNamed(image_ids[9]); |
| 108 right_arrow = *rb.GetImageSkiaNamed(image_ids[10]); |
| 109 bottom_arrow = *rb.GetImageSkiaNamed(image_ids[11]); |
| 110 } |
| 33 } | 111 } |
| 34 | 112 |
| 35 gfx::ImageSkia* left; | 113 gfx::ImageSkia left; |
| 36 gfx::ImageSkia* top_left; | 114 gfx::ImageSkia top_left; |
| 37 gfx::ImageSkia* top; | 115 gfx::ImageSkia top; |
| 38 gfx::ImageSkia* top_right; | 116 gfx::ImageSkia top_right; |
| 39 gfx::ImageSkia* right; | 117 gfx::ImageSkia right; |
| 40 gfx::ImageSkia* bottom_right; | 118 gfx::ImageSkia bottom_right; |
| 41 gfx::ImageSkia* bottom; | 119 gfx::ImageSkia bottom; |
| 42 gfx::ImageSkia* bottom_left; | 120 gfx::ImageSkia bottom_left; |
| 43 gfx::ImageSkia* left_arrow; | 121 |
| 44 gfx::ImageSkia* top_arrow; | 122 gfx::ImageSkia left_arrow; |
| 45 gfx::ImageSkia* right_arrow; | 123 gfx::ImageSkia top_arrow; |
| 46 gfx::ImageSkia* bottom_arrow; | 124 gfx::ImageSkia right_arrow; |
| 125 gfx::ImageSkia bottom_arrow; |
| 126 |
| 127 int arrow_interior_height; // The height inside the arrow image, in pixels. |
| 47 int border_thickness; | 128 int border_thickness; |
| 129 int corner_radius; |
| 48 }; | 130 }; |
| 49 | 131 |
| 50 // static | 132 // static |
| 51 struct BubbleBorder::BorderImages* BubbleBorder::normal_images_ = NULL; | 133 struct BubbleBorder::BorderImages* |
| 52 struct BubbleBorder::BorderImages* BubbleBorder::shadow_images_ = NULL; | 134 BubbleBorder::border_images_[SHADOW_COUNT] = { NULL }; |
| 53 | |
| 54 // The height inside the arrow image, in pixels. | |
| 55 static const int kArrowInteriorHeight = 7; | |
| 56 | 135 |
| 57 BubbleBorder::BubbleBorder(ArrowLocation arrow_location, Shadow shadow) | 136 BubbleBorder::BubbleBorder(ArrowLocation arrow_location, Shadow shadow) |
| 58 : override_arrow_offset_(0), | 137 : override_arrow_offset_(0), |
| 59 arrow_location_(arrow_location), | 138 arrow_location_(arrow_location), |
| 60 alignment_(ALIGN_ARROW_TO_MID_ANCHOR), | 139 alignment_(ALIGN_ARROW_TO_MID_ANCHOR), |
| 61 background_color_(SK_ColorWHITE) { | 140 background_color_(SK_ColorWHITE) { |
| 141 DCHECK(shadow < SHADOW_COUNT); |
| 62 images_ = GetBorderImages(shadow); | 142 images_ = GetBorderImages(shadow); |
| 63 | 143 |
| 64 // Calculate horizontal and vertical insets for arrow by ensuring that | 144 // Calculate horizontal and vertical insets for arrow by ensuring that |
| 65 // the widest arrow and corner images will have enough room to avoid overlap | 145 // the widest arrow and corner images will have enough room to avoid overlap |
| 66 int offset_x = | 146 int offset_x = |
| 67 (std::max(images_->top_arrow->width(), | 147 (std::max(images_->top_arrow.width(), |
| 68 images_->bottom_arrow->width()) / 2) + | 148 images_->bottom_arrow.width()) / 2) + |
| 69 std::max(std::max(images_->top_left->width(), | 149 std::max(std::max(images_->top_left.width(), |
| 70 images_->top_right->width()), | 150 images_->top_right.width()), |
| 71 std::max(images_->bottom_left->width(), | 151 std::max(images_->bottom_left.width(), |
| 72 images_->bottom_right->width())); | 152 images_->bottom_right.width())); |
| 73 int offset_y = | 153 int offset_y = |
| 74 (std::max(images_->left_arrow->height(), | 154 (std::max(images_->left_arrow.height(), |
| 75 images_->right_arrow->height()) / 2) + | 155 images_->right_arrow.height()) / 2) + |
| 76 std::max(std::max(images_->top_left->height(), | 156 std::max(std::max(images_->top_left.height(), |
| 77 images_->top_right->height()), | 157 images_->top_right.height()), |
| 78 std::max(images_->bottom_left->height(), | 158 std::max(images_->bottom_left.height(), |
| 79 images_->bottom_right->height())); | 159 images_->bottom_right.height())); |
| 80 arrow_offset_ = std::max(offset_x, offset_y); | 160 arrow_offset_ = std::max(offset_x, offset_y); |
| 81 } | 161 } |
| 82 | 162 |
| 83 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to, | 163 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to, |
| 84 const gfx::Size& contents_size) const { | 164 const gfx::Size& contents_size) const { |
| 85 // Desired size is size of contents enlarged by the size of the border images. | 165 // Desired size is size of contents enlarged by the size of the border images. |
| 86 gfx::Size border_size(contents_size); | 166 gfx::Size border_size(contents_size); |
| 87 gfx::Insets insets; | 167 gfx::Insets insets; |
| 88 GetInsets(&insets); | 168 GetInsets(&insets); |
| 89 border_size.Enlarge(insets.width(), insets.height()); | 169 border_size.Enlarge(insets.width(), insets.height()); |
| 90 | 170 |
| 91 // Ensure the bubble has a minimum size that draws arrows correctly. | 171 // Ensure the bubble has a minimum size that draws arrows correctly. |
| 92 if (is_arrow_on_horizontal(arrow_location_)) | 172 if (is_arrow_on_horizontal(arrow_location_)) |
| 93 border_size.set_width(std::max(border_size.width(), 2 * arrow_offset_)); | 173 border_size.set_width(std::max(border_size.width(), 2 * arrow_offset_)); |
| 94 else if (has_arrow(arrow_location_)) | 174 else if (has_arrow(arrow_location_)) |
| 95 border_size.set_height(std::max(border_size.height(), 2 * arrow_offset_)); | 175 border_size.set_height(std::max(border_size.height(), 2 * arrow_offset_)); |
| 96 | 176 |
| 97 // Screen position depends on the arrow location. | 177 // Screen position depends on the arrow location. |
| 98 // The arrow should overlap the target by some amount since there is space | 178 // The bubble should overlap the target by some amount since there is space |
| 99 // for shadow between arrow tip and image bounds. | 179 // for shadow between arrow tip/bubble border and image bounds. |
| 100 const int kArrowOverlap = 3; | |
| 101 int x = position_relative_to.x(); | 180 int x = position_relative_to.x(); |
| 102 int y = position_relative_to.y(); | 181 int y = position_relative_to.y(); |
| 103 int w = position_relative_to.width(); | 182 int w = position_relative_to.width(); |
| 104 int h = position_relative_to.height(); | 183 int h = position_relative_to.height(); |
| 105 int arrow_offset = override_arrow_offset_ ? override_arrow_offset_ : | 184 |
| 106 arrow_offset_; | 185 const int arrow_size = images_->arrow_interior_height + kBorderStrokeSize; |
| 186 const int arrow_offset = GetArrowOffset(border_size); |
| 107 | 187 |
| 108 // Calculate bubble x coordinate. | 188 // Calculate bubble x coordinate. |
| 109 switch (arrow_location_) { | 189 switch (arrow_location_) { |
| 110 case TOP_LEFT: | 190 case TOP_LEFT: |
| 111 case BOTTOM_LEFT: | 191 case BOTTOM_LEFT: |
| 112 x += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? w / 2 - arrow_offset : | 192 x += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? w / 2 - arrow_offset : |
| 113 -kArrowOverlap; | 193 -(images_->left.width() - kBorderStrokeSize); |
| 114 break; | 194 break; |
| 115 | 195 |
| 116 case TOP_RIGHT: | 196 case TOP_RIGHT: |
| 117 case BOTTOM_RIGHT: | 197 case BOTTOM_RIGHT: |
| 118 x += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? | 198 x += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? |
| 119 w / 2 + arrow_offset - border_size.width() + 1 : | 199 w / 2 + arrow_offset - border_size.width() + 1 : |
| 120 w - border_size.width() + kArrowOverlap; | 200 w - border_size.width() + images_->right.width() - kBorderStrokeSize; |
| 121 break; | 201 break; |
| 122 | 202 |
| 123 case LEFT_TOP: | 203 case LEFT_TOP: |
| 204 case LEFT_CENTER: |
| 124 case LEFT_BOTTOM: | 205 case LEFT_BOTTOM: |
| 125 x += w - kArrowOverlap; | 206 x += w - (images_->left_arrow.width() - arrow_size); |
| 126 break; | 207 break; |
| 127 | 208 |
| 128 case RIGHT_TOP: | 209 case RIGHT_TOP: |
| 210 case RIGHT_CENTER: |
| 129 case RIGHT_BOTTOM: | 211 case RIGHT_BOTTOM: |
| 130 x += kArrowOverlap - border_size.width(); | 212 x += images_->right_arrow.width() - arrow_size - border_size.width(); |
| 213 break; |
| 214 |
| 215 case TOP_CENTER: |
| 216 case BOTTOM_CENTER: |
| 217 x += w / 2 - arrow_offset; |
| 131 break; | 218 break; |
| 132 | 219 |
| 133 case NONE: | 220 case NONE: |
| 134 case FLOAT: | 221 case FLOAT: |
| 135 x += w / 2 - border_size.width() / 2; | 222 x += w / 2 - border_size.width() / 2; |
| 136 break; | 223 break; |
| 137 } | 224 } |
| 138 | 225 |
| 139 // Calculate bubble y coordinate. | 226 // Calculate bubble y coordinate. |
| 140 switch (arrow_location_) { | 227 switch (arrow_location_) { |
| 141 case TOP_LEFT: | 228 case TOP_LEFT: |
| 229 case TOP_CENTER: |
| 142 case TOP_RIGHT: | 230 case TOP_RIGHT: |
| 143 y += h - kArrowOverlap; | 231 y += h - (images_->top_arrow.height() - arrow_size); |
| 144 break; | 232 break; |
| 145 | 233 |
| 146 case BOTTOM_LEFT: | 234 case BOTTOM_LEFT: |
| 235 case BOTTOM_CENTER: |
| 147 case BOTTOM_RIGHT: | 236 case BOTTOM_RIGHT: |
| 148 y += kArrowOverlap - border_size.height(); | 237 y += images_->bottom_arrow.height() - arrow_size - |
| 238 border_size.height(); |
| 149 break; | 239 break; |
| 150 | 240 |
| 151 case LEFT_TOP: | 241 case LEFT_TOP: |
| 152 case RIGHT_TOP: | 242 case RIGHT_TOP: |
| 153 y += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? h / 2 - arrow_offset : | 243 y += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? h / 2 - arrow_offset : |
| 154 -kArrowOverlap; | 244 -(images_->top.height() - kBorderStrokeSize); |
| 155 break; | 245 break; |
| 156 | 246 |
| 157 case LEFT_BOTTOM: | 247 case LEFT_BOTTOM: |
| 158 case RIGHT_BOTTOM: | 248 case RIGHT_BOTTOM: |
| 159 y += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? | 249 y += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? |
| 160 h / 2 + arrow_offset - border_size.height() + 1 : | 250 h / 2 + arrow_offset - border_size.height() + 1 : |
| 161 h - border_size.height() + kArrowOverlap; | 251 h - border_size.height() + images_->bottom.height() - |
| 252 kBorderStrokeSize; |
| 253 break; |
| 254 |
| 255 case LEFT_CENTER: |
| 256 case RIGHT_CENTER: |
| 257 y += h / 2 - arrow_offset; |
| 162 break; | 258 break; |
| 163 | 259 |
| 164 case NONE: | 260 case NONE: |
| 165 y += h; | 261 y += h; |
| 166 break; | 262 break; |
| 167 | 263 |
| 168 case FLOAT: | 264 case FLOAT: |
| 169 y += h / 2 - border_size.height() / 2; | 265 y += h / 2 - border_size.height() / 2; |
| 170 break; | 266 break; |
| 171 } | 267 } |
| 172 | 268 |
| 173 return gfx::Rect(x, y, border_size.width(), border_size.height()); | 269 return gfx::Rect(x, y, border_size.width(), border_size.height()); |
| 174 } | 270 } |
| 175 | 271 |
| 176 void BubbleBorder::GetInsets(gfx::Insets* insets) const { | 272 void BubbleBorder::GetInsets(gfx::Insets* insets) const { |
| 177 return GetInsetsForArrowLocation(insets, arrow_location()); | 273 return GetInsetsForArrowLocation(insets, arrow_location()); |
| 178 } | 274 } |
| 179 | 275 |
| 180 void BubbleBorder::GetInsetsForArrowLocation(gfx::Insets* insets, | 276 void BubbleBorder::GetInsetsForArrowLocation(gfx::Insets* insets, |
| 181 ArrowLocation arrow_loc) const { | 277 ArrowLocation arrow_loc) const { |
| 182 int top = images_->top->height(); | 278 int top = images_->top.height(); |
| 183 int bottom = images_->bottom->height(); | 279 int bottom = images_->bottom.height(); |
| 184 int left = images_->left->width(); | 280 int left = images_->left.width(); |
| 185 int right = images_->right->width(); | 281 int right = images_->right.width(); |
| 186 switch (arrow_loc) { | 282 switch (arrow_loc) { |
| 187 case TOP_LEFT: | 283 case TOP_LEFT: |
| 284 case TOP_CENTER: |
| 188 case TOP_RIGHT: | 285 case TOP_RIGHT: |
| 189 top = std::max(top, images_->top_arrow->height()); | 286 top = std::max(top, images_->top_arrow.height()); |
| 190 break; | 287 break; |
| 191 | 288 |
| 192 case BOTTOM_LEFT: | 289 case BOTTOM_LEFT: |
| 290 case BOTTOM_CENTER: |
| 193 case BOTTOM_RIGHT: | 291 case BOTTOM_RIGHT: |
| 194 bottom = std::max(bottom, images_->bottom_arrow->height()); | 292 bottom = std::max(bottom, images_->bottom_arrow.height()); |
| 195 break; | 293 break; |
| 196 | 294 |
| 197 case LEFT_TOP: | 295 case LEFT_TOP: |
| 296 case LEFT_CENTER: |
| 198 case LEFT_BOTTOM: | 297 case LEFT_BOTTOM: |
| 199 left = std::max(left, images_->left_arrow->width()); | 298 left = std::max(left, images_->left_arrow.width()); |
| 200 break; | 299 break; |
| 201 | 300 |
| 202 case RIGHT_TOP: | 301 case RIGHT_TOP: |
| 302 case RIGHT_CENTER: |
| 203 case RIGHT_BOTTOM: | 303 case RIGHT_BOTTOM: |
| 204 right = std::max(right, images_->right_arrow->width()); | 304 right = std::max(right, images_->right_arrow.width()); |
| 205 break; | 305 break; |
| 206 | 306 |
| 207 case NONE: | 307 case NONE: |
| 208 case FLOAT: | 308 case FLOAT: |
| 209 // Nothing to do. | 309 // Nothing to do. |
| 210 break; | 310 break; |
| 211 } | 311 } |
| 212 insets->Set(top, left, bottom, right); | 312 insets->Set(top, left, bottom, right); |
| 213 } | 313 } |
| 214 | 314 |
| 215 int BubbleBorder::GetBorderThickness() const { | 315 int BubbleBorder::GetBorderThickness() const { |
| 216 return images_->border_thickness; | 316 return images_->border_thickness; |
| 217 } | 317 } |
| 218 | 318 |
| 219 int BubbleBorder::SetArrowOffset(int offset, const gfx::Size& contents_size) { | 319 int BubbleBorder::GetBorderCornerRadius() const { |
| 220 gfx::Size border_size(contents_size); | 320 return images_->corner_radius; |
| 221 gfx::Insets insets; | 321 } |
| 222 GetInsets(&insets); | 322 |
| 223 border_size.Enlarge(insets.left() + insets.right(), | 323 int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const { |
| 224 insets.top() + insets.bottom()); | 324 int arrow_offset = arrow_offset_; |
| 225 offset = std::max(arrow_offset_, | 325 if (override_arrow_offset_) { |
| 226 std::min(offset, (is_arrow_on_horizontal(arrow_location_) ? | 326 arrow_offset = override_arrow_offset_; |
| 327 } else if (is_arrow_at_center(arrow_location_)) { |
| 328 if (is_arrow_on_horizontal(arrow_location_)) |
| 329 arrow_offset = border_size.width() / 2; |
| 330 else |
| 331 arrow_offset = border_size.height() / 2; |
| 332 } |
| 333 |
| 334 // |arrow_offset_| contains the minimum offset required to draw border images |
| 335 // correctly. It's defined in terms of number of pixels from the beginning of |
| 336 // the edge. The maximum arrow offset is the edge size - |arrow_offset_|. The |
| 337 // following statement clamps the calculated arrow offset within that range. |
| 338 return std::max(arrow_offset_, |
| 339 std::min(arrow_offset, (is_arrow_on_horizontal(arrow_location_) ? |
| 227 border_size.width() : border_size.height()) - arrow_offset_)); | 340 border_size.width() : border_size.height()) - arrow_offset_)); |
| 228 override_arrow_offset_ = offset; | |
| 229 return override_arrow_offset_; | |
| 230 } | 341 } |
| 231 | 342 |
| 232 // static | 343 // static |
| 233 BubbleBorder::BorderImages* BubbleBorder::GetBorderImages(Shadow shadow) { | 344 BubbleBorder::BorderImages* BubbleBorder::GetBorderImages(Shadow shadow) { |
| 234 if (shadow == SHADOW && shadow_images_ == NULL) { | 345 CHECK_LT(shadow, SHADOW_COUNT); |
| 235 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 346 |
| 236 shadow_images_ = new BorderImages(); | 347 struct BorderImages*& images = border_images_[shadow]; |
| 237 shadow_images_->left = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_L); | 348 if (images) |
| 238 shadow_images_->top_left = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_TL); | 349 return images; |
| 239 shadow_images_->top = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_T); | 350 |
| 240 shadow_images_->top_right = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_TR); | 351 switch (shadow) { |
| 241 shadow_images_->right = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_R); | 352 case SHADOW: |
| 242 shadow_images_->bottom_right = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_BR); | 353 images = new BorderImages(kShadowImages, |
| 243 shadow_images_->bottom = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_B); | 354 arraysize(kShadowImages), |
| 244 shadow_images_->bottom_left = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_BL); | 355 0, 10, 4); |
| 245 shadow_images_->left_arrow = new gfx::ImageSkia(); | 356 break; |
| 246 shadow_images_->top_arrow = new gfx::ImageSkia(); | 357 case NO_SHADOW: |
| 247 shadow_images_->right_arrow = new gfx::ImageSkia(); | 358 images = new BorderImages(kNoShadowImages, |
| 248 shadow_images_->bottom_arrow = new gfx::ImageSkia(); | 359 arraysize(kNoShadowImages), |
| 249 shadow_images_->border_thickness = 10; | 360 7, 0, 4); |
| 250 } else if (shadow == NO_SHADOW && normal_images_ == NULL) { | 361 break; |
| 251 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 362 case BIG_SHADOW: |
| 252 normal_images_ = new BorderImages(); | 363 images = new BorderImages(kBigShadowImages, |
| 253 normal_images_->left = rb.GetImageSkiaNamed(IDR_BUBBLE_L); | 364 arraysize(kBigShadowImages), |
| 254 normal_images_->top_left = rb.GetImageSkiaNamed(IDR_BUBBLE_TL); | 365 9, 0, 3); |
| 255 normal_images_->top = rb.GetImageSkiaNamed(IDR_BUBBLE_T); | 366 break; |
| 256 normal_images_->top_right = rb.GetImageSkiaNamed(IDR_BUBBLE_TR); | 367 case SMALL_SHADOW: |
| 257 normal_images_->right = rb.GetImageSkiaNamed(IDR_BUBBLE_R); | 368 images = new BorderImages(kSmallShadowImages, |
| 258 normal_images_->bottom_right = rb.GetImageSkiaNamed(IDR_BUBBLE_BR); | 369 arraysize(kSmallShadowImages), |
| 259 normal_images_->bottom = rb.GetImageSkiaNamed(IDR_BUBBLE_B); | 370 9, 0, 3); |
| 260 normal_images_->bottom_left = rb.GetImageSkiaNamed(IDR_BUBBLE_BL); | 371 break; |
| 261 normal_images_->left_arrow = rb.GetImageSkiaNamed(IDR_BUBBLE_L_ARROW); | 372 case SHADOW_COUNT: |
| 262 normal_images_->top_arrow = rb.GetImageSkiaNamed(IDR_BUBBLE_T_ARROW); | 373 NOTREACHED(); |
| 263 normal_images_->right_arrow = rb.GetImageSkiaNamed(IDR_BUBBLE_R_ARROW); | 374 break; |
| 264 normal_images_->bottom_arrow = rb.GetImageSkiaNamed(IDR_BUBBLE_B_ARROW); | |
| 265 normal_images_->border_thickness = 0; | |
| 266 } | 375 } |
| 267 return shadow == SHADOW ? shadow_images_ : normal_images_; | 376 |
| 377 return images; |
| 268 } | 378 } |
| 269 | 379 |
| 270 BubbleBorder::~BubbleBorder() {} | 380 BubbleBorder::~BubbleBorder() {} |
| 271 | 381 |
| 272 void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { | 382 void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { |
| 273 // Convenience shorthand variables. | 383 // Convenience shorthand variables. |
| 274 const int tl_width = images_->top_left->width(); | 384 const int tl_width = images_->top_left.width(); |
| 275 const int tl_height = images_->top_left->height(); | 385 const int tl_height = images_->top_left.height(); |
| 276 const int t_height = images_->top->height(); | 386 const int t_height = images_->top.height(); |
| 277 const int tr_width = images_->top_right->width(); | 387 const int tr_width = images_->top_right.width(); |
| 278 const int tr_height = images_->top_right->height(); | 388 const int tr_height = images_->top_right.height(); |
| 279 const int l_width = images_->left->width(); | 389 const int l_width = images_->left.width(); |
| 280 const int r_width = images_->right->width(); | 390 const int r_width = images_->right.width(); |
| 281 const int br_width = images_->bottom_right->width(); | 391 const int br_width = images_->bottom_right.width(); |
| 282 const int br_height = images_->bottom_right->height(); | 392 const int br_height = images_->bottom_right.height(); |
| 283 const int b_height = images_->bottom->height(); | 393 const int b_height = images_->bottom.height(); |
| 284 const int bl_width = images_->bottom_left->width(); | 394 const int bl_width = images_->bottom_left.width(); |
| 285 const int bl_height = images_->bottom_left->height(); | 395 const int bl_height = images_->bottom_left.height(); |
| 286 | 396 |
| 287 gfx::Insets insets; | 397 gfx::Insets insets; |
| 288 GetInsets(&insets); | 398 GetInsets(&insets); |
| 289 const int top = insets.top() - t_height; | 399 const int top = insets.top() - t_height; |
| 290 const int bottom = view.height() - insets.bottom() + b_height; | 400 const int bottom = view.height() - insets.bottom() + b_height; |
| 291 const int left = insets.left() - l_width; | 401 const int left = insets.left() - l_width; |
| 292 const int right = view.width() - insets.right() + r_width; | 402 const int right = view.width() - insets.right() + r_width; |
| 293 const int height = bottom - top; | 403 const int height = bottom - top; |
| 294 const int width = right - left; | 404 const int width = right - left; |
| 295 | 405 |
| 296 // |arrow_offset| is offset of arrow from the begining of the edge. | 406 // |arrow_offset| is offset of arrow from the beginning of the edge. |
| 297 int arrow_offset = arrow_offset_; | 407 int arrow_offset = GetArrowOffset(view.size()); |
| 298 if (override_arrow_offset_) | 408 if (!is_arrow_at_center(arrow_location_)) { |
| 299 arrow_offset = override_arrow_offset_; | 409 if (is_arrow_on_horizontal(arrow_location_) && |
| 300 else if (is_arrow_on_horizontal(arrow_location_) && | 410 !is_arrow_on_left(arrow_location_)) { |
| 301 !is_arrow_on_left(arrow_location_)) { | 411 arrow_offset = view.width() - arrow_offset - 1; |
| 302 arrow_offset = view.width() - arrow_offset - 1; | 412 } else if (!is_arrow_on_horizontal(arrow_location_) && |
| 303 } else if (!is_arrow_on_horizontal(arrow_location_) && | 413 !is_arrow_on_top(arrow_location_)) { |
| 304 !is_arrow_on_top(arrow_location_)) { | 414 arrow_offset = view.height() - arrow_offset - 1; |
| 305 arrow_offset = view.height() - arrow_offset - 1; | 415 } |
| 306 } | 416 } |
| 307 | 417 |
| 308 // Left edge. | 418 // Left edge. |
| 309 if (arrow_location_ == LEFT_TOP || arrow_location_ == LEFT_BOTTOM) { | 419 if (arrow_location_ == LEFT_TOP || |
| 420 arrow_location_ == LEFT_CENTER || |
| 421 arrow_location_ == LEFT_BOTTOM) { |
| 310 int start_y = top + tl_height; | 422 int start_y = top + tl_height; |
| 311 int before_arrow = | 423 int before_arrow = |
| 312 arrow_offset - start_y - images_->left_arrow->height() / 2; | 424 arrow_offset - start_y - images_->left_arrow.height() / 2; |
| 313 int after_arrow = height - tl_height - bl_height - | 425 int after_arrow = height - tl_height - bl_height - |
| 314 images_->left_arrow->height() - before_arrow; | 426 images_->left_arrow.height() - before_arrow; |
| 315 // Shift tip coordinates half pixel so that skia draws the tip correctly. | 427 // Shift tip coordinates half pixel so that skia draws the tip correctly. |
| 316 DrawArrowInterior(canvas, | 428 DrawArrowInterior(canvas, |
| 317 images_->left_arrow->width() - kArrowInteriorHeight - 0.5f, | 429 images_->left_arrow.width() - images_->arrow_interior_height - 0.5f, |
| 318 start_y + before_arrow + images_->left_arrow->height() / 2 - 0.5f); | 430 start_y + before_arrow + images_->left_arrow.height() / 2 - 0.5f); |
| 319 DrawEdgeWithArrow(canvas, | 431 DrawEdgeWithArrow(canvas, |
| 320 false, | 432 false, |
| 321 images_->left, | 433 images_->left, |
| 322 images_->left_arrow, | 434 images_->left_arrow, |
| 323 left, | 435 left, |
| 324 start_y, | 436 start_y, |
| 325 before_arrow, | 437 before_arrow, |
| 326 after_arrow, | 438 after_arrow, |
| 327 images_->left->width() - images_->left_arrow->width()); | 439 images_->left.width() - images_->left_arrow.width()); |
| 328 } else { | 440 } else { |
| 329 canvas->TileImageInt(*images_->left, left, top + tl_height, l_width, | 441 canvas->TileImageInt(images_->left, left, top + tl_height, l_width, |
| 330 height - tl_height - bl_height); | 442 height - tl_height - bl_height); |
| 331 } | 443 } |
| 332 | 444 |
| 333 // Top left corner. | 445 // Top left corner. |
| 334 canvas->DrawImageInt(*images_->top_left, left, top); | 446 canvas->DrawImageInt(images_->top_left, left, top); |
| 335 | 447 |
| 336 // Top edge. | 448 // Top edge. |
| 337 if (arrow_location_ == TOP_LEFT || arrow_location_ == TOP_RIGHT) { | 449 if (arrow_location_ == TOP_LEFT || |
| 450 arrow_location_ == TOP_CENTER || |
| 451 arrow_location_ == TOP_RIGHT) { |
| 338 int start_x = left + tl_width; | 452 int start_x = left + tl_width; |
| 339 int before_arrow = arrow_offset - start_x - images_->top_arrow->width() / 2; | 453 int before_arrow = arrow_offset - start_x - images_->top_arrow.width() / 2; |
| 340 int after_arrow = width - tl_width - tr_width - | 454 int after_arrow = width - tl_width - tr_width - |
| 341 images_->top_arrow->width() - before_arrow; | 455 images_->top_arrow.width() - before_arrow; |
| 342 DrawArrowInterior(canvas, | 456 DrawArrowInterior(canvas, |
| 343 start_x + before_arrow + images_->top_arrow->width() / 2, | 457 start_x + before_arrow + images_->top_arrow.width() / 2, |
| 344 images_->top_arrow->height() - kArrowInteriorHeight); | 458 images_->top_arrow.height() - images_->arrow_interior_height); |
| 345 DrawEdgeWithArrow(canvas, | 459 DrawEdgeWithArrow(canvas, |
| 346 true, | 460 true, |
| 347 images_->top, | 461 images_->top, |
| 348 images_->top_arrow, | 462 images_->top_arrow, |
| 349 start_x, | 463 start_x, |
| 350 top, | 464 top, |
| 351 before_arrow, | 465 before_arrow, |
| 352 after_arrow, | 466 after_arrow, |
| 353 images_->top->height() - images_->top_arrow->height()); | 467 images_->top.height() - images_->top_arrow.height()); |
| 354 } else { | 468 } else { |
| 355 canvas->TileImageInt(*images_->top, left + tl_width, top, | 469 canvas->TileImageInt(images_->top, left + tl_width, top, |
| 356 width - tl_width - tr_width, t_height); | 470 width - tl_width - tr_width, t_height); |
| 357 } | 471 } |
| 358 | 472 |
| 359 // Top right corner. | 473 // Top right corner. |
| 360 canvas->DrawImageInt(*images_->top_right, right - tr_width, top); | 474 canvas->DrawImageInt(images_->top_right, right - tr_width, top); |
| 361 | 475 |
| 362 // Right edge. | 476 // Right edge. |
| 363 if (arrow_location_ == RIGHT_TOP || arrow_location_ == RIGHT_BOTTOM) { | 477 if (arrow_location_ == RIGHT_TOP || |
| 478 arrow_location_ == RIGHT_CENTER || |
| 479 arrow_location_ == RIGHT_BOTTOM) { |
| 364 int start_y = top + tr_height; | 480 int start_y = top + tr_height; |
| 365 int before_arrow = | 481 int before_arrow = |
| 366 arrow_offset - start_y - images_->right_arrow->height() / 2; | 482 arrow_offset - start_y - images_->right_arrow.height() / 2; |
| 367 int after_arrow = height - tl_height - bl_height - | 483 int after_arrow = height - tl_height - bl_height - |
| 368 images_->right_arrow->height() - before_arrow; | 484 images_->right_arrow.height() - before_arrow; |
| 369 // Shift tip coordinates half pixel so that skia draws the tip correctly. | 485 // Shift tip coordinates half pixel so that skia draws the tip correctly. |
| 370 DrawArrowInterior(canvas, | 486 DrawArrowInterior(canvas, |
| 371 right - r_width + kArrowInteriorHeight - 0.5f, | 487 right - r_width + images_->arrow_interior_height - 0.5f, |
| 372 start_y + before_arrow + images_->right_arrow->height() / 2 - 0.5f); | 488 start_y + before_arrow + images_->right_arrow.height() / 2 - 0.5f); |
| 373 DrawEdgeWithArrow(canvas, | 489 DrawEdgeWithArrow(canvas, |
| 374 false, | 490 false, |
| 375 images_->right, | 491 images_->right, |
| 376 images_->right_arrow, | 492 images_->right_arrow, |
| 377 right - r_width, | 493 right - r_width, |
| 378 start_y, | 494 start_y, |
| 379 before_arrow, | 495 before_arrow, |
| 380 after_arrow, | 496 after_arrow, |
| 381 0); | 497 0); |
| 382 } else { | 498 } else { |
| 383 canvas->TileImageInt(*images_->right, right - r_width, top + tr_height, | 499 canvas->TileImageInt(images_->right, right - r_width, top + tr_height, |
| 384 r_width, height - tr_height - br_height); | 500 r_width, height - tr_height - br_height); |
| 385 } | 501 } |
| 386 | 502 |
| 387 // Bottom right corner. | 503 // Bottom right corner. |
| 388 canvas->DrawImageInt(*images_->bottom_right, | 504 canvas->DrawImageInt(images_->bottom_right, |
| 389 right - br_width, | 505 right - br_width, |
| 390 bottom - br_height); | 506 bottom - br_height); |
| 391 | 507 |
| 392 // Bottom edge. | 508 // Bottom edge. |
| 393 if (arrow_location_ == BOTTOM_LEFT || arrow_location_ == BOTTOM_RIGHT) { | 509 if (arrow_location_ == BOTTOM_LEFT || |
| 510 arrow_location_ == BOTTOM_CENTER || |
| 511 arrow_location_ == BOTTOM_RIGHT) { |
| 394 int start_x = left + bl_width; | 512 int start_x = left + bl_width; |
| 395 int before_arrow = | 513 int before_arrow = |
| 396 arrow_offset - start_x - images_->bottom_arrow->width() / 2; | 514 arrow_offset - start_x - images_->bottom_arrow.width() / 2; |
| 397 int after_arrow = width - bl_width - br_width - | 515 int after_arrow = width - bl_width - br_width - |
| 398 images_->bottom_arrow->width() - before_arrow; | 516 images_->bottom_arrow.width() - before_arrow; |
| 399 DrawArrowInterior(canvas, | 517 DrawArrowInterior(canvas, |
| 400 start_x + before_arrow + images_->bottom_arrow->width() / 2, | 518 start_x + before_arrow + images_->bottom_arrow.width() / 2, |
| 401 bottom - b_height + kArrowInteriorHeight); | 519 bottom - b_height + images_->arrow_interior_height); |
| 402 DrawEdgeWithArrow(canvas, | 520 DrawEdgeWithArrow(canvas, |
| 403 true, | 521 true, |
| 404 images_->bottom, | 522 images_->bottom, |
| 405 images_->bottom_arrow, | 523 images_->bottom_arrow, |
| 406 start_x, | 524 start_x, |
| 407 bottom - b_height, | 525 bottom - b_height, |
| 408 before_arrow, | 526 before_arrow, |
| 409 after_arrow, | 527 after_arrow, |
| 410 0); | 528 0); |
| 411 } else { | 529 } else { |
| 412 canvas->TileImageInt(*images_->bottom, left + bl_width, bottom - b_height, | 530 canvas->TileImageInt(images_->bottom, left + bl_width, bottom - b_height, |
| 413 width - bl_width - br_width, b_height); | 531 width - bl_width - br_width, b_height); |
| 414 } | 532 } |
| 415 | 533 |
| 416 // Bottom left corner. | 534 // Bottom left corner. |
| 417 canvas->DrawImageInt(*images_->bottom_left, left, bottom - bl_height); | 535 canvas->DrawImageInt(images_->bottom_left, left, bottom - bl_height); |
| 418 } | 536 } |
| 419 | 537 |
| 420 void BubbleBorder::DrawEdgeWithArrow(gfx::Canvas* canvas, | 538 void BubbleBorder::DrawEdgeWithArrow(gfx::Canvas* canvas, |
| 421 bool is_horizontal, | 539 bool is_horizontal, |
| 422 gfx::ImageSkia* edge, | 540 const gfx::ImageSkia& edge, |
| 423 gfx::ImageSkia* arrow, | 541 const gfx::ImageSkia& arrow, |
| 424 int start_x, | 542 int start_x, |
| 425 int start_y, | 543 int start_y, |
| 426 int before_arrow, | 544 int before_arrow, |
| 427 int after_arrow, | 545 int after_arrow, |
| 428 int offset) const { | 546 int offset) const { |
| 429 /* Here's what the parameters mean: | 547 /* Here's what the parameters mean: |
| 430 * start_x | 548 * start_x |
| 431 * . | 549 * . |
| 432 * . ┌───┐ ┬ offset | 550 * . ┌───┐ ┬ offset |
| 433 * start_y..........┌────┬────────┤ ▲ ├────────┬────┐ | 551 * start_y..........┌────┬────────┤ ▲ ├────────┬────┐ |
| 434 * │ / │--------│∙ ∙│--------│ \ │ | 552 * │ / │--------│∙ ∙│--------│ \ │ |
| 435 * │ / ├────────┴───┴────────┤ \ │ | 553 * │ / ├────────┴───┴────────┤ \ │ |
| 436 * ├───┬┘ └┬───┤ | 554 * ├───┬┘ └┬───┤ |
| 437 * └───┬────┘ └───┬────┘ | 555 * └───┬────┘ └───┬────┘ |
| 438 * before_arrow ─┘ └─ after_arrow | 556 * before_arrow ─┘ └─ after_arrow |
| 439 */ | 557 */ |
| 440 if (before_arrow) { | 558 if (before_arrow) { |
| 441 canvas->TileImageInt(*edge, start_x, start_y, | 559 canvas->TileImageInt(edge, start_x, start_y, |
| 442 is_horizontal ? before_arrow : edge->width(), | 560 is_horizontal ? before_arrow : edge.width(), |
| 443 is_horizontal ? edge->height() : before_arrow); | 561 is_horizontal ? edge.height() : before_arrow); |
| 444 } | 562 } |
| 445 | 563 |
| 446 canvas->DrawImageInt(*arrow, | 564 canvas->DrawImageInt(arrow, |
| 447 start_x + (is_horizontal ? before_arrow : offset), | 565 start_x + (is_horizontal ? before_arrow : offset), |
| 448 start_y + (is_horizontal ? offset : before_arrow)); | 566 start_y + (is_horizontal ? offset : before_arrow)); |
| 449 | 567 |
| 450 if (after_arrow) { | 568 if (after_arrow) { |
| 451 start_x += (is_horizontal ? before_arrow + arrow->width() : 0); | 569 start_x += (is_horizontal ? before_arrow + arrow.width() : 0); |
| 452 start_y += (is_horizontal ? 0 : before_arrow + arrow->height()); | 570 start_y += (is_horizontal ? 0 : before_arrow + arrow.height()); |
| 453 canvas->TileImageInt(*edge, start_x, start_y, | 571 canvas->TileImageInt(edge, start_x, start_y, |
| 454 is_horizontal ? after_arrow : edge->width(), | 572 is_horizontal ? after_arrow : edge.width(), |
| 455 is_horizontal ? edge->height() : after_arrow); | 573 is_horizontal ? edge.height() : after_arrow); |
| 456 } | 574 } |
| 457 } | 575 } |
| 458 | 576 |
| 459 void BubbleBorder::DrawArrowInterior(gfx::Canvas* canvas, | 577 void BubbleBorder::DrawArrowInterior(gfx::Canvas* canvas, |
| 460 float tip_x, | 578 float tip_x, |
| 461 float tip_y) const { | 579 float tip_y) const { |
| 462 const bool is_horizontal = is_arrow_on_horizontal(arrow_location_); | 580 const bool is_horizontal = is_arrow_on_horizontal(arrow_location_); |
| 463 const bool positive_offset = is_horizontal ? | 581 const bool positive_offset = is_horizontal ? |
| 464 is_arrow_on_top(arrow_location_) : is_arrow_on_left(arrow_location_); | 582 is_arrow_on_top(arrow_location_) : is_arrow_on_left(arrow_location_); |
| 465 const int offset_to_next_vertex = positive_offset ? | 583 const int offset_to_next_vertex = positive_offset ? |
| 466 kArrowInteriorHeight : -kArrowInteriorHeight; | 584 images_->arrow_interior_height : -images_->arrow_interior_height; |
| 467 | 585 |
| 468 SkPath path; | 586 SkPath path; |
| 469 path.incReserve(4); | 587 path.incReserve(4); |
| 470 path.moveTo(SkDoubleToScalar(tip_x), SkDoubleToScalar(tip_y)); | 588 path.moveTo(SkDoubleToScalar(tip_x), SkDoubleToScalar(tip_y)); |
| 471 path.lineTo(SkDoubleToScalar(tip_x + offset_to_next_vertex), | 589 path.lineTo(SkDoubleToScalar(tip_x + offset_to_next_vertex), |
| 472 SkDoubleToScalar(tip_y + offset_to_next_vertex)); | 590 SkDoubleToScalar(tip_y + offset_to_next_vertex)); |
| 473 if (is_horizontal) { | 591 if (is_horizontal) { |
| 474 path.lineTo(SkDoubleToScalar(tip_x - offset_to_next_vertex), | 592 path.lineTo(SkDoubleToScalar(tip_x - offset_to_next_vertex), |
| 475 SkDoubleToScalar(tip_y + offset_to_next_vertex)); | 593 SkDoubleToScalar(tip_y + offset_to_next_vertex)); |
| 476 } else { | 594 } else { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 499 // contents, which we need to fill with the background color. | 617 // contents, which we need to fill with the background color. |
| 500 // NOTE: This doesn't handle an arrow location of "NONE", which has square top | 618 // NOTE: This doesn't handle an arrow location of "NONE", which has square top |
| 501 // corners. | 619 // corners. |
| 502 SkPaint paint; | 620 SkPaint paint; |
| 503 paint.setAntiAlias(true); | 621 paint.setAntiAlias(true); |
| 504 paint.setStyle(SkPaint::kFill_Style); | 622 paint.setStyle(SkPaint::kFill_Style); |
| 505 paint.setColor(border_->background_color()); | 623 paint.setColor(border_->background_color()); |
| 506 SkPath path; | 624 SkPath path; |
| 507 gfx::Rect bounds(view->GetContentsBounds()); | 625 gfx::Rect bounds(view->GetContentsBounds()); |
| 508 bounds.Inset(-border_->GetBorderThickness(), -border_->GetBorderThickness()); | 626 bounds.Inset(-border_->GetBorderThickness(), -border_->GetBorderThickness()); |
| 509 SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius()); | 627 SkScalar radius = SkIntToScalar(border_->GetBorderCornerRadius()); |
| 510 path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius); | 628 path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius); |
| 511 canvas->DrawPath(path, paint); | 629 canvas->DrawPath(path, paint); |
| 512 } | 630 } |
| 513 | 631 |
| 514 } // namespace views | 632 } // namespace views |
| OLD | NEW |