1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_WM_CORE_IMAGE_GRID_H_
#define UI_WM_CORE_IMAGE_GRID_H_
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_delegate.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/wm/wm_export.h"
namespace gfx {
class Image;
} // namespace gfx
namespace wm {
// An ImageGrid is a 3x3 array of ui::Layers, each containing an image.
//
// As the grid is resized, its images fill the requested space:
// - corner images are not scaled
// - top and bottom images are scaled horizontally
// - left and right images are scaled vertically
// - the center image is scaled in both directions
//
// If one of the non-center images is smaller than the largest images in its
// row or column, it will be aligned with the outside of the grid. For
// example, given 4x4 top-left and top-right images and a 1x2 top images:
//
// +--------+---------------------+--------+
// | | top | |
// | top- +---------------------+ top- +
// | left | | right |
// +----+---+ +---+----+
// | | | |
// ...
//
// This may seem odd at first, but it lets ImageGrid be used to draw shadows
// with curved corners that extend inwards beyond a window's borders. In the
// below example, the top-left corner image is overlaid on top of the window's
// top-left corner:
//
// +---------+-----------------------
// | ..xxx|XXXXXXXXXXXXXXXXXX
// | .xXXXXX|XXXXXXXXXXXXXXXXXX_____
// | .xXX | ^ window's top edge
// | .xXX |
// +---------+
// | xXX|
// | xXX|< window's left edge
// | xXX|
// ...
//
class WM_EXPORT ImageGrid {
public:
// Helper class for use by tests.
class WM_EXPORT TestAPI {
public:
TestAPI(ImageGrid* grid) : grid_(grid) {}
gfx::Rect top_left_clip_rect() const {
return grid_->top_left_painter_->clip_rect_;
}
gfx::Rect top_right_clip_rect() const {
return grid_->top_right_painter_->clip_rect_;
}
gfx::Rect bottom_left_clip_rect() const {
return grid_->bottom_left_painter_->clip_rect_;
}
gfx::Rect bottom_right_clip_rect() const {
return grid_->bottom_right_painter_->clip_rect_;
}
// Returns |layer|'s bounds after applying the layer's current transform.
gfx::RectF GetTransformedLayerBounds(const ui::Layer& layer);
private:
ImageGrid* grid_; // not owned
DISALLOW_COPY_AND_ASSIGN(TestAPI);
};
ImageGrid();
~ImageGrid();
ui::Layer* layer() { return layer_.get(); }
int top_image_height() const { return top_image_height_; }
int bottom_image_height() const { return bottom_image_height_; }
int left_image_width() const { return left_image_width_; }
int right_image_width() const { return right_image_width_; }
// Visible to allow independent layer animations and for testing.
ui::Layer* top_left_layer() const { return top_left_layer_.get(); }
ui::Layer* top_layer() const { return top_layer_.get(); }
ui::Layer* top_right_layer() const { return top_right_layer_.get(); }
ui::Layer* left_layer() const { return left_layer_.get(); }
ui::Layer* center_layer() const { return center_layer_.get(); }
ui::Layer* right_layer() const { return right_layer_.get(); }
ui::Layer* bottom_left_layer() const { return bottom_left_layer_.get(); }
ui::Layer* bottom_layer() const { return bottom_layer_.get(); }
ui::Layer* bottom_right_layer() const { return bottom_right_layer_.get(); }
// Sets the grid to display the passed-in images (any of which can be NULL).
// Ownership of the images remains with the caller. May be called more than
// once to switch images.
void SetImages(const gfx::Image* top_left_image,
const gfx::Image* top_image,
const gfx::Image* top_right_image,
const gfx::Image* left_image,
const gfx::Image* center_image,
const gfx::Image* right_image,
const gfx::Image* bottom_left_image,
const gfx::Image* bottom_image,
const gfx::Image* bottom_right_image);
void SetSize(const gfx::Size& size);
// Sets the grid to a position and size such that the inner edges of the top,
// bottom, left and right images will be flush with |content_bounds_in_dip|.
void SetContentBounds(const gfx::Rect& content_bounds_in_dip);
private:
// Delegate responsible for painting a specific image on a layer.
class ImagePainter : public ui::LayerDelegate {
public:
ImagePainter(const gfx::ImageSkia& image) : image_(image) {}
~ImagePainter() override {}
// Clips |layer| to |clip_rect|. Triggers a repaint if the clipping
// rectangle has changed. An empty rectangle disables clipping.
void SetClipRect(const gfx::Rect& clip_rect, ui::Layer* layer);
// ui::LayerDelegate implementation:
void OnPaintLayer(gfx::Canvas* canvas) override;
void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
void OnDeviceScaleFactorChanged(float device_scale_factor) override;
base::Closure PrepareForLayerBoundsChange() override;
private:
friend class TestAPI;
const gfx::ImageSkia image_;
gfx::Rect clip_rect_;
DISALLOW_COPY_AND_ASSIGN(ImagePainter);
};
enum ImageType {
HORIZONTAL,
VERTICAL,
NONE,
};
// Sets |layer_ptr| and |painter_ptr| to display |image| and adds the
// passed-in layer to |layer_|. If image is NULL resets |layer_ptr| and
// |painter_ptr| and removes any existing layer from |layer_|.
// If |type| is either HORIZONTAL or VERTICAL, it may resize the image to
// guarantee that it has minimum size in order for scaling work properly
// with fractional device scale factors. crbug.com/376519.
void SetImage(const gfx::Image* image,
scoped_ptr<ui::Layer>* layer_ptr,
scoped_ptr<ImagePainter>* painter_ptr,
ImageType type);
// Layer that contains all of the image layers.
scoped_ptr<ui::Layer> layer_;
// The grid's dimensions.
gfx::Size size_;
// Heights and widths of the images displayed by |top_layer_|,
// |bottom_layer_|, |left_layer_|, and |right_layer_|.
int top_image_height_;
int bottom_image_height_;
int left_image_width_;
int right_image_width_;
// Heights of the tallest images in the top and bottom rows and the widest
// images in the left and right columns. Note that we may have less actual
// space than this available if the images are large and |size_| is small.
int base_top_row_height_;
int base_bottom_row_height_;
int base_left_column_width_;
int base_right_column_width_;
// Layers used to display the various images. Children of |layer_|.
// Positions for which no images were supplied are NULL.
scoped_ptr<ui::Layer> top_left_layer_;
scoped_ptr<ui::Layer> top_layer_;
scoped_ptr<ui::Layer> top_right_layer_;
scoped_ptr<ui::Layer> left_layer_;
scoped_ptr<ui::Layer> center_layer_;
scoped_ptr<ui::Layer> right_layer_;
scoped_ptr<ui::Layer> bottom_left_layer_;
scoped_ptr<ui::Layer> bottom_layer_;
scoped_ptr<ui::Layer> bottom_right_layer_;
// Delegates responsible for painting the above layers.
// Positions for which no images were supplied are NULL.
scoped_ptr<ImagePainter> top_left_painter_;
scoped_ptr<ImagePainter> top_painter_;
scoped_ptr<ImagePainter> top_right_painter_;
scoped_ptr<ImagePainter> left_painter_;
scoped_ptr<ImagePainter> center_painter_;
scoped_ptr<ImagePainter> right_painter_;
scoped_ptr<ImagePainter> bottom_left_painter_;
scoped_ptr<ImagePainter> bottom_painter_;
scoped_ptr<ImagePainter> bottom_right_painter_;
DISALLOW_COPY_AND_ASSIGN(ImageGrid);
};
} // namespace wm
#endif // UI_WM_CORE_IMAGE_GRID_H_
|