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