summaryrefslogtreecommitdiffstats
path: root/ash/wm/image_grid.h
blob: 7b53f88ecaa3437bc716adbf32dbe4830f9b98dc (plain)
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
223
224
225
226
// 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 ASH_WM_IMAGE_GRID_H_
#define ASH_WM_IMAGE_GRID_H_
#pragma once

#include "ash/ash_export.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/rect.h"
#include "ui/gfx/size.h"

namespace aura {
class Window;
}  // namespace aura

namespace gfx {
class Image;
}  // namespace gfx

namespace ash {
namespace internal {

// 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 ASH_EXPORT ImageGrid {
 public:
  // Helper class for use by tests.
  class ASH_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::Rect GetTransformedLayerBounds(const ui::Layer& layer);

   private:
    ImageGrid* grid_;  // not owned

    DISALLOW_COPY_AND_ASSIGN(TestAPI);
  };

  explicit ImageGrid(aura::Window* window);
  ~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::Image* image) : image_(image) {}
    virtual ~ImagePainter() {}

    // 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:
    virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;

   private:
    friend class TestAPI;

    const gfx::Image* image_;  // not owned

    gfx::Rect clip_rect_;

    DISALLOW_COPY_AND_ASSIGN(ImagePainter);
  };

  // Returns the dimensions of |image| if non-NULL or gfx::Size(0, 0) otherwise.
  static gfx::Size GetImageSize(const gfx::Image* image);

  // Returns true if |layer|'s bounds don't fit within |size|.
  static bool LayerExceedsSize(const ui::Layer* layer, const gfx::Size& size);

  // 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_|.
  void SetImage(const gfx::Image* image,
                scoped_ptr<ui::Layer>* layer_ptr,
                scoped_ptr<ImagePainter>* painter_ptr);

  // A possibly-arbitrary window that is drawn at the same DPI
  // (i.e. on the same monitor) as this grid.
  // TODO(oshima): move scale factor to ui/compositor/ and remove this.
  aura::Window* window_;

  // 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 internal
}  // namespace ash

#endif  // ASH_WM_IMAGE_GRID_H_