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
20namespace skia {
21
22namespace {
23
24// URI label for a lazily decoded SkPixelRef.
25const char kLabelLazyDecoded[] = "lazy";
26
27class 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
49class 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
351class 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
392void 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
412