nine_patch_layer_impl.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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 15namespace cc { 16 17NinePatchLayerImpl::NinePatchLayerImpl(LayerTreeImpl* tree_impl, int id) 18 : UIResourceLayerImpl(tree_impl, id), 19 fill_center_(false) {} 20 21NinePatchLayerImpl::~NinePatchLayerImpl() {} 22 23scoped_ptr<LayerImpl> NinePatchLayerImpl::CreateLayerImpl( 24 LayerTreeImpl* tree_impl) { 25 return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); 26} 27 28void 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 35static 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 47void 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 65void 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 83void 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 visible_rect = 217 occlusion_tracker.UnoccludedContentRect(layer_top_left, draw_transform()); 218 if (!visible_rect.IsEmpty()) { 219 TextureDrawQuad* quad = 220 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 221 quad->SetNew(shared_quad_state, 222 layer_top_left, 223 opaque_rect, 224 visible_rect, 225 resource, 226 premultiplied_alpha, 227 uv_top_left.origin(), 228 uv_top_left.bottom_right(), 229 SK_ColorTRANSPARENT, 230 vertex_opacity, 231 flipped); 232 } 233 234 visible_rect = occlusion_tracker.UnoccludedContentRect(layer_top_right, 235 draw_transform()); 236 if (!visible_rect.IsEmpty()) { 237 TextureDrawQuad* quad = 238 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 239 quad->SetNew(shared_quad_state, 240 layer_top_right, 241 opaque_rect, 242 visible_rect, 243 resource, 244 premultiplied_alpha, 245 uv_top_right.origin(), 246 uv_top_right.bottom_right(), 247 SK_ColorTRANSPARENT, 248 vertex_opacity, 249 flipped); 250 } 251 252 visible_rect = occlusion_tracker.UnoccludedContentRect(layer_bottom_left, 253 draw_transform()); 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_tracker.UnoccludedContentRect(layer_bottom_right, 271 draw_transform()); 272 if (!visible_rect.IsEmpty()) { 273 TextureDrawQuad* quad = 274 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 275 quad->SetNew(shared_quad_state, 276 layer_bottom_right, 277 opaque_rect, 278 visible_rect, 279 resource, 280 premultiplied_alpha, 281 uv_bottom_right.origin(), 282 uv_bottom_right.bottom_right(), 283 SK_ColorTRANSPARENT, 284 vertex_opacity, 285 flipped); 286 } 287 288 visible_rect = 289 occlusion_tracker.UnoccludedContentRect(layer_top, draw_transform()); 290 if (!visible_rect.IsEmpty()) { 291 TextureDrawQuad* quad = 292 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 293 quad->SetNew(shared_quad_state, 294 layer_top, 295 opaque_rect, 296 visible_rect, 297 resource, 298 premultiplied_alpha, 299 uv_top.origin(), 300 uv_top.bottom_right(), 301 SK_ColorTRANSPARENT, 302 vertex_opacity, 303 flipped); 304 } 305 306 visible_rect = 307 occlusion_tracker.UnoccludedContentRect(layer_left, draw_transform()); 308 if (!visible_rect.IsEmpty()) { 309 TextureDrawQuad* quad = 310 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 311 quad->SetNew(shared_quad_state, 312 layer_left, 313 opaque_rect, 314 visible_rect, 315 resource, 316 premultiplied_alpha, 317 uv_left.origin(), 318 uv_left.bottom_right(), 319 SK_ColorTRANSPARENT, 320 vertex_opacity, 321 flipped); 322 } 323 324 visible_rect = 325 occlusion_tracker.UnoccludedContentRect(layer_right, draw_transform()); 326 if (!visible_rect.IsEmpty()) { 327 TextureDrawQuad* quad = 328 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 329 quad->SetNew(shared_quad_state, 330 layer_right, 331 opaque_rect, 332 layer_right, 333 resource, 334 premultiplied_alpha, 335 uv_right.origin(), 336 uv_right.bottom_right(), 337 SK_ColorTRANSPARENT, 338 vertex_opacity, 339 flipped); 340 } 341 342 visible_rect = 343 occlusion_tracker.UnoccludedContentRect(layer_bottom, draw_transform()); 344 if (!visible_rect.IsEmpty()) { 345 TextureDrawQuad* quad = 346 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 347 quad->SetNew(shared_quad_state, 348 layer_bottom, 349 opaque_rect, 350 visible_rect, 351 resource, 352 premultiplied_alpha, 353 uv_bottom.origin(), 354 uv_bottom.bottom_right(), 355 SK_ColorTRANSPARENT, 356 vertex_opacity, 357 flipped); 358 } 359 360 if (fill_center_) { 361 visible_rect = 362 occlusion_tracker.UnoccludedContentRect(layer_center, draw_transform()); 363 if (!visible_rect.IsEmpty()) { 364 TextureDrawQuad* quad = 365 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); 366 quad->SetNew(shared_quad_state, 367 layer_center, 368 opaque_rect, 369 visible_rect, 370 resource, 371 premultiplied_alpha, 372 uv_center.origin(), 373 uv_center.bottom_right(), 374 SK_ColorTRANSPARENT, 375 vertex_opacity, 376 flipped); 377 } 378 } 379} 380 381const char* NinePatchLayerImpl::LayerTypeAsString() const { 382 return "cc::NinePatchLayerImpl"; 383} 384 385base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const { 386 base::DictionaryValue* result = LayerImpl::LayerTreeAsJson(); 387 388 base::ListValue* list = new base::ListValue; 389 list->AppendInteger(image_aperture_.origin().x()); 390 list->AppendInteger(image_aperture_.origin().y()); 391 list->AppendInteger(image_aperture_.size().width()); 392 list->AppendInteger(image_aperture_.size().height()); 393 result->Set("ImageAperture", list); 394 395 list = new base::ListValue; 396 list->AppendInteger(image_bounds_.width()); 397 list->AppendInteger(image_bounds_.height()); 398 result->Set("ImageBounds", list); 399 400 result->Set("Border", MathUtil::AsValue(border_).release()); 401 402 result->SetBoolean("FillCenter", fill_center_); 403 404 return result; 405} 406 407} // namespace cc 408