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 "cc/layers/nine_patch_layer_impl.h" 6 7 #include "base/strings/stringprintf.h" 8 #include "base/values.h" 9 #include "cc/base/math_util.h" 10 #include "cc/quads/texture_draw_quad.h" 11 #include "cc/trees/layer_tree_impl.h" 12 #include "cc/trees/occlusion_tracker.h" 13 #include "ui/gfx/rect_f.h" 14 15 namespace cc { 16 17 NinePatchLayerImpl::NinePatchLayerImpl(LayerTreeImpl* tree_impl, int id) 18 : UIResourceLayerImpl(tree_impl, id), 19 fill_center_(false) {} 20 21 NinePatchLayerImpl::~NinePatchLayerImpl() {} 22 23 scoped_ptr<LayerImpl> NinePatchLayerImpl::CreateLayerImpl( 24 LayerTreeImpl* tree_impl) { 25 return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); 26 } 27 28 void NinePatchLayerImpl::PushPropertiesTo(LayerImpl* layer) { 29 UIResourceLayerImpl::PushPropertiesTo(layer); 30 NinePatchLayerImpl* layer_impl = static_cast<NinePatchLayerImpl*>(layer); 31 32 layer_impl->SetLayout(image_aperture_, border_, fill_center_); 33 } 34 35 static gfx::RectF NormalizedRect(float x, 36 float y, 37 float width, 38 float height, 39 float total_width, 40 float total_height) { 41 return gfx::RectF(x / total_width, 42 y / total_height, 43 width / total_width, 44 height / total_height); 45 } 46 47 void NinePatchLayerImpl::SetLayout(const gfx::Rect& aperture, 48 const gfx::Rect& border, 49 bool fill_center) { 50 // This check imposes an ordering on the call sequence. An UIResource must 51 // exist before SetLayout can be called. 52 DCHECK(ui_resource_id_); 53 54 if (image_aperture_ == aperture && 55 border_ == border && fill_center_ == fill_center) 56 return; 57 58 image_aperture_ = aperture; 59 border_ = border; 60 fill_center_ = fill_center; 61 62 NoteLayerPropertyChanged(); 63 } 64 65 void NinePatchLayerImpl::CheckGeometryLimitations() { 66 // |border| is in layer space. It cannot exceed the bounds of the layer. 67 DCHECK_GE(bounds().width(), border_.width()); 68 DCHECK_GE(bounds().height(), border_.height()); 69 70 // Sanity Check on |border| 71 DCHECK_LE(border_.x(), border_.width()); 72 DCHECK_LE(border_.y(), border_.height()); 73 DCHECK_GE(border_.x(), 0); 74 DCHECK_GE(border_.y(), 0); 75 76 // |aperture| is in image space. It cannot exceed the bounds of the bitmap. 77 DCHECK(!image_aperture_.size().IsEmpty()); 78 DCHECK(gfx::Rect(image_bounds_).Contains(image_aperture_)) 79 << "image_bounds_ " << gfx::Rect(image_bounds_).ToString() 80 << " image_aperture_ " << image_aperture_.ToString(); 81 } 82 83 void NinePatchLayerImpl::AppendQuads( 84 RenderPass* render_pass, 85 const OcclusionTracker<LayerImpl>& occlusion_tracker, 86 AppendQuadsData* append_quads_data) { 87 CheckGeometryLimitations(); 88 SharedQuadState* shared_quad_state = 89 render_pass->CreateAndAppendSharedQuadState(); 90 PopulateSharedQuadState(shared_quad_state); 91 92 AppendDebugBorderQuad( 93 render_pass, content_bounds(), shared_quad_state, append_quads_data); 94 95 if (!ui_resource_id_) 96 return; 97 98 ResourceProvider::ResourceId resource = 99 layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_); 100 101 if (!resource) 102 return; 103 104 static const bool flipped = false; 105 static const bool premultiplied_alpha = true; 106 107 DCHECK(!bounds().IsEmpty()); 108 109 // NinePatch border widths in layer space. 110 int layer_left_width = border_.x(); 111 int layer_top_height = border_.y(); 112 int layer_right_width = border_.width() - layer_left_width; 113 int layer_bottom_height = border_.height() - layer_top_height; 114 115 int layer_middle_width = bounds().width() - border_.width(); 116 int layer_middle_height = bounds().height() - border_.height(); 117 118 // Patch positions in layer space 119 gfx::Rect layer_top_left(0, 0, layer_left_width, layer_top_height); 120 gfx::Rect layer_top_right(bounds().width() - layer_right_width, 121 0, 122 layer_right_width, 123 layer_top_height); 124 gfx::Rect layer_bottom_left(0, 125 bounds().height() - layer_bottom_height, 126 layer_left_width, 127 layer_bottom_height); 128 gfx::Rect layer_bottom_right(layer_top_right.x(), 129 layer_bottom_left.y(), 130 layer_right_width, 131 layer_bottom_height); 132 gfx::Rect layer_top( 133 layer_top_left.right(), 0, layer_middle_width, layer_top_height); 134 gfx::Rect layer_left( 135 0, layer_top_left.bottom(), layer_left_width, layer_middle_height); 136 gfx::Rect layer_right(layer_top_right.x(), 137 layer_top_right.bottom(), 138 layer_right_width, 139 layer_left.height()); 140 gfx::Rect layer_bottom(layer_top.x(), 141 layer_bottom_left.y(), 142 layer_top.width(), 143 layer_bottom_height); 144 gfx::Rect layer_center(layer_left_width, 145 layer_top_height, 146 layer_middle_width, 147 layer_middle_height); 148 149 // Note the following values are in image (bitmap) space. 150 float image_width = image_bounds_.width(); 151 float image_height = image_bounds_.height(); 152 153 int image_aperture_left_width = image_aperture_.x(); 154 int image_aperture_top_height = image_aperture_.y(); 155 int image_aperture_right_width = image_width - image_aperture_.right(); 156 int image_aperture_bottom_height = image_height - image_aperture_.bottom(); 157 // Patch positions in bitmap UV space (from zero to one) 158 gfx::RectF uv_top_left = NormalizedRect(0, 159 0, 160 image_aperture_left_width, 161 image_aperture_top_height, 162 image_width, 163 image_height); 164 gfx::RectF uv_top_right = 165 NormalizedRect(image_width - image_aperture_right_width, 166 0, 167 image_aperture_right_width, 168 image_aperture_top_height, 169 image_width, 170 image_height); 171 gfx::RectF uv_bottom_left = 172 NormalizedRect(0, 173 image_height - image_aperture_bottom_height, 174 image_aperture_left_width, 175 image_aperture_bottom_height, 176 image_width, 177 image_height); 178 gfx::RectF uv_bottom_right = 179 NormalizedRect(image_width - image_aperture_right_width, 180 image_height - image_aperture_bottom_height, 181 image_aperture_right_width, 182 image_aperture_bottom_height, 183 image_width, 184 image_height); 185 gfx::RectF uv_top( 186 uv_top_left.right(), 187 0, 188 (image_width - image_aperture_left_width - image_aperture_right_width) / 189 image_width, 190 (image_aperture_top_height) / image_height); 191 gfx::RectF uv_left(0, 192 uv_top_left.bottom(), 193 image_aperture_left_width / image_width, 194 (image_height - image_aperture_top_height - 195 image_aperture_bottom_height) / 196 image_height); 197 gfx::RectF uv_right(uv_top_right.x(), 198 uv_top_right.bottom(), 199 image_aperture_right_width / image_width, 200 uv_left.height()); 201 gfx::RectF uv_bottom(uv_top.x(), 202 uv_bottom_left.y(), 203 uv_top.width(), 204 image_aperture_bottom_height / image_height); 205 gfx::RectF uv_center(uv_top_left.right(), 206 uv_top_left.bottom(), 207 uv_top.width(), 208 uv_left.height()); 209 210 // Nothing is opaque here. 211 // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness? 212 gfx::Rect opaque_rect; 213 gfx::Rect visible_rect; 214 const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; 215 216 Occlusion occlusion = 217 occlusion_tracker.GetCurrentOcclusionForLayer(draw_transform()); 218 219 visible_rect = occlusion.GetUnoccludedContentRect(layer_top_left); 220 if (!visible_rect.IsEmpty()) { 221 TextureDrawQuad* quad = 222 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 223 quad->SetNew(shared_quad_state, 224 layer_top_left, 225 opaque_rect, 226 visible_rect, 227 resource, 228 premultiplied_alpha, 229 uv_top_left.origin(), 230 uv_top_left.bottom_right(), 231 SK_ColorTRANSPARENT, 232 vertex_opacity, 233 flipped); 234 } 235 236 visible_rect = occlusion.GetUnoccludedContentRect(layer_top_right); 237 if (!visible_rect.IsEmpty()) { 238 TextureDrawQuad* quad = 239 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 240 quad->SetNew(shared_quad_state, 241 layer_top_right, 242 opaque_rect, 243 visible_rect, 244 resource, 245 premultiplied_alpha, 246 uv_top_right.origin(), 247 uv_top_right.bottom_right(), 248 SK_ColorTRANSPARENT, 249 vertex_opacity, 250 flipped); 251 } 252 253 visible_rect = occlusion.GetUnoccludedContentRect(layer_bottom_left); 254 if (!visible_rect.IsEmpty()) { 255 TextureDrawQuad* quad = 256 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 257 quad->SetNew(shared_quad_state, 258 layer_bottom_left, 259 opaque_rect, 260 visible_rect, 261 resource, 262 premultiplied_alpha, 263 uv_bottom_left.origin(), 264 uv_bottom_left.bottom_right(), 265 SK_ColorTRANSPARENT, 266 vertex_opacity, 267 flipped); 268 } 269 270 visible_rect = occlusion.GetUnoccludedContentRect(layer_bottom_right); 271 if (!visible_rect.IsEmpty()) { 272 TextureDrawQuad* quad = 273 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 274 quad->SetNew(shared_quad_state, 275 layer_bottom_right, 276 opaque_rect, 277 visible_rect, 278 resource, 279 premultiplied_alpha, 280 uv_bottom_right.origin(), 281 uv_bottom_right.bottom_right(), 282 SK_ColorTRANSPARENT, 283 vertex_opacity, 284 flipped); 285 } 286 287 visible_rect = occlusion.GetUnoccludedContentRect(layer_top); 288 if (!visible_rect.IsEmpty()) { 289 TextureDrawQuad* quad = 290 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 291 quad->SetNew(shared_quad_state, 292 layer_top, 293 opaque_rect, 294 visible_rect, 295 resource, 296 premultiplied_alpha, 297 uv_top.origin(), 298 uv_top.bottom_right(), 299 SK_ColorTRANSPARENT, 300 vertex_opacity, 301 flipped); 302 } 303 304 visible_rect = occlusion.GetUnoccludedContentRect(layer_left); 305 if (!visible_rect.IsEmpty()) { 306 TextureDrawQuad* quad = 307 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 308 quad->SetNew(shared_quad_state, 309 layer_left, 310 opaque_rect, 311 visible_rect, 312 resource, 313 premultiplied_alpha, 314 uv_left.origin(), 315 uv_left.bottom_right(), 316 SK_ColorTRANSPARENT, 317 vertex_opacity, 318 flipped); 319 } 320 321 visible_rect = occlusion.GetUnoccludedContentRect(layer_right); 322 if (!visible_rect.IsEmpty()) { 323 TextureDrawQuad* quad = 324 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 325 quad->SetNew(shared_quad_state, 326 layer_right, 327 opaque_rect, 328 layer_right, 329 resource, 330 premultiplied_alpha, 331 uv_right.origin(), 332 uv_right.bottom_right(), 333 SK_ColorTRANSPARENT, 334 vertex_opacity, 335 flipped); 336 } 337 338 visible_rect = occlusion.GetUnoccludedContentRect(layer_bottom); 339 if (!visible_rect.IsEmpty()) { 340 TextureDrawQuad* quad = 341 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 342 quad->SetNew(shared_quad_state, 343 layer_bottom, 344 opaque_rect, 345 visible_rect, 346 resource, 347 premultiplied_alpha, 348 uv_bottom.origin(), 349 uv_bottom.bottom_right(), 350 SK_ColorTRANSPARENT, 351 vertex_opacity, 352 flipped); 353 } 354 355 if (fill_center_) { 356 visible_rect = occlusion.GetUnoccludedContentRect(layer_center); 357 if (!visible_rect.IsEmpty()) { 358 TextureDrawQuad* quad = 359 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 360 quad->SetNew(shared_quad_state, 361 layer_center, 362 opaque_rect, 363 visible_rect, 364 resource, 365 premultiplied_alpha, 366 uv_center.origin(), 367 uv_center.bottom_right(), 368 SK_ColorTRANSPARENT, 369 vertex_opacity, 370 flipped); 371 } 372 } 373 } 374 375 const char* NinePatchLayerImpl::LayerTypeAsString() const { 376 return "cc::NinePatchLayerImpl"; 377 } 378 379 base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const { 380 base::DictionaryValue* result = LayerImpl::LayerTreeAsJson(); 381 382 base::ListValue* list = new base::ListValue; 383 list->AppendInteger(image_aperture_.origin().x()); 384 list->AppendInteger(image_aperture_.origin().y()); 385 list->AppendInteger(image_aperture_.size().width()); 386 list->AppendInteger(image_aperture_.size().height()); 387 result->Set("ImageAperture", list); 388 389 list = new base::ListValue; 390 list->AppendInteger(image_bounds_.width()); 391 list->AppendInteger(image_bounds_.height()); 392 result->Set("ImageBounds", list); 393 394 result->Set("Border", MathUtil::AsValue(border_).release()); 395 396 result->SetBoolean("FillCenter", fill_center_); 397 398 return result; 399 } 400 401 } // namespace cc 402