Add some UMAs for offline pages
[chromium-blink-merge.git] / skia / ext / pixel_ref_utils.cc
blob46a2a73200eb44395a190018fdaad7b3b659cac4
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/SkPath.h"
14 #include "third_party/skia/include/core/SkPixelRef.h"
15 #include "third_party/skia/include/core/SkRRect.h"
16 #include "third_party/skia/include/core/SkRect.h"
17 #include "third_party/skia/include/core/SkShader.h"
18 #include "third_party/skia/include/core/SkTextBlob.h"
19 #include "third_party/skia/include/utils/SkNoSaveLayerCanvas.h"
20 #include "third_party/skia/src/core/SkRasterClip.h"
22 namespace skia {
24 namespace {
26 class DiscardablePixelRefSet {
27 public:
28 DiscardablePixelRefSet(
29 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs)
30 : pixel_refs_(pixel_refs) {}
32 void Add(SkPixelRef* pixel_ref,
33 const SkRect& rect,
34 const SkMatrix& matrix,
35 SkFilterQuality filter_quality) {
36 // We should only be saving discardable pixel refs.
37 SkASSERT(pixel_ref);
38 SkASSERT(pixel_ref->isLazyGenerated());
40 PixelRefUtils::PositionPixelRef position_pixel_ref;
41 position_pixel_ref.pixel_ref = pixel_ref;
42 position_pixel_ref.pixel_ref_rect = rect;
43 position_pixel_ref.matrix = matrix;
44 position_pixel_ref.filter_quality = filter_quality;
45 pixel_refs_->push_back(position_pixel_ref);
48 private:
49 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs_;
52 class GatherPixelRefDevice : public SkBitmapDevice {
53 public:
54 GatherPixelRefDevice(const SkBitmap& bm,
55 DiscardablePixelRefSet* pixel_ref_set)
56 : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
58 void drawPaint(const SkDraw& draw, const SkPaint& paint) override {
59 SkBitmap bitmap;
60 if (GetBitmapFromPaint(paint, &bitmap)) {
61 SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
62 AddBitmap(bitmap, clip_rect, *draw.fMatrix, paint.getFilterQuality());
66 void drawPoints(const SkDraw& draw,
67 SkCanvas::PointMode mode,
68 size_t count,
69 const SkPoint points[],
70 const SkPaint& paint) override {
71 SkBitmap bitmap;
72 if (!GetBitmapFromPaint(paint, &bitmap))
73 return;
75 if (count == 0)
76 return;
78 SkPoint min_point = points[0];
79 SkPoint max_point = points[0];
80 for (size_t i = 1; i < count; ++i) {
81 const SkPoint& point = points[i];
82 min_point.set(std::min(min_point.x(), point.x()),
83 std::min(min_point.y(), point.y()));
84 max_point.set(std::max(max_point.x(), point.x()),
85 std::max(max_point.y(), point.y()));
88 SkRect bounds = SkRect::MakeLTRB(
89 min_point.x(), min_point.y(), max_point.x(), max_point.y());
91 GatherPixelRefDevice::drawRect(draw, bounds, paint);
93 void drawRect(const SkDraw& draw,
94 const SkRect& rect,
95 const SkPaint& paint) override {
96 SkBitmap bitmap;
97 if (GetBitmapFromPaint(paint, &bitmap)) {
98 SkRect mapped_rect;
99 draw.fMatrix->mapRect(&mapped_rect, rect);
100 if (mapped_rect.intersects(SkRect::Make(draw.fRC->getBounds()))) {
101 AddBitmap(bitmap, mapped_rect, *draw.fMatrix, paint.getFilterQuality());
105 void drawOval(const SkDraw& draw,
106 const SkRect& rect,
107 const SkPaint& paint) override {
108 GatherPixelRefDevice::drawRect(draw, rect, paint);
110 void drawRRect(const SkDraw& draw,
111 const SkRRect& rect,
112 const SkPaint& paint) override {
113 GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
115 void drawPath(const SkDraw& draw,
116 const SkPath& path,
117 const SkPaint& paint,
118 const SkMatrix* pre_path_matrix,
119 bool path_is_mutable) override {
120 SkBitmap bitmap;
121 if (!GetBitmapFromPaint(paint, &bitmap))
122 return;
124 SkRect path_bounds = path.getBounds();
125 SkRect final_rect;
126 if (pre_path_matrix != NULL)
127 pre_path_matrix->mapRect(&final_rect, path_bounds);
128 else
129 final_rect = path_bounds;
131 GatherPixelRefDevice::drawRect(draw, final_rect, paint);
133 void drawBitmap(const SkDraw& draw,
134 const SkBitmap& bitmap,
135 const SkMatrix& matrix,
136 const SkPaint& paint) override {
137 SkMatrix total_matrix;
138 total_matrix.setConcat(*draw.fMatrix, matrix);
140 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
141 SkRect mapped_rect;
142 total_matrix.mapRect(&mapped_rect, bitmap_rect);
143 AddBitmap(bitmap, mapped_rect, total_matrix, paint.getFilterQuality());
145 SkBitmap paint_bitmap;
146 if (GetBitmapFromPaint(paint, &paint_bitmap)) {
147 AddBitmap(paint_bitmap, mapped_rect, total_matrix,
148 paint.getFilterQuality());
151 void drawBitmapRect(const SkDraw& draw,
152 const SkBitmap& bitmap,
153 const SkRect* src_or_null,
154 const SkRect& dst,
155 const SkPaint& paint,
156 SkCanvas::SrcRectConstraint) override {
157 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
158 SkMatrix matrix;
159 matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
160 GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint);
162 void drawSprite(const SkDraw& draw,
163 const SkBitmap& bitmap,
164 int x,
165 int y,
166 const SkPaint& paint) override {
167 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
168 SkMatrix matrix;
169 matrix.setTranslate(x, y);
171 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
172 SkRect mapped_rect;
173 matrix.mapRect(&mapped_rect, bitmap_rect);
175 SkMatrix identity;
176 identity.setIdentity();
177 // Sprites aren't affected by current matrix, so use the identity matrix.
178 AddBitmap(bitmap, mapped_rect, identity, paint.getFilterQuality());
179 SkBitmap paint_bitmap;
180 if (GetBitmapFromPaint(paint, &paint_bitmap))
181 AddBitmap(paint_bitmap, mapped_rect, identity, paint.getFilterQuality());
183 void drawImage(const SkDraw& draw,
184 const SkImage* image,
185 SkScalar x,
186 SkScalar y,
187 const SkPaint& paint) override {
188 const SkMatrix image_matrix = SkMatrix::MakeTrans(x, y);
189 DrawImageInternal(draw, image, image_matrix, paint);
191 void drawImageRect(const SkDraw& draw,
192 const SkImage* image,
193 const SkRect* src_or_null,
194 const SkRect& dst,
195 const SkPaint& paint,
196 SkCanvas::SrcRectConstraint) override {
197 const SkRect src = src_or_null
198 ? *src_or_null
199 : SkRect::MakeIWH(image->width(), image->height());
200 const SkMatrix image_matrix =
201 SkMatrix::MakeRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
202 DrawImageInternal(draw, image, image_matrix, paint);
204 void drawText(const SkDraw& draw,
205 const void* text,
206 size_t len,
207 SkScalar x,
208 SkScalar y,
209 const SkPaint& paint) override {
210 SkBitmap bitmap;
211 if (!GetBitmapFromPaint(paint, &bitmap))
212 return;
214 // Math is borrowed from SkBBoxRecord
215 SkRect bounds;
216 paint.measureText(text, len, &bounds);
217 SkPaint::FontMetrics metrics;
218 paint.getFontMetrics(&metrics);
220 if (paint.isVerticalText()) {
221 SkScalar h = bounds.fBottom - bounds.fTop;
222 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
223 bounds.fTop -= h / 2;
224 bounds.fBottom -= h / 2;
226 bounds.fBottom += metrics.fBottom;
227 bounds.fTop += metrics.fTop;
228 } else {
229 SkScalar w = bounds.fRight - bounds.fLeft;
230 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
231 bounds.fLeft -= w / 2;
232 bounds.fRight -= w / 2;
233 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
234 bounds.fLeft -= w;
235 bounds.fRight -= w;
237 bounds.fTop = metrics.fTop;
238 bounds.fBottom = metrics.fBottom;
241 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
242 bounds.fLeft -= pad;
243 bounds.fRight += pad;
244 bounds.fLeft += x;
245 bounds.fRight += x;
246 bounds.fTop += y;
247 bounds.fBottom += y;
249 GatherPixelRefDevice::drawRect(draw, bounds, paint);
251 void drawPosText(const SkDraw& draw,
252 const void* text,
253 size_t len,
254 const SkScalar pos[],
255 int scalars_per_pos,
256 const SkPoint& offset,
257 const SkPaint& paint) override {
258 SkBitmap bitmap;
259 if (!GetBitmapFromPaint(paint, &bitmap))
260 return;
262 if (len == 0)
263 return;
265 // Similar to SkDraw asserts.
266 SkASSERT(scalars_per_pos == 1 || scalars_per_pos == 2);
268 SkPoint min_point = SkPoint::Make(offset.x() + pos[0],
269 offset.y() + (2 == scalars_per_pos ? pos[1] : 0));
270 SkPoint max_point = min_point;
272 for (size_t i = 0; i < len; ++i) {
273 SkScalar x = offset.x() + pos[i * scalars_per_pos];
274 SkScalar y = offset.y() + (2 == scalars_per_pos ? pos[i * scalars_per_pos + 1] : 0);
276 min_point.set(std::min(x, min_point.x()), std::min(y, min_point.y()));
277 max_point.set(std::max(x, max_point.x()), std::max(y, max_point.y()));
280 SkRect bounds = SkRect::MakeLTRB(
281 min_point.x(), min_point.y(), max_point.x(), max_point.y());
283 // Math is borrowed from SkBBoxRecord
284 SkPaint::FontMetrics metrics;
285 paint.getFontMetrics(&metrics);
287 bounds.fTop += metrics.fTop;
288 bounds.fBottom += metrics.fBottom;
290 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
291 bounds.fLeft += pad;
292 bounds.fRight -= pad;
294 GatherPixelRefDevice::drawRect(draw, bounds, paint);
296 void drawTextOnPath(const SkDraw& draw,
297 const void* text,
298 size_t len,
299 const SkPath& path,
300 const SkMatrix* matrix,
301 const SkPaint& paint) override {
302 SkBitmap bitmap;
303 if (!GetBitmapFromPaint(paint, &bitmap))
304 return;
306 // Math is borrowed from SkBBoxRecord
307 SkRect bounds = path.getBounds();
308 SkPaint::FontMetrics metrics;
309 paint.getFontMetrics(&metrics);
311 SkScalar pad = metrics.fTop;
312 bounds.fLeft += pad;
313 bounds.fRight -= pad;
314 bounds.fTop += pad;
315 bounds.fBottom -= pad;
317 GatherPixelRefDevice::drawRect(draw, bounds, paint);
319 void drawTextBlob(const SkDraw& draw,
320 const SkTextBlob* blob,
321 SkScalar x, SkScalar y,
322 const SkPaint& paint,
323 SkDrawFilter*) override {
324 SkBitmap bitmap;
325 if (!GetBitmapFromPaint(paint, &bitmap))
326 return;
328 const SkRect bounds = blob->bounds().makeOffset(x, y);
329 GatherPixelRefDevice::drawRect(draw, bounds, paint);
332 void drawVertices(const SkDraw& draw,
333 SkCanvas::VertexMode,
334 int vertex_count,
335 const SkPoint verts[],
336 const SkPoint texs[],
337 const SkColor colors[],
338 SkXfermode* xmode,
339 const uint16_t indices[],
340 int index_count,
341 const SkPaint& paint) override {
342 GatherPixelRefDevice::drawPoints(
343 draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
345 void drawDevice(const SkDraw&,
346 SkBaseDevice*,
347 int x,
348 int y,
349 const SkPaint&) override {}
351 protected:
352 bool onReadPixels(const SkImageInfo& info,
353 void* pixels,
354 size_t rowBytes,
355 int x,
356 int y) override {
357 return false;
360 bool onWritePixels(const SkImageInfo& info,
361 const void* pixels,
362 size_t rowBytes,
363 int x,
364 int y) override {
365 return false;
368 private:
369 DiscardablePixelRefSet* pixel_ref_set_;
371 void AddBitmap(const SkBitmap& bm,
372 const SkRect& rect,
373 const SkMatrix& matrix,
374 SkFilterQuality filter_quality) {
375 const SkRect canvas_rect = SkRect::Make(imageInfo().bounds());
376 if (rect.intersects(canvas_rect) && bm.pixelRef()->isLazyGenerated()) {
377 pixel_ref_set_->Add(bm.pixelRef(), rect, matrix, filter_quality);
381 void AddImage(const SkImage* image,
382 const SkRect& rect,
383 const SkMatrix& matrix,
384 SkFilterQuality filter_quality) {
385 const SkRect canvas_rect = SkRect::Make(imageInfo().bounds());
386 if (rect.intersects(canvas_rect) && image->isLazyGenerated()) {
387 SkBitmap bm;
388 if (image->asLegacyBitmap(&bm, SkImage::kRO_LegacyBitmapMode) && bm.pixelRef()) {
389 pixel_ref_set_->Add(bm.pixelRef(), rect, matrix, filter_quality);
394 bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) {
395 SkShader* shader = paint.getShader();
396 if (shader) {
397 // Check whether the shader is a gradient in order to prevent generation
398 // of bitmaps from gradient shaders, which implement asABitmap.
399 if (SkShader::kNone_GradientType == shader->asAGradient(NULL))
400 return shader->asABitmap(bm, NULL, NULL);
402 return false;
405 void DrawImageInternal(const SkDraw& draw,
406 const SkImage* image,
407 const SkMatrix& matrix,
408 const SkPaint& paint) {
409 const SkMatrix total_matrix = SkMatrix::Concat(*draw.fMatrix, matrix);
410 const SkRect image_rect = SkRect::MakeIWH(image->width(), image->height());
411 SkRect mapped_rect;
412 total_matrix.mapRect(&mapped_rect, image_rect);
413 AddImage(image, mapped_rect, total_matrix, paint.getFilterQuality());
415 SkBitmap paint_bitmap;
416 if (GetBitmapFromPaint(paint, &paint_bitmap)) {
417 AddBitmap(paint_bitmap, mapped_rect, total_matrix,
418 paint.getFilterQuality());
423 } // namespace
425 void PixelRefUtils::GatherDiscardablePixelRefs(
426 SkPicture* picture,
427 std::vector<PositionPixelRef>* pixel_refs) {
428 pixel_refs->clear();
429 DiscardablePixelRefSet pixel_ref_set(pixel_refs);
431 SkRect picture_bounds = picture->cullRect();
432 SkIRect picture_ibounds = picture_bounds.roundOut();
433 SkBitmap empty_bitmap;
434 // Use right/bottom as the size so that we don't need a translate and, as a
435 // result, the information is returned relative to the picture's origin.
436 empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture_ibounds.right(),
437 picture_ibounds.bottom()));
439 GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
440 SkNoSaveLayerCanvas canvas(&device);
442 canvas.drawPicture(picture);
445 } // namespace skia