• 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/quads/texture_draw_quad.h"
11 #include "cc/trees/layer_tree_impl.h"
12 #include "cc/trees/occlusion_tracker.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(RenderPass * render_pass,const OcclusionTracker<LayerImpl> & occlusion_tracker,AppendQuadsData * append_quads_data)83 void NinePatchLayerImpl::AppendQuads(
84     RenderPass* render_pass,
85     const OcclusionTracker<LayerImpl>& occlusion_tracker,
86     AppendQuadsData* append_quads_data) {
87   CheckGeometryLimitations();
88   SharedQuadState* shared_quad_state =
89       render_pass->CreateAndAppendSharedQuadState();
90   PopulateSharedQuadState(shared_quad_state);
91 
92   AppendDebugBorderQuad(
93       render_pass, content_bounds(), shared_quad_state, append_quads_data);
94 
95   if (!ui_resource_id_)
96     return;
97 
98   ResourceProvider::ResourceId resource =
99       layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_);
100 
101   if (!resource)
102     return;
103 
104   static const bool flipped = false;
105   static const bool premultiplied_alpha = true;
106 
107   DCHECK(!bounds().IsEmpty());
108 
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;
114 
115   int layer_middle_width = bounds().width() - border_.width();
116   int layer_middle_height = bounds().height() - border_.height();
117 
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,
121                             0,
122                             layer_right_width,
123                             layer_top_height);
124   gfx::Rect layer_bottom_left(0,
125                               bounds().height() - layer_bottom_height,
126                               layer_left_width,
127                               layer_bottom_height);
128   gfx::Rect layer_bottom_right(layer_top_right.x(),
129                                layer_bottom_left.y(),
130                                layer_right_width,
131                                layer_bottom_height);
132   gfx::Rect layer_top(
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(),
138                         layer_right_width,
139                         layer_left.height());
140   gfx::Rect layer_bottom(layer_top.x(),
141                          layer_bottom_left.y(),
142                          layer_top.width(),
143                          layer_bottom_height);
144   gfx::Rect layer_center(layer_left_width,
145                          layer_top_height,
146                          layer_middle_width,
147                          layer_middle_height);
148 
149   // Note the following values are in image (bitmap) space.
150   float image_width = image_bounds_.width();
151   float image_height = image_bounds_.height();
152 
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,
159                                           0,
160                                           image_aperture_left_width,
161                                           image_aperture_top_height,
162                                           image_width,
163                                           image_height);
164   gfx::RectF uv_top_right =
165       NormalizedRect(image_width - image_aperture_right_width,
166                      0,
167                      image_aperture_right_width,
168                      image_aperture_top_height,
169                      image_width,
170                      image_height);
171   gfx::RectF uv_bottom_left =
172       NormalizedRect(0,
173                      image_height - image_aperture_bottom_height,
174                      image_aperture_left_width,
175                      image_aperture_bottom_height,
176                      image_width,
177                      image_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,
183                      image_width,
184                      image_height);
185   gfx::RectF uv_top(
186       uv_top_left.right(),
187       0,
188       (image_width - image_aperture_left_width - image_aperture_right_width) /
189           image_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) /
196                          image_height);
197   gfx::RectF uv_right(uv_top_right.x(),
198                       uv_top_right.bottom(),
199                       image_aperture_right_width / image_width,
200                       uv_left.height());
201   gfx::RectF uv_bottom(uv_top.x(),
202                        uv_bottom_left.y(),
203                        uv_top.width(),
204                        image_aperture_bottom_height / image_height);
205   gfx::RectF uv_center(uv_top_left.right(),
206                        uv_top_left.bottom(),
207                        uv_top.width(),
208                        uv_left.height());
209 
210   // Nothing is opaque here.
211   // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness?
212   gfx::Rect opaque_rect;
213   gfx::Rect visible_rect;
214   const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
215 
216   Occlusion occlusion =
217       occlusion_tracker.GetCurrentOcclusionForLayer(draw_transform());
218 
219   visible_rect = occlusion.GetUnoccludedContentRect(layer_top_left);
220   if (!visible_rect.IsEmpty()) {
221     TextureDrawQuad* quad =
222         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
223     quad->SetNew(shared_quad_state,
224                  layer_top_left,
225                  opaque_rect,
226                  visible_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   }
235 
236   visible_rect = occlusion.GetUnoccludedContentRect(layer_top_right);
237   if (!visible_rect.IsEmpty()) {
238     TextureDrawQuad* quad =
239         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
240     quad->SetNew(shared_quad_state,
241                  layer_top_right,
242                  opaque_rect,
243                  visible_rect,
244                  resource,
245                  premultiplied_alpha,
246                  uv_top_right.origin(),
247                  uv_top_right.bottom_right(),
248                  SK_ColorTRANSPARENT,
249                  vertex_opacity,
250                  flipped);
251   }
252 
253   visible_rect = occlusion.GetUnoccludedContentRect(layer_bottom_left);
254   if (!visible_rect.IsEmpty()) {
255     TextureDrawQuad* quad =
256         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
257     quad->SetNew(shared_quad_state,
258                  layer_bottom_left,
259                  opaque_rect,
260                  visible_rect,
261                  resource,
262                  premultiplied_alpha,
263                  uv_bottom_left.origin(),
264                  uv_bottom_left.bottom_right(),
265                  SK_ColorTRANSPARENT,
266                  vertex_opacity,
267                  flipped);
268   }
269 
270   visible_rect = occlusion.GetUnoccludedContentRect(layer_bottom_right);
271   if (!visible_rect.IsEmpty()) {
272     TextureDrawQuad* quad =
273         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
274     quad->SetNew(shared_quad_state,
275                  layer_bottom_right,
276                  opaque_rect,
277                  visible_rect,
278                  resource,
279                  premultiplied_alpha,
280                  uv_bottom_right.origin(),
281                  uv_bottom_right.bottom_right(),
282                  SK_ColorTRANSPARENT,
283                  vertex_opacity,
284                  flipped);
285   }
286 
287   visible_rect = occlusion.GetUnoccludedContentRect(layer_top);
288   if (!visible_rect.IsEmpty()) {
289     TextureDrawQuad* quad =
290         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
291     quad->SetNew(shared_quad_state,
292                  layer_top,
293                  opaque_rect,
294                  visible_rect,
295                  resource,
296                  premultiplied_alpha,
297                  uv_top.origin(),
298                  uv_top.bottom_right(),
299                  SK_ColorTRANSPARENT,
300                  vertex_opacity,
301                  flipped);
302   }
303 
304   visible_rect = occlusion.GetUnoccludedContentRect(layer_left);
305   if (!visible_rect.IsEmpty()) {
306     TextureDrawQuad* quad =
307         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
308     quad->SetNew(shared_quad_state,
309                  layer_left,
310                  opaque_rect,
311                  visible_rect,
312                  resource,
313                  premultiplied_alpha,
314                  uv_left.origin(),
315                  uv_left.bottom_right(),
316                  SK_ColorTRANSPARENT,
317                  vertex_opacity,
318                  flipped);
319   }
320 
321   visible_rect = occlusion.GetUnoccludedContentRect(layer_right);
322   if (!visible_rect.IsEmpty()) {
323     TextureDrawQuad* quad =
324         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
325     quad->SetNew(shared_quad_state,
326                  layer_right,
327                  opaque_rect,
328                  layer_right,
329                  resource,
330                  premultiplied_alpha,
331                  uv_right.origin(),
332                  uv_right.bottom_right(),
333                  SK_ColorTRANSPARENT,
334                  vertex_opacity,
335                  flipped);
336   }
337 
338   visible_rect = occlusion.GetUnoccludedContentRect(layer_bottom);
339   if (!visible_rect.IsEmpty()) {
340     TextureDrawQuad* quad =
341         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
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   }
354 
355   if (fill_center_) {
356     visible_rect = occlusion.GetUnoccludedContentRect(layer_center);
357     if (!visible_rect.IsEmpty()) {
358       TextureDrawQuad* quad =
359           render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
360       quad->SetNew(shared_quad_state,
361                    layer_center,
362                    opaque_rect,
363                    visible_rect,
364                    resource,
365                    premultiplied_alpha,
366                    uv_center.origin(),
367                    uv_center.bottom_right(),
368                    SK_ColorTRANSPARENT,
369                    vertex_opacity,
370                    flipped);
371     }
372   }
373 }
374 
LayerTypeAsString() const375 const char* NinePatchLayerImpl::LayerTypeAsString() const {
376   return "cc::NinePatchLayerImpl";
377 }
378 
LayerTreeAsJson() const379 base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const {
380   base::DictionaryValue* result = LayerImpl::LayerTreeAsJson();
381 
382   base::ListValue* list = new base::ListValue;
383   list->AppendInteger(image_aperture_.origin().x());
384   list->AppendInteger(image_aperture_.origin().y());
385   list->AppendInteger(image_aperture_.size().width());
386   list->AppendInteger(image_aperture_.size().height());
387   result->Set("ImageAperture", list);
388 
389   list = new base::ListValue;
390   list->AppendInteger(image_bounds_.width());
391   list->AppendInteger(image_bounds_.height());
392   result->Set("ImageBounds", list);
393 
394   result->Set("Border", MathUtil::AsValue(border_).release());
395 
396   result->SetBoolean("FillCenter", fill_center_);
397 
398   return result;
399 }
400 
401 }  // namespace cc
402