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

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

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

Powered by Google App Engine
This is Rietveld 408576698