summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsaintlou@chromium.org <saintlou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-23 14:19:04 +0000
committersaintlou@chromium.org <saintlou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-23 14:19:04 +0000
commitc20b78a3fce7bea018c37d7ab41b86330fad6b87 (patch)
tree3f2209a2e5b7a4fc77d355bdb1ff1df414d65aea /views
parent4664d6f30434ab7453c7d5e912345f95ececdb07 (diff)
downloadchromium_src-c20b78a3fce7bea018c37d7ab41b86330fad6b87.zip
chromium_src-c20b78a3fce7bea018c37d7ab41b86330fad6b87.tar.gz
chromium_src-c20b78a3fce7bea018c37d7ab41b86330fad6b87.tar.bz2
move bubble border code and update references to it.
BUG=None TEST=None Review URL: http://codereview.chromium.org/7629009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97856 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/bubble/bubble_border.cc450
-rw-r--r--views/bubble/bubble_border.h176
-rw-r--r--views/views.gyp9
3 files changed, 635 insertions, 0 deletions
diff --git a/views/bubble/bubble_border.cc b/views/bubble/bubble_border.cc
new file mode 100644
index 0000000..80e1bc8
--- /dev/null
+++ b/views/bubble/bubble_border.cc
@@ -0,0 +1,450 @@
+// Copyright (c) 2011 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 "views/bubble/bubble_border.h"
+
+#include <algorithm> // for std::max
+
+#include "base/logging.h"
+#include "grit/ui_resources.h"
+#include "grit/ui_resources_standard.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/path.h"
+
+namespace views {
+
+// 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;
+SkBitmap* BubbleBorder::top_arrow_ = NULL;
+SkBitmap* BubbleBorder::bottom_arrow_ = NULL;
+SkBitmap* BubbleBorder::left_arrow_ = NULL;
+SkBitmap* BubbleBorder::right_arrow_ = NULL;
+
+// static
+int BubbleBorder::arrow_offset_;
+
+// The height inside the arrow image, in pixels.
+static const int kArrowInteriorHeight = 7;
+
+gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to,
+ const gfx::Size& contents_size) const {
+ // 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());
+
+ // Screen position depends on the arrow location.
+ // The arrow should overlap the target by some amount since there is space
+ // for shadow between arrow tip and bitmap bounds.
+ const int kArrowOverlap = 3;
+ int x = position_relative_to.x();
+ int y = position_relative_to.y();
+ int w = position_relative_to.width();
+ int h = position_relative_to.height();
+ int arrow_offset = override_arrow_offset_ ? override_arrow_offset_ :
+ arrow_offset_;
+
+ // Calculate bubble x coordinate.
+ switch (arrow_location_) {
+ case TOP_LEFT:
+ case BOTTOM_LEFT:
+ x += w / 2 - arrow_offset;
+ break;
+
+ case TOP_RIGHT:
+ case BOTTOM_RIGHT:
+ x += w / 2 + arrow_offset - border_size.width() + 1;
+ break;
+
+ case LEFT_TOP:
+ case LEFT_BOTTOM:
+ x += w - kArrowOverlap;
+ break;
+
+ case RIGHT_TOP:
+ case RIGHT_BOTTOM:
+ x += kArrowOverlap - border_size.width();
+ break;
+
+ case NONE:
+ case FLOAT:
+ x += w / 2 - border_size.width() / 2;
+ break;
+ }
+
+ // Calculate bubble y coordinate.
+ switch (arrow_location_) {
+ case TOP_LEFT:
+ case TOP_RIGHT:
+ y += h - kArrowOverlap;
+ break;
+
+ case BOTTOM_LEFT:
+ case BOTTOM_RIGHT:
+ y += kArrowOverlap - border_size.height();
+ break;
+
+ case LEFT_TOP:
+ case RIGHT_TOP:
+ y += h / 2 - arrow_offset;
+ break;
+
+ case LEFT_BOTTOM:
+ case RIGHT_BOTTOM:
+ y += h / 2 + arrow_offset - border_size.height() + 1;
+ break;
+
+ case NONE:
+ y += h;
+ break;
+
+ case FLOAT:
+ y += h / 2 - border_size.height() / 2;
+ break;
+ }
+
+ return gfx::Rect(x, y, border_size.width(), border_size.height());
+}
+
+void BubbleBorder::GetInsets(gfx::Insets* insets) const {
+ int top = top_->height();
+ int bottom = bottom_->height();
+ int left = left_->width();
+ int right = right_->width();
+ switch (arrow_location_) {
+ case TOP_LEFT:
+ case TOP_RIGHT:
+ top = std::max(top, top_arrow_->height());
+ break;
+
+ case BOTTOM_LEFT:
+ case BOTTOM_RIGHT:
+ bottom = std::max(bottom, bottom_arrow_->height());
+ break;
+
+ case LEFT_TOP:
+ case LEFT_BOTTOM:
+ left = std::max(left, left_arrow_->width());
+ break;
+
+ case RIGHT_TOP:
+ case RIGHT_BOTTOM:
+ right = std::max(right, right_arrow_->width());
+ break;
+
+ case NONE:
+ case FLOAT:
+ // Nothing to do.
+ break;
+ }
+ insets->Set(top, left, bottom, right);
+}
+
+int BubbleBorder::SetArrowOffset(int offset, const gfx::Size& contents_size) {
+ gfx::Size border_size(contents_size);
+ gfx::Insets insets;
+ GetInsets(&insets);
+ border_size.Enlarge(insets.left() + insets.right(),
+ insets.top() + insets.bottom());
+ offset = std::max(arrow_offset_,
+ std::min(offset, (is_arrow_on_horizontal(arrow_location_) ?
+ border_size.width() : border_size.height()) - arrow_offset_));
+ override_arrow_offset_ = offset;
+ return override_arrow_offset_;
+}
+
+// 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);
+ left_arrow_ = rb.GetBitmapNamed(IDR_BUBBLE_L_ARROW);
+ top_arrow_ = rb.GetBitmapNamed(IDR_BUBBLE_T_ARROW);
+ right_arrow_ = rb.GetBitmapNamed(IDR_BUBBLE_R_ARROW);
+ bottom_arrow_ = rb.GetBitmapNamed(IDR_BUBBLE_B_ARROW);
+
+ // Calculate horizontal and vertical insets for arrow by ensuring that
+ // the widest arrow and corner images will have enough room to avoid overlap
+ int offset_x =
+ (std::max(top_arrow_->width(), bottom_arrow_->width()) / 2) +
+ std::max(std::max(top_left_->width(), top_right_->width()),
+ std::max(bottom_left_->width(), bottom_right_->width()));
+ int offset_y =
+ (std::max(left_arrow_->height(), right_arrow_->height()) / 2) +
+ std::max(std::max(top_left_->height(), top_right_->height()),
+ std::max(bottom_left_->height(), bottom_right_->height()));
+ arrow_offset_ = std::max(offset_x, offset_y);
+
+ initialized = true;
+ }
+}
+
+void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const {
+ // Convenience shorthand variables.
+ const int tl_width = top_left_->width();
+ const int tl_height = top_left_->height();
+ const int t_height = top_->height();
+ const int tr_width = top_right_->width();
+ const int tr_height = top_right_->height();
+ const int l_width = left_->width();
+ const int r_width = right_->width();
+ const int br_width = bottom_right_->width();
+ const int br_height = bottom_right_->height();
+ const int b_height = bottom_->height();
+ const int bl_width = bottom_left_->width();
+ const int bl_height = bottom_left_->height();
+
+ gfx::Insets insets;
+ GetInsets(&insets);
+ const int top = insets.top() - t_height;
+ const int bottom = view.height() - insets.bottom() + b_height;
+ const int left = insets.left() - l_width;
+ const int right = view.width() - insets.right() + r_width;
+ const int height = bottom - top;
+ const int width = right - left;
+
+ // |arrow_offset| is offset of arrow from the begining of the edge.
+ int arrow_offset = arrow_offset_;
+ if (override_arrow_offset_)
+ arrow_offset = override_arrow_offset_;
+ else if (is_arrow_on_horizontal(arrow_location_) &&
+ !is_arrow_on_left(arrow_location_)) {
+ arrow_offset = view.width() - arrow_offset - 1;
+ } else if (!is_arrow_on_horizontal(arrow_location_) &&
+ !is_arrow_on_top(arrow_location_)) {
+ arrow_offset = view.height() - arrow_offset - 1;
+ }
+
+ // Left edge.
+ if (arrow_location_ == LEFT_TOP || arrow_location_ == LEFT_BOTTOM) {
+ int start_y = top + tl_height;
+ int before_arrow = arrow_offset - start_y - left_arrow_->height() / 2;
+ int after_arrow =
+ height - tl_height - bl_height - left_arrow_->height() - before_arrow;
+ DrawArrowInterior(canvas,
+ false,
+ left_arrow_->width() - kArrowInteriorHeight,
+ start_y + before_arrow + left_arrow_->height() / 2,
+ kArrowInteriorHeight,
+ left_arrow_->height() / 2 - 1);
+ DrawEdgeWithArrow(canvas,
+ false,
+ left_,
+ left_arrow_,
+ left,
+ start_y,
+ before_arrow,
+ after_arrow,
+ left_->width() - left_arrow_->width());
+ } else {
+ canvas->TileImageInt(*left_, left, top + tl_height, l_width,
+ height - tl_height - bl_height);
+ }
+
+ // Top left corner.
+ canvas->DrawBitmapInt(*top_left_, left, top);
+
+ // Top edge.
+ if (arrow_location_ == TOP_LEFT || arrow_location_ == TOP_RIGHT) {
+ int start_x = left + tl_width;
+ int before_arrow = arrow_offset - start_x - top_arrow_->width() / 2;
+ int after_arrow =
+ width - tl_width - tr_width - top_arrow_->width() - before_arrow;
+ DrawArrowInterior(canvas,
+ true,
+ start_x + before_arrow + top_arrow_->width() / 2,
+ top_arrow_->height() - kArrowInteriorHeight,
+ 1 - top_arrow_->width() / 2,
+ kArrowInteriorHeight);
+ DrawEdgeWithArrow(canvas,
+ true,
+ top_,
+ top_arrow_,
+ start_x,
+ top,
+ before_arrow,
+ after_arrow,
+ top_->height() - top_arrow_->height());
+ } else {
+ canvas->TileImageInt(*top_, left + tl_width, top,
+ width - tl_width - tr_width, t_height);
+ }
+
+ // Top right corner.
+ canvas->DrawBitmapInt(*top_right_, right - tr_width, top);
+
+ // Right edge.
+ if (arrow_location_ == RIGHT_TOP || arrow_location_ == RIGHT_BOTTOM) {
+ int start_y = top + tr_height;
+ int before_arrow = arrow_offset - start_y - right_arrow_->height() / 2;
+ int after_arrow = height - tl_height - bl_height -
+ right_arrow_->height() - before_arrow;
+ DrawArrowInterior(canvas,
+ false,
+ right - r_width + kArrowInteriorHeight,
+ start_y + before_arrow + right_arrow_->height() / 2,
+ -kArrowInteriorHeight,
+ right_arrow_->height() / 2 - 1);
+ DrawEdgeWithArrow(canvas,
+ false,
+ right_,
+ right_arrow_,
+ right - r_width,
+ start_y,
+ before_arrow,
+ after_arrow,
+ 0);
+ } else {
+ canvas->TileImageInt(*right_, right - r_width, top + tr_height, r_width,
+ height - tr_height - br_height);
+ }
+
+ // Bottom right corner.
+ canvas->DrawBitmapInt(*bottom_right_, right - br_width, bottom - br_height);
+
+ // Bottom edge.
+ if (arrow_location_ == BOTTOM_LEFT || arrow_location_ == BOTTOM_RIGHT) {
+ int start_x = left + bl_width;
+ int before_arrow = arrow_offset - start_x - bottom_arrow_->width() / 2;
+ int after_arrow =
+ width - bl_width - br_width - bottom_arrow_->width() - before_arrow;
+ DrawArrowInterior(canvas,
+ true,
+ start_x + before_arrow + bottom_arrow_->width() / 2,
+ bottom - b_height + kArrowInteriorHeight,
+ 1 - bottom_arrow_->width() / 2,
+ -kArrowInteriorHeight);
+ DrawEdgeWithArrow(canvas,
+ true,
+ bottom_,
+ bottom_arrow_,
+ start_x,
+ bottom - b_height,
+ before_arrow,
+ after_arrow,
+ 0);
+ } else {
+ canvas->TileImageInt(*bottom_, left + bl_width, bottom - b_height,
+ width - bl_width - br_width, b_height);
+ }
+
+ // Bottom left corner.
+ canvas->DrawBitmapInt(*bottom_left_, left, bottom - bl_height);
+}
+
+void BubbleBorder::DrawEdgeWithArrow(gfx::Canvas* canvas,
+ bool is_horizontal,
+ SkBitmap* edge,
+ SkBitmap* arrow,
+ int start_x,
+ int start_y,
+ int before_arrow,
+ int after_arrow,
+ int offset) const {
+ /* Here's what the parameters mean:
+ * start_x
+ * .
+ * . ┌───┐ ┬ offset
+ * start_y..........┌────┬────────┤ ▲ ├────────┬────┐
+ * │ / │--------│∙ ∙│--------│ \ │
+ * │ / ├────────┴───┴────────┤ \ │
+ * ├───┬┘ └┬───┤
+ * └───┬────┘ └───┬────┘
+ * before_arrow ─┘ └─ after_arrow
+ */
+ if (before_arrow) {
+ canvas->TileImageInt(*edge, start_x, start_y,
+ is_horizontal ? before_arrow : edge->width(),
+ is_horizontal ? edge->height() : before_arrow);
+ }
+
+ canvas->DrawBitmapInt(*arrow,
+ start_x + (is_horizontal ? before_arrow : offset),
+ start_y + (is_horizontal ? offset : before_arrow));
+
+ if (after_arrow) {
+ start_x += (is_horizontal ? before_arrow + arrow->width() : 0);
+ start_y += (is_horizontal ? 0 : before_arrow + arrow->height());
+ canvas->TileImageInt(*edge, start_x, start_y,
+ is_horizontal ? after_arrow : edge->width(),
+ is_horizontal ? edge->height() : after_arrow);
+ }
+}
+
+void BubbleBorder::DrawArrowInterior(gfx::Canvas* canvas,
+ bool is_horizontal,
+ int tip_x,
+ int tip_y,
+ int shift_x,
+ int shift_y) const {
+ /* This function fills the interior of the arrow with background color.
+ * It draws isosceles triangle under semitransparent arrow tip.
+ *
+ * Here's what the parameters mean:
+ *
+ * ┌──────── |tip_x|
+ * ┌─────┐
+ * │ ▲ │ ──── |tip y|
+ * │∙∙∙∙∙│ ┐
+ * └─────┘ └─── |shift_x| (offset from tip to vertexes of isosceles triangle)
+ * └────────── |shift_y|
+ */
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(background_color_);
+ gfx::Path path;
+ path.incReserve(4);
+ path.moveTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
+ path.lineTo(SkIntToScalar(tip_x + shift_x),
+ SkIntToScalar(tip_y + shift_y));
+ if (is_horizontal)
+ path.lineTo(SkIntToScalar(tip_x - shift_x), SkIntToScalar(tip_y + shift_y));
+ else
+ path.lineTo(SkIntToScalar(tip_x + shift_x), SkIntToScalar(tip_y - shift_y));
+ path.close();
+ canvas->AsCanvasSkia()->drawPath(path, paint);
+}
+
+/////////////////////////
+
+void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
+ // The border of this view creates an anti-aliased round-rect region for the
+ // contents, which we need to fill with the background color.
+ // NOTE: This doesn't handle an arrow location of "NONE", which has square top
+ // corners.
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(border_->background_color());
+ gfx::Path path;
+ gfx::Rect bounds(view->GetContentsBounds());
+ SkRect rect;
+ rect.set(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()),
+ SkIntToScalar(bounds.right()), SkIntToScalar(bounds.bottom()));
+ SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius());
+ path.addRoundRect(rect, radius, radius);
+ canvas->AsCanvasSkia()->drawPath(path, paint);
+}
+
+} // namespace views
diff --git a/views/bubble/bubble_border.h b/views/bubble/bubble_border.h
new file mode 100644
index 0000000..9f68fd7
--- /dev/null
+++ b/views/bubble/bubble_border.h
@@ -0,0 +1,176 @@
+// Copyright (c) 2010 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.
+
+#ifndef VIEWS_BUBBLE_BUBBLE_BORDER_H_
+#define VIEWS_BUBBLE_BUBBLE_BORDER_H_
+#pragma once
+
+#include "third_party/skia/include/core/SkColor.h"
+#include "views/background.h"
+#include "views/border.h"
+
+class SkBitmap;
+
+namespace views {
+
+// Renders a border, with optional arrow, and a custom dropshadow.
+// This can be used to produce floating "bubble" objects with rounded corners.
+class VIEWS_EXPORT BubbleBorder : public views::Border {
+ public:
+ // Possible locations for the (optional) arrow.
+ // 0 bit specifies left or right.
+ // 1 bit specifies top or bottom.
+ // 2 bit specifies horizontal or vertical.
+ enum ArrowLocation {
+ TOP_LEFT = 0,
+ TOP_RIGHT = 1,
+ BOTTOM_LEFT = 2,
+ BOTTOM_RIGHT = 3,
+ LEFT_TOP = 4,
+ RIGHT_TOP = 5,
+ LEFT_BOTTOM = 6,
+ RIGHT_BOTTOM = 7,
+ NONE = 8, // No arrow. Positioned under the supplied rect.
+ FLOAT = 9 // No arrow. Centered over the supplied rect.
+ };
+
+ explicit BubbleBorder(ArrowLocation arrow_location)
+ : override_arrow_offset_(0),
+ arrow_location_(arrow_location),
+ background_color_(SK_ColorWHITE) {
+ InitClass();
+ }
+
+ // Returns the radius of the corner of the border.
+ static int GetCornerRadius() {
+ // We can't safely calculate a border radius by comparing the sizes of the
+ // side and corner images, because either may have been extended in various
+ // directions in order to do more subtle dropshadow fading or other effects.
+ // So we hardcode the most accurate value.
+ return 4;
+ }
+
+ // Sets the location for the arrow.
+ void set_arrow_location(ArrowLocation arrow_location) {
+ arrow_location_ = arrow_location;
+ }
+ ArrowLocation arrow_location() const { return arrow_location_; }
+
+ static ArrowLocation horizontal_mirror(ArrowLocation loc) {
+ return loc >= NONE ? loc : static_cast<ArrowLocation>(loc ^ 1);
+ }
+
+ static ArrowLocation vertical_mirror(ArrowLocation loc) {
+ return loc >= NONE ? loc : static_cast<ArrowLocation>(loc ^ 2);
+ }
+
+ static bool has_arrow(ArrowLocation loc) {
+ return loc >= NONE ? false : true;
+ }
+
+ static bool is_arrow_on_left(ArrowLocation loc) {
+ return loc >= NONE ? false : !(loc & 1);
+ }
+
+ static bool is_arrow_on_top(ArrowLocation loc) {
+ return loc >= NONE ? false : !(loc & 2);
+ }
+
+ static bool is_arrow_on_horizontal(ArrowLocation loc) {
+ return loc >= NONE ? false : !(loc & 4);
+ }
+
+ // Sets the background color for the arrow body. This is irrelevant if you do
+ // not also set the arrow location to something other than NONE.
+ void set_background_color(SkColor background_color) {
+ background_color_ = background_color;
+ }
+ SkColor background_color() const { return background_color_; }
+
+ // For borders with an arrow, gives the desired bounds (in screen coordinates)
+ // given the rect to point to and the size of the contained contents. This
+ // depends on the arrow location, so if you change that, you should call this
+ // again to find out the new coordinates.
+ gfx::Rect GetBounds(const gfx::Rect& position_relative_to,
+ const gfx::Size& contents_size) const;
+
+ // Sets a fixed offset for the arrow from the beginning of corresponding edge.
+ // The arrow will still point to the same location but the bubble will shift
+ // location to make that happen. Returns actuall arrow offset, in case of
+ // overflow it differ from desired.
+ int SetArrowOffset(int offset, const gfx::Size& contents_size);
+
+ // Overridden from views::Border:
+ virtual void GetInsets(gfx::Insets* insets) const;
+
+ private:
+ // Loads images if necessary.
+ static void InitClass();
+
+ virtual ~BubbleBorder() { }
+
+ // Overridden from views::Border:
+ virtual void Paint(const views::View& view, gfx::Canvas* canvas) const;
+
+ void DrawEdgeWithArrow(gfx::Canvas* canvas,
+ bool is_horizontal,
+ SkBitmap* edge,
+ SkBitmap* arrow,
+ int start_x,
+ int start_y,
+ int before_arrow,
+ int after_arrow,
+ int offset) const;
+
+ void DrawArrowInterior(gfx::Canvas* canvas,
+ bool is_horizontal,
+ int tip_x,
+ int tip_y,
+ int shift_x,
+ int shift_y) const;
+
+ // Border graphics.
+ static SkBitmap* left_;
+ static SkBitmap* top_left_;
+ static SkBitmap* top_;
+ static SkBitmap* top_right_;
+ static SkBitmap* right_;
+ static SkBitmap* bottom_right_;
+ static SkBitmap* bottom_;
+ static SkBitmap* bottom_left_;
+ static SkBitmap* left_arrow_;
+ static SkBitmap* top_arrow_;
+ static SkBitmap* right_arrow_;
+ static SkBitmap* bottom_arrow_;
+
+ // Minimal offset of the arrow from the closet edge of bounding rect.
+ static int arrow_offset_;
+
+ // If specified, overrides the pre-calculated |arrow_offset_| of the arrow.
+ int override_arrow_offset_;
+
+ ArrowLocation arrow_location_;
+ SkColor background_color_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleBorder);
+};
+
+// A Background that clips itself to the specified BubbleBorder and uses
+// the background color of the BubbleBorder.
+class BubbleBackground : public views::Background {
+ public:
+ explicit BubbleBackground(BubbleBorder* border) : border_(border) {}
+
+ // Background overrides.
+ virtual void Paint(gfx::Canvas* canvas, views::View* view) const;
+
+ private:
+ BubbleBorder* border_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleBackground);
+};
+
+} // namespace views
+
+#endif // VIEWS_BUBBLE_BUBBLE_BORDER_H_
diff --git a/views/views.gyp b/views/views.gyp
index 7e5ca8a..c5e5a27 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -39,6 +39,7 @@
'../ui/gfx/compositor/compositor.gyp:compositor',
'../ui/ui.gyp:ui',
'../ui/ui.gyp:ui_resources',
+ '../ui/ui.gyp:ui_resources_standard',
],
'defines': [
'VIEWS_IMPLEMENTATION',
@@ -55,6 +56,8 @@
'background.h',
'border.cc',
'border.h',
+ 'bubble/bubble_border.cc',
+ 'bubble/bubble_border.h',
'context_menu_controller.h',
'controls/button/button.cc',
'controls/button/button.h',
@@ -450,6 +453,7 @@
'../ui/base/strings/ui_strings.gyp:ui_strings',
'../ui/ui.gyp:ui',
'../ui/ui.gyp:ui_resources',
+ '../ui/ui.gyp:ui_resources_standard',
'views',
],
'include_dirs': [
@@ -487,6 +491,7 @@
'widget/widget_unittest.cc',
'<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources.rc',
+ '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources_standard/ui_resources_standard.rc',
],
'conditions': [
['toolkit_uses_gtk == 1', {
@@ -547,6 +552,7 @@
'../ui/ui.gyp:ui',
'../ui/ui.gyp:gfx_resources',
'../ui/ui.gyp:ui_resources',
+ '../ui/ui.gyp:ui_resources_standard',
'views',
],
'include_dirs': [
@@ -593,6 +599,7 @@
'test/test_views_delegate.h',
'<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc',
'<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources.rc',
+ '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources_standard/ui_resources_standard.rc',
],
'conditions': [
['toolkit_uses_gtk == 1', {
@@ -692,6 +699,7 @@
'../ui/ui.gyp:gfx_resources',
'../ui/ui.gyp:ui',
'../ui/ui.gyp:ui_resources',
+ '../ui/ui.gyp:ui_resources_standard',
'views',
'views_desktop_lib',
],
@@ -704,6 +712,7 @@
'desktop/desktop_views_delegate.h',
'<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc',
'<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources.rc',
+ '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources_standard/ui_resources_standard.rc',
],
'conditions': [
['toolkit_uses_gtk == 1', {