15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// Use of this source code is governed by a BSD-style license that can be
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// found in the LICENSE file.
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "ui/wm/core/image_grid.h"
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <algorithm>
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "third_party/skia/include/core/SkColor.h"
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "third_party/skia/include/core/SkXfermode.h"
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "ui/compositor/dip_util.h"
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "ui/gfx/canvas.h"
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "ui/gfx/image/image.h"
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "ui/gfx/image/image_skia_operations.h"
15e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "ui/gfx/rect.h"
16031d655004e505a15e92580a16a181d1d247c4d5David 'Digit' Turner#include "ui/gfx/rect_conversions.h"
17d0edecb426b34ddb9b10b81dea19aee04a61a385David 'Digit' Turner#include "ui/gfx/size.h"
18d413fa5f2916a2a46494edb320340486b262644cDavid 'Digit' Turner#include "ui/gfx/size_conversions.h"
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "ui/gfx/transform.h"
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerusing std::max;
225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerusing std::min;
23a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner
245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnernamespace wm {
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnernamespace {
265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// Sets the scaling for the transform applied to a layer.  The left, top,
285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// right and bottom layers are stretched to the height or width of the
295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// center image.
305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid ScaleWidth(gfx::Size center, ui::Layer* layer, gfx::Transform& transform) {
325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  float layer_width = layer->bounds().width() * layer->device_scale_factor();
335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  float scale = static_cast<float>(center.width()) / layer_width;
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  transform.Scale(scale, 1.0);
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
377627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turnervoid ScaleHeight(gfx::Size center,
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 ui::Layer* layer,
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 gfx::Transform& transform) {
40a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner  float layer_height = layer->bounds().height() * layer->device_scale_factor();
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  float scale = static_cast<float>(center.height()) / layer_height;
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  transform.Scale(1.0, scale);
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// Returns the dimensions of |image| if non-NULL or gfx::Size(0, 0) otherwise.
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnergfx::Size GetImageSize(const gfx::Image* image) {
47a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner  return image ? gfx::Size(image->ToImageSkia()->width(),
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           image->ToImageSkia()->height())
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner               : gfx::Size();
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// Returns true if |layer|'s bounds don't fit within |size|.
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerbool LayerExceedsSize(const ui::Layer* layer, const gfx::Size& size) {
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  return layer->bounds().width() > size.width() ||
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         layer->bounds().height() > size.height();
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}  // namespace
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
607627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turnergfx::RectF ImageGrid::TestAPI::GetTransformedLayerBounds(
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const ui::Layer& layer) {
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  gfx::RectF bounds = layer.bounds();
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  layer.transform().TransformRect(&bounds);
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  return bounds;
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerImageGrid::ImageGrid()
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    : layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)),
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      top_image_height_(0),
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      bottom_image_height_(0),
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      left_image_width_(0),
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      right_image_width_(0),
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      base_top_row_height_(0),
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      base_bottom_row_height_(0),
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      base_left_column_width_(0),
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      base_right_column_width_(0) {
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
78a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner
79aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' TurnerImageGrid::~ImageGrid() {
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid ImageGrid::SetImages(const gfx::Image* top_left_image,
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          const gfx::Image* top_image,
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          const gfx::Image* top_right_image,
85aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner                          const gfx::Image* left_image,
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          const gfx::Image* center_image,
87a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner                          const gfx::Image* right_image,
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          const gfx::Image* bottom_left_image,
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          const gfx::Image* bottom_image,
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          const gfx::Image* bottom_right_image) {
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  SetImage(top_left_image, &top_left_layer_, &top_left_painter_, NONE);
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  SetImage(top_image, &top_layer_, &top_painter_, HORIZONTAL);
937627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  SetImage(top_right_image, &top_right_layer_, &top_right_painter_, NONE);
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  SetImage(left_image, &left_layer_, &left_painter_, VERTICAL);
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  SetImage(center_image, &center_layer_, &center_painter_, NONE);
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  SetImage(right_image, &right_layer_, &right_painter_, VERTICAL);
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  SetImage(bottom_left_image, &bottom_left_layer_, &bottom_left_painter_, NONE);
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  SetImage(bottom_image, &bottom_layer_, &bottom_painter_, HORIZONTAL);
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  SetImage(
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      bottom_right_image, &bottom_right_layer_, &bottom_right_painter_, NONE);
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  top_image_height_ = GetImageSize(top_image).height();
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  bottom_image_height_ = GetImageSize(bottom_image).height();
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  left_image_width_ = GetImageSize(left_image).width();
1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  right_image_width_ = GetImageSize(right_image).width();
1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  base_top_row_height_ = max(GetImageSize(top_left_image).height(),
1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             max(GetImageSize(top_image).height(),
1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 GetImageSize(top_right_image).height()));
1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  base_bottom_row_height_ = max(GetImageSize(bottom_left_image).height(),
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                max(GetImageSize(bottom_image).height(),
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                    GetImageSize(bottom_right_image).height()));
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  base_left_column_width_ = max(GetImageSize(top_left_image).width(),
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                max(GetImageSize(left_image).width(),
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                    GetImageSize(bottom_left_image).width()));
116a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner  base_right_column_width_ = max(GetImageSize(top_right_image).width(),
1177627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner                                 max(GetImageSize(right_image).width(),
1187627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner                                     GetImageSize(bottom_right_image).width()));
1197627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  // Invalidate previous |size_| so calls to SetSize() will recompute it.
1217627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  size_.SetSize(0, 0);
1227627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner}
1237627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner
1247627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turnervoid ImageGrid::SetSize(const gfx::Size& size) {
1257627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  if (size_ == size)
1267627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner    return;
1277627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner
1287627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  size_ = size;
1297627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner
1307627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  gfx::Rect updated_bounds = layer_->bounds();
1317627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  updated_bounds.set_size(size);
1327627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  layer_->SetBounds(updated_bounds);
1337627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner
1347627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  // Calculate the available amount of space for corner images on all sides of
1357627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  // the grid.  If the images don't fit, we need to clip them.
1367627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  const int left = min(base_left_column_width_, size_.width() / 2);
1377627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  const int right = min(base_right_column_width_, size_.width() - left);
1387627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  const int top = min(base_top_row_height_, size_.height() / 2);
1397627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  const int bottom = min(base_bottom_row_height_, size_.height() - top);
1407627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner
1417627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner  // The remaining space goes to the center image.
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  int center_width = std::max(size.width() - left - right, 0);
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  int center_height = std::max(size.height() - top - bottom, 0);
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  // At non-integer scale factors, the ratio of dimensions in DIP is not
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  // necessarily the same as the ratio in physical pixels due to rounding.  Set
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  // the transform on each of the layers based on dimensions in pixels.
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  gfx::Size center_size_in_pixels = gfx::ToFlooredSize(gfx::ScaleSize(
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      gfx::Size(center_width, center_height), layer_->device_scale_factor()));
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  if (top_layer_.get()) {
1527627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner    if (center_width > 0) {
1537627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner      gfx::Transform transform;
1547627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner      transform.Translate(left, 0);
1557627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner      ScaleWidth(center_size_in_pixels, top_layer_.get(), transform);
1567627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner      top_layer_->SetTransform(transform);
1577627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner    }
1587627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner    top_layer_->SetVisible(center_width > 0);
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  }
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  if (bottom_layer_.get()) {
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (center_width > 0) {
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      gfx::Transform transform;
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      transform.Translate(
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner          left, size.height() - bottom_layer_->bounds().height());
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      ScaleWidth(center_size_in_pixels, bottom_layer_.get(), transform);
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      bottom_layer_->SetTransform(transform);
1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
168a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner    bottom_layer_->SetVisible(center_width > 0);
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  }
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  if (left_layer_.get()) {
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (center_height > 0) {
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      gfx::Transform transform;
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      transform.Translate(0, top);
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      ScaleHeight(center_size_in_pixels, left_layer_.get(), transform);
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      left_layer_->SetTransform(transform);
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    left_layer_->SetVisible(center_height > 0);
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  }
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  if (right_layer_.get()) {
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (center_height > 0) {
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      gfx::Transform transform;
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      transform.Translate(
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner          size.width() - right_layer_->bounds().width(), top);
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      ScaleHeight(center_size_in_pixels, right_layer_.get(), transform);
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      right_layer_->SetTransform(transform);
186cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije    }
187cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije    right_layer_->SetVisible(center_height > 0);
188cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije  }
189cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije
190cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije  if (top_left_layer_.get()) {
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // No transformation needed; it should be at (0, 0) and unscaled.
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    top_left_painter_->SetClipRect(
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LayerExceedsSize(top_left_layer_.get(), gfx::Size(left, top)) ?
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            gfx::Rect(gfx::Rect(0, 0, left, top)) :
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            gfx::Rect(),
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        top_left_layer_.get());
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  }
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  if (top_right_layer_.get()) {
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    gfx::Transform transform;
200a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner    transform.Translate(size.width() - top_right_layer_->bounds().width(), 0.0);
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    top_right_layer_->SetTransform(transform);
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    top_right_painter_->SetClipRect(
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LayerExceedsSize(top_right_layer_.get(), gfx::Size(right, top)) ?
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            gfx::Rect(top_right_layer_->bounds().width() - right, 0,
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                      right, top) :
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            gfx::Rect(),
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        top_right_layer_.get());
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  }
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  if (bottom_left_layer_.get()) {
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    gfx::Transform transform;
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    transform.Translate(
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        0.0, size.height() - bottom_left_layer_->bounds().height());
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bottom_left_layer_->SetTransform(transform);
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bottom_left_painter_->SetClipRect(
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LayerExceedsSize(bottom_left_layer_.get(), gfx::Size(left, bottom)) ?
216a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner            gfx::Rect(0, bottom_left_layer_->bounds().height() - bottom,
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                      left, bottom) :
2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            gfx::Rect(),
219a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner        bottom_left_layer_.get());
220aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner  }
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner  if (bottom_right_layer_.get()) {
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    gfx::Transform transform;
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    transform.Translate(
2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        size.width() - bottom_right_layer_->bounds().width(),
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        size.height() - bottom_right_layer_->bounds().height());
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bottom_right_layer_->SetTransform(transform);
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bottom_right_painter_->SetClipRect(
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LayerExceedsSize(bottom_right_layer_.get(), gfx::Size(right, bottom)) ?
2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            gfx::Rect(bottom_right_layer_->bounds().width() - right,
230                      bottom_right_layer_->bounds().height() - bottom,
231                      right, bottom) :
232            gfx::Rect(),
233        bottom_right_layer_.get());
234  }
235
236  if (center_layer_.get()) {
237    if (center_width > 0 && center_height > 0) {
238      gfx::Transform transform;
239      transform.Translate(left, top);
240      transform.Scale(center_width / center_layer_->bounds().width(),
241                      center_height / center_layer_->bounds().height());
242      center_layer_->SetTransform(transform);
243    }
244    center_layer_->SetVisible(center_width > 0 && center_height > 0);
245  }
246}
247
248void ImageGrid::SetContentBounds(const gfx::Rect& content_bounds) {
249
250  SetSize(gfx::Size(
251      content_bounds.width() + left_image_width_ + right_image_width_,
252      content_bounds.height() + top_image_height_ +
253      bottom_image_height_));
254  layer_->SetBounds(
255      gfx::Rect(content_bounds.x() - left_image_width_,
256                content_bounds.y() - top_image_height_,
257                layer_->bounds().width(),
258                layer_->bounds().height()));
259}
260
261void ImageGrid::ImagePainter::SetClipRect(const gfx::Rect& clip_rect,
262                                          ui::Layer* layer) {
263  if (clip_rect != clip_rect_) {
264    clip_rect_ = clip_rect;
265    layer->SchedulePaint(layer->bounds());
266  }
267}
268
269void ImageGrid::ImagePainter::OnPaintLayer(gfx::Canvas* canvas) {
270  if (!clip_rect_.IsEmpty())
271    canvas->ClipRect(clip_rect_);
272  canvas->DrawImageInt(image_, 0, 0);
273}
274
275void ImageGrid::ImagePainter::OnDelegatedFrameDamage(
276    const gfx::Rect& damage_rect_in_dip) {
277}
278
279void ImageGrid::ImagePainter::OnDeviceScaleFactorChanged(
280    float device_scale_factor) {
281  // Redrawing will take care of scale factor change.
282}
283
284base::Closure ImageGrid::ImagePainter::PrepareForLayerBoundsChange() {
285  return base::Closure();
286}
287
288void ImageGrid::SetImage(const gfx::Image* image,
289                         scoped_ptr<ui::Layer>* layer_ptr,
290                         scoped_ptr<ImagePainter>* painter_ptr,
291                         ImageType type) {
292  // Minimum width (for HORIZONTAL) or height (for VERTICAL) of the
293  // |image| so that layers are scaled property if the device scale
294  // factor is non integral.
295  const int kMinimumSize = 20;
296
297  // Clean out old layers and painters.
298  if (layer_ptr->get())
299    layer_->Remove(layer_ptr->get());
300  layer_ptr->reset();
301  painter_ptr->reset();
302
303  // If we're not using an image, we're done.
304  if (!image)
305    return;
306
307  gfx::ImageSkia image_skia = image->AsImageSkia();
308  switch (type) {
309    case HORIZONTAL:
310      if (image_skia.width() < kMinimumSize) {
311        image_skia = gfx::ImageSkiaOperations::CreateResizedImage(
312            image_skia,
313            skia::ImageOperations::RESIZE_GOOD,
314            gfx::Size(kMinimumSize, image_skia.height()));
315      }
316      break;
317    case VERTICAL:
318      if (image_skia.height() < kMinimumSize) {
319        image_skia = gfx::ImageSkiaOperations::CreateResizedImage(
320            image_skia,
321            skia::ImageOperations::RESIZE_GOOD,
322            gfx::Size(image_skia.width(), kMinimumSize));
323      }
324      break;
325    case NONE:
326      break;
327  }
328
329  // Set up the new layer and painter.
330  layer_ptr->reset(new ui::Layer(ui::LAYER_TEXTURED));
331
332  const gfx::Size size = image_skia.size();
333  layer_ptr->get()->SetBounds(gfx::Rect(0, 0, size.width(), size.height()));
334
335  painter_ptr->reset(new ImagePainter(image_skia));
336  layer_ptr->get()->set_delegate(painter_ptr->get());
337  layer_ptr->get()->SetFillsBoundsOpaquely(false);
338  layer_ptr->get()->SetVisible(true);
339  layer_->Add(layer_ptr->get());
340}
341
342}  // namespace wm
343