Home | History | Annotate | Download | only in layers
      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 
     17 NinePatchLayerImpl::NinePatchLayerImpl(LayerTreeImpl* tree_impl, int id)
     18     : UIResourceLayerImpl(tree_impl, id),
     19       fill_center_(false) {}
     20 
     21 NinePatchLayerImpl::~NinePatchLayerImpl() {}
     22 
     23 scoped_ptr<LayerImpl> NinePatchLayerImpl::CreateLayerImpl(
     24     LayerTreeImpl* tree_impl) {
     25   return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
     26 }
     27 
     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 
     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 
     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 
     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 
     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 
    343 const char* NinePatchLayerImpl::LayerTypeAsString() const {
    344   return "cc::NinePatchLayerImpl";
    345 }
    346 
    347 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