OLD | NEW |
| (Empty) |
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/SkPath.h" | |
14 #include "third_party/skia/include/core/SkPixelRef.h" | |
15 #include "third_party/skia/include/core/SkRect.h" | |
16 #include "third_party/skia/include/core/SkRRect.h" | |
17 #include "third_party/skia/include/core/SkShader.h" | |
18 #include "third_party/skia/include/utils/SkNoSaveLayerCanvas.h" | |
19 #include "third_party/skia/src/core/SkRasterClip.h" | |
20 | |
21 namespace skia { | |
22 | |
23 namespace { | |
24 | |
25 // URI label for a discardable SkPixelRef. | |
26 const char kLabelDiscardable[] = "discardable"; | |
27 | |
28 class DiscardablePixelRefSet { | |
29 public: | |
30 DiscardablePixelRefSet( | |
31 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs) | |
32 : pixel_refs_(pixel_refs) {} | |
33 | |
34 void Add(SkPixelRef* pixel_ref, const SkRect& rect) { | |
35 // Only save discardable pixel refs. | |
36 if (pixel_ref->getURI() && | |
37 !strcmp(pixel_ref->getURI(), kLabelDiscardable)) { | |
38 PixelRefUtils::PositionPixelRef position_pixel_ref; | |
39 position_pixel_ref.pixel_ref = pixel_ref; | |
40 position_pixel_ref.pixel_ref_rect = rect; | |
41 pixel_refs_->push_back(position_pixel_ref); | |
42 } | |
43 } | |
44 | |
45 private: | |
46 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs_; | |
47 }; | |
48 | |
49 class GatherPixelRefDevice : public SkBitmapDevice { | |
50 public: | |
51 GatherPixelRefDevice(const SkBitmap& bm, | |
52 DiscardablePixelRefSet* pixel_ref_set) | |
53 : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {} | |
54 | |
55 void drawPaint(const SkDraw& draw, const SkPaint& paint) 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 | |
63 void drawPoints(const SkDraw& draw, | |
64 SkCanvas::PointMode mode, | |
65 size_t count, | |
66 const SkPoint points[], | |
67 const SkPaint& paint) 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 } | |
90 void drawRect(const SkDraw& draw, | |
91 const SkRect& rect, | |
92 const SkPaint& paint) override { | |
93 SkBitmap bitmap; | |
94 if (GetBitmapFromPaint(paint, &bitmap)) { | |
95 SkRect mapped_rect; | |
96 draw.fMatrix->mapRect(&mapped_rect, rect); | |
97 if (mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds()))) | |
98 AddBitmap(bitmap, mapped_rect); | |
99 } | |
100 } | |
101 void drawOval(const SkDraw& draw, | |
102 const SkRect& rect, | |
103 const SkPaint& paint) override { | |
104 GatherPixelRefDevice::drawRect(draw, rect, paint); | |
105 } | |
106 void drawRRect(const SkDraw& draw, | |
107 const SkRRect& rect, | |
108 const SkPaint& paint) override { | |
109 GatherPixelRefDevice::drawRect(draw, rect.rect(), paint); | |
110 } | |
111 void drawPath(const SkDraw& draw, | |
112 const SkPath& path, | |
113 const SkPaint& paint, | |
114 const SkMatrix* pre_path_matrix, | |
115 bool path_is_mutable) 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 } | |
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); | |
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 } | |
145 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::SrcRectConstraint flags) 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 } | |
156 void drawSprite(const SkDraw& draw, | |
157 const SkBitmap& bitmap, | |
158 int x, | |
159 int y, | |
160 const SkPaint& paint) 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 } | |
174 void drawText(const SkDraw& draw, | |
175 const void* text, | |
176 size_t len, | |
177 SkScalar x, | |
178 SkScalar y, | |
179 const SkPaint& paint) 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 } | |
221 void drawPosText(const SkDraw& draw, | |
222 const void* text, | |
223 size_t len, | |
224 const SkScalar pos[], | |
225 int scalars_per_pos, | |
226 const SkPoint& offset, | |
227 const SkPaint& paint) 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 = SkPoint::Make(offset.x() + pos[0], | |
239 offset.y() + (2 == scalars_per_pos ? pos[1
] : 0)); | |
240 SkPoint max_point = min_point; | |
241 | |
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); | |
245 | |
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())); | |
248 } | |
249 | |
250 SkRect bounds = SkRect::MakeLTRB( | |
251 min_point.x(), min_point.y(), max_point.x(), max_point.y()); | |
252 | |
253 // Math is borrowed from SkBBoxRecord | |
254 SkPaint::FontMetrics metrics; | |
255 paint.getFontMetrics(&metrics); | |
256 | |
257 bounds.fTop += metrics.fTop; | |
258 bounds.fBottom += metrics.fBottom; | |
259 | |
260 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2; | |
261 bounds.fLeft += pad; | |
262 bounds.fRight -= pad; | |
263 | |
264 GatherPixelRefDevice::drawRect(draw, bounds, paint); | |
265 } | |
266 void drawTextOnPath(const SkDraw& draw, | |
267 const void* text, | |
268 size_t len, | |
269 const SkPath& path, | |
270 const SkMatrix* matrix, | |
271 const SkPaint& paint) override { | |
272 SkBitmap bitmap; | |
273 if (!GetBitmapFromPaint(paint, &bitmap)) | |
274 return; | |
275 | |
276 // Math is borrowed from SkBBoxRecord | |
277 SkRect bounds = path.getBounds(); | |
278 SkPaint::FontMetrics metrics; | |
279 paint.getFontMetrics(&metrics); | |
280 | |
281 SkScalar pad = metrics.fTop; | |
282 bounds.fLeft += pad; | |
283 bounds.fRight -= pad; | |
284 bounds.fTop += pad; | |
285 bounds.fBottom -= pad; | |
286 | |
287 GatherPixelRefDevice::drawRect(draw, bounds, paint); | |
288 } | |
289 void drawVertices(const SkDraw& draw, | |
290 SkCanvas::VertexMode, | |
291 int vertex_count, | |
292 const SkPoint verts[], | |
293 const SkPoint texs[], | |
294 const SkColor colors[], | |
295 SkXfermode* xmode, | |
296 const uint16_t indices[], | |
297 int index_count, | |
298 const SkPaint& paint) override { | |
299 GatherPixelRefDevice::drawPoints( | |
300 draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint); | |
301 } | |
302 void drawDevice(const SkDraw&, | |
303 SkBaseDevice*, | |
304 int x, | |
305 int y, | |
306 const SkPaint&) override {} | |
307 | |
308 protected: | |
309 bool onReadPixels(const SkImageInfo& info, | |
310 void* pixels, | |
311 size_t rowBytes, | |
312 int x, | |
313 int y) override { | |
314 return false; | |
315 } | |
316 | |
317 bool onWritePixels(const SkImageInfo& info, | |
318 const void* pixels, | |
319 size_t rowBytes, | |
320 int x, | |
321 int y) override { | |
322 return false; | |
323 } | |
324 | |
325 private: | |
326 DiscardablePixelRefSet* pixel_ref_set_; | |
327 | |
328 void AddBitmap(const SkBitmap& bm, const SkRect& rect) { | |
329 SkRect canvas_rect = SkRect::MakeWH(width(), height()); | |
330 SkRect paint_rect = SkRect::MakeEmpty(); | |
331 if (paint_rect.intersect(rect, canvas_rect)) | |
332 pixel_ref_set_->Add(bm.pixelRef(), paint_rect); | |
333 } | |
334 | |
335 bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) { | |
336 SkShader* shader = paint.getShader(); | |
337 if (shader) { | |
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->isABitmap(bm, NULL, NULL); | |
342 } | |
343 return false; | |
344 } | |
345 }; | |
346 | |
347 } // namespace | |
348 | |
349 void PixelRefUtils::GatherDiscardablePixelRefs( | |
350 SkPicture* picture, | |
351 std::vector<PositionPixelRef>* pixel_refs) { | |
352 pixel_refs->clear(); | |
353 DiscardablePixelRefSet pixel_ref_set(pixel_refs); | |
354 | |
355 SkRect picture_bounds = picture->cullRect(); | |
356 SkIRect picture_ibounds = picture_bounds.roundOut(); | |
357 SkBitmap empty_bitmap; | |
358 empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture_ibounds.width(), | |
359 picture_ibounds.height())); | |
360 | |
361 GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set); | |
362 SkNoSaveLayerCanvas canvas(&device); | |
363 | |
364 // Draw the picture pinned against our top/left corner. | |
365 canvas.translate(-picture_bounds.left(), -picture_bounds.top()); | |
366 canvas.drawPicture(picture); | |
367 } | |
368 | |
369 } // namespace skia | |
OLD | NEW |