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/layers/quad_sink.h"
     10 #include "cc/quads/texture_draw_quad.h"
     11 #include "ui/gfx/rect_f.h"
     12 
     13 namespace cc {
     14 
     15 NinePatchLayerImpl::NinePatchLayerImpl(LayerTreeImpl* tree_impl, int id)
     16     : LayerImpl(tree_impl, id),
     17       resource_id_(0) {}
     18 
     19 NinePatchLayerImpl::~NinePatchLayerImpl() {}
     20 
     21 ResourceProvider::ResourceId NinePatchLayerImpl::ContentsResourceId() const {
     22   return 0;
     23 }
     24 
     25 scoped_ptr<LayerImpl> NinePatchLayerImpl::CreateLayerImpl(
     26     LayerTreeImpl* tree_impl) {
     27   return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
     28 }
     29 
     30 void NinePatchLayerImpl::PushPropertiesTo(LayerImpl* layer) {
     31   LayerImpl::PushPropertiesTo(layer);
     32   NinePatchLayerImpl* layer_impl = static_cast<NinePatchLayerImpl*>(layer);
     33 
     34   if (!resource_id_)
     35     return;
     36 
     37   layer_impl->SetResourceId(resource_id_);
     38   layer_impl->SetLayout(image_bounds_, image_aperture_);
     39 }
     40 
     41 static gfx::RectF NormalizedRect(float x,
     42                                  float y,
     43                                  float width,
     44                                  float height,
     45                                  float total_width,
     46                                  float total_height) {
     47   return gfx::RectF(x / total_width,
     48                     y / total_height,
     49                     width / total_width,
     50                     height / total_height);
     51 }
     52 
     53 void NinePatchLayerImpl::SetLayout(gfx::Size image_bounds, gfx::Rect aperture) {
     54   image_bounds_ = image_bounds;
     55   image_aperture_ = aperture;
     56 }
     57 
     58 bool NinePatchLayerImpl::WillDraw(DrawMode draw_mode,
     59                                   ResourceProvider* resource_provider) {
     60   if (!resource_id_ || draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
     61     return false;
     62   return LayerImpl::WillDraw(draw_mode, resource_provider);
     63 }
     64 
     65 void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
     66                                      AppendQuadsData* append_quads_data) {
     67   DCHECK(resource_id_);
     68 
     69   SharedQuadState* shared_quad_state =
     70       quad_sink->UseSharedQuadState(CreateSharedQuadState());
     71   AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
     72 
     73   static const bool flipped = false;
     74   static const bool premultiplied_alpha = true;
     75 
     76   DCHECK(!bounds().IsEmpty());
     77 
     78   // NinePatch border widths in bitmap pixel space
     79   int left_width = image_aperture_.x();
     80   int top_height = image_aperture_.y();
     81   int right_width = image_bounds_.width() - image_aperture_.right();
     82   int bottom_height = image_bounds_.height() - image_aperture_.bottom();
     83 
     84   // If layer can't fit the corners, clip to show the outer edges of the
     85   // image.
     86   int corner_total_width = left_width + right_width;
     87   int middle_width = bounds().width() - corner_total_width;
     88   if (middle_width < 0) {
     89     float left_width_proportion =
     90         static_cast<float>(left_width) / corner_total_width;
     91     int left_width_crop = middle_width * left_width_proportion;
     92     left_width += left_width_crop;
     93     right_width = bounds().width() - left_width;
     94     middle_width = 0;
     95   }
     96   int corner_total_height = top_height + bottom_height;
     97   int middle_height = bounds().height() - corner_total_height;
     98   if (middle_height < 0) {
     99     float top_height_proportion =
    100         static_cast<float>(top_height) / corner_total_height;
    101     int top_height_crop = middle_height * top_height_proportion;
    102     top_height += top_height_crop;
    103     bottom_height = bounds().height() - top_height;
    104     middle_height = 0;
    105   }
    106 
    107   // Patch positions in layer space
    108   gfx::Rect top_left(0, 0, left_width, top_height);
    109   gfx::Rect top_right(
    110       bounds().width() - right_width, 0, right_width, top_height);
    111   gfx::Rect bottom_left(
    112       0, bounds().height() - bottom_height, left_width, bottom_height);
    113   gfx::Rect bottom_right(
    114       top_right.x(), bottom_left.y(), right_width, bottom_height);
    115   gfx::Rect top(top_left.right(), 0, middle_width, top_height);
    116   gfx::Rect left(0, top_left.bottom(), left_width, middle_height);
    117   gfx::Rect right(top_right.x(),
    118                   top_right.bottom(),
    119                   right_width,
    120                   left.height());
    121   gfx::Rect bottom(top.x(), bottom_left.y(), top.width(), bottom_height);
    122 
    123   float img_width = image_bounds_.width();
    124   float img_height = image_bounds_.height();
    125 
    126   // Patch positions in bitmap UV space (from zero to one)
    127   gfx::RectF uv_top_left = NormalizedRect(0,
    128                                           0,
    129                                           left_width,
    130                                           top_height,
    131                                           img_width,
    132                                           img_height);
    133   gfx::RectF uv_top_right = NormalizedRect(img_width - right_width,
    134                                            0,
    135                                            right_width,
    136                                            top_height,
    137                                            img_width,
    138                                            img_height);
    139   gfx::RectF uv_bottom_left = NormalizedRect(0,
    140                                              img_height - bottom_height,
    141                                              left_width,
    142                                              bottom_height,
    143                                              img_width,
    144                                              img_height);
    145   gfx::RectF uv_bottom_right = NormalizedRect(img_width - right_width,
    146                                               img_height - bottom_height,
    147                                               right_width,
    148                                               bottom_height,
    149                                               img_width,
    150                                               img_height);
    151   gfx::RectF uv_top(uv_top_left.right(),
    152                    0,
    153                    (img_width - left_width - right_width) / img_width,
    154                    (top_height) / img_height);
    155   gfx::RectF uv_left(0,
    156                     uv_top_left.bottom(),
    157                     left_width / img_width,
    158                     (img_height - top_height - bottom_height) / img_height);
    159   gfx::RectF uv_right(uv_top_right.x(),
    160                      uv_top_right.bottom(),
    161                      right_width / img_width,
    162                      uv_left.height());
    163   gfx::RectF uv_bottom(uv_top.x(),
    164                       uv_bottom_left.y(),
    165                       uv_top.width(),
    166                       bottom_height / img_height);
    167 
    168   // Nothing is opaque here.
    169   // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness?
    170   gfx::Rect opaque_rect;
    171   const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
    172   scoped_ptr<TextureDrawQuad> quad;
    173 
    174   quad = TextureDrawQuad::Create();
    175   quad->SetNew(shared_quad_state,
    176                top_left,
    177                opaque_rect,
    178                resource_id_,
    179                premultiplied_alpha,
    180                uv_top_left.origin(),
    181                uv_top_left.bottom_right(),
    182                SK_ColorTRANSPARENT,
    183                vertex_opacity,
    184                flipped);
    185   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    186 
    187   quad = TextureDrawQuad::Create();
    188   quad->SetNew(shared_quad_state,
    189                top_right,
    190                opaque_rect,
    191                resource_id_,
    192                premultiplied_alpha,
    193                uv_top_right.origin(),
    194                uv_top_right.bottom_right(),
    195                SK_ColorTRANSPARENT,
    196                vertex_opacity,
    197                flipped);
    198   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    199 
    200   quad = TextureDrawQuad::Create();
    201   quad->SetNew(shared_quad_state,
    202                bottom_left,
    203                opaque_rect,
    204                resource_id_,
    205                premultiplied_alpha,
    206                uv_bottom_left.origin(),
    207                uv_bottom_left.bottom_right(),
    208                SK_ColorTRANSPARENT,
    209                vertex_opacity,
    210                flipped);
    211   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    212 
    213   quad = TextureDrawQuad::Create();
    214   quad->SetNew(shared_quad_state,
    215                bottom_right,
    216                opaque_rect,
    217                resource_id_,
    218                premultiplied_alpha,
    219                uv_bottom_right.origin(),
    220                uv_bottom_right.bottom_right(),
    221                SK_ColorTRANSPARENT,
    222                vertex_opacity,
    223                flipped);
    224   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    225 
    226   quad = TextureDrawQuad::Create();
    227   quad->SetNew(shared_quad_state,
    228                top,
    229                opaque_rect,
    230                resource_id_,
    231                premultiplied_alpha,
    232                uv_top.origin(),
    233                uv_top.bottom_right(),
    234                SK_ColorTRANSPARENT,
    235                vertex_opacity,
    236                flipped);
    237   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    238 
    239   quad = TextureDrawQuad::Create();
    240   quad->SetNew(shared_quad_state,
    241                left,
    242                opaque_rect,
    243                resource_id_,
    244                premultiplied_alpha,
    245                uv_left.origin(),
    246                uv_left.bottom_right(),
    247                SK_ColorTRANSPARENT,
    248                vertex_opacity,
    249                flipped);
    250   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    251 
    252   quad = TextureDrawQuad::Create();
    253   quad->SetNew(shared_quad_state,
    254                right,
    255                opaque_rect,
    256                resource_id_,
    257                premultiplied_alpha,
    258                uv_right.origin(),
    259                uv_right.bottom_right(),
    260                SK_ColorTRANSPARENT,
    261                vertex_opacity,
    262                flipped);
    263   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    264 
    265   quad = TextureDrawQuad::Create();
    266   quad->SetNew(shared_quad_state,
    267                bottom,
    268                opaque_rect,
    269                resource_id_,
    270                premultiplied_alpha,
    271                uv_bottom.origin(),
    272                uv_bottom.bottom_right(),
    273                SK_ColorTRANSPARENT,
    274                vertex_opacity,
    275                flipped);
    276   quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    277 }
    278 
    279 void NinePatchLayerImpl::DidLoseOutputSurface() {
    280   resource_id_ = 0;
    281 }
    282 
    283 const char* NinePatchLayerImpl::LayerTypeAsString() const {
    284   return "cc::NinePatchLayerImpl";
    285 }
    286 
    287 base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const {
    288   base::DictionaryValue* result = LayerImpl::LayerTreeAsJson();
    289 
    290   base::ListValue* list = new base::ListValue;
    291   list->AppendInteger(image_aperture_.origin().x());
    292   list->AppendInteger(image_aperture_.origin().y());
    293   list->AppendInteger(image_aperture_.size().width());
    294   list->AppendInteger(image_aperture_.size().height());
    295   result->Set("ImageAperture", list);
    296 
    297   list = new base::ListValue;
    298   list->AppendInteger(image_bounds_.width());
    299   list->AppendInteger(image_bounds_.height());
    300   result->Set("ImageBounds", list);
    301 
    302   return result;
    303 }
    304 
    305 }  // namespace cc
    306