• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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"
19 
20 namespace skia {
21 
22 namespace {
23 
24 // URI label for a discardable SkPixelRef.
25 const char kLabelDiscardable[] = "discardable";
26 
27 class DiscardablePixelRefSet {
28  public:
DiscardablePixelRefSet(std::vector<PixelRefUtils::PositionPixelRef> * pixel_refs)29   DiscardablePixelRefSet(
30       std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs)
31       : pixel_refs_(pixel_refs) {}
32 
Add(SkPixelRef * pixel_ref,const SkRect & rect)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);
41     }
42   }
43 
44  private:
45   std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs_;
46 };
47 
48 class GatherPixelRefDevice : public SkBitmapDevice {
49  public:
GatherPixelRefDevice(const SkBitmap & bm,DiscardablePixelRefSet * pixel_ref_set)50   GatherPixelRefDevice(const SkBitmap& bm,
51                        DiscardablePixelRefSet* pixel_ref_set)
52       : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
53 
clear(SkColor color)54   virtual void clear(SkColor color) SK_OVERRIDE {}
drawPaint(const SkDraw & draw,const SkPaint & paint)55   virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_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 
drawPoints(const SkDraw & draw,SkCanvas::PointMode mode,size_t count,const SkPoint points[],const SkPaint & paint)63   virtual void drawPoints(const SkDraw& draw,
64                           SkCanvas::PointMode mode,
65                           size_t count,
66                           const SkPoint points[],
67                           const SkPaint& paint) SK_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   }
drawRect(const SkDraw & draw,const SkRect & rect,const SkPaint & paint)90   virtual void drawRect(const SkDraw& draw,
91                         const SkRect& rect,
92                         const SkPaint& paint) SK_OVERRIDE {
93     SkBitmap bitmap;
94     if (GetBitmapFromPaint(paint, &bitmap)) {
95       SkRect mapped_rect;
96       draw.fMatrix->mapRect(&mapped_rect, rect);
97       mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds()));
98       AddBitmap(bitmap, mapped_rect);
99     }
100   }
drawOval(const SkDraw & draw,const SkRect & rect,const SkPaint & paint)101   virtual void drawOval(const SkDraw& draw,
102                         const SkRect& rect,
103                         const SkPaint& paint) SK_OVERRIDE {
104     GatherPixelRefDevice::drawRect(draw, rect, paint);
105   }
drawRRect(const SkDraw & draw,const SkRRect & rect,const SkPaint & paint)106   virtual void drawRRect(const SkDraw& draw,
107                          const SkRRect& rect,
108                          const SkPaint& paint) SK_OVERRIDE {
109     GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
110   }
drawPath(const SkDraw & draw,const SkPath & path,const SkPaint & paint,const SkMatrix * pre_path_matrix,bool path_is_mutable)111   virtual void drawPath(const SkDraw& draw,
112                         const SkPath& path,
113                         const SkPaint& paint,
114                         const SkMatrix* pre_path_matrix,
115                         bool path_is_mutable) SK_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   }
drawBitmap(const SkDraw & draw,const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint & 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);
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   }
drawBitmapRect(const SkDraw & draw,const SkBitmap & bitmap,const SkRect * src_or_null,const SkRect & dst,const SkPaint & paint,SkCanvas::DrawBitmapRectFlags flags)145   virtual 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::DrawBitmapRectFlags flags) SK_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   }
drawSprite(const SkDraw & draw,const SkBitmap & bitmap,int x,int y,const SkPaint & paint)156   virtual void drawSprite(const SkDraw& draw,
157                           const SkBitmap& bitmap,
158                           int x,
159                           int y,
160                           const SkPaint& paint) SK_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   }
drawText(const SkDraw & draw,const void * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)174   virtual void drawText(const SkDraw& draw,
175                         const void* text,
176                         size_t len,
177                         SkScalar x,
178                         SkScalar y,
179                         const SkPaint& paint) SK_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   }
drawPosText(const SkDraw & draw,const void * text,size_t len,const SkScalar pos[],SkScalar const_y,int scalars_per_pos,const SkPaint & paint)221   virtual void drawPosText(const SkDraw& draw,
222                            const void* text,
223                            size_t len,
224                            const SkScalar pos[],
225                            SkScalar const_y,
226                            int scalars_per_pos,
227                            const SkPaint& paint) SK_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;
239     SkPoint max_point;
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]);
246     }
247 
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];
253 
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()));
256     }
257 
258     SkRect bounds = SkRect::MakeLTRB(
259         min_point.x(), min_point.y(), max_point.x(), max_point.y());
260 
261     // Math is borrowed from SkBBoxRecord
262     SkPaint::FontMetrics metrics;
263     paint.getFontMetrics(&metrics);
264 
265     bounds.fTop += metrics.fTop;
266     bounds.fBottom += metrics.fBottom;
267 
268     SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
269     bounds.fLeft += pad;
270     bounds.fRight -= pad;
271 
272     GatherPixelRefDevice::drawRect(draw, bounds, paint);
273   }
drawTextOnPath(const SkDraw & draw,const void * text,size_t len,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)274   virtual void drawTextOnPath(const SkDraw& draw,
275                               const void* text,
276                               size_t len,
277                               const SkPath& path,
278                               const SkMatrix* matrix,
279                               const SkPaint& paint) SK_OVERRIDE {
280     SkBitmap bitmap;
281     if (!GetBitmapFromPaint(paint, &bitmap))
282       return;
283 
284     // Math is borrowed from SkBBoxRecord
285     SkRect bounds = path.getBounds();
286     SkPaint::FontMetrics metrics;
287     paint.getFontMetrics(&metrics);
288 
289     SkScalar pad = metrics.fTop;
290     bounds.fLeft += pad;
291     bounds.fRight -= pad;
292     bounds.fTop += pad;
293     bounds.fBottom -= pad;
294 
295     GatherPixelRefDevice::drawRect(draw, bounds, paint);
296   }
drawVertices(const SkDraw & draw,SkCanvas::VertexMode,int vertex_count,const SkPoint verts[],const SkPoint texs[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int index_count,const SkPaint & paint)297   virtual void drawVertices(const SkDraw& draw,
298                             SkCanvas::VertexMode,
299                             int vertex_count,
300                             const SkPoint verts[],
301                             const SkPoint texs[],
302                             const SkColor colors[],
303                             SkXfermode* xmode,
304                             const uint16_t indices[],
305                             int index_count,
306                             const SkPaint& paint) SK_OVERRIDE {
307     GatherPixelRefDevice::drawPoints(
308         draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
309   }
drawDevice(const SkDraw &,SkBaseDevice *,int x,int y,const SkPaint &)310   virtual void drawDevice(const SkDraw&,
311                           SkBaseDevice*,
312                           int x,
313                           int y,
314                           const SkPaint&) SK_OVERRIDE {}
315 
316  protected:
onReadPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,int x,int y)317   virtual bool onReadPixels(const SkImageInfo& info,
318                             void* pixels,
319                             size_t rowBytes,
320                             int x,
321                             int y) SK_OVERRIDE {
322     return false;
323   }
324 
onWritePixels(const SkImageInfo & info,const void * pixels,size_t rowBytes,int x,int y)325   virtual bool onWritePixels(const SkImageInfo& info,
326                              const void* pixels,
327                              size_t rowBytes,
328                              int x,
329                              int y) SK_OVERRIDE {
330     return false;
331   }
332 
333  private:
334   DiscardablePixelRefSet* pixel_ref_set_;
335 
AddBitmap(const SkBitmap & bm,const SkRect & rect)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);
341   }
342 
GetBitmapFromPaint(const SkPaint & paint,SkBitmap * bm)343   bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) {
344     SkShader* shader = paint.getShader();
345     if (shader) {
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);
350     }
351     return false;
352   }
353 };
354 
355 }  // namespace
356 
GatherDiscardablePixelRefs(SkPicture * picture,std::vector<PositionPixelRef> * pixel_refs)357 void PixelRefUtils::GatherDiscardablePixelRefs(
358     SkPicture* picture,
359     std::vector<PositionPixelRef>* pixel_refs) {
360   pixel_refs->clear();
361   DiscardablePixelRefSet pixel_ref_set(pixel_refs);
362 
363   SkBitmap empty_bitmap;
364   empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture->width(), picture->height()));
365 
366   GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
367   SkNoSaveLayerCanvas canvas(&device);
368 
369   canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()),
370                   SkRegion::kIntersect_Op,
371                   false);
372   canvas.drawPicture(picture);
373 }
374 
375 }  // namespace skia
376