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 virtual void clear(SkColor color
) SK_OVERRIDE
{}
55 virtual void drawPaint(const SkDraw
& draw
, const SkPaint
& paint
) SK_OVERRIDE
{
57 if (GetBitmapFromPaint(paint
, &bitmap
)) {
58 SkRect clip_rect
= SkRect::Make(draw
.fRC
->getBounds());
59 AddBitmap(bitmap
, clip_rect
);
63 virtual void drawPoints(const SkDraw
& draw
,
64 SkCanvas::PointMode mode
,
66 const SkPoint points
[],
67 const SkPaint
& paint
) SK_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 virtual void drawRect(const SkDraw
& draw
,
92 const SkPaint
& paint
) SK_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 virtual void drawOval(const SkDraw
& draw
,
103 const SkPaint
& paint
) SK_OVERRIDE
{
104 GatherPixelRefDevice::drawRect(draw
, rect
, paint
);
106 virtual void drawRRect(const SkDraw
& draw
,
108 const SkPaint
& paint
) SK_OVERRIDE
{
109 GatherPixelRefDevice::drawRect(draw
, rect
.rect(), paint
);
111 virtual void drawPath(const SkDraw
& draw
,
113 const SkPaint
& paint
,
114 const SkMatrix
* pre_path_matrix
,
115 bool path_is_mutable
) SK_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 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
);
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 virtual void drawBitmapRect(const SkDraw
& draw
,
146 const SkBitmap
& bitmap
,
147 const SkRect
* src_or_null
,
149 const SkPaint
& paint
,
150 SkCanvas::DrawBitmapRectFlags flags
) SK_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 virtual void drawSprite(const SkDraw
& draw
,
157 const SkBitmap
& bitmap
,
160 const SkPaint
& paint
) SK_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 virtual void drawText(const SkDraw
& draw
,
179 const SkPaint
& paint
) SK_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 virtual void drawPosText(const SkDraw
& draw
,
224 const SkScalar pos
[],
227 const SkPaint
& paint
) SK_OVERRIDE
{
229 if (!GetBitmapFromPaint(paint
, &bitmap
))
235 // Similar to SkDraw asserts.
236 SkASSERT(scalars_per_pos
== 1 || scalars_per_pos
== 2);
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]);
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];
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()));
258 SkRect bounds
= SkRect::MakeLTRB(
259 min_point
.x(), min_point
.y(), max_point
.x(), max_point
.y());
261 // Math is borrowed from SkBBoxRecord
262 SkPaint::FontMetrics metrics
;
263 paint
.getFontMetrics(&metrics
);
265 bounds
.fTop
+= metrics
.fTop
;
266 bounds
.fBottom
+= metrics
.fBottom
;
268 SkScalar pad
= (metrics
.fTop
- metrics
.fBottom
) / 2;
270 bounds
.fRight
-= pad
;
272 GatherPixelRefDevice::drawRect(draw
, bounds
, paint
);
274 virtual void drawTextOnPath(const SkDraw
& draw
,
278 const SkMatrix
* matrix
,
279 const SkPaint
& paint
) SK_OVERRIDE
{
281 if (!GetBitmapFromPaint(paint
, &bitmap
))
284 // Math is borrowed from SkBBoxRecord
285 SkRect bounds
= path
.getBounds();
286 SkPaint::FontMetrics metrics
;
287 paint
.getFontMetrics(&metrics
);
289 SkScalar pad
= metrics
.fTop
;
291 bounds
.fRight
-= pad
;
293 bounds
.fBottom
-= pad
;
295 GatherPixelRefDevice::drawRect(draw
, bounds
, paint
);
297 virtual void drawVertices(const SkDraw
& draw
,
298 SkCanvas::VertexMode
,
300 const SkPoint verts
[],
301 const SkPoint texs
[],
302 const SkColor colors
[],
304 const uint16_t indices
[],
306 const SkPaint
& paint
) SK_OVERRIDE
{
307 GatherPixelRefDevice::drawPoints(
308 draw
, SkCanvas::kPolygon_PointMode
, vertex_count
, verts
, paint
);
310 virtual void drawDevice(const SkDraw
&,
314 const SkPaint
&) SK_OVERRIDE
{}
317 virtual bool onReadPixels(const SkImageInfo
& info
,
325 virtual bool onWritePixels(const SkImageInfo
& info
,
334 DiscardablePixelRefSet
* pixel_ref_set_
;
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
);
343 bool GetBitmapFromPaint(const SkPaint
& paint
, SkBitmap
* bm
) {
344 SkShader
* shader
= paint
.getShader();
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
);
357 void PixelRefUtils::GatherDiscardablePixelRefs(
359 std::vector
<PositionPixelRef
>* pixel_refs
) {
361 DiscardablePixelRefSet
pixel_ref_set(pixel_refs
);
363 SkBitmap empty_bitmap
;
364 empty_bitmap
.setInfo(SkImageInfo::MakeUnknown(picture
->width(), picture
->height()));
366 GatherPixelRefDevice
device(empty_bitmap
, &pixel_ref_set
);
367 SkNoSaveLayerCanvas
canvas(&device
);
369 canvas
.clipRect(SkRect::MakeWH(picture
->width(), picture
->height()),
370 SkRegion::kIntersect_Op
,
372 canvas
.drawPicture(picture
);