| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
| 2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. | 3 // LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/views/bubble_border.h" | 5 #include "chrome/browser/views/bubble_border.h" |
| 6 | 6 |
| 7 #include "app/gfx/canvas.h" | 7 #include "app/gfx/canvas.h" |
| 8 #include "app/gfx/path.h" | 8 #include "app/gfx/path.h" |
| 9 #include "app/resource_bundle.h" | 9 #include "app/resource_bundle.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "grit/theme_resources.h" | 11 #include "grit/theme_resources.h" |
| 12 #include "third_party/skia/include/core/SkBitmap.h" | 12 #include "third_party/skia/include/core/SkBitmap.h" |
| 13 | 13 |
| 14 // static | 14 // static |
| 15 SkBitmap* BubbleBorder::left_ = NULL; | 15 SkBitmap* BubbleBorder::left_ = NULL; |
| 16 SkBitmap* BubbleBorder::top_left_ = NULL; | 16 SkBitmap* BubbleBorder::top_left_ = NULL; |
| 17 SkBitmap* BubbleBorder::top_ = NULL; | 17 SkBitmap* BubbleBorder::top_ = NULL; |
| 18 SkBitmap* BubbleBorder::top_right_ = NULL; | 18 SkBitmap* BubbleBorder::top_right_ = NULL; |
| 19 SkBitmap* BubbleBorder::right_ = NULL; | 19 SkBitmap* BubbleBorder::right_ = NULL; |
| 20 SkBitmap* BubbleBorder::bottom_right_ = NULL; | 20 SkBitmap* BubbleBorder::bottom_right_ = NULL; |
| 21 SkBitmap* BubbleBorder::bottom_ = NULL; | 21 SkBitmap* BubbleBorder::bottom_ = NULL; |
| 22 SkBitmap* BubbleBorder::bottom_left_ = NULL; | 22 SkBitmap* BubbleBorder::bottom_left_ = NULL; |
| 23 SkBitmap* BubbleBorder::top_arrow_ = NULL; |
| 24 SkBitmap* BubbleBorder::bottom_arrow_ = NULL; |
| 25 |
| 26 //static |
| 27 int BubbleBorder::arrow_x_offset_; |
| 28 |
| 29 // The height inside the arrow image, in pixels. |
| 30 static const int kArrowInteriorHeight = 7; |
| 23 | 31 |
| 24 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to, | 32 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to, |
| 25 const gfx::Size& contents_size) const { | 33 const gfx::Size& contents_size) const { |
| 26 // The spacing (in pixels) between |position_relative_to| and the bubble | 34 // The spacing (in pixels) between |position_relative_to| and the bubble |
| 27 // content. | 35 // content. |
| 28 const int kBubbleSpacing = 2; | 36 const int kBubbleSpacing = 2; |
| 29 | 37 |
| 30 // Desired size is size of contents enlarged by the size of the border images. | 38 // Desired size is size of contents enlarged by the size of the border images. |
| 31 gfx::Size border_size(contents_size); | 39 gfx::Size border_size(contents_size); |
| 32 gfx::Insets insets; | 40 gfx::Insets insets; |
| 33 GetInsets(&insets); | 41 GetInsets(&insets); |
| 34 border_size.Enlarge(insets.left() + insets.right(), | 42 border_size.Enlarge(insets.left() + insets.right(), |
| 35 insets.top() + insets.bottom()); | 43 insets.top() + insets.bottom()); |
| 36 | 44 |
| 37 int x = position_relative_to.x() + (position_relative_to.width() / 2) - | 45 // Screen position depends on the arrow location. |
| 38 (contents_size.width() / 2) - insets.left(); | 46 int x = position_relative_to.x() + (position_relative_to.width() / 2); |
| 39 int y = position_relative_to.bottom() - (top_->height() - kBubbleSpacing); | 47 if (arrow_is_left()) |
| 48 x -= arrow_x_offset_; |
| 49 else if (arrow_location_ == NONE) |
| 50 x -= ((contents_size.width() / 2) + insets.left()); |
| 51 else |
| 52 x += (arrow_x_offset_ - border_size.width() + 1); |
| 53 int y = position_relative_to.y(); |
| 54 if (arrow_is_top()) { |
| 55 y += (position_relative_to.height() - |
| 56 (top_arrow_->height() - kBubbleSpacing)); |
| 57 } else if (arrow_location_ == NONE) { |
| 58 y += (position_relative_to.height() - (top_->height() - kBubbleSpacing)); |
| 59 } else { |
| 60 y += ((bottom_arrow_->height() - kBubbleSpacing) - border_size.height()); |
| 61 } |
| 40 | 62 |
| 41 return gfx::Rect(x, y, border_size.width(), border_size.height()); | 63 return gfx::Rect(x, y, border_size.width(), border_size.height()); |
| 42 } | 64 } |
| 43 | 65 |
| 44 void BubbleBorder::GetInsets(gfx::Insets* insets) const { | 66 void BubbleBorder::GetInsets(gfx::Insets* insets) const { |
| 45 insets->Set(top_->height(), left_->width(), bottom_->height(), | 67 int top = top_->height(); |
| 46 right_->width()); | 68 int bottom = bottom_->height(); |
| 69 if (arrow_is_top()) |
| 70 top = std::max(top, top_arrow_->height()); |
| 71 else if (arrow_location_ != NONE) |
| 72 bottom = std::max(bottom, bottom_arrow_->height()); |
| 73 insets->Set(top, left_->width(), bottom, right_->width()); |
| 47 } | 74 } |
| 48 | 75 |
| 49 // static | 76 // static |
| 50 void BubbleBorder::InitClass() { | 77 void BubbleBorder::InitClass() { |
| 51 static bool initialized = false; | 78 static bool initialized = false; |
| 52 if (!initialized) { | 79 if (!initialized) { |
| 53 // Load images. | 80 // Load images. |
| 54 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 81 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 55 left_ = rb.GetBitmapNamed(IDR_BUBBLE_L); | 82 left_ = rb.GetBitmapNamed(IDR_BUBBLE_L); |
| 56 top_left_ = rb.GetBitmapNamed(IDR_BUBBLE_TL); | 83 top_left_ = rb.GetBitmapNamed(IDR_BUBBLE_TL); |
| 57 top_ = rb.GetBitmapNamed(IDR_BUBBLE_T); | 84 top_ = rb.GetBitmapNamed(IDR_BUBBLE_T); |
| 58 top_right_ = rb.GetBitmapNamed(IDR_BUBBLE_TR); | 85 top_right_ = rb.GetBitmapNamed(IDR_BUBBLE_TR); |
| 59 right_ = rb.GetBitmapNamed(IDR_BUBBLE_R); | 86 right_ = rb.GetBitmapNamed(IDR_BUBBLE_R); |
| 60 bottom_right_ = rb.GetBitmapNamed(IDR_BUBBLE_BR); | 87 bottom_right_ = rb.GetBitmapNamed(IDR_BUBBLE_BR); |
| 61 bottom_ = rb.GetBitmapNamed(IDR_BUBBLE_B); | 88 bottom_ = rb.GetBitmapNamed(IDR_BUBBLE_B); |
| 62 bottom_left_ = rb.GetBitmapNamed(IDR_BUBBLE_BL); | 89 bottom_left_ = rb.GetBitmapNamed(IDR_BUBBLE_BL); |
| 90 top_arrow_ = rb.GetBitmapNamed(IDR_BUBBLE_T_ARROW); |
| 91 bottom_arrow_ = rb.GetBitmapNamed(IDR_BUBBLE_B_ARROW); |
| 92 |
| 93 // Calculate horizontal inset for arrow by ensuring that the widest arrow |
| 94 // and corner images will have enough room to avoid overlap. |
| 95 arrow_x_offset_ = |
| 96 (std::max(top_arrow_->width(), bottom_arrow_->width()) / 2) + |
| 97 std::max(std::max(top_left_->width(), top_right_->width()), |
| 98 std::max(bottom_left_->width(), bottom_right_->width())); |
| 63 | 99 |
| 64 initialized = true; | 100 initialized = true; |
| 65 } | 101 } |
| 66 } | 102 } |
| 67 | 103 |
| 68 void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { | 104 void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { |
| 69 // Convenience shorthand variables | 105 // Convenience shorthand variables |
| 70 int width = view.width(); | 106 int width = view.width(); |
| 71 int tl_width = top_left_->width(); | 107 int tl_width = top_left_->width(); |
| 72 int tl_height = top_left_->height(); | 108 int tl_height = top_left_->height(); |
| 73 int t_height = top_->height(); | 109 int t_height = top_->height(); |
| 74 int tr_width = top_right_->width(); | 110 int tr_width = top_right_->width(); |
| 75 int tr_height = top_right_->height(); | 111 int tr_height = top_right_->height(); |
| 76 int r_width = right_->width(); | 112 int r_width = right_->width(); |
| 77 int br_width = bottom_right_->width(); | 113 int br_width = bottom_right_->width(); |
| 78 int br_height = bottom_right_->height(); | 114 int br_height = bottom_right_->height(); |
| 79 int b_height = bottom_->height(); | 115 int b_height = bottom_->height(); |
| 80 int bl_width = bottom_left_->width(); | 116 int bl_width = bottom_left_->width(); |
| 81 int bl_height = bottom_left_->height(); | 117 int bl_height = bottom_left_->height(); |
| 82 | 118 |
| 83 /* The variables below can be confusing; here's what they mean: | 119 /* The variables below can be confusing; here's what they mean: |
| 84 * | 120 * |
| 85 * border_top∙∙∙∙∙∙∙┌────┬────────┬────┐ | 121 * 0∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙┌───┐ ┌───┐ |
| 86 * │ / │--------│ \ │ | 122 * border_top∙∙∙∙∙∙∙┌────┬─┤ ▲ ├──────┤ ▲ ├─┬────┐ |
| 87 * top∙∙∙∙∙∙∙∙∙∙∙∙∙∙│ / ├────────┤ \ │ | 123 * │ / │-│∙ ∙│------│∙ ∙│-│ \ │ |
| 88 * tl_bottom∙∙∙∙∙∙├───┬┘ └┬───┤∙∙∙∙∙∙tr_bottom | 124 * top∙∙∙∙∙∙∙∙∙∙∙∙∙∙│ / ├─┴───┴──────┴───┴─┤ \ │ |
| 89 * │ | │ │ | │ | 125 * tl_bottom∙∙∙∙∙∙├───┬┘ └┬───┤∙∙∙∙∙∙tr_bottom |
| 90 * │ | │ │ | │ | 126 * │ | │ │ | │ |
| 91 * │ | │ │ | │ | 127 * │ | │ │ | │ |
| 92 * bl_y∙∙∙∙∙∙∙∙∙∙∙├───┴┐ ┌┴───┤∙∙∙∙∙∙br_y | 128 * │ | │ │ | │ |
| 93 * bottom∙∙∙∙∙∙∙∙∙∙∙│ \ ├────────┤ / │ | 129 * bl_y∙∙∙∙∙∙∙∙∙∙∙├───┴┐ ┌┴───┤∙∙∙∙∙∙br_y |
| 94 * │ \ │--------│ / │ | 130 * bottom∙∙∙∙∙∙∙∙∙∙∙│ \ ├─┬───┬──────┬───┬─┤ / │ |
| 95 * border_bottom∙∙∙∙└────┴────────┴────┘ | 131 * │ \ │-│. .│------│. .│-│ / │ |
| 132 * border_bottom∙∙∙∙└────┴─┤ ▼ ├──────┤ ▼ ├─┴────┘ |
| 133 * view.height()∙∙∙∙∙∙∙∙∙∙∙└───┘ └───┘ |
| 134 * |
| 135 * (At most one of the arrows will be drawn) |
| 96 */ | 136 */ |
| 97 | 137 |
| 98 gfx::Insets insets; | 138 gfx::Insets insets; |
| 99 GetInsets(&insets); | 139 GetInsets(&insets); |
| 100 int top = insets.top(); | 140 int top = insets.top(); |
| 101 int border_top = top - t_height; | 141 int border_top = top - t_height; |
| 102 int tl_bottom = border_top + tl_height; | 142 int tl_bottom = border_top + tl_height; |
| 103 int tr_bottom = border_top + tr_height; | 143 int tr_bottom = border_top + tr_height; |
| 104 int bottom = view.height() - insets.bottom(); | 144 int bottom = view.height() - insets.bottom(); |
| 105 int border_bottom = bottom + b_height; | 145 int border_bottom = bottom + b_height; |
| 106 int bl_y = border_bottom - bl_height; | 146 int bl_y = border_bottom - bl_height; |
| 107 int br_y = border_bottom - br_height; | 147 int br_y = border_bottom - br_height; |
| 108 | 148 |
| 109 // Top left corner | 149 // Top left corner |
| 110 canvas->DrawBitmapInt(*top_left_, 0, border_top); | 150 canvas->DrawBitmapInt(*top_left_, 0, border_top); |
| 111 | 151 |
| 112 // Top edge | |
| 113 canvas->TileImageInt(*top_, tl_width, border_top, width - tl_width - tr_width, | |
| 114 t_height); | |
| 115 | |
| 116 // Top right corner | 152 // Top right corner |
| 117 canvas->DrawBitmapInt(*top_right_, width - tr_width, border_top); | 153 canvas->DrawBitmapInt(*top_right_, width - tr_width, border_top); |
| 118 | 154 |
| 119 // Right edge | 155 // Right edge |
| 120 canvas->TileImageInt(*right_, width - r_width, tr_bottom, r_width, | 156 canvas->TileImageInt(*right_, width - r_width, tr_bottom, r_width, |
| 121 br_y - tr_bottom); | 157 br_y - tr_bottom); |
| 122 | 158 |
| 123 // Bottom right corner | 159 // Bottom right corner |
| 124 canvas->DrawBitmapInt(*bottom_right_, width - br_width, br_y); | 160 canvas->DrawBitmapInt(*bottom_right_, width - br_width, br_y); |
| 125 | 161 |
| 126 // Bottom edge | |
| 127 canvas->TileImageInt(*bottom_, bl_width, bottom, width - bl_width - br_width, | |
| 128 b_height); | |
| 129 | 162 |
| 130 // Bottom left corner | 163 // Bottom left corner |
| 131 canvas->DrawBitmapInt(*bottom_left_, 0, bl_y); | 164 canvas->DrawBitmapInt(*bottom_left_, 0, bl_y); |
| 132 | 165 |
| 133 // Left edge | 166 // Left edge |
| 134 canvas->TileImageInt(*left_, 0, tl_bottom, left_->width(), bl_y - tl_bottom); | 167 canvas->TileImageInt(*left_, 0, tl_bottom, left_->width(), bl_y - tl_bottom); |
| 168 |
| 169 // Arrow edge, if necessary |
| 170 bool should_draw_top_edge = true; |
| 171 bool should_draw_bottom_edge = true; |
| 172 if (arrow_location_ != NONE) { |
| 173 /* Here's what the variables below mean (without loss of generality): |
| 174 * |
| 175 * arrow_center |
| 176 * arrow_x │ arrow_r |
| 177 * │ │ │ |
| 178 * left_of_edge─┬────┐ │ │ │ ┌────┬─right_of_edge |
| 179 * arrow_y∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙┌───┐ |
| 180 * edge_y∙∙∙∙∙∙∙┌────┬───┤ ▲ ├───────┬────┐ ┐ |
| 181 * │ / │---│∙ ∙│-------│ \ │ ├─e_height |
| 182 * │ / ├───┴───┴───────┤ \ │ ┘ |
| 183 * ├───┬┘ └┬───┤ |
| 184 * | | └─┬─┘ | | |
| 185 * ∙ ∙└─┬─┘ │ └───┬───┘∙ ∙ |
| 186 * left_of_arrow─┘ │ └─right_of_arrow |
| 187 * arrow_width |
| 188 * |
| 189 * Not shown: border_y and tip_y contain the base and tip coordinates inside |
| 190 * the arrow for use filling the arrow interior with the background color. |
| 191 */ |
| 192 |
| 193 SkBitmap* edge; |
| 194 SkBitmap* arrow; |
| 195 int left_of_edge, right_of_edge, edge_y, arrow_y; |
| 196 SkScalar border_y, tip_y; |
| 197 if (arrow_is_top()) { |
| 198 should_draw_top_edge = false; |
| 199 edge = top_; |
| 200 arrow = top_arrow_; |
| 201 left_of_edge = tl_width; |
| 202 right_of_edge = tr_width; |
| 203 edge_y = border_top; |
| 204 arrow_y = top - top_arrow_->height(); |
| 205 border_y = SkIntToScalar(top); |
| 206 tip_y = SkIntToScalar(top - kArrowInteriorHeight); |
| 207 } else { |
| 208 should_draw_bottom_edge = false; |
| 209 edge = bottom_; |
| 210 arrow = bottom_arrow_; |
| 211 left_of_edge = bl_width; |
| 212 right_of_edge = br_width; |
| 213 edge_y = arrow_y = bottom; |
| 214 border_y = SkIntToScalar(bottom); |
| 215 tip_y = SkIntToScalar(bottom + kArrowInteriorHeight); |
| 216 } |
| 217 int arrow_width = (arrow_is_top() ? top_arrow_ : bottom_arrow_)->width(); |
| 218 int arrow_center = arrow_is_left() ? |
| 219 arrow_x_offset_ : width - arrow_x_offset_ - 1; |
| 220 int arrow_x = arrow_center - (arrow_width / 2); |
| 221 SkScalar arrow_interior_x = |
| 222 SkIntToScalar(arrow_center - kArrowInteriorHeight); |
| 223 SkScalar arrow_interior_r = |
| 224 SkIntToScalar(arrow_center + kArrowInteriorHeight); |
| 225 int arrow_r = arrow_x + arrow_width; |
| 226 int e_height = edge->height(); |
| 227 |
| 228 // Edge to the left of the arrow |
| 229 int left_of_arrow = arrow_x - left_of_edge; |
| 230 if (left_of_arrow) { |
| 231 canvas->TileImageInt(*edge, left_of_edge, edge_y, left_of_arrow, |
| 232 e_height); |
| 233 } |
| 234 |
| 235 // Interior of the arrow (filled with background color) |
| 236 SkPaint paint; |
| 237 paint.setStyle(SkPaint::kFill_Style); |
| 238 paint.setColor(background_color_); |
| 239 gfx::Path path; |
| 240 path.incReserve(4); |
| 241 path.moveTo(arrow_interior_x, border_y); |
| 242 path.lineTo(SkIntToScalar(arrow_center), tip_y); |
| 243 path.lineTo(arrow_interior_r, border_y); |
| 244 path.close(); |
| 245 canvas->drawPath(path, paint); |
| 246 |
| 247 // Arrow border |
| 248 canvas->DrawBitmapInt(*arrow, arrow_x, arrow_y); |
| 249 |
| 250 // Edge to the right of the arrow |
| 251 int right_of_arrow = width - arrow_r - right_of_edge; |
| 252 if (right_of_arrow) |
| 253 canvas->TileImageInt(*edge, arrow_r, edge_y, right_of_arrow, e_height); |
| 254 } |
| 255 |
| 256 // Top edge, if not already drawn |
| 257 if (should_draw_top_edge) { |
| 258 canvas->TileImageInt(*top_, tl_width, border_top, |
| 259 width - tl_width - tr_width, t_height); |
| 260 } |
| 261 |
| 262 // Bottom edge, if not already drawn |
| 263 if (should_draw_bottom_edge) { |
| 264 canvas->TileImageInt(*bottom_, bl_width, bottom, |
| 265 width - bl_width - br_width, b_height); |
| 266 } |
| 135 } | 267 } |
| OLD | NEW |