nine_patch_layer_impl.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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
15namespace cc {
16
17NinePatchLayerImpl::NinePatchLayerImpl(LayerTreeImpl* tree_impl, int id)
18    : UIResourceLayerImpl(tree_impl, id),
19      fill_center_(false) {}
20
21NinePatchLayerImpl::~NinePatchLayerImpl() {}
22
23scoped_ptr<LayerImpl> NinePatchLayerImpl::CreateLayerImpl(
24    LayerTreeImpl* tree_impl) {
25  return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
26}
27
28void 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
35static 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
47void 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
65void 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
83void 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  visible_rect =
217      occlusion_tracker.UnoccludedContentRect(layer_top_left, draw_transform());
218  if (!visible_rect.IsEmpty()) {
219    TextureDrawQuad* quad =
220        render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
221    quad->SetNew(shared_quad_state,
222                 layer_top_left,
223                 opaque_rect,
224                 visible_rect,
225                 resource,
226                 premultiplied_alpha,
227                 uv_top_left.origin(),
228                 uv_top_left.bottom_right(),
229                 SK_ColorTRANSPARENT,
230                 vertex_opacity,
231                 flipped);
232  }
233
234  visible_rect = occlusion_tracker.UnoccludedContentRect(layer_top_right,
235                                                         draw_transform());
236  if (!visible_rect.IsEmpty()) {
237    TextureDrawQuad* quad =
238        render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
239    quad->SetNew(shared_quad_state,
240                 layer_top_right,
241                 opaque_rect,
242                 visible_rect,
243                 resource,
244                 premultiplied_alpha,
245                 uv_top_right.origin(),
246                 uv_top_right.bottom_right(),
247                 SK_ColorTRANSPARENT,
248                 vertex_opacity,
249                 flipped);
250  }
251
252  visible_rect = occlusion_tracker.UnoccludedContentRect(layer_bottom_left,
253                                                         draw_transform());
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_tracker.UnoccludedContentRect(layer_bottom_right,
271                                                         draw_transform());
272  if (!visible_rect.IsEmpty()) {
273    TextureDrawQuad* quad =
274        render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
275    quad->SetNew(shared_quad_state,
276                 layer_bottom_right,
277                 opaque_rect,
278                 visible_rect,
279                 resource,
280                 premultiplied_alpha,
281                 uv_bottom_right.origin(),
282                 uv_bottom_right.bottom_right(),
283                 SK_ColorTRANSPARENT,
284                 vertex_opacity,
285                 flipped);
286  }
287
288  visible_rect =
289      occlusion_tracker.UnoccludedContentRect(layer_top, draw_transform());
290  if (!visible_rect.IsEmpty()) {
291    TextureDrawQuad* quad =
292        render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
293    quad->SetNew(shared_quad_state,
294                 layer_top,
295                 opaque_rect,
296                 visible_rect,
297                 resource,
298                 premultiplied_alpha,
299                 uv_top.origin(),
300                 uv_top.bottom_right(),
301                 SK_ColorTRANSPARENT,
302                 vertex_opacity,
303                 flipped);
304  }
305
306  visible_rect =
307      occlusion_tracker.UnoccludedContentRect(layer_left, draw_transform());
308  if (!visible_rect.IsEmpty()) {
309    TextureDrawQuad* quad =
310        render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
311    quad->SetNew(shared_quad_state,
312                 layer_left,
313                 opaque_rect,
314                 visible_rect,
315                 resource,
316                 premultiplied_alpha,
317                 uv_left.origin(),
318                 uv_left.bottom_right(),
319                 SK_ColorTRANSPARENT,
320                 vertex_opacity,
321                 flipped);
322  }
323
324  visible_rect =
325      occlusion_tracker.UnoccludedContentRect(layer_right, draw_transform());
326  if (!visible_rect.IsEmpty()) {
327    TextureDrawQuad* quad =
328        render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
329    quad->SetNew(shared_quad_state,
330                 layer_right,
331                 opaque_rect,
332                 layer_right,
333                 resource,
334                 premultiplied_alpha,
335                 uv_right.origin(),
336                 uv_right.bottom_right(),
337                 SK_ColorTRANSPARENT,
338                 vertex_opacity,
339                 flipped);
340  }
341
342  visible_rect =
343      occlusion_tracker.UnoccludedContentRect(layer_bottom, draw_transform());
344  if (!visible_rect.IsEmpty()) {
345    TextureDrawQuad* quad =
346        render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
347    quad->SetNew(shared_quad_state,
348                 layer_bottom,
349                 opaque_rect,
350                 visible_rect,
351                 resource,
352                 premultiplied_alpha,
353                 uv_bottom.origin(),
354                 uv_bottom.bottom_right(),
355                 SK_ColorTRANSPARENT,
356                 vertex_opacity,
357                 flipped);
358  }
359
360  if (fill_center_) {
361    visible_rect =
362        occlusion_tracker.UnoccludedContentRect(layer_center, draw_transform());
363    if (!visible_rect.IsEmpty()) {
364      TextureDrawQuad* quad =
365          render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
366      quad->SetNew(shared_quad_state,
367                   layer_center,
368                   opaque_rect,
369                   visible_rect,
370                   resource,
371                   premultiplied_alpha,
372                   uv_center.origin(),
373                   uv_center.bottom_right(),
374                   SK_ColorTRANSPARENT,
375                   vertex_opacity,
376                   flipped);
377    }
378  }
379}
380
381const char* NinePatchLayerImpl::LayerTypeAsString() const {
382  return "cc::NinePatchLayerImpl";
383}
384
385base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const {
386  base::DictionaryValue* result = LayerImpl::LayerTreeAsJson();
387
388  base::ListValue* list = new base::ListValue;
389  list->AppendInteger(image_aperture_.origin().x());
390  list->AppendInteger(image_aperture_.origin().y());
391  list->AppendInteger(image_aperture_.size().width());
392  list->AppendInteger(image_aperture_.size().height());
393  result->Set("ImageAperture", list);
394
395  list = new base::ListValue;
396  list->AppendInteger(image_bounds_.width());
397  list->AppendInteger(image_bounds_.height());
398  result->Set("ImageBounds", list);
399
400  result->Set("Border", MathUtil::AsValue(border_).release());
401
402  result->SetBoolean("FillCenter", fill_center_);
403
404  return result;
405}
406
407}  // namespace cc
408