• 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(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