summaryrefslogtreecommitdiffstats
path: root/chrome/browser/views/bubble_border.cc
blob: 8bf01703e035d973a0a053520893a1979a03ad0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.

#include "chrome/browser/views/bubble_border.h"

#include "app/gfx/canvas.h"
#include "app/gfx/path.h"
#include "app/resource_bundle.h"
#include "base/logging.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"

// static
SkBitmap* BubbleBorder::left_ = NULL;
SkBitmap* BubbleBorder::top_left_ = NULL;
SkBitmap* BubbleBorder::top_ = NULL;
SkBitmap* BubbleBorder::top_right_ = NULL;
SkBitmap* BubbleBorder::right_ = NULL;
SkBitmap* BubbleBorder::bottom_right_ = NULL;
SkBitmap* BubbleBorder::bottom_ = NULL;
SkBitmap* BubbleBorder::bottom_left_ = NULL;

gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to,
                                  const gfx::Size& contents_size) const {
  // The spacing (in pixels) between |position_relative_to| and the bubble
  // content.
  const int kBubbleSpacing = 2;

  // Desired size is size of contents enlarged by the size of the border images.
  gfx::Size border_size(contents_size);
  gfx::Insets insets;
  GetInsets(&insets);
  border_size.Enlarge(insets.left() + insets.right(),
                      insets.top() + insets.bottom());

  int x = position_relative_to.x() + (position_relative_to.width() / 2) -
      (contents_size.width() / 2) - insets.left();
  int y = position_relative_to.bottom() - (top_->height() - kBubbleSpacing);

  return gfx::Rect(x, y, border_size.width(), border_size.height());
}

void BubbleBorder::GetInsets(gfx::Insets* insets) const {
  insets->Set(top_->height(), left_->width(), bottom_->height(),
              right_->width());
}

// static
void BubbleBorder::InitClass() {
  static bool initialized = false;
  if (!initialized) {
    // Load images.
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    left_ = rb.GetBitmapNamed(IDR_BUBBLE_L);
    top_left_ = rb.GetBitmapNamed(IDR_BUBBLE_TL);
    top_ = rb.GetBitmapNamed(IDR_BUBBLE_T);
    top_right_ = rb.GetBitmapNamed(IDR_BUBBLE_TR);
    right_ = rb.GetBitmapNamed(IDR_BUBBLE_R);
    bottom_right_ = rb.GetBitmapNamed(IDR_BUBBLE_BR);
    bottom_ = rb.GetBitmapNamed(IDR_BUBBLE_B);
    bottom_left_ = rb.GetBitmapNamed(IDR_BUBBLE_BL);

    initialized = true;
  }
}

void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const {
  // Convenience shorthand variables
  int width = view.width();
  int tl_width = top_left_->width();
  int tl_height = top_left_->height();
  int t_height = top_->height();
  int tr_width = top_right_->width();
  int tr_height = top_right_->height();
  int r_width = right_->width();
  int br_width = bottom_right_->width();
  int br_height = bottom_right_->height();
  int b_height = bottom_->height();
  int bl_width = bottom_left_->width();
  int bl_height = bottom_left_->height();

  /* The variables below can be confusing; here's what they mean:
   *
   * border_top∙∙∙∙∙∙∙┌────┬────────┬────┐
   *                  │  / │--------│ \  │
   * top∙∙∙∙∙∙∙∙∙∙∙∙∙∙│ /  ├────────┤  \ │
   *   tl_bottom∙∙∙∙∙∙├───┬┘        └┬───┤∙∙∙∙∙∙tr_bottom
   *                  │ | │          │ | │
   *                  │ | │          │ | │
   *                  │ | │          │ | │
   *   bl_y∙∙∙∙∙∙∙∙∙∙∙├───┴┐        ┌┴───┤∙∙∙∙∙∙br_y
   * bottom∙∙∙∙∙∙∙∙∙∙∙│ \  ├────────┤  / │
   *                  │  \ │--------│ /  │
   * border_bottom∙∙∙∙└────┴────────┴────┘
   */

  gfx::Insets insets;
  GetInsets(&insets);
  int top = insets.top();
  int border_top = top - t_height;
  int tl_bottom = border_top + tl_height;
  int tr_bottom = border_top + tr_height;
  int bottom = view.height() - insets.bottom();
  int border_bottom = bottom + b_height;
  int bl_y = border_bottom - bl_height;
  int br_y = border_bottom - br_height;

  // Top left corner
  canvas->DrawBitmapInt(*top_left_, 0, border_top);

  // Top edge
  canvas->TileImageInt(*top_, tl_width, border_top, width - tl_width - tr_width,
                       t_height);

  // Top right corner
  canvas->DrawBitmapInt(*top_right_, width - tr_width, border_top);

  // Right edge
  canvas->TileImageInt(*right_, width - r_width, tr_bottom, r_width,
                       br_y - tr_bottom);

  // Bottom right corner
  canvas->DrawBitmapInt(*bottom_right_, width - br_width, br_y);

  // Bottom edge
  canvas->TileImageInt(*bottom_, bl_width, bottom, width - bl_width - br_width,
                       b_height);

  // Bottom left corner
  canvas->DrawBitmapInt(*bottom_left_, 0, bl_y);

  // Left edge
  canvas->TileImageInt(*left_, 0, tl_bottom, left_->width(), bl_y - tl_bottom);
}