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.
4
5 #include "skia/ext/pixel_ref_utils.h"
6
7 #include <algorithm>
8
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"
19
20 namespace skia {
21
22 namespace {
23
24 // URI label for a discardable SkPixelRef.
25 const char kLabelDiscardable[] = "discardable";
26
27 class DiscardablePixelRefSet {
28 public:
DiscardablePixelRefSet(std::vector<PixelRefUtils::PositionPixelRef> * pixel_refs)29 DiscardablePixelRefSet(
30 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs)
31 : pixel_refs_(pixel_refs) {}
32
Add(SkPixelRef * pixel_ref,const SkRect & rect)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);
41 }
42 }
43
44 private:
45 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs_;
46 };
47
48 class GatherPixelRefDevice : public SkBitmapDevice {
49 public:
GatherPixelRefDevice(const SkBitmap & bm,DiscardablePixelRefSet * pixel_ref_set)50 GatherPixelRefDevice(const SkBitmap& bm,
51 DiscardablePixelRefSet* pixel_ref_set)
52 : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
53
clear(SkColor color)54 virtual void clear(SkColor color) SK_OVERRIDE {}
drawPaint(const SkDraw & draw,const SkPaint & paint)55 virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
56 SkBitmap bitmap;
57 if (GetBitmapFromPaint(paint, &bitmap)) {
58 SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
59 AddBitmap(bitmap, clip_rect);
60 }
61 }
62
drawPoints(const SkDraw & draw,SkCanvas::PointMode mode,size_t count,const SkPoint points[],const SkPaint & paint)63 virtual void drawPoints(const SkDraw& draw,
64 SkCanvas::PointMode mode,
65 size_t count,
66 const SkPoint points[],
67 const SkPaint& paint) SK_OVERRIDE {
68 SkBitmap bitmap;
69 if (!GetBitmapFromPaint(paint, &bitmap))
70 return;
71
72 if (count == 0)
73 return;
74
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()));
83 }
84
85 SkRect bounds = SkRect::MakeLTRB(
86 min_point.x(), min_point.y(), max_point.x(), max_point.y());
87
88 GatherPixelRefDevice::drawRect(draw, bounds, paint);
89 }
drawRect(const SkDraw & draw,const SkRect & rect,const SkPaint & paint)90 virtual void drawRect(const SkDraw& draw,
91 const SkRect& rect,
92 const SkPaint& paint) SK_OVERRIDE {
93 SkBitmap bitmap;
94 if (GetBitmapFromPaint(paint, &bitmap)) {
95 SkRect mapped_rect;
96 draw.fMatrix->mapRect(&mapped_rect, rect);
97 mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds()));
98 AddBitmap(bitmap, mapped_rect);
99 }
100 }
drawOval(const SkDraw & draw,const SkRect & rect,const SkPaint & paint)101 virtual void drawOval(const SkDraw& draw,
102 const SkRect& rect,
103 const SkPaint& paint) SK_OVERRIDE {
104 GatherPixelRefDevice::drawRect(draw, rect, paint);
105 }
drawRRect(const SkDraw & draw,const SkRRect & rect,const SkPaint & paint)106 virtual void drawRRect(const SkDraw& draw,
107 const SkRRect& rect,
108 const SkPaint& paint) SK_OVERRIDE {
109 GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
110 }
drawPath(const SkDraw & draw,const SkPath & path,const SkPaint & paint,const SkMatrix * pre_path_matrix,bool path_is_mutable)111 virtual void drawPath(const SkDraw& draw,
112 const SkPath& path,
113 const SkPaint& paint,
114 const SkMatrix* pre_path_matrix,
115 bool path_is_mutable) SK_OVERRIDE {
116 SkBitmap bitmap;
117 if (!GetBitmapFromPaint(paint, &bitmap))
118 return;
119
120 SkRect path_bounds = path.getBounds();
121 SkRect final_rect;
122 if (pre_path_matrix != NULL)
123 pre_path_matrix->mapRect(&final_rect, path_bounds);
124 else
125 final_rect = path_bounds;
126
127 GatherPixelRefDevice::drawRect(draw, final_rect, paint);
128 }
drawBitmap(const SkDraw & draw,const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint & paint)129 virtual void drawBitmap(const SkDraw& draw,
130 const SkBitmap& bitmap,
131 const SkMatrix& matrix,
132 const SkPaint& paint) SK_OVERRIDE {
133 SkMatrix total_matrix;
134 total_matrix.setConcat(*draw.fMatrix, matrix);
135
136 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
137 SkRect mapped_rect;
138 total_matrix.mapRect(&mapped_rect, bitmap_rect);
139 AddBitmap(bitmap, mapped_rect);
140
141 SkBitmap paint_bitmap;
142 if (GetBitmapFromPaint(paint, &paint_bitmap))
143 AddBitmap(paint_bitmap, mapped_rect);
144 }
drawBitmapRect(const SkDraw & draw,const SkBitmap & bitmap,const SkRect * src_or_null,const SkRect & dst,const SkPaint & paint,SkCanvas::DrawBitmapRectFlags flags)145 virtual void drawBitmapRect(const SkDraw& draw,
146 const SkBitmap& bitmap,
147 const SkRect* src_or_null,
148 const SkRect& dst,
149 const SkPaint& paint,
150 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
151 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
152 SkMatrix matrix;
153 matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
154 GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint);
155 }
drawSprite(const SkDraw & draw,const SkBitmap & bitmap,int x,int y,const SkPaint & paint)156 virtual void drawSprite(const SkDraw& draw,
157 const SkBitmap& bitmap,
158 int x,
159 int y,
160 const SkPaint& paint) SK_OVERRIDE {
161 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
162 SkMatrix matrix;
163 matrix.setTranslate(x, y);
164
165 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
166 SkRect mapped_rect;
167 matrix.mapRect(&mapped_rect, bitmap_rect);
168
169 AddBitmap(bitmap, mapped_rect);
170 SkBitmap paint_bitmap;
171 if (GetBitmapFromPaint(paint, &paint_bitmap))
172 AddBitmap(paint_bitmap, mapped_rect);
173 }
drawText(const SkDraw & draw,const void * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)174 virtual void drawText(const SkDraw& draw,
175 const void* text,
176 size_t len,
177 SkScalar x,
178 SkScalar y,
179 const SkPaint& paint) SK_OVERRIDE {
180 SkBitmap bitmap;
181 if (!GetBitmapFromPaint(paint, &bitmap))
182 return;
183
184 // Math is borrowed from SkBBoxRecord
185 SkRect bounds;
186 paint.measureText(text, len, &bounds);
187 SkPaint::FontMetrics metrics;
188 paint.getFontMetrics(&metrics);
189
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;
195 }
196 bounds.fBottom += metrics.fBottom;
197 bounds.fTop += metrics.fTop;
198 } else {
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) {
204 bounds.fLeft -= w;
205 bounds.fRight -= w;
206 }
207 bounds.fTop = metrics.fTop;
208 bounds.fBottom = metrics.fBottom;
209 }
210
211 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
212 bounds.fLeft -= pad;
213 bounds.fRight += pad;
214 bounds.fLeft += x;
215 bounds.fRight += x;
216 bounds.fTop += y;
217 bounds.fBottom += y;
218
219 GatherPixelRefDevice::drawRect(draw, bounds, paint);
220 }
drawPosText(const SkDraw & draw,const void * text,size_t len,const SkScalar pos[],SkScalar const_y,int scalars_per_pos,const SkPaint & paint)221 virtual void drawPosText(const SkDraw& draw,
222 const void* text,
223 size_t len,
224 const SkScalar pos[],
225 SkScalar const_y,
226 int scalars_per_pos,
227 const SkPaint& paint) SK_OVERRIDE {
228 SkBitmap bitmap;
229 if (!GetBitmapFromPaint(paint, &bitmap))
230 return;
231
232 if (len == 0)
233 return;
234
235 // Similar to SkDraw asserts.
236 SkASSERT(scalars_per_pos == 1 || scalars_per_pos == 2);
237
238 SkPoint min_point;
239 SkPoint max_point;
240 if (scalars_per_pos == 1) {
241 min_point.set(pos[0], const_y);
242 max_point.set(pos[0], const_y);
243 } else if (scalars_per_pos == 2) {
244 min_point.set(pos[0], const_y + pos[1]);
245 max_point.set(pos[0], const_y + pos[1]);
246 }
247
248 for (size_t i = 0; i < len; ++i) {
249 SkScalar x = pos[i * scalars_per_pos];
250 SkScalar y = const_y;
251 if (scalars_per_pos == 2)
252 y += pos[i * scalars_per_pos + 1];
253
254 min_point.set(std::min(x, min_point.x()), std::min(y, min_point.y()));
255 max_point.set(std::max(x, max_point.x()), std::max(y, max_point.y()));
256 }
257
258 SkRect bounds = SkRect::MakeLTRB(
259 min_point.x(), min_point.y(), max_point.x(), max_point.y());
260
261 // Math is borrowed from SkBBoxRecord
262 SkPaint::FontMetrics metrics;
263 paint.getFontMetrics(&metrics);
264
265 bounds.fTop += metrics.fTop;
266 bounds.fBottom += metrics.fBottom;
267
268 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
269 bounds.fLeft += pad;
270 bounds.fRight -= pad;
271
272 GatherPixelRefDevice::drawRect(draw, bounds, paint);
273 }
drawTextOnPath(const SkDraw & draw,const void * text,size_t len,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)274 virtual void drawTextOnPath(const SkDraw& draw,
275 const void* text,
276 size_t len,
277 const SkPath& path,
278 const SkMatrix* matrix,
279 const SkPaint& paint) SK_OVERRIDE {
280 SkBitmap bitmap;
281 if (!GetBitmapFromPaint(paint, &bitmap))
282 return;
283
284 // Math is borrowed from SkBBoxRecord
285 SkRect bounds = path.getBounds();
286 SkPaint::FontMetrics metrics;
287 paint.getFontMetrics(&metrics);
288
289 SkScalar pad = metrics.fTop;
290 bounds.fLeft += pad;
291 bounds.fRight -= pad;
292 bounds.fTop += pad;
293 bounds.fBottom -= pad;
294
295 GatherPixelRefDevice::drawRect(draw, bounds, paint);
296 }
drawVertices(const SkDraw & draw,SkCanvas::VertexMode,int vertex_count,const SkPoint verts[],const SkPoint texs[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int index_count,const SkPaint & paint)297 virtual void drawVertices(const SkDraw& draw,
298 SkCanvas::VertexMode,
299 int vertex_count,
300 const SkPoint verts[],
301 const SkPoint texs[],
302 const SkColor colors[],
303 SkXfermode* xmode,
304 const uint16_t indices[],
305 int index_count,
306 const SkPaint& paint) SK_OVERRIDE {
307 GatherPixelRefDevice::drawPoints(
308 draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
309 }
drawDevice(const SkDraw &,SkBaseDevice *,int x,int y,const SkPaint &)310 virtual void drawDevice(const SkDraw&,
311 SkBaseDevice*,
312 int x,
313 int y,
314 const SkPaint&) SK_OVERRIDE {}
315
316 protected:
onReadPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,int x,int y)317 virtual bool onReadPixels(const SkImageInfo& info,
318 void* pixels,
319 size_t rowBytes,
320 int x,
321 int y) SK_OVERRIDE {
322 return false;
323 }
324
onWritePixels(const SkImageInfo & info,const void * pixels,size_t rowBytes,int x,int y)325 virtual bool onWritePixels(const SkImageInfo& info,
326 const void* pixels,
327 size_t rowBytes,
328 int x,
329 int y) SK_OVERRIDE {
330 return false;
331 }
332
333 private:
334 DiscardablePixelRefSet* pixel_ref_set_;
335
AddBitmap(const SkBitmap & bm,const SkRect & rect)336 void AddBitmap(const SkBitmap& bm, const SkRect& rect) {
337 SkRect canvas_rect = SkRect::MakeWH(width(), height());
338 SkRect paint_rect = SkRect::MakeEmpty();
339 paint_rect.intersect(rect, canvas_rect);
340 pixel_ref_set_->Add(bm.pixelRef(), paint_rect);
341 }
342
GetBitmapFromPaint(const SkPaint & paint,SkBitmap * bm)343 bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) {
344 SkShader* shader = paint.getShader();
345 if (shader) {
346 // Check whether the shader is a gradient in order to prevent generation
347 // of bitmaps from gradient shaders, which implement asABitmap.
348 if (SkShader::kNone_GradientType == shader->asAGradient(NULL))
349 return shader->asABitmap(bm, NULL, NULL);
350 }
351 return false;
352 }
353 };
354
355 } // namespace
356
GatherDiscardablePixelRefs(SkPicture * picture,std::vector<PositionPixelRef> * pixel_refs)357 void PixelRefUtils::GatherDiscardablePixelRefs(
358 SkPicture* picture,
359 std::vector<PositionPixelRef>* pixel_refs) {
360 pixel_refs->clear();
361 DiscardablePixelRefSet pixel_ref_set(pixel_refs);
362
363 SkBitmap empty_bitmap;
364 empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture->width(), picture->height()));
365
366 GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
367 SkNoSaveLayerCanvas canvas(&device);
368
369 canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()),
370 SkRegion::kIntersect_Op,
371 false);
372 canvas.drawPicture(picture);
373 }
374
375 } // namespace skia
376