Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / skia / ext / pixel_ref_utils.cc
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:
29   DiscardablePixelRefSet(
30       std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs)
31       : pixel_refs_(pixel_refs) {}
32
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:
50   GatherPixelRefDevice(const SkBitmap& bm,
51                        DiscardablePixelRefSet* pixel_ref_set)
52       : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
53
54   void clear(SkColor color) override {}
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       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::DrawBitmapRectFlags 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     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->asABitmap(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   SkBitmap empty_bitmap;
356   empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture->width(), picture->height()));
357
358   GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
359   SkNoSaveLayerCanvas canvas(&device);
360
361   canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()),
362                   SkRegion::kIntersect_Op,
363                   false);
364   canvas.drawPicture(picture);
365 }
366
367 }  // namespace skia