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