OLD | NEW |
| (Empty) |
1 // Copyright 2013 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/lazy_pixel_ref_utils.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "skia/ext/lazy_pixel_ref.h" | |
10 #include "third_party/skia/include/core/SkBitmapDevice.h" | |
11 #include "third_party/skia/include/core/SkCanvas.h" | |
12 #include "third_party/skia/include/core/SkData.h" | |
13 #include "third_party/skia/include/core/SkDraw.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/src/core/SkRasterClip.h" | |
19 | |
20 namespace skia { | |
21 | |
22 namespace { | |
23 | |
24 // URI label for a lazily decoded SkPixelRef. | |
25 const char kLabelLazyDecoded[] = "lazy"; | |
26 | |
27 class LazyPixelRefSet { | |
28 public: | |
29 LazyPixelRefSet( | |
30 std::vector<LazyPixelRefUtils::PositionLazyPixelRef>* pixel_refs) | |
31 : pixel_refs_(pixel_refs) {} | |
32 | |
33 void Add(SkPixelRef* pixel_ref, const SkRect& rect) { | |
34 // Only save lazy pixel refs. | |
35 if (pixel_ref->getURI() && | |
36 !strcmp(pixel_ref->getURI(), kLabelLazyDecoded)) { | |
37 LazyPixelRefUtils::PositionLazyPixelRef position_pixel_ref; | |
38 position_pixel_ref.lazy_pixel_ref = | |
39 static_cast<skia::LazyPixelRef*>(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<LazyPixelRefUtils::PositionLazyPixelRef>* pixel_refs_; | |
47 }; | |
48 | |
49 class GatherPixelRefDevice : public SkBitmapDevice { | |
50 public: | |
51 GatherPixelRefDevice(const SkBitmap& bm, LazyPixelRefSet* lazy_pixel_ref_set) | |
52 : SkBitmapDevice(bm), lazy_pixel_ref_set_(lazy_pixel_ref_set) {} | |
53 | |
54 virtual void clear(SkColor color) SK_OVERRIDE {} | |
55 virtual void writePixels(const SkBitmap& bitmap, | |
56 int x, | |
57 int y, | |
58 SkCanvas::Config8888 config8888) SK_OVERRIDE {} | |
59 | |
60 virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE { | |
61 SkBitmap bitmap; | |
62 if (GetBitmapFromPaint(paint, &bitmap)) { | |
63 SkRect clip_rect = SkRect::Make(draw.fRC->getBounds()); | |
64 AddBitmap(bitmap, clip_rect); | |
65 } | |
66 } | |
67 | |
68 virtual void drawPoints(const SkDraw& draw, | |
69 SkCanvas::PointMode mode, | |
70 size_t count, | |
71 const SkPoint points[], | |
72 const SkPaint& paint) SK_OVERRIDE { | |
73 SkBitmap bitmap; | |
74 if (!GetBitmapFromPaint(paint, &bitmap)) | |
75 return; | |
76 | |
77 if (count == 0) | |
78 return; | |
79 | |
80 SkPoint min_point = points[0]; | |
81 SkPoint max_point = points[0]; | |
82 for (size_t i = 1; i < count; ++i) { | |
83 const SkPoint& point = points[i]; | |
84 min_point.set(std::min(min_point.x(), point.x()), | |
85 std::min(min_point.y(), point.y())); | |
86 max_point.set(std::max(max_point.x(), point.x()), | |
87 std::max(max_point.y(), point.y())); | |
88 } | |
89 | |
90 SkRect bounds = SkRect::MakeLTRB( | |
91 min_point.x(), min_point.y(), max_point.x(), max_point.y()); | |
92 | |
93 GatherPixelRefDevice::drawRect(draw, bounds, paint); | |
94 } | |
95 virtual void drawRect(const SkDraw& draw, | |
96 const SkRect& rect, | |
97 const SkPaint& paint) SK_OVERRIDE { | |
98 SkBitmap bitmap; | |
99 if (GetBitmapFromPaint(paint, &bitmap)) { | |
100 SkRect mapped_rect; | |
101 draw.fMatrix->mapRect(&mapped_rect, rect); | |
102 mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds())); | |
103 AddBitmap(bitmap, mapped_rect); | |
104 } | |
105 } | |
106 virtual void drawOval(const SkDraw& draw, | |
107 const SkRect& rect, | |
108 const SkPaint& paint) SK_OVERRIDE { | |
109 GatherPixelRefDevice::drawRect(draw, rect, paint); | |
110 } | |
111 virtual void drawRRect(const SkDraw& draw, | |
112 const SkRRect& rect, | |
113 const SkPaint& paint) SK_OVERRIDE { | |
114 GatherPixelRefDevice::drawRect(draw, rect.rect(), paint); | |
115 } | |
116 virtual void drawPath(const SkDraw& draw, | |
117 const SkPath& path, | |
118 const SkPaint& paint, | |
119 const SkMatrix* pre_path_matrix, | |
120 bool path_is_mutable) SK_OVERRIDE { | |
121 SkBitmap bitmap; | |
122 if (!GetBitmapFromPaint(paint, &bitmap)) | |
123 return; | |
124 | |
125 SkRect path_bounds = path.getBounds(); | |
126 SkRect final_rect; | |
127 if (pre_path_matrix != NULL) | |
128 pre_path_matrix->mapRect(&final_rect, path_bounds); | |
129 else | |
130 final_rect = path_bounds; | |
131 | |
132 GatherPixelRefDevice::drawRect(draw, final_rect, paint); | |
133 } | |
134 virtual void drawBitmap(const SkDraw& draw, | |
135 const SkBitmap& bitmap, | |
136 const SkMatrix& matrix, | |
137 const SkPaint& paint) SK_OVERRIDE { | |
138 SkMatrix total_matrix; | |
139 total_matrix.setConcat(*draw.fMatrix, matrix); | |
140 | |
141 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height()); | |
142 SkRect mapped_rect; | |
143 total_matrix.mapRect(&mapped_rect, bitmap_rect); | |
144 AddBitmap(bitmap, mapped_rect); | |
145 | |
146 SkBitmap paint_bitmap; | |
147 if (GetBitmapFromPaint(paint, &paint_bitmap)) | |
148 AddBitmap(paint_bitmap, mapped_rect); | |
149 } | |
150 virtual void drawBitmapRect(const SkDraw& draw, | |
151 const SkBitmap& bitmap, | |
152 const SkRect* src_or_null, | |
153 const SkRect& dst, | |
154 const SkPaint& paint, | |
155 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE { | |
156 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height()); | |
157 SkMatrix matrix; | |
158 matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit); | |
159 GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint); | |
160 } | |
161 virtual void drawSprite(const SkDraw& draw, | |
162 const SkBitmap& bitmap, | |
163 int x, | |
164 int y, | |
165 const SkPaint& paint) SK_OVERRIDE { | |
166 // Sprites aren't affected by current matrix, so we can't reuse drawRect. | |
167 SkMatrix matrix; | |
168 matrix.setTranslate(x, y); | |
169 | |
170 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height()); | |
171 SkRect mapped_rect; | |
172 matrix.mapRect(&mapped_rect, bitmap_rect); | |
173 | |
174 AddBitmap(bitmap, mapped_rect); | |
175 SkBitmap paint_bitmap; | |
176 if (GetBitmapFromPaint(paint, &paint_bitmap)) | |
177 AddBitmap(paint_bitmap, mapped_rect); | |
178 } | |
179 virtual void drawText(const SkDraw& draw, | |
180 const void* text, | |
181 size_t len, | |
182 SkScalar x, | |
183 SkScalar y, | |
184 const SkPaint& paint) SK_OVERRIDE { | |
185 SkBitmap bitmap; | |
186 if (!GetBitmapFromPaint(paint, &bitmap)) | |
187 return; | |
188 | |
189 // Math is borrowed from SkBBoxRecord | |
190 SkRect bounds; | |
191 paint.measureText(text, len, &bounds); | |
192 SkPaint::FontMetrics metrics; | |
193 paint.getFontMetrics(&metrics); | |
194 | |
195 if (paint.isVerticalText()) { | |
196 SkScalar h = bounds.fBottom - bounds.fTop; | |
197 if (paint.getTextAlign() == SkPaint::kCenter_Align) { | |
198 bounds.fTop -= h / 2; | |
199 bounds.fBottom -= h / 2; | |
200 } | |
201 bounds.fBottom += metrics.fBottom; | |
202 bounds.fTop += metrics.fTop; | |
203 } else { | |
204 SkScalar w = bounds.fRight - bounds.fLeft; | |
205 if (paint.getTextAlign() == SkPaint::kCenter_Align) { | |
206 bounds.fLeft -= w / 2; | |
207 bounds.fRight -= w / 2; | |
208 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { | |
209 bounds.fLeft -= w; | |
210 bounds.fRight -= w; | |
211 } | |
212 bounds.fTop = metrics.fTop; | |
213 bounds.fBottom = metrics.fBottom; | |
214 } | |
215 | |
216 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2; | |
217 bounds.fLeft -= pad; | |
218 bounds.fRight += pad; | |
219 bounds.fLeft += x; | |
220 bounds.fRight += x; | |
221 bounds.fTop += y; | |
222 bounds.fBottom += y; | |
223 | |
224 GatherPixelRefDevice::drawRect(draw, bounds, paint); | |
225 } | |
226 virtual void drawPosText(const SkDraw& draw, | |
227 const void* text, | |
228 size_t len, | |
229 const SkScalar pos[], | |
230 SkScalar const_y, | |
231 int scalars_per_pos, | |
232 const SkPaint& paint) SK_OVERRIDE { | |
233 SkBitmap bitmap; | |
234 if (!GetBitmapFromPaint(paint, &bitmap)) | |
235 return; | |
236 | |
237 if (len == 0) | |
238 return; | |
239 | |
240 // Similar to SkDraw asserts. | |
241 SkASSERT(scalars_per_pos == 1 || scalars_per_pos == 2); | |
242 | |
243 SkPoint min_point; | |
244 SkPoint max_point; | |
245 if (scalars_per_pos == 1) { | |
246 min_point.set(pos[0], const_y); | |
247 max_point.set(pos[0], const_y); | |
248 } else if (scalars_per_pos == 2) { | |
249 min_point.set(pos[0], const_y + pos[1]); | |
250 max_point.set(pos[0], const_y + pos[1]); | |
251 } | |
252 | |
253 for (size_t i = 0; i < len; ++i) { | |
254 SkScalar x = pos[i * scalars_per_pos]; | |
255 SkScalar y = const_y; | |
256 if (scalars_per_pos == 2) | |
257 y += pos[i * scalars_per_pos + 1]; | |
258 | |
259 min_point.set(std::min(x, min_point.x()), std::min(y, min_point.y())); | |
260 max_point.set(std::max(x, max_point.x()), std::max(y, max_point.y())); | |
261 } | |
262 | |
263 SkRect bounds = SkRect::MakeLTRB( | |
264 min_point.x(), min_point.y(), max_point.x(), max_point.y()); | |
265 | |
266 // Math is borrowed from SkBBoxRecord | |
267 SkPaint::FontMetrics metrics; | |
268 paint.getFontMetrics(&metrics); | |
269 | |
270 bounds.fTop += metrics.fTop; | |
271 bounds.fBottom += metrics.fBottom; | |
272 | |
273 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2; | |
274 bounds.fLeft += pad; | |
275 bounds.fRight -= pad; | |
276 | |
277 GatherPixelRefDevice::drawRect(draw, bounds, paint); | |
278 } | |
279 virtual void drawTextOnPath(const SkDraw& draw, | |
280 const void* text, | |
281 size_t len, | |
282 const SkPath& path, | |
283 const SkMatrix* matrix, | |
284 const SkPaint& paint) SK_OVERRIDE { | |
285 SkBitmap bitmap; | |
286 if (!GetBitmapFromPaint(paint, &bitmap)) | |
287 return; | |
288 | |
289 // Math is borrowed from SkBBoxRecord | |
290 SkRect bounds = path.getBounds(); | |
291 SkPaint::FontMetrics metrics; | |
292 paint.getFontMetrics(&metrics); | |
293 | |
294 SkScalar pad = metrics.fTop; | |
295 bounds.fLeft += pad; | |
296 bounds.fRight -= pad; | |
297 bounds.fTop += pad; | |
298 bounds.fBottom -= pad; | |
299 | |
300 GatherPixelRefDevice::drawRect(draw, bounds, paint); | |
301 } | |
302 virtual void drawVertices(const SkDraw& draw, | |
303 SkCanvas::VertexMode, | |
304 int vertex_count, | |
305 const SkPoint verts[], | |
306 const SkPoint texs[], | |
307 const SkColor colors[], | |
308 SkXfermode* xmode, | |
309 const uint16_t indices[], | |
310 int index_count, | |
311 const SkPaint& paint) SK_OVERRIDE { | |
312 GatherPixelRefDevice::drawPoints( | |
313 draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint); | |
314 } | |
315 virtual void drawDevice(const SkDraw&, | |
316 SkBaseDevice*, | |
317 int x, | |
318 int y, | |
319 const SkPaint&) SK_OVERRIDE {} | |
320 | |
321 protected: | |
322 virtual bool onReadPixels(const SkBitmap& bitmap, | |
323 int x, | |
324 int y, | |
325 SkCanvas::Config8888 config8888) SK_OVERRIDE { | |
326 return false; | |
327 } | |
328 | |
329 private: | |
330 LazyPixelRefSet* lazy_pixel_ref_set_; | |
331 | |
332 void AddBitmap(const SkBitmap& bm, const SkRect& rect) { | |
333 SkRect canvas_rect = SkRect::MakeWH(width(), height()); | |
334 SkRect paint_rect = SkRect::MakeEmpty(); | |
335 paint_rect.intersect(rect, canvas_rect); | |
336 lazy_pixel_ref_set_->Add(bm.pixelRef(), paint_rect); | |
337 } | |
338 | |
339 bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) { | |
340 SkShader* shader = paint.getShader(); | |
341 if (shader) { | |
342 // Check whether the shader is a gradient in order to prevent generation | |
343 // of bitmaps from gradient shaders, which implement asABitmap. | |
344 if (SkShader::kNone_GradientType == shader->asAGradient(NULL)) | |
345 return shader->asABitmap(bm, NULL, NULL); | |
346 } | |
347 return false; | |
348 } | |
349 }; | |
350 | |
351 class NoSaveLayerCanvas : public SkCanvas { | |
352 public: | |
353 NoSaveLayerCanvas(SkBaseDevice* device) : INHERITED(device) {} | |
354 | |
355 // Turn saveLayer() into save() for speed, should not affect correctness. | |
356 virtual int saveLayer(const SkRect* bounds, | |
357 const SkPaint* paint, | |
358 SaveFlags flags) SK_OVERRIDE { | |
359 | |
360 // Like SkPictureRecord, we don't want to create layers, but we do need | |
361 // to respect the save and (possibly) its rect-clip. | |
362 int count = this->INHERITED::save(flags); | |
363 if (bounds) { | |
364 this->INHERITED::clipRectBounds(bounds, flags, NULL); | |
365 } | |
366 return count; | |
367 } | |
368 | |
369 // Disable aa for speed. | |
370 virtual bool clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) | |
371 SK_OVERRIDE { | |
372 return this->INHERITED::clipRect(rect, op, false); | |
373 } | |
374 | |
375 virtual bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA) | |
376 SK_OVERRIDE { | |
377 return this->updateClipConservativelyUsingBounds( | |
378 path.getBounds(), op, path.isInverseFillType()); | |
379 } | |
380 virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) | |
381 SK_OVERRIDE { | |
382 return this->updateClipConservativelyUsingBounds( | |
383 rrect.getBounds(), op, false); | |
384 } | |
385 | |
386 private: | |
387 typedef SkCanvas INHERITED; | |
388 }; | |
389 | |
390 } // namespace | |
391 | |
392 void LazyPixelRefUtils::GatherPixelRefs( | |
393 SkPicture* picture, | |
394 std::vector<PositionLazyPixelRef>* lazy_pixel_refs) { | |
395 lazy_pixel_refs->clear(); | |
396 LazyPixelRefSet pixel_ref_set(lazy_pixel_refs); | |
397 | |
398 SkBitmap empty_bitmap; | |
399 empty_bitmap.setConfig( | |
400 SkBitmap::kNo_Config, picture->width(), picture->height()); | |
401 | |
402 GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set); | |
403 NoSaveLayerCanvas canvas(&device); | |
404 | |
405 canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()), | |
406 SkRegion::kIntersect_Op, | |
407 false); | |
408 canvas.drawPicture(*picture); | |
409 } | |
410 | |
411 } // namespace skia | |
OLD | NEW |