nine_patch_layer_impl.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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/layers/quad_sink.h" 10#include "cc/quads/texture_draw_quad.h" 11#include "ui/gfx/rect_f.h" 12 13namespace cc { 14 15NinePatchLayerImpl::NinePatchLayerImpl(LayerTreeImpl* tree_impl, int id) 16 : LayerImpl(tree_impl, id), 17 resource_id_(0) {} 18 19NinePatchLayerImpl::~NinePatchLayerImpl() {} 20 21ResourceProvider::ResourceId NinePatchLayerImpl::ContentsResourceId() const { 22 return 0; 23} 24 25scoped_ptr<LayerImpl> NinePatchLayerImpl::CreateLayerImpl( 26 LayerTreeImpl* tree_impl) { 27 return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); 28} 29 30void NinePatchLayerImpl::PushPropertiesTo(LayerImpl* layer) { 31 LayerImpl::PushPropertiesTo(layer); 32 NinePatchLayerImpl* layer_impl = static_cast<NinePatchLayerImpl*>(layer); 33 34 if (!resource_id_) 35 return; 36 37 layer_impl->SetResourceId(resource_id_); 38 layer_impl->SetLayout(image_bounds_, image_aperture_); 39} 40 41static gfx::RectF NormalizedRect(float x, 42 float y, 43 float width, 44 float height, 45 float total_width, 46 float total_height) { 47 return gfx::RectF(x / total_width, 48 y / total_height, 49 width / total_width, 50 height / total_height); 51} 52 53void NinePatchLayerImpl::SetLayout(gfx::Size image_bounds, gfx::Rect aperture) { 54 image_bounds_ = image_bounds; 55 image_aperture_ = aperture; 56} 57 58bool NinePatchLayerImpl::WillDraw(DrawMode draw_mode, 59 ResourceProvider* resource_provider) { 60 if (!resource_id_ || draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) 61 return false; 62 return LayerImpl::WillDraw(draw_mode, resource_provider); 63} 64 65void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink, 66 AppendQuadsData* append_quads_data) { 67 SharedQuadState* shared_quad_state = 68 quad_sink->UseSharedQuadState(CreateSharedQuadState()); 69 AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data); 70 71 if (!resource_id_) 72 return; 73 74 static const bool flipped = false; 75 static const bool premultiplied_alpha = true; 76 77 DCHECK(!bounds().IsEmpty()); 78 79 // NinePatch border widths in bitmap pixel space 80 int left_width = image_aperture_.x(); 81 int top_height = image_aperture_.y(); 82 int right_width = image_bounds_.width() - image_aperture_.right(); 83 int bottom_height = image_bounds_.height() - image_aperture_.bottom(); 84 85 // If layer can't fit the corners, clip to show the outer edges of the 86 // image. 87 int corner_total_width = left_width + right_width; 88 int middle_width = bounds().width() - corner_total_width; 89 if (middle_width < 0) { 90 float left_width_proportion = 91 static_cast<float>(left_width) / corner_total_width; 92 int left_width_crop = middle_width * left_width_proportion; 93 left_width += left_width_crop; 94 right_width = bounds().width() - left_width; 95 middle_width = 0; 96 } 97 int corner_total_height = top_height + bottom_height; 98 int middle_height = bounds().height() - corner_total_height; 99 if (middle_height < 0) { 100 float top_height_proportion = 101 static_cast<float>(top_height) / corner_total_height; 102 int top_height_crop = middle_height * top_height_proportion; 103 top_height += top_height_crop; 104 bottom_height = bounds().height() - top_height; 105 middle_height = 0; 106 } 107 108 // Patch positions in layer space 109 gfx::Rect top_left(0, 0, left_width, top_height); 110 gfx::Rect top_right( 111 bounds().width() - right_width, 0, right_width, top_height); 112 gfx::Rect bottom_left( 113 0, bounds().height() - bottom_height, left_width, bottom_height); 114 gfx::Rect bottom_right( 115 top_right.x(), bottom_left.y(), right_width, bottom_height); 116 gfx::Rect top(top_left.right(), 0, middle_width, top_height); 117 gfx::Rect left(0, top_left.bottom(), left_width, middle_height); 118 gfx::Rect right(top_right.x(), 119 top_right.bottom(), 120 right_width, 121 left.height()); 122 gfx::Rect bottom(top.x(), bottom_left.y(), top.width(), bottom_height); 123 124 float img_width = image_bounds_.width(); 125 float img_height = image_bounds_.height(); 126 127 // Patch positions in bitmap UV space (from zero to one) 128 gfx::RectF uv_top_left = NormalizedRect(0, 129 0, 130 left_width, 131 top_height, 132 img_width, 133 img_height); 134 gfx::RectF uv_top_right = NormalizedRect(img_width - right_width, 135 0, 136 right_width, 137 top_height, 138 img_width, 139 img_height); 140 gfx::RectF uv_bottom_left = NormalizedRect(0, 141 img_height - bottom_height, 142 left_width, 143 bottom_height, 144 img_width, 145 img_height); 146 gfx::RectF uv_bottom_right = NormalizedRect(img_width - right_width, 147 img_height - bottom_height, 148 right_width, 149 bottom_height, 150 img_width, 151 img_height); 152 gfx::RectF uv_top(uv_top_left.right(), 153 0, 154 (img_width - left_width - right_width) / img_width, 155 (top_height) / img_height); 156 gfx::RectF uv_left(0, 157 uv_top_left.bottom(), 158 left_width / img_width, 159 (img_height - top_height - bottom_height) / img_height); 160 gfx::RectF uv_right(uv_top_right.x(), 161 uv_top_right.bottom(), 162 right_width / img_width, 163 uv_left.height()); 164 gfx::RectF uv_bottom(uv_top.x(), 165 uv_bottom_left.y(), 166 uv_top.width(), 167 bottom_height / img_height); 168 169 // Nothing is opaque here. 170 // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness? 171 gfx::Rect opaque_rect; 172 const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; 173 scoped_ptr<TextureDrawQuad> quad; 174 175 quad = TextureDrawQuad::Create(); 176 quad->SetNew(shared_quad_state, 177 top_left, 178 opaque_rect, 179 resource_id_, 180 premultiplied_alpha, 181 uv_top_left.origin(), 182 uv_top_left.bottom_right(), 183 SK_ColorTRANSPARENT, 184 vertex_opacity, 185 flipped); 186 quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); 187 188 quad = TextureDrawQuad::Create(); 189 quad->SetNew(shared_quad_state, 190 top_right, 191 opaque_rect, 192 resource_id_, 193 premultiplied_alpha, 194 uv_top_right.origin(), 195 uv_top_right.bottom_right(), 196 SK_ColorTRANSPARENT, 197 vertex_opacity, 198 flipped); 199 quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); 200 201 quad = TextureDrawQuad::Create(); 202 quad->SetNew(shared_quad_state, 203 bottom_left, 204 opaque_rect, 205 resource_id_, 206 premultiplied_alpha, 207 uv_bottom_left.origin(), 208 uv_bottom_left.bottom_right(), 209 SK_ColorTRANSPARENT, 210 vertex_opacity, 211 flipped); 212 quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); 213 214 quad = TextureDrawQuad::Create(); 215 quad->SetNew(shared_quad_state, 216 bottom_right, 217 opaque_rect, 218 resource_id_, 219 premultiplied_alpha, 220 uv_bottom_right.origin(), 221 uv_bottom_right.bottom_right(), 222 SK_ColorTRANSPARENT, 223 vertex_opacity, 224 flipped); 225 quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); 226 227 quad = TextureDrawQuad::Create(); 228 quad->SetNew(shared_quad_state, 229 top, 230 opaque_rect, 231 resource_id_, 232 premultiplied_alpha, 233 uv_top.origin(), 234 uv_top.bottom_right(), 235 SK_ColorTRANSPARENT, 236 vertex_opacity, 237 flipped); 238 quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); 239 240 quad = TextureDrawQuad::Create(); 241 quad->SetNew(shared_quad_state, 242 left, 243 opaque_rect, 244 resource_id_, 245 premultiplied_alpha, 246 uv_left.origin(), 247 uv_left.bottom_right(), 248 SK_ColorTRANSPARENT, 249 vertex_opacity, 250 flipped); 251 quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); 252 253 quad = TextureDrawQuad::Create(); 254 quad->SetNew(shared_quad_state, 255 right, 256 opaque_rect, 257 resource_id_, 258 premultiplied_alpha, 259 uv_right.origin(), 260 uv_right.bottom_right(), 261 SK_ColorTRANSPARENT, 262 vertex_opacity, 263 flipped); 264 quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); 265 266 quad = TextureDrawQuad::Create(); 267 quad->SetNew(shared_quad_state, 268 bottom, 269 opaque_rect, 270 resource_id_, 271 premultiplied_alpha, 272 uv_bottom.origin(), 273 uv_bottom.bottom_right(), 274 SK_ColorTRANSPARENT, 275 vertex_opacity, 276 flipped); 277 quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); 278} 279 280void NinePatchLayerImpl::DidLoseOutputSurface() { 281 resource_id_ = 0; 282} 283 284const char* NinePatchLayerImpl::LayerTypeAsString() const { 285 return "cc::NinePatchLayerImpl"; 286} 287 288base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const { 289 base::DictionaryValue* result = LayerImpl::LayerTreeAsJson(); 290 291 base::ListValue* list = new base::ListValue; 292 list->AppendInteger(image_aperture_.origin().x()); 293 list->AppendInteger(image_aperture_.origin().y()); 294 list->AppendInteger(image_aperture_.size().width()); 295 list->AppendInteger(image_aperture_.size().height()); 296 result->Set("ImageAperture", list); 297 298 list = new base::ListValue; 299 list->AppendInteger(image_bounds_.width()); 300 list->AppendInteger(image_bounds_.height()); 301 result->Set("ImageBounds", list); 302 303 return result; 304} 305 306} // namespace cc 307