Use temporary zoom level for virtual keyboard.
[chromium-blink-merge.git] / skia / ext / pixel_ref_utils.cc
blob7029d46ff6b6eccd9e3b827966753f5f8edc4b38
1 // Copyright 2014 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.
5 #include "skia/ext/pixel_ref_utils.h"
7 #include <algorithm>
9 #include "third_party/skia/include/core/SkBitmapDevice.h"
10 #include "third_party/skia/include/core/SkCanvas.h"
11 #include "third_party/skia/include/core/SkData.h"
12 #include "third_party/skia/include/core/SkDraw.h"
13 #include "third_party/skia/include/core/SkPixelRef.h"
14 #include "third_party/skia/include/core/SkRRect.h"
15 #include "third_party/skia/include/core/SkRect.h"
16 #include "third_party/skia/include/core/SkShader.h"
17 #include "third_party/skia/include/utils/SkNoSaveLayerCanvas.h"
18 #include "third_party/skia/src/core/SkRasterClip.h"
20 namespace skia {
22 namespace {
24 // URI label for a discardable SkPixelRef.
25 const char kLabelDiscardable[] = "discardable";
27 class DiscardablePixelRefSet {
28 public:
29 DiscardablePixelRefSet(
30 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs)
31 : pixel_refs_(pixel_refs) {}
33 void Add(SkPixelRef* pixel_ref, const SkRect& rect) {
34 // Only save discardable pixel refs.
35 if (pixel_ref->getURI() &&
36 !strcmp(pixel_ref->getURI(), kLabelDiscardable)) {
37 PixelRefUtils::PositionPixelRef position_pixel_ref;
38 position_pixel_ref.pixel_ref = pixel_ref;
39 position_pixel_ref.pixel_ref_rect = rect;
40 pixel_refs_->push_back(position_pixel_ref);
44 private:
45 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs_;
48 class GatherPixelRefDevice : public SkBitmapDevice {
49 public:
50 GatherPixelRefDevice(const SkBitmap& bm,
51 DiscardablePixelRefSet* pixel_ref_set)
52 : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
54 void drawPaint(const SkDraw& draw, const SkPaint& paint) override {
55 SkBitmap bitmap;
56 if (GetBitmapFromPaint(paint, &bitmap)) {
57 SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
58 AddBitmap(bitmap, clip_rect);
62 void drawPoints(const SkDraw& draw,
63 SkCanvas::PointMode mode,
64 size_t count,
65 const SkPoint points[],
66 const SkPaint& paint) override {
67 SkBitmap bitmap;
68 if (!GetBitmapFromPaint(paint, &bitmap))
69 return;
71 if (count == 0)
72 return;
74 SkPoint min_point = points[0];
75 SkPoint max_point = points[0];
76 for (size_t i = 1; i < count; ++i) {
77 const SkPoint& point = points[i];
78 min_point.set(std::min(min_point.x(), point.x()),
79 std::min(min_point.y(), point.y()));
80 max_point.set(std::max(max_point.x(), point.x()),
81 std::max(max_point.y(), point.y()));
84 SkRect bounds = SkRect::MakeLTRB(
85 min_point.x(), min_point.y(), max_point.x(), max_point.y());
87 GatherPixelRefDevice::drawRect(draw, bounds, paint);
89 void drawRect(const SkDraw& draw,
90 const SkRect& rect,
91 const SkPaint& paint) override {
92 SkBitmap bitmap;
93 if (GetBitmapFromPaint(paint, &bitmap)) {
94 SkRect mapped_rect;
95 draw.fMatrix->mapRect(&mapped_rect, rect);
96 if (mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds())))
97 AddBitmap(bitmap, mapped_rect);
100 void drawOval(const SkDraw& draw,
101 const SkRect& rect,
102 const SkPaint& paint) override {
103 GatherPixelRefDevice::drawRect(draw, rect, paint);
105 void drawRRect(const SkDraw& draw,
106 const SkRRect& rect,
107 const SkPaint& paint) override {
108 GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
110 void drawPath(const SkDraw& draw,
111 const SkPath& path,
112 const SkPaint& paint,
113 const SkMatrix* pre_path_matrix,
114 bool path_is_mutable) override {
115 SkBitmap bitmap;
116 if (!GetBitmapFromPaint(paint, &bitmap))
117 return;
119 SkRect path_bounds = path.getBounds();
120 SkRect final_rect;
121 if (pre_path_matrix != NULL)
122 pre_path_matrix->mapRect(&final_rect, path_bounds);
123 else
124 final_rect = path_bounds;
126 GatherPixelRefDevice::drawRect(draw, final_rect, paint);
128 void drawBitmap(const SkDraw& draw,
129 const SkBitmap& bitmap,
130 const SkMatrix& matrix,
131 const SkPaint& paint) override {
132 SkMatrix total_matrix;
133 total_matrix.setConcat(*draw.fMatrix, matrix);
135 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
136 SkRect mapped_rect;
137 total_matrix.mapRect(&mapped_rect, bitmap_rect);
138 AddBitmap(bitmap, mapped_rect);
140 SkBitmap paint_bitmap;
141 if (GetBitmapFromPaint(paint, &paint_bitmap))
142 AddBitmap(paint_bitmap, mapped_rect);
144 void drawBitmapRect(const SkDraw& draw,
145 const SkBitmap& bitmap,
146 const SkRect* src_or_null,
147 const SkRect& dst,
148 const SkPaint& paint,
149 SkCanvas::DrawBitmapRectFlags flags) override {
150 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
151 SkMatrix matrix;
152 matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
153 GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint);
155 void drawSprite(const SkDraw& draw,
156 const SkBitmap& bitmap,
157 int x,
158 int y,
159 const SkPaint& paint) override {
160 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
161 SkMatrix matrix;
162 matrix.setTranslate(x, y);
164 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
165 SkRect mapped_rect;
166 matrix.mapRect(&mapped_rect, bitmap_rect);
168 AddBitmap(bitmap, mapped_rect);
169 SkBitmap paint_bitmap;
170 if (GetBitmapFromPaint(paint, &paint_bitmap))
171 AddBitmap(paint_bitmap, mapped_rect);
173 void drawText(const SkDraw& draw,
174 const void* text,
175 size_t len,
176 SkScalar x,
177 SkScalar y,
178 const SkPaint& paint) override {
179 SkBitmap bitmap;
180 if (!GetBitmapFromPaint(paint, &bitmap))
181 return;
183 // Math is borrowed from SkBBoxRecord
184 SkRect bounds;
185 paint.measureText(text, len, &bounds);
186 SkPaint::FontMetrics metrics;
187 paint.getFontMetrics(&metrics);
189 if (paint.isVerticalText()) {
190 SkScalar h = bounds.fBottom - bounds.fTop;
191 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
192 bounds.fTop -= h / 2;
193 bounds.fBottom -= h / 2;
195 bounds.fBottom += metrics.fBottom;
196 bounds.fTop += metrics.fTop;
197 } else {
198 SkScalar w = bounds.fRight - bounds.fLeft;
199 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
200 bounds.fLeft -= w / 2;
201 bounds.fRight -= w / 2;
202 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
203 bounds.fLeft -= w;
204 bounds.fRight -= w;
206 bounds.fTop = metrics.fTop;
207 bounds.fBottom = metrics.fBottom;
210 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
211 bounds.fLeft -= pad;
212 bounds.fRight += pad;
213 bounds.fLeft += x;
214 bounds.fRight += x;
215 bounds.fTop += y;
216 bounds.fBottom += y;
218 GatherPixelRefDevice::drawRect(draw, bounds, paint);
220 void drawPosText(const SkDraw& draw,
221 const void* text,
222 size_t len,
223 const SkScalar pos[],
224 int scalars_per_pos,
225 const SkPoint& offset,
226 const SkPaint& paint) override {
227 SkBitmap bitmap;
228 if (!GetBitmapFromPaint(paint, &bitmap))
229 return;
231 if (len == 0)
232 return;
234 // Similar to SkDraw asserts.
235 SkASSERT(scalars_per_pos == 1 || scalars_per_pos == 2);
237 SkPoint min_point = SkPoint::Make(offset.x() + pos[0],
238 offset.y() + (2 == scalars_per_pos ? pos[1] : 0));
239 SkPoint max_point = min_point;
241 for (size_t i = 0; i < len; ++i) {
242 SkScalar x = offset.x() + pos[i * scalars_per_pos];
243 SkScalar y = offset.y() + (2 == scalars_per_pos ? pos[i * scalars_per_pos + 1] : 0);
245 min_point.set(std::min(x, min_point.x()), std::min(y, min_point.y()));
246 max_point.set(std::max(x, max_point.x()), std::max(y, max_point.y()));
249 SkRect bounds = SkRect::MakeLTRB(
250 min_point.x(), min_point.y(), max_point.x(), max_point.y());
252 // Math is borrowed from SkBBoxRecord
253 SkPaint::FontMetrics metrics;
254 paint.getFontMetrics(&metrics);
256 bounds.fTop += metrics.fTop;
257 bounds.fBottom += metrics.fBottom;
259 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
260 bounds.fLeft += pad;
261 bounds.fRight -= pad;
263 GatherPixelRefDevice::drawRect(draw, bounds, paint);
265 void drawTextOnPath(const SkDraw& draw,
266 const void* text,
267 size_t len,
268 const SkPath& path,
269 const SkMatrix* matrix,
270 const SkPaint& paint) override {
271 SkBitmap bitmap;
272 if (!GetBitmapFromPaint(paint, &bitmap))
273 return;
275 // Math is borrowed from SkBBoxRecord
276 SkRect bounds = path.getBounds();
277 SkPaint::FontMetrics metrics;
278 paint.getFontMetrics(&metrics);
280 SkScalar pad = metrics.fTop;
281 bounds.fLeft += pad;
282 bounds.fRight -= pad;
283 bounds.fTop += pad;
284 bounds.fBottom -= pad;
286 GatherPixelRefDevice::drawRect(draw, bounds, paint);
288 void drawVertices(const SkDraw& draw,
289 SkCanvas::VertexMode,
290 int vertex_count,
291 const SkPoint verts[],
292 const SkPoint texs[],
293 const SkColor colors[],
294 SkXfermode* xmode,
295 const uint16_t indices[],
296 int index_count,
297 const SkPaint& paint) override {
298 GatherPixelRefDevice::drawPoints(
299 draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
301 void drawDevice(const SkDraw&,
302 SkBaseDevice*,
303 int x,
304 int y,
305 const SkPaint&) override {}
307 protected:
308 bool onReadPixels(const SkImageInfo& info,
309 void* pixels,
310 size_t rowBytes,
311 int x,
312 int y) override {
313 return false;
316 bool onWritePixels(const SkImageInfo& info,
317 const void* pixels,
318 size_t rowBytes,
319 int x,
320 int y) override {
321 return false;
324 private:
325 DiscardablePixelRefSet* pixel_ref_set_;
327 void AddBitmap(const SkBitmap& bm, const SkRect& rect) {
328 SkRect canvas_rect = SkRect::MakeWH(width(), height());
329 SkRect paint_rect = SkRect::MakeEmpty();
330 if (paint_rect.intersect(rect, canvas_rect))
331 pixel_ref_set_->Add(bm.pixelRef(), paint_rect);
334 bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) {
335 SkShader* shader = paint.getShader();
336 if (shader) {
337 // Check whether the shader is a gradient in order to prevent generation
338 // of bitmaps from gradient shaders, which implement asABitmap.
339 if (SkShader::kNone_GradientType == shader->asAGradient(NULL))
340 return shader->asABitmap(bm, NULL, NULL);
342 return false;
346 } // namespace
348 void PixelRefUtils::GatherDiscardablePixelRefs(
349 SkPicture* picture,
350 std::vector<PositionPixelRef>* pixel_refs) {
351 pixel_refs->clear();
352 DiscardablePixelRefSet pixel_ref_set(pixel_refs);
354 SkRect picture_bounds = picture->cullRect();
355 SkIRect picture_ibounds = picture_bounds.roundOut();
356 SkBitmap empty_bitmap;
357 empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture_ibounds.width(),
358 picture_ibounds.height()));
360 GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
361 SkNoSaveLayerCanvas canvas(&device);
363 // Draw the picture pinned against our top/left corner.
364 canvas.translate(-picture_bounds.left(), -picture_bounds.top());
365 canvas.drawPicture(picture);
368 } // namespace skia