nine_patch_layer_impl.cc revision 010d83a9304c5a91596085d917d248abff47903a
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
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(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(quad_sink, shared_quad_state, append_quads_data);
90
91  if (!ui_resource_id_)
92    return;
93
94  ResourceProvider::ResourceId resource =
95      layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_);
96
97  if (!resource)
98    return;
99
100  static const bool flipped = false;
101  static const bool premultiplied_alpha = true;
102
103  DCHECK(!bounds().IsEmpty());
104
105  // NinePatch border widths in layer space.
106  int layer_left_width = border_.x();
107  int layer_top_height = border_.y();
108  int layer_right_width = border_.width() - layer_left_width;
109  int layer_bottom_height = border_.height() - layer_top_height;
110
111  int layer_middle_width = bounds().width() - border_.width();
112  int layer_middle_height = bounds().height() - border_.height();
113
114  // Patch positions in layer space
115  gfx::Rect layer_top_left(0, 0, layer_left_width, layer_top_height);
116  gfx::Rect layer_top_right(bounds().width() - layer_right_width,
117                            0,
118                            layer_right_width,
119                            layer_top_height);
120  gfx::Rect layer_bottom_left(0,
121                              bounds().height() - layer_bottom_height,
122                              layer_left_width,
123                              layer_bottom_height);
124  gfx::Rect layer_bottom_right(layer_top_right.x(),
125                               layer_bottom_left.y(),
126                               layer_right_width,
127                               layer_bottom_height);
128  gfx::Rect layer_top(
129      layer_top_left.right(), 0, layer_middle_width, layer_top_height);
130  gfx::Rect layer_left(
131      0, layer_top_left.bottom(), layer_left_width, layer_middle_height);
132  gfx::Rect layer_right(layer_top_right.x(),
133                        layer_top_right.bottom(),
134                        layer_right_width,
135                        layer_left.height());
136  gfx::Rect layer_bottom(layer_top.x(),
137                         layer_bottom_left.y(),
138                         layer_top.width(),
139                         layer_bottom_height);
140  gfx::Rect layer_center(layer_left_width,
141                         layer_top_height,
142                         layer_middle_width,
143                         layer_middle_height);
144
145  // Note the following values are in image (bitmap) space.
146  float image_width = image_bounds_.width();
147  float image_height = image_bounds_.height();
148
149  int image_aperture_left_width = image_aperture_.x();
150  int image_aperture_top_height = image_aperture_.y();
151  int image_aperture_right_width = image_width - image_aperture_.right();
152  int image_aperture_bottom_height = image_height - image_aperture_.bottom();
153  // Patch positions in bitmap UV space (from zero to one)
154  gfx::RectF uv_top_left = NormalizedRect(0,
155                                          0,
156                                          image_aperture_left_width,
157                                          image_aperture_top_height,
158                                          image_width,
159                                          image_height);
160  gfx::RectF uv_top_right =
161      NormalizedRect(image_width - image_aperture_right_width,
162                     0,
163                     image_aperture_right_width,
164                     image_aperture_top_height,
165                     image_width,
166                     image_height);
167  gfx::RectF uv_bottom_left =
168      NormalizedRect(0,
169                     image_height - image_aperture_bottom_height,
170                     image_aperture_left_width,
171                     image_aperture_bottom_height,
172                     image_width,
173                     image_height);
174  gfx::RectF uv_bottom_right =
175      NormalizedRect(image_width - image_aperture_right_width,
176                     image_height - image_aperture_bottom_height,
177                     image_aperture_right_width,
178                     image_aperture_bottom_height,
179                     image_width,
180                     image_height);
181  gfx::RectF uv_top(
182      uv_top_left.right(),
183      0,
184      (image_width - image_aperture_left_width - image_aperture_right_width) /
185          image_width,
186      (image_aperture_top_height) / image_height);
187  gfx::RectF uv_left(0,
188                     uv_top_left.bottom(),
189                     image_aperture_left_width / image_width,
190                     (image_height - image_aperture_top_height -
191                      image_aperture_bottom_height) /
192                         image_height);
193  gfx::RectF uv_right(uv_top_right.x(),
194                      uv_top_right.bottom(),
195                      image_aperture_right_width / image_width,
196                      uv_left.height());
197  gfx::RectF uv_bottom(uv_top.x(),
198                       uv_bottom_left.y(),
199                       uv_top.width(),
200                       image_aperture_bottom_height / image_height);
201  gfx::RectF uv_center(uv_top_left.right(),
202                       uv_top_left.bottom(),
203                       uv_top.width(),
204                       uv_left.height());
205
206  // Nothing is opaque here.
207  // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness?
208  gfx::Rect opaque_rect;
209  gfx::Rect visible_rect;
210  const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
211  scoped_ptr<TextureDrawQuad> quad;
212
213  visible_rect =
214      quad_sink->UnoccludedContentRect(layer_top_left, draw_transform());
215  if (!visible_rect.IsEmpty()) {
216    quad = TextureDrawQuad::Create();
217    quad->SetNew(shared_quad_state,
218                 layer_top_left,
219                 opaque_rect,
220                 visible_rect,
221                 resource,
222                 premultiplied_alpha,
223                 uv_top_left.origin(),
224                 uv_top_left.bottom_right(),
225                 SK_ColorTRANSPARENT,
226                 vertex_opacity,
227                 flipped);
228    quad_sink->Append(quad.PassAs<DrawQuad>());
229  }
230
231  visible_rect =
232      quad_sink->UnoccludedContentRect(layer_top_right, draw_transform());
233  if (!visible_rect.IsEmpty()) {
234    quad = TextureDrawQuad::Create();
235    quad->SetNew(shared_quad_state,
236                 layer_top_right,
237                 opaque_rect,
238                 visible_rect,
239                 resource,
240                 premultiplied_alpha,
241                 uv_top_right.origin(),
242                 uv_top_right.bottom_right(),
243                 SK_ColorTRANSPARENT,
244                 vertex_opacity,
245                 flipped);
246    quad_sink->Append(quad.PassAs<DrawQuad>());
247  }
248
249  visible_rect =
250      quad_sink->UnoccludedContentRect(layer_bottom_left, draw_transform());
251  if (!visible_rect.IsEmpty()) {
252    quad = TextureDrawQuad::Create();
253    quad->SetNew(shared_quad_state,
254                 layer_bottom_left,
255                 opaque_rect,
256                 visible_rect,
257                 resource,
258                 premultiplied_alpha,
259                 uv_bottom_left.origin(),
260                 uv_bottom_left.bottom_right(),
261                 SK_ColorTRANSPARENT,
262                 vertex_opacity,
263                 flipped);
264    quad_sink->Append(quad.PassAs<DrawQuad>());
265  }
266
267  visible_rect =
268      quad_sink->UnoccludedContentRect(layer_bottom_right, draw_transform());
269  if (!visible_rect.IsEmpty()) {
270    quad = TextureDrawQuad::Create();
271    quad->SetNew(shared_quad_state,
272                 layer_bottom_right,
273                 opaque_rect,
274                 visible_rect,
275                 resource,
276                 premultiplied_alpha,
277                 uv_bottom_right.origin(),
278                 uv_bottom_right.bottom_right(),
279                 SK_ColorTRANSPARENT,
280                 vertex_opacity,
281                 flipped);
282    quad_sink->Append(quad.PassAs<DrawQuad>());
283  }
284
285  visible_rect = quad_sink->UnoccludedContentRect(layer_top, draw_transform());
286  if (!visible_rect.IsEmpty()) {
287    quad = TextureDrawQuad::Create();
288    quad->SetNew(shared_quad_state,
289                 layer_top,
290                 opaque_rect,
291                 visible_rect,
292                 resource,
293                 premultiplied_alpha,
294                 uv_top.origin(),
295                 uv_top.bottom_right(),
296                 SK_ColorTRANSPARENT,
297                 vertex_opacity,
298                 flipped);
299    quad_sink->Append(quad.PassAs<DrawQuad>());
300  }
301
302  visible_rect = quad_sink->UnoccludedContentRect(layer_left, draw_transform());
303  if (!visible_rect.IsEmpty()) {
304    quad = TextureDrawQuad::Create();
305    quad->SetNew(shared_quad_state,
306                 layer_left,
307                 opaque_rect,
308                 visible_rect,
309                 resource,
310                 premultiplied_alpha,
311                 uv_left.origin(),
312                 uv_left.bottom_right(),
313                 SK_ColorTRANSPARENT,
314                 vertex_opacity,
315                 flipped);
316    quad_sink->Append(quad.PassAs<DrawQuad>());
317  }
318
319  visible_rect =
320      quad_sink->UnoccludedContentRect(layer_right, draw_transform());
321  if (!visible_rect.IsEmpty()) {
322    quad = TextureDrawQuad::Create();
323    quad->SetNew(shared_quad_state,
324                 layer_right,
325                 opaque_rect,
326                 layer_right,
327                 resource,
328                 premultiplied_alpha,
329                 uv_right.origin(),
330                 uv_right.bottom_right(),
331                 SK_ColorTRANSPARENT,
332                 vertex_opacity,
333                 flipped);
334    quad_sink->Append(quad.PassAs<DrawQuad>());
335  }
336
337  visible_rect =
338      quad_sink->UnoccludedContentRect(layer_bottom, draw_transform());
339  if (!visible_rect.IsEmpty()) {
340    quad = TextureDrawQuad::Create();
341    quad->SetNew(shared_quad_state,
342                 layer_bottom,
343                 opaque_rect,
344                 visible_rect,
345                 resource,
346                 premultiplied_alpha,
347                 uv_bottom.origin(),
348                 uv_bottom.bottom_right(),
349                 SK_ColorTRANSPARENT,
350                 vertex_opacity,
351                 flipped);
352    quad_sink->Append(quad.PassAs<DrawQuad>());
353  }
354
355  if (fill_center_) {
356    visible_rect =
357        quad_sink->UnoccludedContentRect(layer_center, draw_transform());
358    if (!visible_rect.IsEmpty()) {
359      quad = TextureDrawQuad::Create();
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      quad_sink->Append(quad.PassAs<DrawQuad>());
372    }
373  }
374}
375
376const char* NinePatchLayerImpl::LayerTypeAsString() const {
377  return "cc::NinePatchLayerImpl";
378}
379
380base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const {
381  base::DictionaryValue* result = LayerImpl::LayerTreeAsJson();
382
383  base::ListValue* list = new base::ListValue;
384  list->AppendInteger(image_aperture_.origin().x());
385  list->AppendInteger(image_aperture_.origin().y());
386  list->AppendInteger(image_aperture_.size().width());
387  list->AppendInteger(image_aperture_.size().height());
388  result->Set("ImageAperture", list);
389
390  list = new base::ListValue;
391  list->AppendInteger(image_bounds_.width());
392  list->AppendInteger(image_bounds_.height());
393  result->Set("ImageBounds", list);
394
395  result->Set("Border", MathUtil::AsValue(border_).release());
396
397  base::FundamentalValue* fill_center =
398      base::Value::CreateBooleanValue(fill_center_);
399  result->Set("FillCenter", fill_center);
400
401  return result;
402}
403
404}  // namespace cc
405