• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(gfx::Rect aperture,gfx::Rect border,bool fill_center)47 void NinePatchLayerImpl::SetLayout(gfx::Rect aperture,
48                                    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   // 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.
70 
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());
75 
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);
81 
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_));
86 
87   // Avoid the degenerate cases where the aperture touches the edge of the
88   // image.
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);
93 }
94 
AppendQuads(QuadSink * quad_sink,AppendQuadsData * append_quads_data)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);
101 
102   if (!ui_resource_id_)
103     return;
104 
105   ResourceProvider::ResourceId resource =
106       layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_);
107 
108   if (!resource)
109     return;
110 
111   static const bool flipped = false;
112   static const bool premultiplied_alpha = true;
113 
114   DCHECK(!bounds().IsEmpty());
115 
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;
121 
122   int layer_middle_width = bounds().width() - border_.width();
123   int layer_middle_height = bounds().height() - border_.height();
124 
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,
128                             0,
129                             layer_right_width,
130                             layer_top_height);
131   gfx::Rect layer_bottom_left(0,
132                               bounds().height() - layer_bottom_height,
133                               layer_left_width,
134                               layer_bottom_height);
135   gfx::Rect layer_bottom_right(layer_top_right.x(),
136                                layer_bottom_left.y(),
137                                layer_right_width,
138                                layer_bottom_height);
139   gfx::Rect layer_top(
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(),
145                         layer_right_width,
146                         layer_left.height());
147   gfx::Rect layer_bottom(layer_top.x(),
148                          layer_bottom_left.y(),
149                          layer_top.width(),
150                          layer_bottom_height);
151   gfx::Rect layer_center(layer_left_width,
152                          layer_top_height,
153                          layer_middle_width,
154                          layer_middle_height);
155 
156   // Note the following values are in image (bitmap) space.
157   float image_width = image_bounds_.width();
158   float image_height = image_bounds_.height();
159 
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,
166                                           0,
167                                           image_aperture_left_width,
168                                           image_aperture_top_height,
169                                           image_width,
170                                           image_height);
171   gfx::RectF uv_top_right =
172       NormalizedRect(image_width - image_aperture_right_width,
173                      0,
174                      image_aperture_right_width,
175                      image_aperture_top_height,
176                      image_width,
177                      image_height);
178   gfx::RectF uv_bottom_left =
179       NormalizedRect(0,
180                      image_height - image_aperture_bottom_height,
181                      image_aperture_left_width,
182                      image_aperture_bottom_height,
183                      image_width,
184                      image_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,
190                      image_width,
191                      image_height);
192   gfx::RectF uv_top(
193       uv_top_left.right(),
194       0,
195       (image_width - image_aperture_left_width - image_aperture_right_width) /
196           image_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) /
203                          image_height);
204   gfx::RectF uv_right(uv_top_right.x(),
205                       uv_top_right.bottom(),
206                       image_aperture_right_width / image_width,
207                       uv_left.height());
208   gfx::RectF uv_bottom(uv_top.x(),
209                        uv_bottom_left.y(),
210                        uv_top.width(),
211                        image_aperture_bottom_height / image_height);
212   gfx::RectF uv_center(uv_top_left.right(),
213                        uv_top_left.bottom(),
214                        uv_top.width(),
215                        uv_left.height());
216 
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;
222 
223   quad = TextureDrawQuad::Create();
224   quad->SetNew(shared_quad_state,
225                layer_top_left,
226                opaque_rect,
227                resource,
228                premultiplied_alpha,
229                uv_top_left.origin(),
230                uv_top_left.bottom_right(),
231                SK_ColorTRANSPARENT,
232                vertex_opacity,
233                flipped);
234   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
235 
236   quad = TextureDrawQuad::Create();
237   quad->SetNew(shared_quad_state,
238                layer_top_right,
239                opaque_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>(), append_quads_data);
248 
249   quad = TextureDrawQuad::Create();
250   quad->SetNew(shared_quad_state,
251                layer_bottom_left,
252                opaque_rect,
253                resource,
254                premultiplied_alpha,
255                uv_bottom_left.origin(),
256                uv_bottom_left.bottom_right(),
257                SK_ColorTRANSPARENT,
258                vertex_opacity,
259                flipped);
260   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
261 
262   quad = TextureDrawQuad::Create();
263   quad->SetNew(shared_quad_state,
264                layer_bottom_right,
265                opaque_rect,
266                resource,
267                premultiplied_alpha,
268                uv_bottom_right.origin(),
269                uv_bottom_right.bottom_right(),
270                SK_ColorTRANSPARENT,
271                vertex_opacity,
272                flipped);
273   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
274 
275   quad = TextureDrawQuad::Create();
276   quad->SetNew(shared_quad_state,
277                layer_top,
278                opaque_rect,
279                resource,
280                premultiplied_alpha,
281                uv_top.origin(),
282                uv_top.bottom_right(),
283                SK_ColorTRANSPARENT,
284                vertex_opacity,
285                flipped);
286   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
287 
288   quad = TextureDrawQuad::Create();
289   quad->SetNew(shared_quad_state,
290                layer_left,
291                opaque_rect,
292                resource,
293                premultiplied_alpha,
294                uv_left.origin(),
295                uv_left.bottom_right(),
296                SK_ColorTRANSPARENT,
297                vertex_opacity,
298                flipped);
299   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
300 
301   quad = TextureDrawQuad::Create();
302   quad->SetNew(shared_quad_state,
303                layer_right,
304                opaque_rect,
305                resource,
306                premultiplied_alpha,
307                uv_right.origin(),
308                uv_right.bottom_right(),
309                SK_ColorTRANSPARENT,
310                vertex_opacity,
311                flipped);
312   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
313 
314   quad = TextureDrawQuad::Create();
315   quad->SetNew(shared_quad_state,
316                layer_bottom,
317                opaque_rect,
318                resource,
319                premultiplied_alpha,
320                uv_bottom.origin(),
321                uv_bottom.bottom_right(),
322                SK_ColorTRANSPARENT,
323                vertex_opacity,
324                flipped);
325   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
326 
327   if (fill_center_) {
328     quad = TextureDrawQuad::Create();
329     quad->SetNew(shared_quad_state,
330                  layer_center,
331                  opaque_rect,
332                  resource,
333                  premultiplied_alpha,
334                  uv_center.origin(),
335                  uv_center.bottom_right(),
336                  SK_ColorTRANSPARENT,
337                  vertex_opacity,
338                  flipped);
339     quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
340   }
341 }
342 
LayerTypeAsString() const343 const char* NinePatchLayerImpl::LayerTypeAsString() const {
344   return "cc::NinePatchLayerImpl";
345 }
346 
LayerTreeAsJson() const347 base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const {
348   base::DictionaryValue* result = LayerImpl::LayerTreeAsJson();
349 
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);
356 
357   list = new base::ListValue;
358   list->AppendInteger(image_bounds_.width());
359   list->AppendInteger(image_bounds_.height());
360   result->Set("ImageBounds", list);
361 
362   result->Set("Border", MathUtil::AsValue(border_).release());
363 
364   base::FundamentalValue* fill_center =
365       base::Value::CreateBooleanValue(fill_center_);
366   result->Set("FillCenter", fill_center);
367 
368   return result;
369 }
370 
371 }  // namespace cc
372