| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright 2016 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/quads/nine_patch_generator.h" | 
 |    6  | 
 |    7 #include "cc/layers/draw_properties.h" | 
 |    8 #include "cc/quads/render_pass.h" | 
 |    9 #include "cc/quads/texture_draw_quad.h" | 
 |   10 #include "cc/trees/layer_tree_impl.h" | 
 |   11 #include "ui/gfx/geometry/rect_conversions.h" | 
 |   12 #include "ui/gfx/geometry/rect_f.h" | 
 |   13  | 
 |   14 namespace cc { | 
 |   15  | 
 |   16 namespace { | 
 |   17  | 
 |   18 // Maximum number of patches that can be produced for one NinePatchLayer. | 
 |   19 const int kMaxOcclusionPatches = 12; | 
 |   20 const int kMaxPatches = 9; | 
 |   21  | 
 |   22 gfx::RectF BoundsToRect(int x1, int y1, int x2, int y2) { | 
 |   23   return gfx::RectF(x1, y1, x2 - x1, y2 - y1); | 
 |   24 } | 
 |   25  | 
 |   26 gfx::RectF NormalizedRect(const gfx::RectF& rect, | 
 |   27                           float total_width, | 
 |   28                           float total_height) { | 
 |   29   return gfx::RectF(rect.x() / total_width, rect.y() / total_height, | 
 |   30                     rect.width() / total_width, rect.height() / total_height); | 
 |   31 } | 
 |   32  | 
 |   33 }  // namespace | 
 |   34  | 
 |   35 NinePatchGenerator::Patch::Patch(const gfx::RectF& image_rect, | 
 |   36                                  const gfx::Size& total_image_bounds, | 
 |   37                                  const gfx::RectF& output_rect) | 
 |   38     : image_rect(image_rect), | 
 |   39       normalized_image_rect(NormalizedRect(image_rect, | 
 |   40                                            total_image_bounds.width(), | 
 |   41                                            total_image_bounds.height())), | 
 |   42       output_rect(output_rect) {} | 
 |   43  | 
 |   44 NinePatchGenerator::NinePatchGenerator() | 
 |   45     : fill_center_(false), nearest_neighbor_(false) {} | 
 |   46  | 
 |   47 bool NinePatchGenerator::SetLayout(const gfx::Size& image_bounds, | 
 |   48                                    const gfx::Size& output_bounds, | 
 |   49                                    const gfx::Rect& aperture, | 
 |   50                                    const gfx::Rect& border, | 
 |   51                                    const gfx::Rect& output_occlusion, | 
 |   52                                    bool fill_center, | 
 |   53                                    bool nearest_neighbor) { | 
 |   54   if (image_bounds_ == image_bounds && output_bounds_ == output_bounds && | 
 |   55       image_aperture_ == aperture && border_ == border && | 
 |   56       fill_center_ == fill_center && output_occlusion_ == output_occlusion && | 
 |   57       nearest_neighbor_ == nearest_neighbor) | 
 |   58     return false; | 
 |   59  | 
 |   60   image_bounds_ = image_bounds; | 
 |   61   output_bounds_ = output_bounds; | 
 |   62   image_aperture_ = aperture; | 
 |   63   border_ = border; | 
 |   64   fill_center_ = fill_center; | 
 |   65   output_occlusion_ = output_occlusion; | 
 |   66   nearest_neighbor_ = nearest_neighbor; | 
 |   67  | 
 |   68   CheckGeometryLimitations(); | 
 |   69  | 
 |   70   return true; | 
 |   71 } | 
 |   72  | 
 |   73 void NinePatchGenerator::CheckGeometryLimitations() { | 
 |   74   // |border| is in layer space.  It cannot exceed the bounds of the layer. | 
 |   75   DCHECK_GE(output_bounds_.width(), border_.width()); | 
 |   76   DCHECK_GE(output_bounds_.height(), border_.height()); | 
 |   77  | 
 |   78   // Sanity Check on |border| | 
 |   79   DCHECK_LE(border_.x(), border_.width()); | 
 |   80   DCHECK_LE(border_.y(), border_.height()); | 
 |   81   DCHECK_GE(border_.x(), 0); | 
 |   82   DCHECK_GE(border_.y(), 0); | 
 |   83  | 
 |   84   // |aperture| is in image space.  It cannot exceed the bounds of the bitmap. | 
 |   85   DCHECK(!image_aperture_.size().IsEmpty()); | 
 |   86   DCHECK(gfx::Rect(image_bounds_).Contains(image_aperture_)) | 
 |   87       << "image_bounds_ " << gfx::Rect(image_bounds_).ToString() | 
 |   88       << " image_aperture_ " << image_aperture_.ToString(); | 
 |   89  | 
 |   90   // Sanity check on |output_occlusion_|. It should always be within the | 
 |   91   // border. | 
 |   92   gfx::Rect border_rect(border_.x(), border_.y(), | 
 |   93                         output_bounds_.width() - border_.width(), | 
 |   94                         output_bounds_.height() - border_.height()); | 
 |   95   DCHECK(output_occlusion_.IsEmpty() || output_occlusion_.Contains(border_rect)) | 
 |   96       << "border_rect " << border_rect.ToString() << " output_occlusion_ " | 
 |   97       << output_occlusion_.ToString(); | 
 |   98 } | 
 |   99  | 
 |  100 std::vector<NinePatchGenerator::Patch> | 
 |  101 NinePatchGenerator::ComputeQuadsWithoutOcclusion() const { | 
 |  102   float image_width = image_bounds_.width(); | 
 |  103   float image_height = image_bounds_.height(); | 
 |  104   float output_width = output_bounds_.width(); | 
 |  105   float output_height = output_bounds_.height(); | 
 |  106   gfx::RectF output_aperture(border_.x(), border_.y(), | 
 |  107                              output_width - border_.width(), | 
 |  108                              output_height - border_.height()); | 
 |  109  | 
 |  110   std::vector<Patch> patches; | 
 |  111   patches.reserve(kMaxPatches); | 
 |  112  | 
 |  113   // Top-left. | 
 |  114   patches.push_back( | 
 |  115       Patch(BoundsToRect(0, 0, image_aperture_.x(), image_aperture_.y()), | 
 |  116             image_bounds_, | 
 |  117             BoundsToRect(0, 0, output_aperture.x(), output_aperture.y()))); | 
 |  118  | 
 |  119   // Top-right. | 
 |  120   patches.push_back(Patch(BoundsToRect(image_aperture_.right(), 0, image_width, | 
 |  121                                        image_aperture_.y()), | 
 |  122                           image_bounds_, | 
 |  123                           BoundsToRect(output_aperture.right(), 0, output_width, | 
 |  124                                        output_aperture.y()))); | 
 |  125  | 
 |  126   // Bottom-left. | 
 |  127   patches.push_back(Patch(BoundsToRect(0, image_aperture_.bottom(), | 
 |  128                                        image_aperture_.x(), image_height), | 
 |  129                           image_bounds_, | 
 |  130                           BoundsToRect(0, output_aperture.bottom(), | 
 |  131                                        output_aperture.x(), output_height))); | 
 |  132  | 
 |  133   // Bottom-right. | 
 |  134   patches.push_back( | 
 |  135       Patch(BoundsToRect(image_aperture_.right(), image_aperture_.bottom(), | 
 |  136                          image_width, image_height), | 
 |  137             image_bounds_, | 
 |  138             BoundsToRect(output_aperture.right(), output_aperture.bottom(), | 
 |  139                          output_width, output_height))); | 
 |  140  | 
 |  141   // Top. | 
 |  142   patches.push_back( | 
 |  143       Patch(BoundsToRect(image_aperture_.x(), 0, image_aperture_.right(), | 
 |  144                          image_aperture_.y()), | 
 |  145             image_bounds_, | 
 |  146             BoundsToRect(output_aperture.x(), 0, output_aperture.right(), | 
 |  147                          output_aperture.y()))); | 
 |  148  | 
 |  149   // Left. | 
 |  150   patches.push_back( | 
 |  151       Patch(BoundsToRect(0, image_aperture_.y(), image_aperture_.x(), | 
 |  152                          image_aperture_.bottom()), | 
 |  153             image_bounds_, | 
 |  154             BoundsToRect(0, output_aperture.y(), output_aperture.x(), | 
 |  155                          output_aperture.bottom()))); | 
 |  156  | 
 |  157   // Right. | 
 |  158   patches.push_back( | 
 |  159       Patch(BoundsToRect(image_aperture_.right(), image_aperture_.y(), | 
 |  160                          image_width, image_aperture_.bottom()), | 
 |  161             image_bounds_, | 
 |  162             BoundsToRect(output_aperture.right(), output_aperture.y(), | 
 |  163                          output_width, output_aperture.bottom()))); | 
 |  164  | 
 |  165   // Bottom. | 
 |  166   patches.push_back( | 
 |  167       Patch(BoundsToRect(image_aperture_.x(), image_aperture_.bottom(), | 
 |  168                          image_aperture_.right(), image_height), | 
 |  169             image_bounds_, | 
 |  170             BoundsToRect(output_aperture.x(), output_aperture.bottom(), | 
 |  171                          output_aperture.right(), output_height))); | 
 |  172  | 
 |  173   // Center. | 
 |  174   if (fill_center_) { | 
 |  175     patches.push_back( | 
 |  176         Patch(BoundsToRect(image_aperture_.x(), image_aperture_.y(), | 
 |  177                            image_aperture_.right(), image_aperture_.bottom()), | 
 |  178               image_bounds_, | 
 |  179               BoundsToRect(output_aperture.x(), output_aperture.y(), | 
 |  180                            output_aperture.right(), output_aperture.bottom()))); | 
 |  181   } | 
 |  182  | 
 |  183   return patches; | 
 |  184 } | 
 |  185  | 
 |  186 std::vector<NinePatchGenerator::Patch> | 
 |  187 NinePatchGenerator::ComputeQuadsWithOcclusion() const { | 
 |  188   float image_width = image_bounds_.width(); | 
 |  189   float image_height = image_bounds_.height(); | 
 |  190  | 
 |  191   float output_width = output_bounds_.width(); | 
 |  192   float output_height = output_bounds_.height(); | 
 |  193  | 
 |  194   float layer_border_right = border_.width() - border_.x(); | 
 |  195   float layer_border_bottom = border_.height() - border_.y(); | 
 |  196  | 
 |  197   float image_aperture_right = image_width - image_aperture_.right(); | 
 |  198   float image_aperture_bottom = image_height - image_aperture_.bottom(); | 
 |  199  | 
 |  200   float output_occlusion_right = output_width - output_occlusion_.right(); | 
 |  201   float output_occlusion_bottom = output_height - output_occlusion_.bottom(); | 
 |  202  | 
 |  203   gfx::RectF image_occlusion(BoundsToRect( | 
 |  204       border_.x() == 0 | 
 |  205           ? 0 | 
 |  206           : (output_occlusion_.x() * image_aperture_.x() / border_.x()), | 
 |  207       border_.y() == 0 | 
 |  208           ? 0 | 
 |  209           : (output_occlusion_.y() * image_aperture_.y() / border_.y()), | 
 |  210       image_width - (layer_border_right == 0 | 
 |  211                          ? 0 | 
 |  212                          : output_occlusion_right * image_aperture_right / | 
 |  213                                layer_border_right), | 
 |  214       image_height - (layer_border_bottom == 0 | 
 |  215                           ? 0 | 
 |  216                           : output_occlusion_bottom * image_aperture_bottom / | 
 |  217                                 layer_border_bottom))); | 
 |  218   gfx::RectF output_aperture(border_.x(), border_.y(), | 
 |  219                              output_width - border_.width(), | 
 |  220                              output_height - border_.height()); | 
 |  221  | 
 |  222   std::vector<Patch> patches; | 
 |  223   patches.reserve(kMaxOcclusionPatches); | 
 |  224  | 
 |  225   // Top-left-left. | 
 |  226   patches.push_back( | 
 |  227       Patch(BoundsToRect(0, 0, image_occlusion.x(), image_aperture_.y()), | 
 |  228             image_bounds_, | 
 |  229             BoundsToRect(0, 0, output_occlusion_.x(), output_aperture.y()))); | 
 |  230  | 
 |  231   // Top-left-right. | 
 |  232   patches.push_back( | 
 |  233       Patch(BoundsToRect(image_occlusion.x(), 0, image_aperture_.x(), | 
 |  234                          image_occlusion.y()), | 
 |  235             image_bounds_, | 
 |  236             BoundsToRect(output_occlusion_.x(), 0, output_aperture.x(), | 
 |  237                          output_occlusion_.y()))); | 
 |  238  | 
 |  239   // Top-center. | 
 |  240   patches.push_back( | 
 |  241       Patch(BoundsToRect(image_aperture_.x(), 0, image_aperture_.right(), | 
 |  242                          image_occlusion.y()), | 
 |  243             image_bounds_, | 
 |  244             BoundsToRect(output_aperture.x(), 0, output_aperture.right(), | 
 |  245                          output_occlusion_.y()))); | 
 |  246  | 
 |  247   // Top-right-left. | 
 |  248   patches.push_back( | 
 |  249       Patch(BoundsToRect(image_aperture_.right(), 0, image_occlusion.right(), | 
 |  250                          image_occlusion.y()), | 
 |  251             image_bounds_, | 
 |  252             BoundsToRect(output_aperture.right(), 0, output_occlusion_.right(), | 
 |  253                          output_occlusion_.y()))); | 
 |  254  | 
 |  255   // Top-right-right. | 
 |  256   patches.push_back(Patch(BoundsToRect(image_occlusion.right(), 0, image_width, | 
 |  257                                        image_aperture_.y()), | 
 |  258                           image_bounds_, | 
 |  259                           BoundsToRect(output_occlusion_.right(), 0, | 
 |  260                                        output_width, output_aperture.y()))); | 
 |  261  | 
 |  262   // Left-center. | 
 |  263   patches.push_back( | 
 |  264       Patch(BoundsToRect(0, image_aperture_.y(), image_occlusion.x(), | 
 |  265                          image_aperture_.bottom()), | 
 |  266             image_bounds_, | 
 |  267             BoundsToRect(0, output_aperture.y(), output_occlusion_.x(), | 
 |  268                          output_aperture.bottom()))); | 
 |  269  | 
 |  270   // Right-center. | 
 |  271   patches.push_back( | 
 |  272       Patch(BoundsToRect(image_occlusion.right(), image_aperture_.y(), | 
 |  273                          image_width, image_aperture_.bottom()), | 
 |  274             image_bounds_, | 
 |  275             BoundsToRect(output_occlusion_.right(), output_aperture.y(), | 
 |  276                          output_width, output_aperture.bottom()))); | 
 |  277  | 
 |  278   // Bottom-left-left. | 
 |  279   patches.push_back(Patch(BoundsToRect(0, image_aperture_.bottom(), | 
 |  280                                        image_occlusion.x(), image_height), | 
 |  281                           image_bounds_, | 
 |  282                           BoundsToRect(0, output_aperture.bottom(), | 
 |  283                                        output_occlusion_.x(), output_height))); | 
 |  284  | 
 |  285   // Bottom-left-right. | 
 |  286   patches.push_back( | 
 |  287       Patch(BoundsToRect(image_occlusion.x(), image_occlusion.bottom(), | 
 |  288                          image_aperture_.x(), image_height), | 
 |  289             image_bounds_, | 
 |  290             BoundsToRect(output_occlusion_.x(), output_occlusion_.bottom(), | 
 |  291                          output_aperture.x(), output_height))); | 
 |  292  | 
 |  293   // Bottom-center. | 
 |  294   patches.push_back( | 
 |  295       Patch(BoundsToRect(image_aperture_.x(), image_occlusion.bottom(), | 
 |  296                          image_aperture_.right(), image_height), | 
 |  297             image_bounds_, | 
 |  298             BoundsToRect(output_aperture.x(), output_occlusion_.bottom(), | 
 |  299                          output_aperture.right(), output_height))); | 
 |  300  | 
 |  301   // Bottom-right-left. | 
 |  302   patches.push_back( | 
 |  303       Patch(BoundsToRect(image_aperture_.right(), image_occlusion.bottom(), | 
 |  304                          image_occlusion.right(), image_height), | 
 |  305             image_bounds_, | 
 |  306             BoundsToRect(output_aperture.right(), output_occlusion_.bottom(), | 
 |  307                          output_occlusion_.right(), output_height))); | 
 |  308  | 
 |  309   // Bottom-right-right. | 
 |  310   patches.push_back( | 
 |  311       Patch(BoundsToRect(image_occlusion.right(), image_aperture_.bottom(), | 
 |  312                          image_width, image_height), | 
 |  313             image_bounds_, | 
 |  314             BoundsToRect(output_occlusion_.right(), output_aperture.bottom(), | 
 |  315                          output_width, output_height))); | 
 |  316  | 
 |  317   return patches; | 
 |  318 } | 
 |  319  | 
 |  320 std::vector<NinePatchGenerator::Patch> NinePatchGenerator::GeneratePatches() | 
 |  321     const { | 
 |  322   DCHECK(!output_bounds_.IsEmpty()); | 
 |  323  | 
 |  324   std::vector<Patch> patches; | 
 |  325  | 
 |  326   if (output_occlusion_.IsEmpty() || fill_center_) | 
 |  327     patches = ComputeQuadsWithoutOcclusion(); | 
 |  328   else | 
 |  329     patches = ComputeQuadsWithOcclusion(); | 
 |  330  | 
 |  331   return patches; | 
 |  332 } | 
 |  333  | 
 |  334 void NinePatchGenerator::AppendQuads(LayerImpl* layer_impl, | 
 |  335                                      UIResourceId ui_resource_id, | 
 |  336                                      RenderPass* render_pass, | 
 |  337                                      SharedQuadState* shared_quad_state, | 
 |  338                                      const std::vector<Patch>& patches) { | 
 |  339   if (!ui_resource_id) | 
 |  340     return; | 
 |  341  | 
 |  342   ResourceId resource = | 
 |  343       layer_impl->layer_tree_impl()->ResourceIdForUIResource(ui_resource_id); | 
 |  344  | 
 |  345   if (!resource) | 
 |  346     return; | 
 |  347  | 
 |  348   const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; | 
 |  349   const bool opaque = | 
 |  350       layer_impl->layer_tree_impl()->IsUIResourceOpaque(ui_resource_id); | 
 |  351   constexpr bool flipped = false; | 
 |  352   constexpr bool premultiplied_alpha = true; | 
 |  353  | 
 |  354   for (const auto& patch : patches) { | 
 |  355     gfx::Rect output_rect = gfx::ToEnclosingRect(patch.output_rect); | 
 |  356     gfx::Rect visible_rect = | 
 |  357         layer_impl->draw_properties() | 
 |  358             .occlusion_in_content_space.GetUnoccludedContentRect(output_rect); | 
 |  359     gfx::Rect opaque_rect = opaque ? visible_rect : gfx::Rect(); | 
 |  360     if (!visible_rect.IsEmpty()) { | 
 |  361       gfx::RectF image_rect = patch.normalized_image_rect; | 
 |  362       TextureDrawQuad* quad = | 
 |  363           render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); | 
 |  364       quad->SetNew(shared_quad_state, output_rect, opaque_rect, visible_rect, | 
 |  365                    resource, premultiplied_alpha, image_rect.origin(), | 
 |  366                    image_rect.bottom_right(), SK_ColorTRANSPARENT, | 
 |  367                    vertex_opacity, flipped, nearest_neighbor_, false); | 
 |  368       layer_impl->ValidateQuadResources(quad); | 
 |  369     } | 
 |  370   } | 
 |  371 } | 
 |  372  | 
 |  373 void NinePatchGenerator::AsJson(base::DictionaryValue* dictionary) const { | 
 |  374   base::ListValue* list = new base::ListValue; | 
 |  375   list->AppendInteger(image_aperture_.origin().x()); | 
 |  376   list->AppendInteger(image_aperture_.origin().y()); | 
 |  377   list->AppendInteger(image_aperture_.size().width()); | 
 |  378   list->AppendInteger(image_aperture_.size().height()); | 
 |  379   dictionary->Set("ImageAperture", list); | 
 |  380  | 
 |  381   list = new base::ListValue; | 
 |  382   list->AppendInteger(image_bounds_.width()); | 
 |  383   list->AppendInteger(image_bounds_.height()); | 
 |  384   dictionary->Set("ImageBounds", list); | 
 |  385  | 
 |  386   dictionary->Set("Border", MathUtil::AsValue(border_).release()); | 
 |  387  | 
 |  388   dictionary->SetBoolean("FillCenter", fill_center_); | 
 |  389  | 
 |  390   list = new base::ListValue; | 
 |  391   list->AppendInteger(output_occlusion_.x()); | 
 |  392   list->AppendInteger(output_occlusion_.y()); | 
 |  393   list->AppendInteger(output_occlusion_.width()); | 
 |  394   list->AppendInteger(output_occlusion_.height()); | 
 |  395   dictionary->Set("OutputOcclusion", list); | 
 |  396 } | 
 |  397  | 
 |  398 }  // namespace cc | 
| OLD | NEW |