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"
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"
24 // URI label for a discardable SkPixelRef.
25 const char kLabelDiscardable[] = "discardable";
27 class DiscardablePixelRefSet {
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);
45 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs_;
48 class GatherPixelRefDevice : public SkBitmapDevice {
50 GatherPixelRefDevice(const SkBitmap& bm,
51 DiscardablePixelRefSet* pixel_ref_set)
52 : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
54 void clear(SkColor color) override {}
55 void drawPaint(const SkDraw& draw, const SkPaint& paint) override {
57 if (GetBitmapFromPaint(paint, &bitmap)) {
58 SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
59 AddBitmap(bitmap, clip_rect);
63 void drawPoints(const SkDraw& draw,
64 SkCanvas::PointMode mode,
66 const SkPoint points[],
67 const SkPaint& paint) override {
69 if (!GetBitmapFromPaint(paint, &bitmap))
75 SkPoint min_point = points[0];
76 SkPoint max_point = points[0];
77 for (size_t i = 1; i < count; ++i) {
78 const SkPoint& point = points[i];
79 min_point.set(std::min(min_point.x(), point.x()),
80 std::min(min_point.y(), point.y()));
81 max_point.set(std::max(max_point.x(), point.x()),
82 std::max(max_point.y(), point.y()));
85 SkRect bounds = SkRect::MakeLTRB(
86 min_point.x(), min_point.y(), max_point.x(), max_point.y());
88 GatherPixelRefDevice::drawRect(draw, bounds, paint);
90 void drawRect(const SkDraw& draw,
92 const SkPaint& paint) override {
94 if (GetBitmapFromPaint(paint, &bitmap)) {
96 draw.fMatrix->mapRect(&mapped_rect, rect);
97 mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds()));
98 AddBitmap(bitmap, mapped_rect);
101 void drawOval(const SkDraw& draw,
103 const SkPaint& paint) override {
104 GatherPixelRefDevice::drawRect(draw, rect, paint);
106 void drawRRect(const SkDraw& draw,
108 const SkPaint& paint) override {
109 GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
111 void drawPath(const SkDraw& draw,
113 const SkPaint& paint,
114 const SkMatrix* pre_path_matrix,
115 bool path_is_mutable) override {
117 if (!GetBitmapFromPaint(paint, &bitmap))
120 SkRect path_bounds = path.getBounds();
122 if (pre_path_matrix != NULL)
123 pre_path_matrix->mapRect(&final_rect, path_bounds);
125 final_rect = path_bounds;
127 GatherPixelRefDevice::drawRect(draw, final_rect, paint);
129 void drawBitmap(const SkDraw& draw,
130 const SkBitmap& bitmap,
131 const SkMatrix& matrix,
132 const SkPaint& paint) override {
133 SkMatrix total_matrix;
134 total_matrix.setConcat(*draw.fMatrix, matrix);
136 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
138 total_matrix.mapRect(&mapped_rect, bitmap_rect);
139 AddBitmap(bitmap, mapped_rect);
141 SkBitmap paint_bitmap;
142 if (GetBitmapFromPaint(paint, &paint_bitmap))
143 AddBitmap(paint_bitmap, mapped_rect);
145 void drawBitmapRect(const SkDraw& draw,
146 const SkBitmap& bitmap,
147 const SkRect* src_or_null,
149 const SkPaint& paint,
150 SkCanvas::DrawBitmapRectFlags flags) override {
151 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
153 matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
154 GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint);
156 void drawSprite(const SkDraw& draw,
157 const SkBitmap& bitmap,
160 const SkPaint& paint) override {
161 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
163 matrix.setTranslate(x, y);
165 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
167 matrix.mapRect(&mapped_rect, bitmap_rect);
169 AddBitmap(bitmap, mapped_rect);
170 SkBitmap paint_bitmap;
171 if (GetBitmapFromPaint(paint, &paint_bitmap))
172 AddBitmap(paint_bitmap, mapped_rect);
174 void drawText(const SkDraw& draw,
179 const SkPaint& paint) override {
181 if (!GetBitmapFromPaint(paint, &bitmap))
184 // Math is borrowed from SkBBoxRecord
186 paint.measureText(text, len, &bounds);
187 SkPaint::FontMetrics metrics;
188 paint.getFontMetrics(&metrics);
190 if (paint.isVerticalText()) {
191 SkScalar h = bounds.fBottom - bounds.fTop;
192 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
193 bounds.fTop -= h / 2;
194 bounds.fBottom -= h / 2;
196 bounds.fBottom += metrics.fBottom;
197 bounds.fTop += metrics.fTop;
199 SkScalar w = bounds.fRight - bounds.fLeft;
200 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
201 bounds.fLeft -= w / 2;
202 bounds.fRight -= w / 2;
203 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
207 bounds.fTop = metrics.fTop;
208 bounds.fBottom = metrics.fBottom;
211 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
213 bounds.fRight += pad;
219 GatherPixelRefDevice::drawRect(draw, bounds, paint);
221 void drawPosText(const SkDraw& draw,
224 const SkScalar pos[],
226 const SkPoint& offset,
227 const SkPaint& paint) override {
229 if (!GetBitmapFromPaint(paint, &bitmap))
235 // Similar to SkDraw asserts.
236 SkASSERT(scalars_per_pos == 1 || scalars_per_pos == 2);
238 SkPoint min_point = SkPoint::Make(offset.x() + pos[0],
239 offset.y() + (2 == scalars_per_pos ? pos[1] : 0));
240 SkPoint max_point = min_point;
242 for (size_t i = 0; i < len; ++i) {
243 SkScalar x = offset.x() + pos[i * scalars_per_pos];
244 SkScalar y = offset.y() + (2 == scalars_per_pos ? pos[i * scalars_per_pos + 1] : 0);
246 min_point.set(std::min(x, min_point.x()), std::min(y, min_point.y()));
247 max_point.set(std::max(x, max_point.x()), std::max(y, max_point.y()));
250 SkRect bounds = SkRect::MakeLTRB(
251 min_point.x(), min_point.y(), max_point.x(), max_point.y());
253 // Math is borrowed from SkBBoxRecord
254 SkPaint::FontMetrics metrics;
255 paint.getFontMetrics(&metrics);
257 bounds.fTop += metrics.fTop;
258 bounds.fBottom += metrics.fBottom;
260 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
262 bounds.fRight -= pad;
264 GatherPixelRefDevice::drawRect(draw, bounds, paint);
266 void drawTextOnPath(const SkDraw& draw,
270 const SkMatrix* matrix,
271 const SkPaint& paint) override {
273 if (!GetBitmapFromPaint(paint, &bitmap))
276 // Math is borrowed from SkBBoxRecord
277 SkRect bounds = path.getBounds();
278 SkPaint::FontMetrics metrics;
279 paint.getFontMetrics(&metrics);
281 SkScalar pad = metrics.fTop;
283 bounds.fRight -= pad;
285 bounds.fBottom -= pad;
287 GatherPixelRefDevice::drawRect(draw, bounds, paint);
289 void drawVertices(const SkDraw& draw,
290 SkCanvas::VertexMode,
292 const SkPoint verts[],
293 const SkPoint texs[],
294 const SkColor colors[],
296 const uint16_t indices[],
298 const SkPaint& paint) override {
299 GatherPixelRefDevice::drawPoints(
300 draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
302 void drawDevice(const SkDraw&,
306 const SkPaint&) override {}
309 bool onReadPixels(const SkImageInfo& info,
317 bool onWritePixels(const SkImageInfo& info,
326 DiscardablePixelRefSet* pixel_ref_set_;
328 void AddBitmap(const SkBitmap& bm, const SkRect& rect) {
329 SkRect canvas_rect = SkRect::MakeWH(width(), height());
330 SkRect paint_rect = SkRect::MakeEmpty();
331 paint_rect.intersect(rect, canvas_rect);
332 pixel_ref_set_->Add(bm.pixelRef(), paint_rect);
335 bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) {
336 SkShader* shader = paint.getShader();
338 // Check whether the shader is a gradient in order to prevent generation
339 // of bitmaps from gradient shaders, which implement asABitmap.
340 if (SkShader::kNone_GradientType == shader->asAGradient(NULL))
341 return shader->asABitmap(bm, NULL, NULL);
349 void PixelRefUtils::GatherDiscardablePixelRefs(
351 std::vector<PositionPixelRef>* pixel_refs) {
353 DiscardablePixelRefSet pixel_ref_set(pixel_refs);
355 SkBitmap empty_bitmap;
356 empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture->width(), picture->height()));
358 GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
359 SkNoSaveLayerCanvas canvas(&device);
361 canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()),
362 SkRegion::kIntersect_Op,
364 canvas.drawPicture(picture);