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
3// found in the LICENSE file.
4
5#include "testing/gtest/include/gtest/gtest.h"
6#include "third_party/skia/include/core/SkBitmap.h"
7#include "ui/views/test/views_test_base.h"
8#include "ui/gfx/image/image.h"
9#include "ui/gfx/image/image_skia.h"
10#include "ui/views/corewm/image_grid.h"
11
12namespace views {
13namespace corewm {
14
15namespace {
16
17// Creates a gfx::Image with the requested dimensions.
18gfx::Image* CreateImage(const gfx::Size& size) {
19  SkBitmap bitmap;
20  bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
21  return new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
22}
23
24}  // namespace
25
26typedef ViewsTestBase ImageGridTest;
27
28// Test that an ImageGrid's layers are transformed correctly when SetSize() is
29// called.
30TEST_F(ImageGridTest, Basic) {
31  // Size of the images around the grid's border.
32  const int kBorder = 2;
33
34  scoped_ptr<gfx::Image> image_1x1(CreateImage(gfx::Size(1, 1)));
35  scoped_ptr<gfx::Image> image_1xB(CreateImage(gfx::Size(1, kBorder)));
36  scoped_ptr<gfx::Image> image_Bx1(CreateImage(gfx::Size(kBorder, 1)));
37  scoped_ptr<gfx::Image> image_BxB(CreateImage(gfx::Size(kBorder, kBorder)));
38
39  ImageGrid grid;
40  grid.SetImages(image_BxB.get(), image_1xB.get(), image_BxB.get(),
41                 image_Bx1.get(), image_1x1.get(), image_Bx1.get(),
42                 image_BxB.get(), image_1xB.get(), image_BxB.get());
43
44  ImageGrid::TestAPI test_api(&grid);
45  ASSERT_TRUE(grid.top_left_layer() != NULL);
46  ASSERT_TRUE(grid.top_layer() != NULL);
47  ASSERT_TRUE(grid.top_right_layer() != NULL);
48  ASSERT_TRUE(grid.left_layer() != NULL);
49  ASSERT_TRUE(grid.center_layer() != NULL);
50  ASSERT_TRUE(grid.right_layer() != NULL);
51  ASSERT_TRUE(grid.bottom_left_layer() != NULL);
52  ASSERT_TRUE(grid.bottom_layer() != NULL);
53  ASSERT_TRUE(grid.bottom_right_layer() != NULL);
54
55  const gfx::Size size(20, 30);
56  grid.SetSize(size);
57
58  // The top-left layer should be flush with the top-left corner and unscaled.
59  EXPECT_EQ(gfx::RectF(0, 0, kBorder, kBorder).ToString(),
60            test_api.GetTransformedLayerBounds(
61                *grid.top_left_layer()).ToString());
62
63  // The top layer should be flush with the top edge and stretched horizontally
64  // between the two top corners.
65  EXPECT_EQ(gfx::RectF(
66                kBorder, 0, size.width() - 2 * kBorder, kBorder).ToString(),
67            test_api.GetTransformedLayerBounds(
68                *grid.top_layer()).ToString());
69
70  // The top-right layer should be flush with the top-right corner and unscaled.
71  EXPECT_EQ(gfx::RectF(size.width() - kBorder, 0, kBorder, kBorder).ToString(),
72            test_api.GetTransformedLayerBounds(
73                *grid.top_right_layer()).ToString());
74
75  // The left layer should be flush with the left edge and stretched vertically
76  // between the two left corners.
77  EXPECT_EQ(gfx::RectF(
78                0, kBorder, kBorder, size.height() - 2 * kBorder).ToString(),
79            test_api.GetTransformedLayerBounds(
80                *grid.left_layer()).ToString());
81
82  // The center layer should fill the space in the middle of the grid.
83  EXPECT_EQ(gfx::RectF(
84                kBorder, kBorder, size.width() - 2 * kBorder,
85                size.height() - 2 * kBorder).ToString(),
86            test_api.GetTransformedLayerBounds(
87                *grid.center_layer()).ToString());
88
89  // The right layer should be flush with the right edge and stretched
90  // vertically between the two right corners.
91  EXPECT_EQ(gfx::RectF(
92                size.width() - kBorder, kBorder,
93                kBorder, size.height() - 2 * kBorder).ToString(),
94            test_api.GetTransformedLayerBounds(
95                *grid.right_layer()).ToString());
96
97  // The bottom-left layer should be flush with the bottom-left corner and
98  // unscaled.
99  EXPECT_EQ(gfx::RectF(0, size.height() - kBorder, kBorder, kBorder).ToString(),
100            test_api.GetTransformedLayerBounds(
101                *grid.bottom_left_layer()).ToString());
102
103  // The bottom layer should be flush with the bottom edge and stretched
104  // horizontally between the two bottom corners.
105  EXPECT_EQ(gfx::RectF(
106                kBorder, size.height() - kBorder,
107                size.width() - 2 * kBorder, kBorder).ToString(),
108            test_api.GetTransformedLayerBounds(
109                *grid.bottom_layer()).ToString());
110
111  // The bottom-right layer should be flush with the bottom-right corner and
112  // unscaled.
113  EXPECT_EQ(gfx::RectF(
114                size.width() - kBorder, size.height() - kBorder,
115                kBorder, kBorder).ToString(),
116            test_api.GetTransformedLayerBounds(
117                *grid.bottom_right_layer()).ToString());
118}
119
120// Test that an ImageGrid's layers are transformed correctly when
121// SetContentBounds() is called.
122TEST_F(ImageGridTest, SetContentBounds) {
123  // Size of the images around the grid's border.
124  const int kBorder = 2;
125
126  scoped_ptr<gfx::Image> image_1x1(CreateImage(gfx::Size(1, 1)));
127  scoped_ptr<gfx::Image> image_1xB(CreateImage(gfx::Size(1, kBorder)));
128  scoped_ptr<gfx::Image> image_Bx1(CreateImage(gfx::Size(kBorder, 1)));
129  scoped_ptr<gfx::Image> image_BxB(CreateImage(gfx::Size(kBorder, kBorder)));
130
131  ImageGrid grid;
132  grid.SetImages(image_BxB.get(), image_1xB.get(), image_BxB.get(),
133                 image_Bx1.get(), image_1x1.get(), image_Bx1.get(),
134                 image_BxB.get(), image_1xB.get(), image_BxB.get());
135
136  ImageGrid::TestAPI test_api(&grid);
137
138  const gfx::Point origin(5, 10);
139  const gfx::Size size(20, 30);
140  grid.SetContentBounds(gfx::Rect(origin, size));
141
142  // The master layer is positioned above the top-left corner of the content
143  // bounds and has height/width that contain the grid and bounds.
144  EXPECT_EQ(gfx::RectF(origin.x() - kBorder,
145                      origin.y() - kBorder,
146                      size.width() + 2 * kBorder,
147                      size.height() + 2 * kBorder).ToString(),
148            test_api.GetTransformedLayerBounds(*grid.layer()).ToString());
149}
150
151// Check that we don't crash if only a single image is supplied.
152TEST_F(ImageGridTest, SingleImage) {
153  const int kBorder = 1;
154  scoped_ptr<gfx::Image> image(CreateImage(gfx::Size(kBorder, kBorder)));
155
156  ImageGrid grid;
157  grid.SetImages(NULL, image.get(), NULL,
158                 NULL, NULL, NULL,
159                 NULL, NULL, NULL);
160
161  ImageGrid::TestAPI test_api(&grid);
162  EXPECT_TRUE(grid.top_left_layer() == NULL);
163  ASSERT_TRUE(grid.top_layer() != NULL);
164  EXPECT_TRUE(grid.top_right_layer() == NULL);
165  EXPECT_TRUE(grid.left_layer() == NULL);
166  EXPECT_TRUE(grid.center_layer() == NULL);
167  EXPECT_TRUE(grid.right_layer() == NULL);
168  EXPECT_TRUE(grid.bottom_left_layer() == NULL);
169  EXPECT_TRUE(grid.bottom_layer() == NULL);
170  EXPECT_TRUE(grid.bottom_right_layer() == NULL);
171
172  const gfx::Size kSize(10, 10);
173  grid.SetSize(kSize);
174
175  // The top layer should be scaled horizontally across the entire width, but it
176  // shouldn't be scaled vertically.
177  EXPECT_EQ(gfx::RectF(0, 0, kSize.width(), kBorder).ToString(),
178            test_api.GetTransformedLayerBounds(
179                *grid.top_layer()).ToString());
180}
181
182// Check that we don't crash when we reset existing images to NULL and
183// reset NULL images to new ones.
184TEST_F(ImageGridTest, ResetImages) {
185  const int kBorder = 1;
186  scoped_ptr<gfx::Image> image(CreateImage(gfx::Size(kBorder, kBorder)));
187
188  ImageGrid grid;
189  grid.SetImages(NULL, image.get(), NULL,
190                 NULL, NULL, NULL,
191                 NULL, NULL, NULL);
192
193  // Only the top edge has a layer.
194  ImageGrid::TestAPI test_api(&grid);
195  ASSERT_TRUE(grid.top_left_layer() == NULL);
196  ASSERT_FALSE(grid.top_layer() == NULL);
197  ASSERT_TRUE(grid.top_right_layer() == NULL);
198  ASSERT_TRUE(grid.left_layer() == NULL);
199  ASSERT_TRUE(grid.center_layer() == NULL);
200  ASSERT_TRUE(grid.right_layer() == NULL);
201  ASSERT_TRUE(grid.bottom_left_layer() == NULL);
202  ASSERT_TRUE(grid.bottom_layer() == NULL);
203  ASSERT_TRUE(grid.bottom_right_layer() == NULL);
204
205  grid.SetImages(NULL, NULL, NULL,
206                 NULL, NULL, NULL,
207                 NULL, image.get(), NULL);
208
209  // Now only the bottom edge has a layer.
210  ASSERT_TRUE(grid.top_left_layer() == NULL);
211  ASSERT_TRUE(grid.top_layer() == NULL);
212  ASSERT_TRUE(grid.top_right_layer() == NULL);
213  ASSERT_TRUE(grid.left_layer() == NULL);
214  ASSERT_TRUE(grid.center_layer() == NULL);
215  ASSERT_TRUE(grid.right_layer() == NULL);
216  ASSERT_TRUE(grid.bottom_left_layer() == NULL);
217  ASSERT_FALSE(grid.bottom_layer() == NULL);
218  ASSERT_TRUE(grid.bottom_right_layer() == NULL);
219}
220
221// Test that side (top, left, right, bottom) layers that are narrower than their
222// adjacent corner layers stay pinned to the outside edges instead of getting
223// moved inwards or scaled.  This exercises the scenario used for shadows.
224TEST_F(ImageGridTest, SmallerSides) {
225  const int kCorner = 2;
226  const int kEdge = 1;
227
228  scoped_ptr<gfx::Image> top_left_image(
229      CreateImage(gfx::Size(kCorner, kCorner)));
230  scoped_ptr<gfx::Image> top_image(CreateImage(gfx::Size(kEdge, kEdge)));
231  scoped_ptr<gfx::Image> top_right_image(
232      CreateImage(gfx::Size(kCorner, kCorner)));
233  scoped_ptr<gfx::Image> left_image(CreateImage(gfx::Size(kEdge, kEdge)));
234  scoped_ptr<gfx::Image> right_image(CreateImage(gfx::Size(kEdge, kEdge)));
235
236  ImageGrid grid;
237  grid.SetImages(top_left_image.get(), top_image.get(), top_right_image.get(),
238                 left_image.get(), NULL, right_image.get(),
239                 NULL, NULL, NULL);
240  ImageGrid::TestAPI test_api(&grid);
241
242  const gfx::Size kSize(20, 30);
243  grid.SetSize(kSize);
244
245  // The top layer should be flush with the top edge and stretched horizontally
246  // between the two top corners.
247  EXPECT_EQ(gfx::RectF(
248                kCorner, 0, kSize.width() - 2 * kCorner, kEdge).ToString(),
249            test_api.GetTransformedLayerBounds(
250                *grid.top_layer()).ToString());
251
252  // The left layer should be flush with the left edge and stretched vertically
253  // between the top left corner and the bottom.
254  EXPECT_EQ(gfx::RectF(
255                0, kCorner, kEdge, kSize.height() - kCorner).ToString(),
256            test_api.GetTransformedLayerBounds(
257                *grid.left_layer()).ToString());
258
259  // The right layer should be flush with the right edge and stretched
260  // vertically between the top right corner and the bottom.
261  EXPECT_EQ(gfx::RectF(
262                kSize.width() - kEdge, kCorner,
263                kEdge, kSize.height() - kCorner).ToString(),
264            test_api.GetTransformedLayerBounds(
265                *grid.right_layer()).ToString());
266}
267
268// Test that we hide or clip layers as needed when the grid is assigned a small
269// size.
270TEST_F(ImageGridTest, TooSmall) {
271  const int kCorner = 5;
272  const int kCenter = 3;
273  const int kEdge = 3;
274
275  scoped_ptr<gfx::Image> top_left_image(
276      CreateImage(gfx::Size(kCorner, kCorner)));
277  scoped_ptr<gfx::Image> top_image(CreateImage(gfx::Size(kEdge, kEdge)));
278  scoped_ptr<gfx::Image> top_right_image(
279      CreateImage(gfx::Size(kCorner, kCorner)));
280  scoped_ptr<gfx::Image> left_image(CreateImage(gfx::Size(kEdge, kEdge)));
281  scoped_ptr<gfx::Image> center_image(CreateImage(gfx::Size(kCenter, kCenter)));
282  scoped_ptr<gfx::Image> right_image(CreateImage(gfx::Size(kEdge, kEdge)));
283  scoped_ptr<gfx::Image> bottom_left_image(
284      CreateImage(gfx::Size(kCorner, kCorner)));
285  scoped_ptr<gfx::Image> bottom_image(CreateImage(gfx::Size(kEdge, kEdge)));
286  scoped_ptr<gfx::Image> bottom_right_image(
287      CreateImage(gfx::Size(kCorner, kCorner)));
288
289  ImageGrid grid;
290  grid.SetImages(
291      top_left_image.get(), top_image.get(), top_right_image.get(),
292      left_image.get(), center_image.get(), right_image.get(),
293      bottom_left_image.get(), bottom_image.get(), bottom_right_image.get());
294  ImageGrid::TestAPI test_api(&grid);
295
296  // Set a size that's smaller than the combined (unscaled) corner images.
297  const gfx::Size kSmallSize(kCorner + kCorner - 3, kCorner + kCorner - 5);
298  grid.SetSize(kSmallSize);
299
300  // The scalable images around the sides and in the center should be hidden.
301  EXPECT_FALSE(grid.top_layer()->visible());
302  EXPECT_FALSE(grid.bottom_layer()->visible());
303  EXPECT_FALSE(grid.left_layer()->visible());
304  EXPECT_FALSE(grid.right_layer()->visible());
305  EXPECT_FALSE(grid.center_layer()->visible());
306
307  // The corner images' clip rects should sum to the expected size.
308  EXPECT_EQ(kSmallSize.width(),
309            test_api.top_left_clip_rect().width() +
310            test_api.top_right_clip_rect().width());
311  EXPECT_EQ(kSmallSize.width(),
312            test_api.bottom_left_clip_rect().width() +
313            test_api.bottom_right_clip_rect().width());
314  EXPECT_EQ(kSmallSize.height(),
315            test_api.top_left_clip_rect().height() +
316            test_api.bottom_left_clip_rect().height());
317  EXPECT_EQ(kSmallSize.height(),
318            test_api.top_right_clip_rect().height() +
319            test_api.bottom_right_clip_rect().height());
320
321  // Resize the grid to be large enough to show all images.
322  const gfx::Size kLargeSize(kCorner + kCorner + kCenter,
323                             kCorner + kCorner + kCenter);
324  grid.SetSize(kLargeSize);
325
326  // The scalable images should be visible now.
327  EXPECT_TRUE(grid.top_layer()->visible());
328  EXPECT_TRUE(grid.bottom_layer()->visible());
329  EXPECT_TRUE(grid.left_layer()->visible());
330  EXPECT_TRUE(grid.right_layer()->visible());
331  EXPECT_TRUE(grid.center_layer()->visible());
332
333  // We shouldn't be clipping the corner images anymore.
334  EXPECT_TRUE(test_api.top_left_clip_rect().IsEmpty());
335  EXPECT_TRUE(test_api.top_right_clip_rect().IsEmpty());
336  EXPECT_TRUE(test_api.bottom_left_clip_rect().IsEmpty());
337  EXPECT_TRUE(test_api.bottom_right_clip_rect().IsEmpty());
338}
339
340}  // namespace corewm
341}  // namespace views
342