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/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"
26 class DiscardablePixelRefSet
{
28 DiscardablePixelRefSet(
29 std::vector
<PixelRefUtils::PositionPixelRef
>* pixel_refs
)
30 : pixel_refs_(pixel_refs
) {}
32 void Add(SkPixelRef
* pixel_ref
,
34 const SkMatrix
& matrix
,
35 SkFilterQuality filter_quality
) {
36 // We should only be saving discardable pixel refs.
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
);
49 std::vector
<PixelRefUtils::PositionPixelRef
>* pixel_refs_
;
52 class GatherPixelRefDevice
: public SkBitmapDevice
{
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
{
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
,
69 const SkPoint points
[],
70 const SkPaint
& paint
) override
{
72 if (!GetBitmapFromPaint(paint
, &bitmap
))
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
,
95 const SkPaint
& paint
) override
{
97 if (GetBitmapFromPaint(paint
, &bitmap
)) {
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
,
107 const SkPaint
& paint
) override
{
108 GatherPixelRefDevice::drawRect(draw
, rect
, paint
);
110 void drawRRect(const SkDraw
& draw
,
112 const SkPaint
& paint
) override
{
113 GatherPixelRefDevice::drawRect(draw
, rect
.rect(), paint
);
115 void drawPath(const SkDraw
& draw
,
117 const SkPaint
& paint
,
118 const SkMatrix
* pre_path_matrix
,
119 bool path_is_mutable
) override
{
121 if (!GetBitmapFromPaint(paint
, &bitmap
))
124 SkRect path_bounds
= path
.getBounds();
126 if (pre_path_matrix
!= NULL
)
127 pre_path_matrix
->mapRect(&final_rect
, path_bounds
);
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());
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
,
155 const SkPaint
& paint
,
156 SkCanvas::SrcRectConstraint
) override
{
157 SkRect bitmap_rect
= SkRect::MakeWH(bitmap
.width(), bitmap
.height());
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
,
166 const SkPaint
& paint
) override
{
167 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
169 matrix
.setTranslate(x
, y
);
171 SkRect bitmap_rect
= SkRect::MakeWH(bitmap
.width(), bitmap
.height());
173 matrix
.mapRect(&mapped_rect
, bitmap_rect
);
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
,
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
,
195 const SkPaint
& paint
,
196 SkCanvas::SrcRectConstraint
) override
{
197 const SkRect src
= 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
,
209 const SkPaint
& paint
) override
{
211 if (!GetBitmapFromPaint(paint
, &bitmap
))
214 // Math is borrowed from SkBBoxRecord
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
;
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
) {
237 bounds
.fTop
= metrics
.fTop
;
238 bounds
.fBottom
= metrics
.fBottom
;
241 SkScalar pad
= (metrics
.fBottom
- metrics
.fTop
) / 2;
243 bounds
.fRight
+= pad
;
249 GatherPixelRefDevice::drawRect(draw
, bounds
, paint
);
251 void drawPosText(const SkDraw
& draw
,
254 const SkScalar pos
[],
256 const SkPoint
& offset
,
257 const SkPaint
& paint
) override
{
259 if (!GetBitmapFromPaint(paint
, &bitmap
))
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;
292 bounds
.fRight
-= pad
;
294 GatherPixelRefDevice::drawRect(draw
, bounds
, paint
);
296 void drawTextOnPath(const SkDraw
& draw
,
300 const SkMatrix
* matrix
,
301 const SkPaint
& paint
) override
{
303 if (!GetBitmapFromPaint(paint
, &bitmap
))
306 // Math is borrowed from SkBBoxRecord
307 SkRect bounds
= path
.getBounds();
308 SkPaint::FontMetrics metrics
;
309 paint
.getFontMetrics(&metrics
);
311 SkScalar pad
= metrics
.fTop
;
313 bounds
.fRight
-= 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
{
325 if (!GetBitmapFromPaint(paint
, &bitmap
))
328 const SkRect bounds
= blob
->bounds().makeOffset(x
, y
);
329 GatherPixelRefDevice::drawRect(draw
, bounds
, paint
);
332 void drawVertices(const SkDraw
& draw
,
333 SkCanvas::VertexMode
,
335 const SkPoint verts
[],
336 const SkPoint texs
[],
337 const SkColor colors
[],
339 const uint16_t indices
[],
341 const SkPaint
& paint
) override
{
342 GatherPixelRefDevice::drawPoints(
343 draw
, SkCanvas::kPolygon_PointMode
, vertex_count
, verts
, paint
);
345 void drawDevice(const SkDraw
&,
349 const SkPaint
&) override
{}
352 bool onReadPixels(const SkImageInfo
& info
,
360 bool onWritePixels(const SkImageInfo
& info
,
369 DiscardablePixelRefSet
* pixel_ref_set_
;
371 void AddBitmap(const SkBitmap
& bm
,
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
,
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()) {
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();
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
);
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());
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());
425 void PixelRefUtils::GatherDiscardablePixelRefs(
427 std::vector
<PositionPixelRef
>* pixel_refs
) {
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
);