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/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"
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()).PassAs
<LayerImpl
>();
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(gfx::Rect aperture
,
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 // TODO(ccameron): the following "greater than or equal to" (GE) checks should
67 // be greater than (GT) to avoid degenerate nine-patches. The relaxed
68 // condition "equal to" is a workaround for the overhang shadow use case and
69 // should be investigated further.
71 // |border| is in layer space. It cannot exceed the bounds of the layer.
72 DCHECK(!border_
.size().IsEmpty());
73 DCHECK_GE(bounds().width(), border_
.width());
74 DCHECK_GE(bounds().height(), border_
.height());
76 // Sanity Check on |border|
77 DCHECK_LT(border_
.x(), border_
.width());
78 DCHECK_LT(border_
.y(), border_
.height());
79 DCHECK_GE(border_
.x(), 0);
80 DCHECK_GE(border_
.y(), 0);
82 // |aperture| is in image space. It cannot exceed the bounds of the bitmap.
83 DCHECK(!image_aperture_
.size().IsEmpty());
84 DCHECK(gfx::Rect(image_bounds_
.width(), image_bounds_
.height())
85 .Contains(image_aperture_
));
87 // Avoid the degenerate cases where the aperture touches the edge of the
89 DCHECK_LT(image_aperture_
.width(), image_bounds_
.width() - 1);
90 DCHECK_LT(image_aperture_
.height(), image_bounds_
.height() - 1);
91 DCHECK_GT(image_aperture_
.x(), 0);
92 DCHECK_GT(image_aperture_
.y(), 0);
95 void NinePatchLayerImpl::AppendQuads(QuadSink
* quad_sink
,
96 AppendQuadsData
* append_quads_data
) {
97 CheckGeometryLimitations();
98 SharedQuadState
* shared_quad_state
=
99 quad_sink
->UseSharedQuadState(CreateSharedQuadState());
100 AppendDebugBorderQuad(quad_sink
, shared_quad_state
, append_quads_data
);
102 if (!ui_resource_id_
)
105 ResourceProvider::ResourceId resource
=
106 layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_
);
111 static const bool flipped
= false;
112 static const bool premultiplied_alpha
= true;
114 DCHECK(!bounds().IsEmpty());
116 // NinePatch border widths in layer space.
117 int layer_left_width
= border_
.x();
118 int layer_top_height
= border_
.y();
119 int layer_right_width
= border_
.width() - layer_left_width
;
120 int layer_bottom_height
= border_
.height() - layer_top_height
;
122 int layer_middle_width
= bounds().width() - border_
.width();
123 int layer_middle_height
= bounds().height() - border_
.height();
125 // Patch positions in layer space
126 gfx::Rect
layer_top_left(0, 0, layer_left_width
, layer_top_height
);
127 gfx::Rect
layer_top_right(bounds().width() - layer_right_width
,
131 gfx::Rect
layer_bottom_left(0,
132 bounds().height() - layer_bottom_height
,
134 layer_bottom_height
);
135 gfx::Rect
layer_bottom_right(layer_top_right
.x(),
136 layer_bottom_left
.y(),
138 layer_bottom_height
);
140 layer_top_left
.right(), 0, layer_middle_width
, layer_top_height
);
141 gfx::Rect
layer_left(
142 0, layer_top_left
.bottom(), layer_left_width
, layer_middle_height
);
143 gfx::Rect
layer_right(layer_top_right
.x(),
144 layer_top_right
.bottom(),
146 layer_left
.height());
147 gfx::Rect
layer_bottom(layer_top
.x(),
148 layer_bottom_left
.y(),
150 layer_bottom_height
);
151 gfx::Rect
layer_center(layer_left_width
,
154 layer_middle_height
);
156 // Note the following values are in image (bitmap) space.
157 float image_width
= image_bounds_
.width();
158 float image_height
= image_bounds_
.height();
160 int image_aperture_left_width
= image_aperture_
.x();
161 int image_aperture_top_height
= image_aperture_
.y();
162 int image_aperture_right_width
= image_width
- image_aperture_
.right();
163 int image_aperture_bottom_height
= image_height
- image_aperture_
.bottom();
164 // Patch positions in bitmap UV space (from zero to one)
165 gfx::RectF uv_top_left
= NormalizedRect(0,
167 image_aperture_left_width
,
168 image_aperture_top_height
,
171 gfx::RectF uv_top_right
=
172 NormalizedRect(image_width
- image_aperture_right_width
,
174 image_aperture_right_width
,
175 image_aperture_top_height
,
178 gfx::RectF uv_bottom_left
=
180 image_height
- image_aperture_bottom_height
,
181 image_aperture_left_width
,
182 image_aperture_bottom_height
,
185 gfx::RectF uv_bottom_right
=
186 NormalizedRect(image_width
- image_aperture_right_width
,
187 image_height
- image_aperture_bottom_height
,
188 image_aperture_right_width
,
189 image_aperture_bottom_height
,
195 (image_width
- image_aperture_left_width
- image_aperture_right_width
) /
197 (image_aperture_top_height
) / image_height
);
198 gfx::RectF
uv_left(0,
199 uv_top_left
.bottom(),
200 image_aperture_left_width
/ image_width
,
201 (image_height
- image_aperture_top_height
-
202 image_aperture_bottom_height
) /
204 gfx::RectF
uv_right(uv_top_right
.x(),
205 uv_top_right
.bottom(),
206 image_aperture_right_width
/ image_width
,
208 gfx::RectF
uv_bottom(uv_top
.x(),
211 image_aperture_bottom_height
/ image_height
);
212 gfx::RectF
uv_center(uv_top_left
.right(),
213 uv_top_left
.bottom(),
217 // Nothing is opaque here.
218 // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness?
219 gfx::Rect opaque_rect
;
220 const float vertex_opacity
[] = {1.0f
, 1.0f
, 1.0f
, 1.0f
};
221 scoped_ptr
<TextureDrawQuad
> quad
;
223 quad
= TextureDrawQuad::Create();
224 quad
->SetNew(shared_quad_state
,
229 uv_top_left
.origin(),
230 uv_top_left
.bottom_right(),
234 quad_sink
->Append(quad
.PassAs
<DrawQuad
>(), append_quads_data
);
236 quad
= TextureDrawQuad::Create();
237 quad
->SetNew(shared_quad_state
,
242 uv_top_right
.origin(),
243 uv_top_right
.bottom_right(),
247 quad_sink
->Append(quad
.PassAs
<DrawQuad
>(), append_quads_data
);
249 quad
= TextureDrawQuad::Create();
250 quad
->SetNew(shared_quad_state
,
255 uv_bottom_left
.origin(),
256 uv_bottom_left
.bottom_right(),
260 quad_sink
->Append(quad
.PassAs
<DrawQuad
>(), append_quads_data
);
262 quad
= TextureDrawQuad::Create();
263 quad
->SetNew(shared_quad_state
,
268 uv_bottom_right
.origin(),
269 uv_bottom_right
.bottom_right(),
273 quad_sink
->Append(quad
.PassAs
<DrawQuad
>(), append_quads_data
);
275 quad
= TextureDrawQuad::Create();
276 quad
->SetNew(shared_quad_state
,
282 uv_top
.bottom_right(),
286 quad_sink
->Append(quad
.PassAs
<DrawQuad
>(), append_quads_data
);
288 quad
= TextureDrawQuad::Create();
289 quad
->SetNew(shared_quad_state
,
295 uv_left
.bottom_right(),
299 quad_sink
->Append(quad
.PassAs
<DrawQuad
>(), append_quads_data
);
301 quad
= TextureDrawQuad::Create();
302 quad
->SetNew(shared_quad_state
,
308 uv_right
.bottom_right(),
312 quad_sink
->Append(quad
.PassAs
<DrawQuad
>(), append_quads_data
);
314 quad
= TextureDrawQuad::Create();
315 quad
->SetNew(shared_quad_state
,
321 uv_bottom
.bottom_right(),
325 quad_sink
->Append(quad
.PassAs
<DrawQuad
>(), append_quads_data
);
328 quad
= TextureDrawQuad::Create();
329 quad
->SetNew(shared_quad_state
,
335 uv_center
.bottom_right(),
339 quad_sink
->Append(quad
.PassAs
<DrawQuad
>(), append_quads_data
);
343 const char* NinePatchLayerImpl::LayerTypeAsString() const {
344 return "cc::NinePatchLayerImpl";
347 base::DictionaryValue
* NinePatchLayerImpl::LayerTreeAsJson() const {
348 base::DictionaryValue
* result
= LayerImpl::LayerTreeAsJson();
350 base::ListValue
* list
= new base::ListValue
;
351 list
->AppendInteger(image_aperture_
.origin().x());
352 list
->AppendInteger(image_aperture_
.origin().y());
353 list
->AppendInteger(image_aperture_
.size().width());
354 list
->AppendInteger(image_aperture_
.size().height());
355 result
->Set("ImageAperture", list
);
357 result
->Set("ImageBounds", MathUtil::AsValue(image_bounds_
).release());
358 result
->Set("Border", MathUtil::AsValue(border_
).release());
360 base::FundamentalValue
* fill_center
=
361 base::Value::CreateBooleanValue(fill_center_
);
362 result
->Set("FillCenter", fill_center
);