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/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 
     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(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 
     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 
     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 
    375 const char* NinePatchLayerImpl::LayerTypeAsString() const {
    376   return "cc::NinePatchLayerImpl";
    377 }
    378 
    379 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