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/src/core/SkRasterClip.h"
23 // URI label for a discardable SkPixelRef.
24 const char kLabelDiscardable
[] = "discardable";
26 class DiscardablePixelRefSet
{
28 DiscardablePixelRefSet(
29 std::vector
<PixelRefUtils::PositionPixelRef
>* pixel_refs
)
30 : pixel_refs_(pixel_refs
) {}
32 void Add(SkPixelRef
* pixel_ref
, const SkRect
& rect
) {
33 // Only save discardable pixel refs.
34 if (pixel_ref
->getURI() &&
35 !strcmp(pixel_ref
->getURI(), kLabelDiscardable
)) {
36 PixelRefUtils::PositionPixelRef position_pixel_ref
;
37 position_pixel_ref
.pixel_ref
= pixel_ref
;
38 position_pixel_ref
.pixel_ref_rect
= rect
;
39 pixel_refs_
->push_back(position_pixel_ref
);
44 std::vector
<PixelRefUtils::PositionPixelRef
>* pixel_refs_
;
47 class GatherPixelRefDevice
: public SkBitmapDevice
{
49 GatherPixelRefDevice(const SkBitmap
& bm
,
50 DiscardablePixelRefSet
* pixel_ref_set
)
51 : SkBitmapDevice(bm
), pixel_ref_set_(pixel_ref_set
) {}
53 virtual void clear(SkColor color
) SK_OVERRIDE
{}
54 virtual void writePixels(const SkBitmap
& bitmap
,
57 SkCanvas::Config8888 config8888
) SK_OVERRIDE
{}
59 virtual void drawPaint(const SkDraw
& draw
, const SkPaint
& paint
) SK_OVERRIDE
{
61 if (GetBitmapFromPaint(paint
, &bitmap
)) {
62 SkRect clip_rect
= SkRect::Make(draw
.fRC
->getBounds());
63 AddBitmap(bitmap
, clip_rect
);
67 virtual void drawPoints(const SkDraw
& draw
,
68 SkCanvas::PointMode mode
,
70 const SkPoint points
[],
71 const SkPaint
& paint
) SK_OVERRIDE
{
73 if (!GetBitmapFromPaint(paint
, &bitmap
))
79 SkPoint min_point
= points
[0];
80 SkPoint max_point
= points
[0];
81 for (size_t i
= 1; i
< count
; ++i
) {
82 const SkPoint
& point
= points
[i
];
83 min_point
.set(std::min(min_point
.x(), point
.x()),
84 std::min(min_point
.y(), point
.y()));
85 max_point
.set(std::max(max_point
.x(), point
.x()),
86 std::max(max_point
.y(), point
.y()));
89 SkRect bounds
= SkRect::MakeLTRB(
90 min_point
.x(), min_point
.y(), max_point
.x(), max_point
.y());
92 GatherPixelRefDevice::drawRect(draw
, bounds
, paint
);
94 virtual void drawRect(const SkDraw
& draw
,
96 const SkPaint
& paint
) SK_OVERRIDE
{
98 if (GetBitmapFromPaint(paint
, &bitmap
)) {
100 draw
.fMatrix
->mapRect(&mapped_rect
, rect
);
101 mapped_rect
.intersect(SkRect::Make(draw
.fRC
->getBounds()));
102 AddBitmap(bitmap
, mapped_rect
);
105 virtual void drawOval(const SkDraw
& draw
,
107 const SkPaint
& paint
) SK_OVERRIDE
{
108 GatherPixelRefDevice::drawRect(draw
, rect
, paint
);
110 virtual void drawRRect(const SkDraw
& draw
,
112 const SkPaint
& paint
) SK_OVERRIDE
{
113 GatherPixelRefDevice::drawRect(draw
, rect
.rect(), paint
);
115 virtual void drawPath(const SkDraw
& draw
,
117 const SkPaint
& paint
,
118 const SkMatrix
* pre_path_matrix
,
119 bool path_is_mutable
) SK_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 virtual void drawBitmap(const SkDraw
& draw
,
134 const SkBitmap
& bitmap
,
135 const SkMatrix
& matrix
,
136 const SkPaint
& paint
) SK_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
);
145 SkBitmap paint_bitmap
;
146 if (GetBitmapFromPaint(paint
, &paint_bitmap
))
147 AddBitmap(paint_bitmap
, mapped_rect
);
149 virtual void drawBitmapRect(const SkDraw
& draw
,
150 const SkBitmap
& bitmap
,
151 const SkRect
* src_or_null
,
153 const SkPaint
& paint
,
154 SkCanvas::DrawBitmapRectFlags flags
) SK_OVERRIDE
{
155 SkRect bitmap_rect
= SkRect::MakeWH(bitmap
.width(), bitmap
.height());
157 matrix
.setRectToRect(bitmap_rect
, dst
, SkMatrix::kFill_ScaleToFit
);
158 GatherPixelRefDevice::drawBitmap(draw
, bitmap
, matrix
, paint
);
160 virtual void drawSprite(const SkDraw
& draw
,
161 const SkBitmap
& bitmap
,
164 const SkPaint
& paint
) SK_OVERRIDE
{
165 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
167 matrix
.setTranslate(x
, y
);
169 SkRect bitmap_rect
= SkRect::MakeWH(bitmap
.width(), bitmap
.height());
171 matrix
.mapRect(&mapped_rect
, bitmap_rect
);
173 AddBitmap(bitmap
, mapped_rect
);
174 SkBitmap paint_bitmap
;
175 if (GetBitmapFromPaint(paint
, &paint_bitmap
))
176 AddBitmap(paint_bitmap
, mapped_rect
);
178 virtual void drawText(const SkDraw
& draw
,
183 const SkPaint
& paint
) SK_OVERRIDE
{
185 if (!GetBitmapFromPaint(paint
, &bitmap
))
188 // Math is borrowed from SkBBoxRecord
190 paint
.measureText(text
, len
, &bounds
);
191 SkPaint::FontMetrics metrics
;
192 paint
.getFontMetrics(&metrics
);
194 if (paint
.isVerticalText()) {
195 SkScalar h
= bounds
.fBottom
- bounds
.fTop
;
196 if (paint
.getTextAlign() == SkPaint::kCenter_Align
) {
197 bounds
.fTop
-= h
/ 2;
198 bounds
.fBottom
-= h
/ 2;
200 bounds
.fBottom
+= metrics
.fBottom
;
201 bounds
.fTop
+= metrics
.fTop
;
203 SkScalar w
= bounds
.fRight
- bounds
.fLeft
;
204 if (paint
.getTextAlign() == SkPaint::kCenter_Align
) {
205 bounds
.fLeft
-= w
/ 2;
206 bounds
.fRight
-= w
/ 2;
207 } else if (paint
.getTextAlign() == SkPaint::kRight_Align
) {
211 bounds
.fTop
= metrics
.fTop
;
212 bounds
.fBottom
= metrics
.fBottom
;
215 SkScalar pad
= (metrics
.fBottom
- metrics
.fTop
) / 2;
217 bounds
.fRight
+= pad
;
223 GatherPixelRefDevice::drawRect(draw
, bounds
, paint
);
225 virtual void drawPosText(const SkDraw
& draw
,
228 const SkScalar pos
[],
231 const SkPaint
& paint
) SK_OVERRIDE
{
233 if (!GetBitmapFromPaint(paint
, &bitmap
))
239 // Similar to SkDraw asserts.
240 SkASSERT(scalars_per_pos
== 1 || scalars_per_pos
== 2);
244 if (scalars_per_pos
== 1) {
245 min_point
.set(pos
[0], const_y
);
246 max_point
.set(pos
[0], const_y
);
247 } else if (scalars_per_pos
== 2) {
248 min_point
.set(pos
[0], const_y
+ pos
[1]);
249 max_point
.set(pos
[0], const_y
+ pos
[1]);
252 for (size_t i
= 0; i
< len
; ++i
) {
253 SkScalar x
= pos
[i
* scalars_per_pos
];
254 SkScalar y
= const_y
;
255 if (scalars_per_pos
== 2)
256 y
+= pos
[i
* scalars_per_pos
+ 1];
258 min_point
.set(std::min(x
, min_point
.x()), std::min(y
, min_point
.y()));
259 max_point
.set(std::max(x
, max_point
.x()), std::max(y
, max_point
.y()));
262 SkRect bounds
= SkRect::MakeLTRB(
263 min_point
.x(), min_point
.y(), max_point
.x(), max_point
.y());
265 // Math is borrowed from SkBBoxRecord
266 SkPaint::FontMetrics metrics
;
267 paint
.getFontMetrics(&metrics
);
269 bounds
.fTop
+= metrics
.fTop
;
270 bounds
.fBottom
+= metrics
.fBottom
;
272 SkScalar pad
= (metrics
.fTop
- metrics
.fBottom
) / 2;
274 bounds
.fRight
-= pad
;
276 GatherPixelRefDevice::drawRect(draw
, bounds
, paint
);
278 virtual void drawTextOnPath(const SkDraw
& draw
,
282 const SkMatrix
* matrix
,
283 const SkPaint
& paint
) SK_OVERRIDE
{
285 if (!GetBitmapFromPaint(paint
, &bitmap
))
288 // Math is borrowed from SkBBoxRecord
289 SkRect bounds
= path
.getBounds();
290 SkPaint::FontMetrics metrics
;
291 paint
.getFontMetrics(&metrics
);
293 SkScalar pad
= metrics
.fTop
;
295 bounds
.fRight
-= pad
;
297 bounds
.fBottom
-= pad
;
299 GatherPixelRefDevice::drawRect(draw
, bounds
, paint
);
301 virtual void drawVertices(const SkDraw
& draw
,
302 SkCanvas::VertexMode
,
304 const SkPoint verts
[],
305 const SkPoint texs
[],
306 const SkColor colors
[],
308 const uint16_t indices
[],
310 const SkPaint
& paint
) SK_OVERRIDE
{
311 GatherPixelRefDevice::drawPoints(
312 draw
, SkCanvas::kPolygon_PointMode
, vertex_count
, verts
, paint
);
314 virtual void drawDevice(const SkDraw
&,
318 const SkPaint
&) SK_OVERRIDE
{}
321 virtual bool onReadPixels(const SkBitmap
& bitmap
,
324 SkCanvas::Config8888 config8888
) SK_OVERRIDE
{
329 DiscardablePixelRefSet
* pixel_ref_set_
;
331 void AddBitmap(const SkBitmap
& bm
, const SkRect
& rect
) {
332 SkRect canvas_rect
= SkRect::MakeWH(width(), height());
333 SkRect paint_rect
= SkRect::MakeEmpty();
334 paint_rect
.intersect(rect
, canvas_rect
);
335 pixel_ref_set_
->Add(bm
.pixelRef(), paint_rect
);
338 bool GetBitmapFromPaint(const SkPaint
& paint
, SkBitmap
* bm
) {
339 SkShader
* shader
= paint
.getShader();
341 // Check whether the shader is a gradient in order to prevent generation
342 // of bitmaps from gradient shaders, which implement asABitmap.
343 if (SkShader::kNone_GradientType
== shader
->asAGradient(NULL
))
344 return shader
->asABitmap(bm
, NULL
, NULL
);
350 class NoSaveLayerCanvas
: public SkCanvas
{
352 NoSaveLayerCanvas(SkBaseDevice
* device
) : INHERITED(device
) {}
354 // Turn saveLayer() into save() for speed, should not affect correctness.
355 virtual int saveLayer(const SkRect
* bounds
,
356 const SkPaint
* paint
,
357 SaveFlags flags
) SK_OVERRIDE
{
359 // Like SkPictureRecord, we don't want to create layers, but we do need
360 // to respect the save and (possibly) its rect-clip.
361 int count
= this->INHERITED::save(flags
);
363 this->INHERITED::clipRectBounds(bounds
, flags
, NULL
);
368 // Disable aa for speed.
369 virtual bool clipRect(const SkRect
& rect
, SkRegion::Op op
, bool doAA
)
371 return this->INHERITED::clipRect(rect
, op
, false);
374 virtual bool clipPath(const SkPath
& path
, SkRegion::Op op
, bool doAA
)
376 return this->updateClipConservativelyUsingBounds(
377 path
.getBounds(), op
, path
.isInverseFillType());
379 virtual bool clipRRect(const SkRRect
& rrect
, SkRegion::Op op
, bool doAA
)
381 return this->updateClipConservativelyUsingBounds(
382 rrect
.getBounds(), op
, false);
386 typedef SkCanvas INHERITED
;
391 void PixelRefUtils::GatherDiscardablePixelRefs(
393 std::vector
<PositionPixelRef
>* pixel_refs
) {
395 DiscardablePixelRefSet
pixel_ref_set(pixel_refs
);
397 SkBitmap empty_bitmap
;
398 empty_bitmap
.setConfig(
399 SkBitmap::kNo_Config
, picture
->width(), picture
->height());
401 GatherPixelRefDevice
device(empty_bitmap
, &pixel_ref_set
);
402 NoSaveLayerCanvas
canvas(&device
);
404 canvas
.clipRect(SkRect::MakeWH(picture
->width(), picture
->height()),
405 SkRegion::kIntersect_Op
,
407 canvas
.drawPicture(*picture
);