Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / skia / ext / pixel_ref_utils.cc
blob8b5f1dca83afb42a9bc0e4c1b021288094124b90
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.
5 #include "skia/ext/pixel_ref_utils.h"
7 #include <algorithm>
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"
20 namespace skia {
22 namespace {
24 // URI label for a discardable SkPixelRef.
25 const char kLabelDiscardable[] = "discardable";
27 class DiscardablePixelRefSet {
28 public:
29 DiscardablePixelRefSet(
30 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs)
31 : pixel_refs_(pixel_refs) {}
33 void Add(SkPixelRef* pixel_ref,
34 const SkRect& rect,
35 const SkMatrix& matrix,
36 SkFilterQuality filter_quality) {
37 // Only save discardable pixel refs.
38 if (pixel_ref->getURI() &&
39 !strcmp(pixel_ref->getURI(), kLabelDiscardable)) {
40 PixelRefUtils::PositionPixelRef position_pixel_ref;
41 position_pixel_ref.pixel_ref = pixel_ref;
42 position_pixel_ref.pixel_ref_rect = rect;
43 position_pixel_ref.matrix = matrix;
44 position_pixel_ref.filter_quality = filter_quality;
45 pixel_refs_->push_back(position_pixel_ref);
49 private:
50 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs_;
53 class GatherPixelRefDevice : public SkBitmapDevice {
54 public:
55 GatherPixelRefDevice(const SkBitmap& bm,
56 DiscardablePixelRefSet* pixel_ref_set)
57 : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
59 void drawPaint(const SkDraw& draw, const SkPaint& paint) override {
60 SkBitmap bitmap;
61 if (GetBitmapFromPaint(paint, &bitmap)) {
62 SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
63 AddBitmap(bitmap, clip_rect, *draw.fMatrix, paint.getFilterQuality());
67 void drawPoints(const SkDraw& draw,
68 SkCanvas::PointMode mode,
69 size_t count,
70 const SkPoint points[],
71 const SkPaint& paint) override {
72 SkBitmap bitmap;
73 if (!GetBitmapFromPaint(paint, &bitmap))
74 return;
76 if (count == 0)
77 return;
79 SkPoint min_point = points[0];
80 SkPoint max_point = points[0];
81 for (size_t i = 1; i < count; ++i) {
82 const SkPoint& point = points[i];
83 min_point.set(std::min(min_point.x(), point.x()),
84 std::min(min_point.y(), point.y()));
85 max_point.set(std::max(max_point.x(), point.x()),
86 std::max(max_point.y(), point.y()));
89 SkRect bounds = SkRect::MakeLTRB(
90 min_point.x(), min_point.y(), max_point.x(), max_point.y());
92 GatherPixelRefDevice::drawRect(draw, bounds, paint);
94 void drawRect(const SkDraw& draw,
95 const SkRect& rect,
96 const SkPaint& paint) override {
97 SkBitmap bitmap;
98 if (GetBitmapFromPaint(paint, &bitmap)) {
99 SkRect mapped_rect;
100 draw.fMatrix->mapRect(&mapped_rect, rect);
101 if (mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds()))) {
102 AddBitmap(bitmap, mapped_rect, *draw.fMatrix, paint.getFilterQuality());
106 void drawOval(const SkDraw& draw,
107 const SkRect& rect,
108 const SkPaint& paint) override {
109 GatherPixelRefDevice::drawRect(draw, rect, paint);
111 void drawRRect(const SkDraw& draw,
112 const SkRRect& rect,
113 const SkPaint& paint) override {
114 GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
116 void drawPath(const SkDraw& draw,
117 const SkPath& path,
118 const SkPaint& paint,
119 const SkMatrix* pre_path_matrix,
120 bool path_is_mutable) override {
121 SkBitmap bitmap;
122 if (!GetBitmapFromPaint(paint, &bitmap))
123 return;
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;
132 GatherPixelRefDevice::drawRect(draw, final_rect, paint);
134 void drawBitmap(const SkDraw& draw,
135 const SkBitmap& bitmap,
136 const SkMatrix& matrix,
137 const SkPaint& paint) override {
138 SkMatrix total_matrix;
139 total_matrix.setConcat(*draw.fMatrix, matrix);
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, total_matrix, paint.getFilterQuality());
146 SkBitmap paint_bitmap;
147 if (GetBitmapFromPaint(paint, &paint_bitmap)) {
148 AddBitmap(paint_bitmap, mapped_rect, total_matrix,
149 paint.getFilterQuality());
152 void drawBitmapRect(const SkDraw& draw,
153 const SkBitmap& bitmap,
154 const SkRect* src_or_null,
155 const SkRect& dst,
156 const SkPaint& paint,
157 SkCanvas::SrcRectConstraint) override {
158 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
159 SkMatrix matrix;
160 matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
161 GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint);
163 void drawSprite(const SkDraw& draw,
164 const SkBitmap& bitmap,
165 int x,
166 int y,
167 const SkPaint& paint) override {
168 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
169 SkMatrix matrix;
170 matrix.setTranslate(x, y);
172 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
173 SkRect mapped_rect;
174 matrix.mapRect(&mapped_rect, bitmap_rect);
176 SkMatrix identity;
177 identity.setIdentity();
178 // Sprites aren't affected by current matrix, so use the identity matrix.
179 AddBitmap(bitmap, mapped_rect, identity, paint.getFilterQuality());
180 SkBitmap paint_bitmap;
181 if (GetBitmapFromPaint(paint, &paint_bitmap))
182 AddBitmap(paint_bitmap, mapped_rect, identity, paint.getFilterQuality());
184 void drawText(const SkDraw& draw,
185 const void* text,
186 size_t len,
187 SkScalar x,
188 SkScalar y,
189 const SkPaint& paint) override {
190 SkBitmap bitmap;
191 if (!GetBitmapFromPaint(paint, &bitmap))
192 return;
194 // Math is borrowed from SkBBoxRecord
195 SkRect bounds;
196 paint.measureText(text, len, &bounds);
197 SkPaint::FontMetrics metrics;
198 paint.getFontMetrics(&metrics);
200 if (paint.isVerticalText()) {
201 SkScalar h = bounds.fBottom - bounds.fTop;
202 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
203 bounds.fTop -= h / 2;
204 bounds.fBottom -= h / 2;
206 bounds.fBottom += metrics.fBottom;
207 bounds.fTop += metrics.fTop;
208 } else {
209 SkScalar w = bounds.fRight - bounds.fLeft;
210 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
211 bounds.fLeft -= w / 2;
212 bounds.fRight -= w / 2;
213 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
214 bounds.fLeft -= w;
215 bounds.fRight -= w;
217 bounds.fTop = metrics.fTop;
218 bounds.fBottom = metrics.fBottom;
221 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
222 bounds.fLeft -= pad;
223 bounds.fRight += pad;
224 bounds.fLeft += x;
225 bounds.fRight += x;
226 bounds.fTop += y;
227 bounds.fBottom += y;
229 GatherPixelRefDevice::drawRect(draw, bounds, paint);
231 void drawPosText(const SkDraw& draw,
232 const void* text,
233 size_t len,
234 const SkScalar pos[],
235 int scalars_per_pos,
236 const SkPoint& offset,
237 const SkPaint& paint) override {
238 SkBitmap bitmap;
239 if (!GetBitmapFromPaint(paint, &bitmap))
240 return;
242 if (len == 0)
243 return;
245 // Similar to SkDraw asserts.
246 SkASSERT(scalars_per_pos == 1 || scalars_per_pos == 2);
248 SkPoint min_point = SkPoint::Make(offset.x() + pos[0],
249 offset.y() + (2 == scalars_per_pos ? pos[1] : 0));
250 SkPoint max_point = min_point;
252 for (size_t i = 0; i < len; ++i) {
253 SkScalar x = offset.x() + pos[i * scalars_per_pos];
254 SkScalar y = offset.y() + (2 == scalars_per_pos ? pos[i * scalars_per_pos + 1] : 0);
256 min_point.set(std::min(x, min_point.x()), std::min(y, min_point.y()));
257 max_point.set(std::max(x, max_point.x()), std::max(y, max_point.y()));
260 SkRect bounds = SkRect::MakeLTRB(
261 min_point.x(), min_point.y(), max_point.x(), max_point.y());
263 // Math is borrowed from SkBBoxRecord
264 SkPaint::FontMetrics metrics;
265 paint.getFontMetrics(&metrics);
267 bounds.fTop += metrics.fTop;
268 bounds.fBottom += metrics.fBottom;
270 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
271 bounds.fLeft += pad;
272 bounds.fRight -= pad;
274 GatherPixelRefDevice::drawRect(draw, bounds, paint);
276 void drawTextOnPath(const SkDraw& draw,
277 const void* text,
278 size_t len,
279 const SkPath& path,
280 const SkMatrix* matrix,
281 const SkPaint& paint) override {
282 SkBitmap bitmap;
283 if (!GetBitmapFromPaint(paint, &bitmap))
284 return;
286 // Math is borrowed from SkBBoxRecord
287 SkRect bounds = path.getBounds();
288 SkPaint::FontMetrics metrics;
289 paint.getFontMetrics(&metrics);
291 SkScalar pad = metrics.fTop;
292 bounds.fLeft += pad;
293 bounds.fRight -= pad;
294 bounds.fTop += pad;
295 bounds.fBottom -= pad;
297 GatherPixelRefDevice::drawRect(draw, bounds, paint);
299 void drawVertices(const SkDraw& draw,
300 SkCanvas::VertexMode,
301 int vertex_count,
302 const SkPoint verts[],
303 const SkPoint texs[],
304 const SkColor colors[],
305 SkXfermode* xmode,
306 const uint16_t indices[],
307 int index_count,
308 const SkPaint& paint) override {
309 GatherPixelRefDevice::drawPoints(
310 draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
312 void drawDevice(const SkDraw&,
313 SkBaseDevice*,
314 int x,
315 int y,
316 const SkPaint&) override {}
318 protected:
319 bool onReadPixels(const SkImageInfo& info,
320 void* pixels,
321 size_t rowBytes,
322 int x,
323 int y) override {
324 return false;
327 bool onWritePixels(const SkImageInfo& info,
328 const void* pixels,
329 size_t rowBytes,
330 int x,
331 int y) override {
332 return false;
335 private:
336 DiscardablePixelRefSet* pixel_ref_set_;
338 void AddBitmap(const SkBitmap& bm,
339 const SkRect& rect,
340 const SkMatrix& matrix,
341 SkFilterQuality filter_quality) {
342 SkRect canvas_rect = SkRect::MakeWH(width(), height());
343 SkRect paint_rect = SkRect::MakeEmpty();
344 if (paint_rect.intersect(rect, canvas_rect)) {
345 pixel_ref_set_->Add(bm.pixelRef(), paint_rect, matrix,
346 filter_quality);
350 bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) {
351 SkShader* shader = paint.getShader();
352 if (shader) {
353 // Check whether the shader is a gradient in order to prevent generation
354 // of bitmaps from gradient shaders, which implement asABitmap.
355 if (SkShader::kNone_GradientType == shader->asAGradient(NULL))
356 return shader->asABitmap(bm, NULL, NULL);
358 return false;
362 } // namespace
364 void PixelRefUtils::GatherDiscardablePixelRefs(
365 SkPicture* picture,
366 std::vector<PositionPixelRef>* pixel_refs) {
367 pixel_refs->clear();
368 DiscardablePixelRefSet pixel_ref_set(pixel_refs);
370 SkRect picture_bounds = picture->cullRect();
371 SkIRect picture_ibounds = picture_bounds.roundOut();
372 SkBitmap empty_bitmap;
373 empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture_ibounds.width(),
374 picture_ibounds.height()));
376 GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
377 SkNoSaveLayerCanvas canvas(&device);
379 // Draw the picture pinned against our top/left corner.
380 canvas.translate(-picture_bounds.left(), -picture_bounds.top());
381 canvas.drawPicture(picture);
384 } // namespace skia