1 // Copyright 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 "base/containers/hash_tables.h" 6 #include "cc/layers/append_quads_data.h" 7 #include "cc/layers/nine_patch_layer_impl.h" 8 #include "cc/quads/texture_draw_quad.h" 9 #include "cc/resources/ui_resource_bitmap.h" 10 #include "cc/resources/ui_resource_client.h" 11 #include "cc/test/fake_impl_proxy.h" 12 #include "cc/test/fake_ui_resource_layer_tree_host_impl.h" 13 #include "cc/test/geometry_test_utils.h" 14 #include "cc/test/layer_test_common.h" 15 #include "cc/trees/single_thread_proxy.h" 16 #include "testing/gmock/include/gmock/gmock.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 #include "ui/gfx/rect_conversions.h" 19 #include "ui/gfx/safe_integer_conversions.h" 20 #include "ui/gfx/transform.h" 21 22 namespace cc { 23 namespace { 24 25 gfx::Rect ToRoundedIntRect(const gfx::RectF& rect_f) { 26 return gfx::Rect(gfx::ToRoundedInt(rect_f.x()), 27 gfx::ToRoundedInt(rect_f.y()), 28 gfx::ToRoundedInt(rect_f.width()), 29 gfx::ToRoundedInt(rect_f.height())); 30 } 31 32 void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size, 33 const gfx::Rect& aperture_rect, 34 const gfx::Size& layer_size, 35 const gfx::Rect& border, 36 bool fill_center, 37 size_t expected_quad_size) { 38 MockOcclusionTracker<LayerImpl> occlusion_tracker; 39 scoped_ptr<RenderPass> render_pass = RenderPass::Create(); 40 gfx::Rect visible_content_rect(layer_size); 41 gfx::Rect expected_remaining(border.x(), 42 border.y(), 43 layer_size.width() - border.width(), 44 layer_size.height() - border.height()); 45 46 FakeImplProxy proxy; 47 TestSharedBitmapManager shared_bitmap_manager; 48 FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager); 49 scoped_ptr<NinePatchLayerImpl> layer = 50 NinePatchLayerImpl::Create(host_impl.active_tree(), 1); 51 layer->draw_properties().visible_content_rect = visible_content_rect; 52 layer->SetBounds(layer_size); 53 layer->SetContentBounds(layer_size); 54 layer->CreateRenderSurface(); 55 layer->draw_properties().render_target = layer.get(); 56 57 UIResourceId uid = 1; 58 bool is_opaque = false; 59 UIResourceBitmap bitmap(bitmap_size, is_opaque); 60 61 host_impl.CreateUIResource(uid, bitmap); 62 layer->SetUIResourceId(uid); 63 layer->SetImageBounds(bitmap_size); 64 layer->SetLayout(aperture_rect, border, fill_center); 65 AppendQuadsData data; 66 layer->AppendQuads(render_pass.get(), occlusion_tracker, &data); 67 68 // Verify quad rects 69 const QuadList& quads = render_pass->quad_list; 70 EXPECT_EQ(expected_quad_size, quads.size()); 71 72 Region remaining(visible_content_rect); 73 size_t i = 0; 74 for (QuadList::ConstIterator iter = quads.begin(); iter != quads.end(); 75 ++iter) { 76 gfx::Rect quad_rect = iter->rect; 77 78 EXPECT_TRUE(visible_content_rect.Contains(quad_rect)) << i; 79 EXPECT_TRUE(remaining.Contains(quad_rect)) << i; 80 remaining.Subtract(Region(quad_rect)); 81 ++i; 82 } 83 84 // Check if the left-over quad is the same size as the mapped aperture quad in 85 // layer space. 86 if (!fill_center) { 87 EXPECT_RECT_EQ(expected_remaining, gfx::ToEnclosedRect(remaining.bounds())); 88 } else { 89 EXPECT_TRUE(remaining.bounds().IsEmpty()); 90 } 91 92 // Verify UV rects 93 gfx::Rect bitmap_rect(bitmap_size); 94 Region tex_remaining(bitmap_rect); 95 for (QuadList::ConstIterator iter = quads.begin(); iter != quads.end(); 96 ++iter) { 97 const TextureDrawQuad* tex_quad = TextureDrawQuad::MaterialCast(&*iter); 98 gfx::RectF tex_rect = 99 gfx::BoundingRect(tex_quad->uv_top_left, tex_quad->uv_bottom_right); 100 tex_rect.Scale(bitmap_size.width(), bitmap_size.height()); 101 tex_remaining.Subtract(Region(ToRoundedIntRect(tex_rect))); 102 } 103 104 if (!fill_center) { 105 EXPECT_RECT_EQ(aperture_rect, tex_remaining.bounds()); 106 Region aperture_region(aperture_rect); 107 EXPECT_EQ(aperture_region, tex_remaining); 108 } else { 109 EXPECT_TRUE(remaining.bounds().IsEmpty()); 110 } 111 } 112 113 TEST(NinePatchLayerImplTest, VerifyDrawQuads) { 114 // Input is a 100x100 bitmap with a 40x50 aperture at x=20, y=30. 115 // The bounds of the layer are set to 400x400. 116 gfx::Size bitmap_size(100, 100); 117 gfx::Size layer_size(400, 500); 118 gfx::Rect aperture_rect(20, 30, 40, 50); 119 gfx::Rect border(40, 40, 80, 80); 120 bool fill_center = false; 121 size_t expected_quad_size = 8; 122 NinePatchLayerLayoutTest(bitmap_size, 123 aperture_rect, 124 layer_size, 125 border, 126 fill_center, 127 expected_quad_size); 128 129 // The bounds of the layer are set to less than the bitmap size. 130 bitmap_size = gfx::Size(100, 100); 131 layer_size = gfx::Size(40, 50); 132 aperture_rect = gfx::Rect(20, 30, 40, 50); 133 border = gfx::Rect(10, 10, 25, 15); 134 fill_center = true; 135 expected_quad_size = 9; 136 NinePatchLayerLayoutTest(bitmap_size, 137 aperture_rect, 138 layer_size, 139 border, 140 fill_center, 141 expected_quad_size); 142 143 // Layer and image sizes are equal. 144 bitmap_size = gfx::Size(100, 100); 145 layer_size = gfx::Size(100, 100); 146 aperture_rect = gfx::Rect(20, 30, 40, 50); 147 border = gfx::Rect(20, 30, 40, 50); 148 fill_center = true; 149 expected_quad_size = 9; 150 NinePatchLayerLayoutTest(bitmap_size, 151 aperture_rect, 152 layer_size, 153 border, 154 fill_center, 155 expected_quad_size); 156 } 157 158 TEST(NinePatchLayerImplTest, VerifyDrawQuadsWithEmptyPatches) { 159 // The top component of the 9-patch is empty, so there should be no quads for 160 // the top three components. 161 gfx::Size bitmap_size(100, 100); 162 gfx::Size layer_size(100, 100); 163 gfx::Rect aperture_rect(10, 0, 80, 90); 164 gfx::Rect border(10, 0, 20, 10); 165 bool fill_center = false; 166 size_t expected_quad_size = 5; 167 NinePatchLayerLayoutTest(bitmap_size, 168 aperture_rect, 169 layer_size, 170 border, 171 fill_center, 172 expected_quad_size); 173 174 // The top and left components of the 9-patch are empty, so there should be no 175 // quads for the left and top components. 176 bitmap_size = gfx::Size(100, 100); 177 layer_size = gfx::Size(100, 100); 178 aperture_rect = gfx::Rect(0, 0, 90, 90); 179 border = gfx::Rect(0, 0, 10, 10); 180 fill_center = false; 181 expected_quad_size = 3; 182 NinePatchLayerLayoutTest(bitmap_size, 183 aperture_rect, 184 layer_size, 185 border, 186 fill_center, 187 expected_quad_size); 188 189 // The aperture is the size of the bitmap and the center doesn't draw. 190 bitmap_size = gfx::Size(100, 100); 191 layer_size = gfx::Size(100, 100); 192 aperture_rect = gfx::Rect(0, 0, 100, 100); 193 border = gfx::Rect(0, 0, 0, 0); 194 fill_center = false; 195 expected_quad_size = 0; 196 NinePatchLayerLayoutTest(bitmap_size, 197 aperture_rect, 198 layer_size, 199 border, 200 fill_center, 201 expected_quad_size); 202 203 // The aperture is the size of the bitmap and the center does draw. 204 bitmap_size = gfx::Size(100, 100); 205 layer_size = gfx::Size(100, 100); 206 aperture_rect = gfx::Rect(0, 0, 100, 100); 207 border = gfx::Rect(0, 0, 0, 0); 208 fill_center = true; 209 expected_quad_size = 1; 210 NinePatchLayerLayoutTest(bitmap_size, 211 aperture_rect, 212 layer_size, 213 border, 214 fill_center, 215 expected_quad_size); 216 } 217 218 TEST(NinePatchLayerImplTest, Occlusion) { 219 gfx::Size layer_size(1000, 1000); 220 gfx::Size viewport_size(1000, 1000); 221 222 LayerTestCommon::LayerImplTest impl; 223 224 SkBitmap sk_bitmap; 225 sk_bitmap.allocN32Pixels(10, 10); 226 sk_bitmap.setImmutable(); 227 UIResourceId uid = 5; 228 UIResourceBitmap bitmap(sk_bitmap); 229 impl.host_impl()->CreateUIResource(uid, bitmap); 230 231 NinePatchLayerImpl* nine_patch_layer_impl = 232 impl.AddChildToRoot<NinePatchLayerImpl>(); 233 nine_patch_layer_impl->SetBounds(layer_size); 234 nine_patch_layer_impl->SetContentBounds(layer_size); 235 nine_patch_layer_impl->SetDrawsContent(true); 236 nine_patch_layer_impl->SetUIResourceId(uid); 237 nine_patch_layer_impl->SetImageBounds(gfx::Size(10, 10)); 238 239 gfx::Rect aperture = gfx::Rect(3, 3, 4, 4); 240 gfx::Rect border = gfx::Rect(300, 300, 400, 400); 241 nine_patch_layer_impl->SetLayout(aperture, border, true); 242 243 impl.CalcDrawProps(viewport_size); 244 245 { 246 SCOPED_TRACE("No occlusion"); 247 gfx::Rect occluded; 248 impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, occluded); 249 250 LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), 251 gfx::Rect(layer_size)); 252 EXPECT_EQ(9u, impl.quad_list().size()); 253 } 254 255 { 256 SCOPED_TRACE("Full occlusion"); 257 gfx::Rect occluded(nine_patch_layer_impl->visible_content_rect()); 258 impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, occluded); 259 260 LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect()); 261 EXPECT_EQ(impl.quad_list().size(), 0u); 262 } 263 264 { 265 SCOPED_TRACE("Partial occlusion"); 266 gfx::Rect occluded(0, 0, 500, 1000); 267 impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, occluded); 268 269 size_t partially_occluded_count = 0; 270 LayerTestCommon::VerifyQuadsAreOccluded( 271 impl.quad_list(), occluded, &partially_occluded_count); 272 // The layer outputs nine quads, three of which are partially occluded, and 273 // three fully occluded. 274 EXPECT_EQ(6u, impl.quad_list().size()); 275 EXPECT_EQ(3u, partially_occluded_count); 276 } 277 } 278 279 } // namespace 280 } // namespace cc 281