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.
5 #include "cc/layers/nine_patch_layer_impl.h"
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.h"
13 #include "ui/gfx/geometry/rect_f.h"
17 NinePatchLayerImpl::NinePatchLayerImpl(LayerTreeImpl
* tree_impl
, int id
)
18 : UIResourceLayerImpl(tree_impl
, id
),
19 fill_center_(false) {}
21 NinePatchLayerImpl::~NinePatchLayerImpl() {}
23 scoped_ptr
<LayerImpl
> NinePatchLayerImpl::CreateLayerImpl(
24 LayerTreeImpl
* tree_impl
) {
25 return NinePatchLayerImpl::Create(tree_impl
, id());
28 void NinePatchLayerImpl::PushPropertiesTo(LayerImpl
* layer
) {
29 UIResourceLayerImpl::PushPropertiesTo(layer
);
30 NinePatchLayerImpl
* layer_impl
= static_cast<NinePatchLayerImpl
*>(layer
);
32 layer_impl
->SetLayout(image_aperture_
, border_
, fill_center_
);
35 static gfx::RectF
NormalizedRect(float x
,
41 return gfx::RectF(x
/ total_width
,
44 height
/ total_height
);
47 void NinePatchLayerImpl::SetLayout(const gfx::Rect
& aperture
,
48 const gfx::Rect
& border
,
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_
);
54 if (image_aperture_
== aperture
&&
55 border_
== border
&& fill_center_
== fill_center
)
58 image_aperture_
= aperture
;
60 fill_center_
= fill_center
;
62 NoteLayerPropertyChanged();
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());
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);
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();
83 void NinePatchLayerImpl::AppendQuads(
84 RenderPass
* render_pass
,
85 AppendQuadsData
* append_quads_data
) {
86 CheckGeometryLimitations();
87 SharedQuadState
* shared_quad_state
=
88 render_pass
->CreateAndAppendSharedQuadState();
89 PopulateSharedQuadState(shared_quad_state
);
91 AppendDebugBorderQuad(render_pass
, bounds(), shared_quad_state
,
98 layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_
);
103 static const bool flipped
= false;
104 static const bool nearest_neighbor
= false;
105 static const bool premultiplied_alpha
= true;
107 DCHECK(!bounds().IsEmpty());
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
;
115 int layer_middle_width
= bounds().width() - border_
.width();
116 int layer_middle_height
= bounds().height() - border_
.height();
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
,
124 gfx::Rect
layer_bottom_left(0,
125 bounds().height() - layer_bottom_height
,
127 layer_bottom_height
);
128 gfx::Rect
layer_bottom_right(layer_top_right
.x(),
129 layer_bottom_left
.y(),
131 layer_bottom_height
);
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(),
139 layer_left
.height());
140 gfx::Rect
layer_bottom(layer_top
.x(),
141 layer_bottom_left
.y(),
143 layer_bottom_height
);
144 gfx::Rect
layer_center(layer_left_width
,
147 layer_middle_height
);
149 // Note the following values are in image (bitmap) space.
150 float image_width
= image_bounds_
.width();
151 float image_height
= image_bounds_
.height();
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,
160 image_aperture_left_width
,
161 image_aperture_top_height
,
164 gfx::RectF uv_top_right
=
165 NormalizedRect(image_width
- image_aperture_right_width
,
167 image_aperture_right_width
,
168 image_aperture_top_height
,
171 gfx::RectF uv_bottom_left
=
173 image_height
- image_aperture_bottom_height
,
174 image_aperture_left_width
,
175 image_aperture_bottom_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
,
188 (image_width
- image_aperture_left_width
- image_aperture_right_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
) /
197 gfx::RectF
uv_right(uv_top_right
.x(),
198 uv_top_right
.bottom(),
199 image_aperture_right_width
/ image_width
,
201 gfx::RectF
uv_bottom(uv_top
.x(),
204 image_aperture_bottom_height
/ image_height
);
205 gfx::RectF
uv_center(uv_top_left
.right(),
206 uv_top_left
.bottom(),
210 gfx::Rect opaque_rect
;
211 gfx::Rect visible_rect
;
212 const float vertex_opacity
[] = {1.0f
, 1.0f
, 1.0f
, 1.0f
};
213 const bool opaque
= layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_
);
216 draw_properties().occlusion_in_content_space
.GetUnoccludedContentRect(
218 opaque_rect
= opaque
? visible_rect
: gfx::Rect();
219 if (!visible_rect
.IsEmpty()) {
220 TextureDrawQuad
* quad
=
221 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
222 quad
->SetNew(shared_quad_state
,
228 uv_top_left
.origin(),
229 uv_top_left
.bottom_right(),
234 ValidateQuadResources(quad
);
238 draw_properties().occlusion_in_content_space
.GetUnoccludedContentRect(
240 opaque_rect
= opaque
? visible_rect
: gfx::Rect();
241 if (!visible_rect
.IsEmpty()) {
242 TextureDrawQuad
* quad
=
243 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
244 quad
->SetNew(shared_quad_state
,
250 uv_top_right
.origin(),
251 uv_top_right
.bottom_right(),
256 ValidateQuadResources(quad
);
260 draw_properties().occlusion_in_content_space
.GetUnoccludedContentRect(
262 opaque_rect
= opaque
? visible_rect
: gfx::Rect();
263 if (!visible_rect
.IsEmpty()) {
264 TextureDrawQuad
* quad
=
265 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
266 quad
->SetNew(shared_quad_state
,
272 uv_bottom_left
.origin(),
273 uv_bottom_left
.bottom_right(),
278 ValidateQuadResources(quad
);
282 draw_properties().occlusion_in_content_space
.GetUnoccludedContentRect(
284 opaque_rect
= opaque
? visible_rect
: gfx::Rect();
285 if (!visible_rect
.IsEmpty()) {
286 TextureDrawQuad
* quad
=
287 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
288 quad
->SetNew(shared_quad_state
,
294 uv_bottom_right
.origin(),
295 uv_bottom_right
.bottom_right(),
300 ValidateQuadResources(quad
);
304 draw_properties().occlusion_in_content_space
.GetUnoccludedContentRect(
306 opaque_rect
= opaque
? visible_rect
: gfx::Rect();
307 if (!visible_rect
.IsEmpty()) {
308 TextureDrawQuad
* quad
=
309 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
310 quad
->SetNew(shared_quad_state
,
317 uv_top
.bottom_right(),
322 ValidateQuadResources(quad
);
326 draw_properties().occlusion_in_content_space
.GetUnoccludedContentRect(
328 opaque_rect
= opaque
? visible_rect
: gfx::Rect();
329 if (!visible_rect
.IsEmpty()) {
330 TextureDrawQuad
* quad
=
331 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
332 quad
->SetNew(shared_quad_state
,
339 uv_left
.bottom_right(),
344 ValidateQuadResources(quad
);
348 draw_properties().occlusion_in_content_space
.GetUnoccludedContentRect(
350 opaque_rect
= opaque
? visible_rect
: gfx::Rect();
351 if (!visible_rect
.IsEmpty()) {
352 TextureDrawQuad
* quad
=
353 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
354 quad
->SetNew(shared_quad_state
,
361 uv_right
.bottom_right(),
366 ValidateQuadResources(quad
);
370 draw_properties().occlusion_in_content_space
.GetUnoccludedContentRect(
372 opaque_rect
= opaque
? visible_rect
: gfx::Rect();
373 if (!visible_rect
.IsEmpty()) {
374 TextureDrawQuad
* quad
=
375 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
376 quad
->SetNew(shared_quad_state
,
383 uv_bottom
.bottom_right(),
388 ValidateQuadResources(quad
);
393 draw_properties().occlusion_in_content_space
.GetUnoccludedContentRect(
395 opaque_rect
= opaque
? visible_rect
: gfx::Rect();
396 if (!visible_rect
.IsEmpty()) {
397 TextureDrawQuad
* quad
=
398 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
399 quad
->SetNew(shared_quad_state
,
406 uv_center
.bottom_right(),
411 ValidateQuadResources(quad
);
416 const char* NinePatchLayerImpl::LayerTypeAsString() const {
417 return "cc::NinePatchLayerImpl";
420 base::DictionaryValue
* NinePatchLayerImpl::LayerTreeAsJson() const {
421 base::DictionaryValue
* result
= LayerImpl::LayerTreeAsJson();
423 base::ListValue
* list
= new base::ListValue
;
424 list
->AppendInteger(image_aperture_
.origin().x());
425 list
->AppendInteger(image_aperture_
.origin().y());
426 list
->AppendInteger(image_aperture_
.size().width());
427 list
->AppendInteger(image_aperture_
.size().height());
428 result
->Set("ImageAperture", list
);
430 list
= new base::ListValue
;
431 list
->AppendInteger(image_bounds_
.width());
432 list
->AppendInteger(image_bounds_
.height());
433 result
->Set("ImageBounds", list
);
435 result
->Set("Border", MathUtil::AsValue(border_
).release());
437 result
->SetBoolean("FillCenter", fill_center_
);