#include "ui/views/bubble/bubble_border.h"
#include <stddef.h>
#include <memory>
#include "base/strings/stringprintf.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/views/bubble/bubble_border_arrow_utils.h"
#include "ui/views/test/views_test_base.h"
namespace views {
using BubbleBorderTest = views::ViewsTestBase;
TEST_F(BubbleBorderTest, GetMirroredArrow) {
EXPECT_EQ(BubbleBorder::TOP_RIGHT,
BubbleBorder::horizontal_mirror(BubbleBorder::TOP_LEFT));
EXPECT_EQ(BubbleBorder::TOP_LEFT,
BubbleBorder::horizontal_mirror(BubbleBorder::TOP_RIGHT));
EXPECT_EQ(BubbleBorder::BOTTOM_RIGHT,
BubbleBorder::horizontal_mirror(BubbleBorder::BOTTOM_LEFT));
EXPECT_EQ(BubbleBorder::BOTTOM_LEFT,
BubbleBorder::horizontal_mirror(BubbleBorder::BOTTOM_RIGHT));
EXPECT_EQ(BubbleBorder::RIGHT_TOP,
BubbleBorder::horizontal_mirror(BubbleBorder::LEFT_TOP));
EXPECT_EQ(BubbleBorder::LEFT_TOP,
BubbleBorder::horizontal_mirror(BubbleBorder::RIGHT_TOP));
EXPECT_EQ(BubbleBorder::RIGHT_BOTTOM,
BubbleBorder::horizontal_mirror(BubbleBorder::LEFT_BOTTOM));
EXPECT_EQ(BubbleBorder::LEFT_BOTTOM,
BubbleBorder::horizontal_mirror(BubbleBorder::RIGHT_BOTTOM));
EXPECT_EQ(BubbleBorder::TOP_CENTER,
BubbleBorder::horizontal_mirror(BubbleBorder::TOP_CENTER));
EXPECT_EQ(BubbleBorder::BOTTOM_CENTER,
BubbleBorder::horizontal_mirror(BubbleBorder::BOTTOM_CENTER));
EXPECT_EQ(BubbleBorder::RIGHT_CENTER,
BubbleBorder::horizontal_mirror(BubbleBorder::LEFT_CENTER));
EXPECT_EQ(BubbleBorder::LEFT_CENTER,
BubbleBorder::horizontal_mirror(BubbleBorder::RIGHT_CENTER));
EXPECT_EQ(BubbleBorder::NONE,
BubbleBorder::horizontal_mirror(BubbleBorder::NONE));
EXPECT_EQ(BubbleBorder::FLOAT,
BubbleBorder::horizontal_mirror(BubbleBorder::FLOAT));
EXPECT_EQ(BubbleBorder::BOTTOM_LEFT,
BubbleBorder::vertical_mirror(BubbleBorder::TOP_LEFT));
EXPECT_EQ(BubbleBorder::BOTTOM_RIGHT,
BubbleBorder::vertical_mirror(BubbleBorder::TOP_RIGHT));
EXPECT_EQ(BubbleBorder::TOP_LEFT,
BubbleBorder::vertical_mirror(BubbleBorder::BOTTOM_LEFT));
EXPECT_EQ(BubbleBorder::TOP_RIGHT,
BubbleBorder::vertical_mirror(BubbleBorder::BOTTOM_RIGHT));
EXPECT_EQ(BubbleBorder::LEFT_BOTTOM,
BubbleBorder::vertical_mirror(BubbleBorder::LEFT_TOP));
EXPECT_EQ(BubbleBorder::RIGHT_BOTTOM,
BubbleBorder::vertical_mirror(BubbleBorder::RIGHT_TOP));
EXPECT_EQ(BubbleBorder::LEFT_TOP,
BubbleBorder::vertical_mirror(BubbleBorder::LEFT_BOTTOM));
EXPECT_EQ(BubbleBorder::RIGHT_TOP,
BubbleBorder::vertical_mirror(BubbleBorder::RIGHT_BOTTOM));
EXPECT_EQ(BubbleBorder::BOTTOM_CENTER,
BubbleBorder::vertical_mirror(BubbleBorder::TOP_CENTER));
EXPECT_EQ(BubbleBorder::TOP_CENTER,
BubbleBorder::vertical_mirror(BubbleBorder::BOTTOM_CENTER));
EXPECT_EQ(BubbleBorder::LEFT_CENTER,
BubbleBorder::vertical_mirror(BubbleBorder::LEFT_CENTER));
EXPECT_EQ(BubbleBorder::RIGHT_CENTER,
BubbleBorder::vertical_mirror(BubbleBorder::RIGHT_CENTER));
EXPECT_EQ(BubbleBorder::NONE,
BubbleBorder::vertical_mirror(BubbleBorder::NONE));
EXPECT_EQ(BubbleBorder::FLOAT,
BubbleBorder::vertical_mirror(BubbleBorder::FLOAT));
}
TEST_F(BubbleBorderTest, HasArrow) {
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::TOP_LEFT));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::TOP_RIGHT));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::BOTTOM_LEFT));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::BOTTOM_RIGHT));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::LEFT_TOP));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::RIGHT_TOP));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::LEFT_BOTTOM));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::RIGHT_BOTTOM));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::TOP_CENTER));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::BOTTOM_CENTER));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::LEFT_CENTER));
EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::RIGHT_CENTER));
EXPECT_FALSE(BubbleBorder::has_arrow(BubbleBorder::NONE));
EXPECT_FALSE(BubbleBorder::has_arrow(BubbleBorder::FLOAT));
}
TEST_F(BubbleBorderTest, IsArrowOnLeft) {
EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::TOP_LEFT));
EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::TOP_RIGHT));
EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::BOTTOM_LEFT));
EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::BOTTOM_RIGHT));
EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::LEFT_TOP));
EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::RIGHT_TOP));
EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::LEFT_BOTTOM));
EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::RIGHT_BOTTOM));
EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::TOP_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::BOTTOM_CENTER));
EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::LEFT_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::RIGHT_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::NONE));
EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::FLOAT));
}
TEST_F(BubbleBorderTest, IsArrowOnTop) {
EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::TOP_LEFT));
EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::TOP_RIGHT));
EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::BOTTOM_LEFT));
EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::BOTTOM_RIGHT));
EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::LEFT_TOP));
EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::RIGHT_TOP));
EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::LEFT_BOTTOM));
EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::RIGHT_BOTTOM));
EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::TOP_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::BOTTOM_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::LEFT_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::RIGHT_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::NONE));
EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::FLOAT));
}
TEST_F(BubbleBorderTest, IsArrowOnHorizontal) {
EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::TOP_LEFT));
EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::TOP_RIGHT));
EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::BOTTOM_LEFT));
EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::BOTTOM_RIGHT));
EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::LEFT_TOP));
EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::RIGHT_TOP));
EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::LEFT_BOTTOM));
EXPECT_FALSE(
BubbleBorder::is_arrow_on_horizontal(BubbleBorder::RIGHT_BOTTOM));
EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::TOP_CENTER));
EXPECT_TRUE(
BubbleBorder::is_arrow_on_horizontal(BubbleBorder::BOTTOM_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::LEFT_CENTER));
EXPECT_FALSE(
BubbleBorder::is_arrow_on_horizontal(BubbleBorder::RIGHT_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::NONE));
EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::FLOAT));
}
TEST_F(BubbleBorderTest, IsArrowAtCenter) {
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::TOP_LEFT));
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::TOP_RIGHT));
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::BOTTOM_LEFT));
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::BOTTOM_RIGHT));
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::LEFT_TOP));
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::RIGHT_TOP));
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::LEFT_BOTTOM));
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::RIGHT_BOTTOM));
EXPECT_TRUE(BubbleBorder::is_arrow_at_center(BubbleBorder::TOP_CENTER));
EXPECT_TRUE(BubbleBorder::is_arrow_at_center(BubbleBorder::BOTTOM_CENTER));
EXPECT_TRUE(BubbleBorder::is_arrow_at_center(BubbleBorder::LEFT_CENTER));
EXPECT_TRUE(BubbleBorder::is_arrow_at_center(BubbleBorder::RIGHT_CENTER));
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::NONE));
EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::FLOAT));
}
TEST_F(BubbleBorderTest, GetSizeForContentsSizeTest) {
views::BubbleBorder border(BubbleBorder::NONE, BubbleBorder::NO_SHADOW);
const gfx::Insets kInsets = border.GetInsets();
const gfx::Size kSmallSize = gfx::Size(1, 2);
const gfx::Size kMediumSize = gfx::Size(50, 60);
const gfx::Size kSmallHorizArrow(kSmallSize.width() + kInsets.width(),
kSmallSize.height() + kInsets.height());
const gfx::Size kSmallVertArrow(kSmallHorizArrow.width(),
kSmallHorizArrow.height());
const gfx::Size kSmallNoArrow(kSmallHorizArrow.width(),
kSmallHorizArrow.height());
const gfx::Size kMediumHorizArrow(kMediumSize.width() + kInsets.width(),
kMediumSize.height() + kInsets.height());
const gfx::Size kMediumVertArrow(kMediumHorizArrow.width(),
kMediumHorizArrow.height());
const gfx::Size kMediumNoArrow(kMediumHorizArrow.width(),
kMediumHorizArrow.height());
struct TestCase {
BubbleBorder::Arrow arrow;
gfx::Size content;
gfx::Size expected_without_arrow;
};
const auto cases = std::to_array<TestCase>(
{
{BubbleBorder::TOP_LEFT, kSmallSize, kSmallNoArrow},
{BubbleBorder::TOP_CENTER, kSmallSize, kSmallNoArrow},
{BubbleBorder::TOP_RIGHT, kSmallSize, kSmallNoArrow},
{BubbleBorder::BOTTOM_LEFT, kSmallSize, kSmallNoArrow},
{BubbleBorder::BOTTOM_CENTER, kSmallSize, kSmallNoArrow},
{BubbleBorder::BOTTOM_RIGHT, kSmallSize, kSmallNoArrow},
{BubbleBorder::LEFT_TOP, kSmallSize, kSmallNoArrow},
{BubbleBorder::LEFT_CENTER, kSmallSize, kSmallNoArrow},
{BubbleBorder::LEFT_BOTTOM, kSmallSize, kSmallNoArrow},
{BubbleBorder::RIGHT_TOP, kSmallSize, kSmallNoArrow},
{BubbleBorder::RIGHT_CENTER, kSmallSize, kSmallNoArrow},
{BubbleBorder::RIGHT_BOTTOM, kSmallSize, kSmallNoArrow},
{BubbleBorder::NONE, kSmallSize, kSmallNoArrow},
{BubbleBorder::FLOAT, kSmallSize, kSmallNoArrow},
{BubbleBorder::TOP_LEFT, kMediumSize, kMediumNoArrow},
{BubbleBorder::TOP_CENTER, kMediumSize, kMediumNoArrow},
{BubbleBorder::TOP_RIGHT, kMediumSize, kMediumNoArrow},
{BubbleBorder::BOTTOM_LEFT, kMediumSize, kMediumNoArrow},
{BubbleBorder::BOTTOM_CENTER, kMediumSize, kMediumNoArrow},
{BubbleBorder::BOTTOM_RIGHT, kMediumSize, kMediumNoArrow},
{BubbleBorder::LEFT_TOP, kMediumSize, kMediumNoArrow},
{BubbleBorder::LEFT_CENTER, kMediumSize, kMediumNoArrow},
{BubbleBorder::LEFT_BOTTOM, kMediumSize, kMediumNoArrow},
{BubbleBorder::RIGHT_TOP, kMediumSize, kMediumNoArrow},
{BubbleBorder::RIGHT_CENTER, kMediumSize, kMediumNoArrow},
{BubbleBorder::RIGHT_BOTTOM, kMediumSize, kMediumNoArrow},
{BubbleBorder::NONE, kMediumSize, kMediumNoArrow},
{BubbleBorder::FLOAT, kMediumSize, kMediumNoArrow}});
for (size_t i = 0; i < std::size(cases); ++i) {
SCOPED_TRACE(base::StringPrintf("i=%d arrow=%d", static_cast<int>(i),
cases[i].arrow));
border.set_arrow(cases[i].arrow);
EXPECT_EQ(cases[i].expected_without_arrow,
border.GetSizeForContentsSize(cases[i].content));
}
}
TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
for (int i = 0; i < BubbleBorder::SHADOW_COUNT; ++i) {
const BubbleBorder::Shadow shadow = static_cast<BubbleBorder::Shadow>(i);
SCOPED_TRACE(testing::Message() << "BubbleBorder::Shadow: " << shadow);
views::BubbleBorder border(BubbleBorder::TOP_LEFT, shadow);
const gfx::Rect kAnchor(100, 100, 20, 30);
const gfx::Size kContentSize(500, 600);
const gfx::Insets kInsets = border.GetInsets();
border.set_arrow(BubbleBorder::TOP_LEFT);
const gfx::Size kTotalSize = border.GetSizeForContentsSize(kContentSize);
border.set_arrow(BubbleBorder::RIGHT_BOTTOM);
EXPECT_EQ(kTotalSize, border.GetSizeForContentsSize(kContentSize));
border.set_arrow(BubbleBorder::NONE);
EXPECT_EQ(kTotalSize, border.GetSizeForContentsSize(kContentSize));
const int kStrokeWidth =
shadow == BubbleBorder::NO_SHADOW ? 0 : BubbleBorder::kStroke;
const int kBorderedContentHeight =
kContentSize.height() + (2 * kStrokeWidth);
const int kStrokeTopInset = kStrokeWidth - kInsets.top();
const int kStrokeBottomInset = kStrokeWidth - kInsets.bottom();
const int kStrokeLeftInset = kStrokeWidth - kInsets.left();
const int kStrokeRightInset = kStrokeWidth - kInsets.right();
const int kTopHorizArrowY = kAnchor.bottom() + kStrokeTopInset;
const int kBottomHorizArrowY =
kAnchor.y() - kTotalSize.height() - kStrokeBottomInset;
const int kLeftVertArrowX =
kAnchor.x() + kAnchor.width() + kStrokeLeftInset;
const int kRightVertArrowX =
kAnchor.x() - kTotalSize.width() - kStrokeRightInset;
struct TestCase {
BubbleBorder::Arrow arrow;
int expected_x;
int expected_y;
};
const auto cases = std::to_array<TestCase>({
{BubbleBorder::TOP_LEFT, kAnchor.x() + kStrokeLeftInset,
kTopHorizArrowY},
{BubbleBorder::TOP_CENTER,
kAnchor.CenterPoint().x() - (kTotalSize.width() / 2), kTopHorizArrowY},
{BubbleBorder::BOTTOM_RIGHT,
kAnchor.x() + kAnchor.width() - kTotalSize.width() - kStrokeRightInset,
kBottomHorizArrowY},
{BubbleBorder::LEFT_TOP, kLeftVertArrowX,
kAnchor.y() + kStrokeTopInset},
{BubbleBorder::LEFT_CENTER, kLeftVertArrowX,
kAnchor.CenterPoint().y() - (kBorderedContentHeight / 2) +
kStrokeTopInset},
{BubbleBorder::RIGHT_BOTTOM, kRightVertArrowX,
kAnchor.y() + kAnchor.height() - kTotalSize.height() -
kStrokeBottomInset},
{BubbleBorder::NONE,
kAnchor.x() + (kAnchor.width() - kTotalSize.width()) / 2,
kAnchor.y() + kAnchor.height()},
{BubbleBorder::FLOAT,
kAnchor.x() + (kAnchor.width() - kTotalSize.width()) / 2,
kAnchor.y() + (kAnchor.height() - kTotalSize.height()) / 2},
});
for (size_t j = 0; j < std::size(cases); ++j) {
SCOPED_TRACE(base::StringPrintf("shadow=%d j=%d arrow=%d",
static_cast<int>(shadow),
static_cast<int>(j), cases[j].arrow));
const BubbleBorder::Arrow arrow = cases[j].arrow;
border.set_arrow(arrow);
gfx::Point origin = border.GetBounds(kAnchor, kContentSize).origin();
EXPECT_EQ(cases[j].expected_x, origin.x());
EXPECT_EQ(cases[j].expected_y, origin.y());
}
}
}
TEST_F(BubbleBorderTest, BubblePositionedCorrectlyWithVisibleArrow) {
views::BubbleBorder border(BubbleBorder::TOP_LEFT,
BubbleBorder::STANDARD_SHADOW);
const gfx::Insets kInsets = border.GetInsets();
border.set_visible_arrow(true);
constexpr gfx::Size kContentSize(200, 150);
constexpr gfx::Point kAnchorOrigin(100, 100);
constexpr gfx::Rect kAnchor1(kAnchorOrigin, gfx::Size(40, 50));
constexpr gfx::Rect kAnchor2(kAnchorOrigin, gfx::Size(400, 300));
constexpr gfx::Rect kAnchor3(kAnchorOrigin, gfx::Size(10, 12));
border.set_arrow(BubbleBorder::TOP_LEFT);
gfx::Rect bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.bottom() +
BubbleBorder::kVisibleArrowLength,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor1.bottom() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.y());
EXPECT_EQ(kAnchor1.x() - kInsets.left(), bounds.x());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.bottom() +
BubbleBorder::kVisibleArrowLength,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor2.bottom() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.y());
EXPECT_EQ(kAnchor2.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip,
bounds.x());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.bottom() +
BubbleBorder::kVisibleArrowLength,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor3.bottom() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.y());
EXPECT_GT(kAnchor3.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip,
bounds.x());
border.set_arrow(BubbleBorder::TOP_CENTER);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.bottom() +
BubbleBorder::kVisibleArrowLength,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor1.bottom() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.y());
EXPECT_EQ(kAnchor1.bottom_center().x() - bounds.width() / 2, bounds.x());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.bottom() +
BubbleBorder::kVisibleArrowLength,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor2.bottom() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.y());
EXPECT_EQ(kAnchor2.bottom_center().x() - bounds.width() / 2, bounds.x());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.bottom() +
BubbleBorder::kVisibleArrowLength,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor3.bottom() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.y());
EXPECT_EQ(kAnchor3.bottom_center().x() - bounds.width() / 2, bounds.x());
border.set_arrow(BubbleBorder::TOP_RIGHT);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.bottom() +
BubbleBorder::kVisibleArrowLength,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor1.bottom() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.y());
EXPECT_EQ(kAnchor1.right() + kInsets.right(), bounds.right());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.bottom() +
BubbleBorder::kVisibleArrowLength,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor2.bottom() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.y());
EXPECT_EQ(
kAnchor2.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip,
bounds.right());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.bottom() +
BubbleBorder::kVisibleArrowLength,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor3.bottom() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.y());
EXPECT_LT(
kAnchor3.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip,
bounds.right());
border.set_arrow(BubbleBorder::BOTTOM_LEFT);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.top() +
BubbleBorder::kVisibleArrowLength +
BubbleBorder::kBorderThicknessDip,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor1.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom());
EXPECT_EQ(kAnchor1.x() - kInsets.left(), bounds.x());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.top() +
BubbleBorder::kVisibleArrowLength +
BubbleBorder::kBorderThicknessDip,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor2.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom());
EXPECT_EQ(kAnchor2.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip,
bounds.x());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.top() +
BubbleBorder::kVisibleArrowLength +
BubbleBorder::kBorderThicknessDip,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor3.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom());
EXPECT_GT(kAnchor3.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip,
bounds.x());
border.set_arrow(BubbleBorder::BOTTOM_CENTER);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.top() +
BubbleBorder::kVisibleArrowLength +
BubbleBorder::kBorderThicknessDip,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor1.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom());
EXPECT_EQ(kAnchor1.bottom_center().x() - bounds.width() / 2, bounds.x());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.top() +
BubbleBorder::kVisibleArrowLength +
BubbleBorder::kBorderThicknessDip,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor2.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom());
EXPECT_EQ(kAnchor2.bottom_center().x() - bounds.width() / 2, bounds.x());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.top() +
BubbleBorder::kVisibleArrowLength +
BubbleBorder::kBorderThicknessDip,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor3.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom());
EXPECT_EQ(kAnchor3.bottom_center().x() - bounds.width() / 2, bounds.x());
border.set_arrow(BubbleBorder::BOTTOM_RIGHT);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.top() +
BubbleBorder::kVisibleArrowLength +
BubbleBorder::kBorderThicknessDip,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor1.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom());
EXPECT_EQ(kAnchor1.right() + kInsets.right(), bounds.right());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.top() +
BubbleBorder::kVisibleArrowLength +
BubbleBorder::kBorderThicknessDip,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor2.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom());
EXPECT_EQ(
kAnchor2.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip,
bounds.right());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.height() + kInsets.top() +
BubbleBorder::kVisibleArrowLength +
BubbleBorder::kBorderThicknessDip,
bounds.height());
EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width());
EXPECT_EQ(kAnchor3.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom());
EXPECT_LT(
kAnchor3.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip,
bounds.right());
border.set_arrow(BubbleBorder::LEFT_TOP);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor1.right() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.x());
EXPECT_EQ(kAnchor1.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip,
bounds.y());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor2.right() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.x());
EXPECT_EQ(kAnchor2.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip,
bounds.y());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor3.right() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.x());
EXPECT_GT(kAnchor3.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip,
bounds.y());
border.set_arrow(BubbleBorder::LEFT_CENTER);
const auto insets = border.GetInsets();
const int shadow_offset = (insets.bottom() - insets.top()) / 2;
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor1.right() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.x());
EXPECT_NEAR(kAnchor1.right_center().y() - bounds.height() / 2, bounds.y(),
shadow_offset);
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor2.right() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.x());
EXPECT_NEAR(kAnchor2.right_center().y() - bounds.height() / 2, bounds.y(),
shadow_offset);
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor3.right() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.x());
EXPECT_NEAR(kAnchor3.right_center().y() - bounds.height() / 2, bounds.y(),
shadow_offset);
border.set_arrow(BubbleBorder::LEFT_BOTTOM);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor1.right() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.x());
EXPECT_EQ(
kAnchor1.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip,
bounds.bottom());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor2.right() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.x());
EXPECT_EQ(
kAnchor2.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip,
bounds.bottom());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor3.right() + BubbleBorder::kVisibleArrowGap +
BubbleBorder::kBorderThicknessDip,
bounds.x());
EXPECT_LT(
kAnchor3.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip,
bounds.bottom());
border.set_arrow(BubbleBorder::RIGHT_TOP);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor1.x() - BubbleBorder::kVisibleArrowGap -
BubbleBorder::kBorderThicknessDip,
bounds.right());
EXPECT_EQ(kAnchor1.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip,
bounds.y());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor2.x() - BubbleBorder::kVisibleArrowGap -
BubbleBorder::kBorderThicknessDip,
bounds.right());
EXPECT_EQ(kAnchor2.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip,
bounds.y());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor3.x() - BubbleBorder::kVisibleArrowGap -
BubbleBorder::kBorderThicknessDip,
bounds.right());
EXPECT_GT(kAnchor3.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip,
bounds.y());
border.set_arrow(BubbleBorder::RIGHT_CENTER);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor1.x() - BubbleBorder::kVisibleArrowGap -
BubbleBorder::kBorderThicknessDip,
bounds.right());
EXPECT_NEAR(kAnchor1.right_center().y() - bounds.height() / 2, bounds.y(),
shadow_offset);
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor2.x() - BubbleBorder::kVisibleArrowGap -
BubbleBorder::kBorderThicknessDip,
bounds.right());
EXPECT_NEAR(kAnchor2.right_center().y() - bounds.height() / 2, bounds.y(),
shadow_offset);
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor3.x() - BubbleBorder::kVisibleArrowGap -
BubbleBorder::kBorderThicknessDip,
bounds.right());
EXPECT_NEAR(kAnchor3.right_center().y() - bounds.height() / 2, bounds.y(),
shadow_offset);
border.set_arrow(BubbleBorder::RIGHT_BOTTOM);
bounds = border.GetBounds(kAnchor1, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor1.x() - BubbleBorder::kVisibleArrowGap -
BubbleBorder::kBorderThicknessDip,
bounds.right());
EXPECT_EQ(
kAnchor1.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip,
bounds.bottom());
bounds = border.GetBounds(kAnchor2, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor2.x() - BubbleBorder::kVisibleArrowGap -
BubbleBorder::kBorderThicknessDip,
bounds.right());
EXPECT_EQ(
kAnchor2.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip,
bounds.bottom());
bounds = border.GetBounds(kAnchor3, kContentSize);
EXPECT_EQ(kContentSize.width() + kInsets.right() +
BubbleBorder::kVisibleArrowLength,
bounds.width());
EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height());
EXPECT_EQ(kAnchor3.x() - BubbleBorder::kVisibleArrowGap -
BubbleBorder::kBorderThicknessDip,
bounds.right());
EXPECT_LT(
kAnchor3.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip,
bounds.bottom());
}
TEST_F(BubbleBorderTest, AddArrowToBubbleCornerAndPointTowardsAnchor) {
const gfx::Rect bubble_bounds(400, 600, 300, 200);
const gfx::Size element_size(350, 100);
int most_left_x_position =
bubble_bounds.x() + BubbleBorder::kVisibleArrowBuffer;
int most_right_x_position = bubble_bounds.right() -
BubbleBorder::kVisibleArrowBuffer -
BubbleBorder::kVisibleArrowRadius * 2;
int upper_arrow_y_position = bubble_bounds.y();
int lower_arrow_y_position =
bubble_bounds.bottom() - BubbleBorder::kVisibleArrowLength;
struct TestCase {
gfx::Point element_origin;
BubbleBorder::Arrow supplied_arrow;
gfx::Point expected_arrow_position;
bool expected_arrow_visibility_and_return_value;
gfx::Rect expected_bubble_bounds;
int popup_min_y = 0;
} test_cases[]{
{{380, 200},
BubbleBorder::Arrow::TOP_LEFT,
{most_left_x_position, upper_arrow_y_position},
true,
bubble_bounds + gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{380, 200},
BubbleBorder::Arrow::TOP_CENTER,
{380 + element_size.width() / 2 - BubbleBorder::kVisibleArrowRadius,
upper_arrow_y_position},
true,
bubble_bounds + gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{380, 200},
BubbleBorder::Arrow::TOP_RIGHT,
{most_right_x_position, upper_arrow_y_position},
true,
bubble_bounds + gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{750, 200},
BubbleBorder::Arrow::TOP_LEFT,
{most_right_x_position, upper_arrow_y_position},
true,
bubble_bounds + gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{750, 200},
BubbleBorder::Arrow::TOP_CENTER,
{most_right_x_position, upper_arrow_y_position},
true,
bubble_bounds + gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{750, 200},
BubbleBorder::Arrow::TOP_RIGHT,
{most_right_x_position, upper_arrow_y_position},
true,
bubble_bounds + gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{0, 200},
BubbleBorder::Arrow::TOP_LEFT,
{most_left_x_position, upper_arrow_y_position},
true,
bubble_bounds + gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{0, 200},
BubbleBorder::Arrow::TOP_CENTER,
{most_left_x_position, upper_arrow_y_position},
true,
bubble_bounds + gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{0, 200},
BubbleBorder::Arrow::TOP_RIGHT,
{most_left_x_position, upper_arrow_y_position},
true,
bubble_bounds + gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{380, 200},
BubbleBorder::Arrow::BOTTOM_LEFT,
{most_left_x_position, lower_arrow_y_position},
true,
bubble_bounds - gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{380, 200},
BubbleBorder::Arrow::BOTTOM_CENTER,
{380 + element_size.width() / 2 - BubbleBorder::kVisibleArrowRadius,
lower_arrow_y_position},
true,
bubble_bounds - gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{380, 200},
BubbleBorder::Arrow::BOTTOM_RIGHT,
{most_right_x_position, lower_arrow_y_position},
true,
bubble_bounds - gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{750, 200},
BubbleBorder::Arrow::BOTTOM_LEFT,
{most_right_x_position, lower_arrow_y_position},
true,
bubble_bounds - gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{750, 200},
BubbleBorder::Arrow::BOTTOM_CENTER,
{most_right_x_position, lower_arrow_y_position},
true,
bubble_bounds - gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{750, 200},
BubbleBorder::Arrow::BOTTOM_RIGHT,
{most_right_x_position, lower_arrow_y_position},
true,
bubble_bounds - gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{0, 200},
BubbleBorder::Arrow::BOTTOM_LEFT,
{most_left_x_position, lower_arrow_y_position},
true,
bubble_bounds - gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{0, 200},
BubbleBorder::Arrow::BOTTOM_CENTER,
{most_left_x_position, lower_arrow_y_position},
true,
bubble_bounds - gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{0, 200},
BubbleBorder::Arrow::BOTTOM_RIGHT,
{most_left_x_position, lower_arrow_y_position},
true,
bubble_bounds - gfx::Vector2d(0, BubbleBorder::kVisibleArrowLength)},
{{0, 650},
BubbleBorder::Arrow::LEFT_TOP,
{bubble_bounds.x(),
650 + element_size.height() / 2 - BubbleBorder::kVisibleArrowRadius},
true,
bubble_bounds + gfx::Vector2d(BubbleBorder::kVisibleArrowLength, 0)},
{{0, 650},
BubbleBorder::Arrow::LEFT_CENTER,
{bubble_bounds.x(),
650 + element_size.height() / 2 - BubbleBorder::kVisibleArrowRadius},
true,
bubble_bounds + gfx::Vector2d(BubbleBorder::kVisibleArrowLength, 0)},
{{0, 650},
BubbleBorder::Arrow::LEFT_BOTTOM,
{bubble_bounds.x(),
650 + element_size.height() / 2 - BubbleBorder::kVisibleArrowRadius},
true,
bubble_bounds + gfx::Vector2d(BubbleBorder::kVisibleArrowLength, 0)},
{{0, 0},
BubbleBorder::Arrow::LEFT_TOP,
{bubble_bounds.x(),
element_size.height() / 2 - BubbleBorder::kVisibleArrowRadius},
true,
{bubble_bounds.x() + BubbleBorder::kVisibleArrowLength,
element_size.height() / 2 - BubbleBorder::kVisibleArrowRadius -
BubbleBorder::kVisibleArrowBuffer,
bubble_bounds.width(), bubble_bounds.height()}},
{{0, 0},
BubbleBorder::Arrow::LEFT_CENTER,
{bubble_bounds.x(),
element_size.height() / 2 - BubbleBorder::kVisibleArrowRadius},
true,
{bubble_bounds.x() + BubbleBorder::kVisibleArrowLength,
element_size.height() / 2 - BubbleBorder::kVisibleArrowRadius -
BubbleBorder::kVisibleArrowBuffer,
bubble_bounds.width(), bubble_bounds.height()}},
{{0, 0},
BubbleBorder::Arrow::LEFT_BOTTOM,
{bubble_bounds.x(),
element_size.height() / 2 - BubbleBorder::kVisibleArrowRadius},
true,
{bubble_bounds.x() + BubbleBorder::kVisibleArrowLength,
element_size.height() / 2 - BubbleBorder::kVisibleArrowRadius -
BubbleBorder::kVisibleArrowBuffer,
bubble_bounds.width(), bubble_bounds.height()}},
{{0, 0},
BubbleBorder::Arrow::LEFT_TOP,
{bubble_bounds.x(),
element_size.height() / 2 - 10 + BubbleBorder::kVisibleArrowBuffer},
true,
{bubble_bounds.x() + BubbleBorder::kVisibleArrowLength,
element_size.height() / 2 - 10, bubble_bounds.width(),
bubble_bounds.height()},
element_size.height() / 2 - 10},
};
for (auto test_case : test_cases) {
gfx::Rect bubble_bounds_copy = bubble_bounds;
views::BubbleBorder border(BubbleBorder::Arrow::NONE,
BubbleBorder::STANDARD_SHADOW);
border.set_arrow(test_case.supplied_arrow);
EXPECT_EQ(border.AddArrowToBubbleCornerAndPointTowardsAnchor(
{test_case.element_origin, element_size}, bubble_bounds_copy,
test_case.popup_min_y),
test_case.expected_arrow_visibility_and_return_value);
EXPECT_EQ(border.visible_arrow(),
test_case.expected_arrow_visibility_and_return_value);
EXPECT_EQ(border.GetVisibibleArrowRectForTesting().origin(),
test_case.expected_arrow_position);
EXPECT_EQ(GetVisibleArrowSize(test_case.supplied_arrow),
border.GetVisibibleArrowRectForTesting().size());
EXPECT_EQ(test_case.expected_bubble_bounds, bubble_bounds_copy);
}
}
TEST_F(BubbleBorderTest,
AddArrowToBubbleCornerAndPointTowardsAnchorWithInsufficientSpace) {
const gfx::Rect insufficient_width_bubble_bounds(0, 0, 10, 200);
const gfx::Rect insufficient_height_bubble_bounds(0, 0, 100, 10);
const gfx::Rect element_bounds(0, 0, 350, 100);
struct TestCase {
gfx::Rect bubble_bounds;
BubbleBorder::Arrow supplied_arrow;
bool expected_arrow_visibility_and_return_value;
} test_cases[]{
{insufficient_height_bubble_bounds, BubbleBorder::Arrow::TOP_CENTER,
true},
{insufficient_width_bubble_bounds, BubbleBorder::Arrow::TOP_CENTER,
false},
{insufficient_height_bubble_bounds, BubbleBorder::Arrow::LEFT_CENTER,
false},
{insufficient_width_bubble_bounds, BubbleBorder::Arrow::LEFT_CENTER,
true},
};
for (auto test_case : test_cases) {
views::BubbleBorder border(BubbleBorder::Arrow::NONE,
BubbleBorder::STANDARD_SHADOW);
border.set_arrow(test_case.supplied_arrow);
EXPECT_EQ(border.AddArrowToBubbleCornerAndPointTowardsAnchor(
element_bounds, test_case.bubble_bounds, 0),
test_case.expected_arrow_visibility_and_return_value);
}
}
TEST_F(BubbleBorderTest, IsVerticalArrow) {
struct TestCase {
BubbleBorder::Arrow arrow;
bool is_vertical_expected;
};
TestCase test_cases[] = {
{BubbleBorder::Arrow::BOTTOM_CENTER, true},
{BubbleBorder::Arrow::BOTTOM_LEFT, true},
{BubbleBorder::Arrow::BOTTOM_RIGHT, true},
{BubbleBorder::Arrow::TOP_CENTER, true},
{BubbleBorder::Arrow::TOP_LEFT, true},
{BubbleBorder::Arrow::TOP_RIGHT, true},
{BubbleBorder::Arrow::LEFT_BOTTOM, false},
{BubbleBorder::Arrow::LEFT_CENTER, false},
{BubbleBorder::Arrow::LEFT_TOP, false},
{BubbleBorder::Arrow::RIGHT_BOTTOM, false},
{BubbleBorder::Arrow::RIGHT_CENTER, false},
{BubbleBorder::Arrow::RIGHT_TOP, false},
};
for (const auto& test_case : test_cases) {
EXPECT_EQ(IsVerticalArrow(test_case.arrow), test_case.is_vertical_expected);
}
}
TEST_F(BubbleBorderTest, GetVisibleArrowSize) {
const gfx::Size vertical_size(2 * BubbleBorder::kVisibleArrowRadius,
BubbleBorder::kVisibleArrowLength);
const gfx::Size horizontal_size(BubbleBorder::kVisibleArrowLength,
2 * BubbleBorder::kVisibleArrowRadius);
struct TestCase {
BubbleBorder::Arrow arrow;
gfx::Size expected_size;
};
TestCase test_cases[] = {
{BubbleBorder::Arrow::BOTTOM_CENTER, vertical_size},
{BubbleBorder::Arrow::BOTTOM_LEFT, vertical_size},
{BubbleBorder::Arrow::BOTTOM_RIGHT, vertical_size},
{BubbleBorder::Arrow::TOP_CENTER, vertical_size},
{BubbleBorder::Arrow::TOP_LEFT, vertical_size},
{BubbleBorder::Arrow::TOP_RIGHT, vertical_size},
{BubbleBorder::Arrow::LEFT_BOTTOM, horizontal_size},
{BubbleBorder::Arrow::LEFT_CENTER, horizontal_size},
{BubbleBorder::Arrow::LEFT_TOP, horizontal_size},
{BubbleBorder::Arrow::RIGHT_BOTTOM, horizontal_size},
{BubbleBorder::Arrow::RIGHT_CENTER, horizontal_size},
{BubbleBorder::Arrow::RIGHT_TOP, horizontal_size},
};
for (const auto& test_case : test_cases) {
EXPECT_EQ(GetVisibleArrowSize(test_case.arrow), test_case.expected_size);
}
}
TEST_F(BubbleBorderTest, MoveContentsBoundsToPlaceVisibleArrow) {
const int arrow_length =
BubbleBorder::kVisibleArrowLength + BubbleBorder::kVisibleArrowGap;
struct TestCase {
BubbleBorder::Arrow arrow;
gfx::Vector2d expected_contents_bounds_move;
gfx::Point initial_bubble_origin = gfx::Point(0, 0);
};
TestCase test_cases[] = {
{BubbleBorder::Arrow::BOTTOM_LEFT, gfx::Vector2d(0, -arrow_length)},
{BubbleBorder::Arrow::BOTTOM_CENTER, gfx::Vector2d(0, -arrow_length)},
{BubbleBorder::Arrow::BOTTOM_RIGHT, gfx::Vector2d(0, -arrow_length)},
{BubbleBorder::Arrow::TOP_LEFT, gfx::Vector2d(0, arrow_length)},
{BubbleBorder::Arrow::TOP_CENTER, gfx::Vector2d(0, arrow_length)},
{BubbleBorder::Arrow::TOP_RIGHT, gfx::Vector2d(0, arrow_length)},
{BubbleBorder::Arrow::LEFT_BOTTOM, gfx::Vector2d(arrow_length, 0)},
{BubbleBorder::Arrow::LEFT_CENTER, gfx::Vector2d(arrow_length, 0)},
{BubbleBorder::Arrow::LEFT_TOP, gfx::Vector2d(arrow_length, 0)},
{BubbleBorder::Arrow::RIGHT_BOTTOM, gfx::Vector2d(-arrow_length, 0)},
{BubbleBorder::Arrow::RIGHT_CENTER, gfx::Vector2d(-arrow_length, 0)},
{BubbleBorder::Arrow::RIGHT_TOP, gfx::Vector2d(-arrow_length, 0)},
};
for (const auto& test_case : test_cases) {
views::BubbleBorder border(test_case.arrow, BubbleBorder::STANDARD_SHADOW);
border.set_visible_arrow(true);
EXPECT_EQ(border.GetContentsBoundsOffsetToPlaceVisibleArrow(
test_case.arrow, true),
test_case.expected_contents_bounds_move);
}
}
}