nine_patch_layer_impl.cc revision 010d83a9304c5a91596085d917d248abff47903a
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/layers/quad_sink.h" 11#include "cc/quads/texture_draw_quad.h" 12#include "cc/trees/layer_tree_impl.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(QuadSink* quad_sink, 84 AppendQuadsData* append_quads_data) { 85 CheckGeometryLimitations(); 86 SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState(); 87 PopulateSharedQuadState(shared_quad_state); 88 89 AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data); 90 91 if (!ui_resource_id_) 92 return; 93 94 ResourceProvider::ResourceId resource = 95 layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_); 96 97 if (!resource) 98 return; 99 100 static const bool flipped = false; 101 static const bool premultiplied_alpha = true; 102 103 DCHECK(!bounds().IsEmpty()); 104 105 // NinePatch border widths in layer space. 106 int layer_left_width = border_.x(); 107 int layer_top_height = border_.y(); 108 int layer_right_width = border_.width() - layer_left_width; 109 int layer_bottom_height = border_.height() - layer_top_height; 110 111 int layer_middle_width = bounds().width() - border_.width(); 112 int layer_middle_height = bounds().height() - border_.height(); 113 114 // Patch positions in layer space 115 gfx::Rect layer_top_left(0, 0, layer_left_width, layer_top_height); 116 gfx::Rect layer_top_right(bounds().width() - layer_right_width, 117 0, 118 layer_right_width, 119 layer_top_height); 120 gfx::Rect layer_bottom_left(0, 121 bounds().height() - layer_bottom_height, 122 layer_left_width, 123 layer_bottom_height); 124 gfx::Rect layer_bottom_right(layer_top_right.x(), 125 layer_bottom_left.y(), 126 layer_right_width, 127 layer_bottom_height); 128 gfx::Rect layer_top( 129 layer_top_left.right(), 0, layer_middle_width, layer_top_height); 130 gfx::Rect layer_left( 131 0, layer_top_left.bottom(), layer_left_width, layer_middle_height); 132 gfx::Rect layer_right(layer_top_right.x(), 133 layer_top_right.bottom(), 134 layer_right_width, 135 layer_left.height()); 136 gfx::Rect layer_bottom(layer_top.x(), 137 layer_bottom_left.y(), 138 layer_top.width(), 139 layer_bottom_height); 140 gfx::Rect layer_center(layer_left_width, 141 layer_top_height, 142 layer_middle_width, 143 layer_middle_height); 144 145 // Note the following values are in image (bitmap) space. 146 float image_width = image_bounds_.width(); 147 float image_height = image_bounds_.height(); 148 149 int image_aperture_left_width = image_aperture_.x(); 150 int image_aperture_top_height = image_aperture_.y(); 151 int image_aperture_right_width = image_width - image_aperture_.right(); 152 int image_aperture_bottom_height = image_height - image_aperture_.bottom(); 153 // Patch positions in bitmap UV space (from zero to one) 154 gfx::RectF uv_top_left = NormalizedRect(0, 155 0, 156 image_aperture_left_width, 157 image_aperture_top_height, 158 image_width, 159 image_height); 160 gfx::RectF uv_top_right = 161 NormalizedRect(image_width - image_aperture_right_width, 162 0, 163 image_aperture_right_width, 164 image_aperture_top_height, 165 image_width, 166 image_height); 167 gfx::RectF uv_bottom_left = 168 NormalizedRect(0, 169 image_height - image_aperture_bottom_height, 170 image_aperture_left_width, 171 image_aperture_bottom_height, 172 image_width, 173 image_height); 174 gfx::RectF uv_bottom_right = 175 NormalizedRect(image_width - image_aperture_right_width, 176 image_height - image_aperture_bottom_height, 177 image_aperture_right_width, 178 image_aperture_bottom_height, 179 image_width, 180 image_height); 181 gfx::RectF uv_top( 182 uv_top_left.right(), 183 0, 184 (image_width - image_aperture_left_width - image_aperture_right_width) / 185 image_width, 186 (image_aperture_top_height) / image_height); 187 gfx::RectF uv_left(0, 188 uv_top_left.bottom(), 189 image_aperture_left_width / image_width, 190 (image_height - image_aperture_top_height - 191 image_aperture_bottom_height) / 192 image_height); 193 gfx::RectF uv_right(uv_top_right.x(), 194 uv_top_right.bottom(), 195 image_aperture_right_width / image_width, 196 uv_left.height()); 197 gfx::RectF uv_bottom(uv_top.x(), 198 uv_bottom_left.y(), 199 uv_top.width(), 200 image_aperture_bottom_height / image_height); 201 gfx::RectF uv_center(uv_top_left.right(), 202 uv_top_left.bottom(), 203 uv_top.width(), 204 uv_left.height()); 205 206 // Nothing is opaque here. 207 // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness? 208 gfx::Rect opaque_rect; 209 gfx::Rect visible_rect; 210 const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; 211 scoped_ptr<TextureDrawQuad> quad; 212 213 visible_rect = 214 quad_sink->UnoccludedContentRect(layer_top_left, draw_transform()); 215 if (!visible_rect.IsEmpty()) { 216 quad = TextureDrawQuad::Create(); 217 quad->SetNew(shared_quad_state, 218 layer_top_left, 219 opaque_rect, 220 visible_rect, 221 resource, 222 premultiplied_alpha, 223 uv_top_left.origin(), 224 uv_top_left.bottom_right(), 225 SK_ColorTRANSPARENT, 226 vertex_opacity, 227 flipped); 228 quad_sink->Append(quad.PassAs<DrawQuad>()); 229 } 230 231 visible_rect = 232 quad_sink->UnoccludedContentRect(layer_top_right, draw_transform()); 233 if (!visible_rect.IsEmpty()) { 234 quad = TextureDrawQuad::Create(); 235 quad->SetNew(shared_quad_state, 236 layer_top_right, 237 opaque_rect, 238 visible_rect, 239 resource, 240 premultiplied_alpha, 241 uv_top_right.origin(), 242 uv_top_right.bottom_right(), 243 SK_ColorTRANSPARENT, 244 vertex_opacity, 245 flipped); 246 quad_sink->Append(quad.PassAs<DrawQuad>()); 247 } 248 249 visible_rect = 250 quad_sink->UnoccludedContentRect(layer_bottom_left, draw_transform()); 251 if (!visible_rect.IsEmpty()) { 252 quad = TextureDrawQuad::Create(); 253 quad->SetNew(shared_quad_state, 254 layer_bottom_left, 255 opaque_rect, 256 visible_rect, 257 resource, 258 premultiplied_alpha, 259 uv_bottom_left.origin(), 260 uv_bottom_left.bottom_right(), 261 SK_ColorTRANSPARENT, 262 vertex_opacity, 263 flipped); 264 quad_sink->Append(quad.PassAs<DrawQuad>()); 265 } 266 267 visible_rect = 268 quad_sink->UnoccludedContentRect(layer_bottom_right, draw_transform()); 269 if (!visible_rect.IsEmpty()) { 270 quad = TextureDrawQuad::Create(); 271 quad->SetNew(shared_quad_state, 272 layer_bottom_right, 273 opaque_rect, 274 visible_rect, 275 resource, 276 premultiplied_alpha, 277 uv_bottom_right.origin(), 278 uv_bottom_right.bottom_right(), 279 SK_ColorTRANSPARENT, 280 vertex_opacity, 281 flipped); 282 quad_sink->Append(quad.PassAs<DrawQuad>()); 283 } 284 285 visible_rect = quad_sink->UnoccludedContentRect(layer_top, draw_transform()); 286 if (!visible_rect.IsEmpty()) { 287 quad = TextureDrawQuad::Create(); 288 quad->SetNew(shared_quad_state, 289 layer_top, 290 opaque_rect, 291 visible_rect, 292 resource, 293 premultiplied_alpha, 294 uv_top.origin(), 295 uv_top.bottom_right(), 296 SK_ColorTRANSPARENT, 297 vertex_opacity, 298 flipped); 299 quad_sink->Append(quad.PassAs<DrawQuad>()); 300 } 301 302 visible_rect = quad_sink->UnoccludedContentRect(layer_left, draw_transform()); 303 if (!visible_rect.IsEmpty()) { 304 quad = TextureDrawQuad::Create(); 305 quad->SetNew(shared_quad_state, 306 layer_left, 307 opaque_rect, 308 visible_rect, 309 resource, 310 premultiplied_alpha, 311 uv_left.origin(), 312 uv_left.bottom_right(), 313 SK_ColorTRANSPARENT, 314 vertex_opacity, 315 flipped); 316 quad_sink->Append(quad.PassAs<DrawQuad>()); 317 } 318 319 visible_rect = 320 quad_sink->UnoccludedContentRect(layer_right, draw_transform()); 321 if (!visible_rect.IsEmpty()) { 322 quad = TextureDrawQuad::Create(); 323 quad->SetNew(shared_quad_state, 324 layer_right, 325 opaque_rect, 326 layer_right, 327 resource, 328 premultiplied_alpha, 329 uv_right.origin(), 330 uv_right.bottom_right(), 331 SK_ColorTRANSPARENT, 332 vertex_opacity, 333 flipped); 334 quad_sink->Append(quad.PassAs<DrawQuad>()); 335 } 336 337 visible_rect = 338 quad_sink->UnoccludedContentRect(layer_bottom, draw_transform()); 339 if (!visible_rect.IsEmpty()) { 340 quad = TextureDrawQuad::Create(); 341 quad->SetNew(shared_quad_state, 342 layer_bottom, 343 opaque_rect, 344 visible_rect, 345 resource, 346 premultiplied_alpha, 347 uv_bottom.origin(), 348 uv_bottom.bottom_right(), 349 SK_ColorTRANSPARENT, 350 vertex_opacity, 351 flipped); 352 quad_sink->Append(quad.PassAs<DrawQuad>()); 353 } 354 355 if (fill_center_) { 356 visible_rect = 357 quad_sink->UnoccludedContentRect(layer_center, draw_transform()); 358 if (!visible_rect.IsEmpty()) { 359 quad = TextureDrawQuad::Create(); 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 quad_sink->Append(quad.PassAs<DrawQuad>()); 372 } 373 } 374} 375 376const char* NinePatchLayerImpl::LayerTypeAsString() const { 377 return "cc::NinePatchLayerImpl"; 378} 379 380base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const { 381 base::DictionaryValue* result = LayerImpl::LayerTreeAsJson(); 382 383 base::ListValue* list = new base::ListValue; 384 list->AppendInteger(image_aperture_.origin().x()); 385 list->AppendInteger(image_aperture_.origin().y()); 386 list->AppendInteger(image_aperture_.size().width()); 387 list->AppendInteger(image_aperture_.size().height()); 388 result->Set("ImageAperture", list); 389 390 list = new base::ListValue; 391 list->AppendInteger(image_bounds_.width()); 392 list->AppendInteger(image_bounds_.height()); 393 result->Set("ImageBounds", list); 394 395 result->Set("Border", MathUtil::AsValue(border_).release()); 396 397 base::FundamentalValue* fill_center = 398 base::Value::CreateBooleanValue(fill_center_); 399 result->Set("FillCenter", fill_center); 400 401 return result; 402} 403 404} // namespace cc 405