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