Add creis, davidben, and mmenke to content/browser/loader/OWNERs.
[chromium-blink-merge.git] / skia / ext / pixel_ref_utils.cc
blob417295ec9370e16dbfc3283a1a4e2d144ae62634
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/src/core/SkRasterClip.h"
19 namespace skia {
21 namespace {
23 // URI label for a discardable SkPixelRef.
24 const char kLabelDiscardable[] = "discardable";
26 class DiscardablePixelRefSet {
27 public:
28 DiscardablePixelRefSet(
29 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs)
30 : pixel_refs_(pixel_refs) {}
32 void Add(SkPixelRef* pixel_ref, const SkRect& rect) {
33 // Only save discardable pixel refs.
34 if (pixel_ref->getURI() &&
35 !strcmp(pixel_ref->getURI(), kLabelDiscardable)) {
36 PixelRefUtils::PositionPixelRef position_pixel_ref;
37 position_pixel_ref.pixel_ref = pixel_ref;
38 position_pixel_ref.pixel_ref_rect = rect;
39 pixel_refs_->push_back(position_pixel_ref);
43 private:
44 std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs_;
47 class GatherPixelRefDevice : public SkBitmapDevice {
48 public:
49 GatherPixelRefDevice(const SkBitmap& bm,
50 DiscardablePixelRefSet* pixel_ref_set)
51 : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
53 virtual void clear(SkColor color) SK_OVERRIDE {}
54 virtual void writePixels(const SkBitmap& bitmap,
55 int x,
56 int y,
57 SkCanvas::Config8888 config8888) SK_OVERRIDE {}
59 virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
60 SkBitmap bitmap;
61 if (GetBitmapFromPaint(paint, &bitmap)) {
62 SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
63 AddBitmap(bitmap, clip_rect);
67 virtual void drawPoints(const SkDraw& draw,
68 SkCanvas::PointMode mode,
69 size_t count,
70 const SkPoint points[],
71 const SkPaint& paint) SK_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 virtual void drawRect(const SkDraw& draw,
95 const SkRect& rect,
96 const SkPaint& paint) SK_OVERRIDE {
97 SkBitmap bitmap;
98 if (GetBitmapFromPaint(paint, &bitmap)) {
99 SkRect mapped_rect;
100 draw.fMatrix->mapRect(&mapped_rect, rect);
101 mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds()));
102 AddBitmap(bitmap, mapped_rect);
105 virtual void drawOval(const SkDraw& draw,
106 const SkRect& rect,
107 const SkPaint& paint) SK_OVERRIDE {
108 GatherPixelRefDevice::drawRect(draw, rect, paint);
110 virtual void drawRRect(const SkDraw& draw,
111 const SkRRect& rect,
112 const SkPaint& paint) SK_OVERRIDE {
113 GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
115 virtual void drawPath(const SkDraw& draw,
116 const SkPath& path,
117 const SkPaint& paint,
118 const SkMatrix* pre_path_matrix,
119 bool path_is_mutable) SK_OVERRIDE {
120 SkBitmap bitmap;
121 if (!GetBitmapFromPaint(paint, &bitmap))
122 return;
124 SkRect path_bounds = path.getBounds();
125 SkRect final_rect;
126 if (pre_path_matrix != NULL)
127 pre_path_matrix->mapRect(&final_rect, path_bounds);
128 else
129 final_rect = path_bounds;
131 GatherPixelRefDevice::drawRect(draw, final_rect, paint);
133 virtual void drawBitmap(const SkDraw& draw,
134 const SkBitmap& bitmap,
135 const SkMatrix& matrix,
136 const SkPaint& paint) SK_OVERRIDE {
137 SkMatrix total_matrix;
138 total_matrix.setConcat(*draw.fMatrix, matrix);
140 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
141 SkRect mapped_rect;
142 total_matrix.mapRect(&mapped_rect, bitmap_rect);
143 AddBitmap(bitmap, mapped_rect);
145 SkBitmap paint_bitmap;
146 if (GetBitmapFromPaint(paint, &paint_bitmap))
147 AddBitmap(paint_bitmap, mapped_rect);
149 virtual void drawBitmapRect(const SkDraw& draw,
150 const SkBitmap& bitmap,
151 const SkRect* src_or_null,
152 const SkRect& dst,
153 const SkPaint& paint,
154 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
155 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
156 SkMatrix matrix;
157 matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
158 GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint);
160 virtual void drawSprite(const SkDraw& draw,
161 const SkBitmap& bitmap,
162 int x,
163 int y,
164 const SkPaint& paint) SK_OVERRIDE {
165 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
166 SkMatrix matrix;
167 matrix.setTranslate(x, y);
169 SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
170 SkRect mapped_rect;
171 matrix.mapRect(&mapped_rect, bitmap_rect);
173 AddBitmap(bitmap, mapped_rect);
174 SkBitmap paint_bitmap;
175 if (GetBitmapFromPaint(paint, &paint_bitmap))
176 AddBitmap(paint_bitmap, mapped_rect);
178 virtual void drawText(const SkDraw& draw,
179 const void* text,
180 size_t len,
181 SkScalar x,
182 SkScalar y,
183 const SkPaint& paint) SK_OVERRIDE {
184 SkBitmap bitmap;
185 if (!GetBitmapFromPaint(paint, &bitmap))
186 return;
188 // Math is borrowed from SkBBoxRecord
189 SkRect bounds;
190 paint.measureText(text, len, &bounds);
191 SkPaint::FontMetrics metrics;
192 paint.getFontMetrics(&metrics);
194 if (paint.isVerticalText()) {
195 SkScalar h = bounds.fBottom - bounds.fTop;
196 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
197 bounds.fTop -= h / 2;
198 bounds.fBottom -= h / 2;
200 bounds.fBottom += metrics.fBottom;
201 bounds.fTop += metrics.fTop;
202 } else {
203 SkScalar w = bounds.fRight - bounds.fLeft;
204 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
205 bounds.fLeft -= w / 2;
206 bounds.fRight -= w / 2;
207 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
208 bounds.fLeft -= w;
209 bounds.fRight -= w;
211 bounds.fTop = metrics.fTop;
212 bounds.fBottom = metrics.fBottom;
215 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
216 bounds.fLeft -= pad;
217 bounds.fRight += pad;
218 bounds.fLeft += x;
219 bounds.fRight += x;
220 bounds.fTop += y;
221 bounds.fBottom += y;
223 GatherPixelRefDevice::drawRect(draw, bounds, paint);
225 virtual void drawPosText(const SkDraw& draw,
226 const void* text,
227 size_t len,
228 const SkScalar pos[],
229 SkScalar const_y,
230 int scalars_per_pos,
231 const SkPaint& paint) SK_OVERRIDE {
232 SkBitmap bitmap;
233 if (!GetBitmapFromPaint(paint, &bitmap))
234 return;
236 if (len == 0)
237 return;
239 // Similar to SkDraw asserts.
240 SkASSERT(scalars_per_pos == 1 || scalars_per_pos == 2);
242 SkPoint min_point;
243 SkPoint max_point;
244 if (scalars_per_pos == 1) {
245 min_point.set(pos[0], const_y);
246 max_point.set(pos[0], const_y);
247 } else if (scalars_per_pos == 2) {
248 min_point.set(pos[0], const_y + pos[1]);
249 max_point.set(pos[0], const_y + pos[1]);
252 for (size_t i = 0; i < len; ++i) {
253 SkScalar x = pos[i * scalars_per_pos];
254 SkScalar y = const_y;
255 if (scalars_per_pos == 2)
256 y += pos[i * scalars_per_pos + 1];
258 min_point.set(std::min(x, min_point.x()), std::min(y, min_point.y()));
259 max_point.set(std::max(x, max_point.x()), std::max(y, max_point.y()));
262 SkRect bounds = SkRect::MakeLTRB(
263 min_point.x(), min_point.y(), max_point.x(), max_point.y());
265 // Math is borrowed from SkBBoxRecord
266 SkPaint::FontMetrics metrics;
267 paint.getFontMetrics(&metrics);
269 bounds.fTop += metrics.fTop;
270 bounds.fBottom += metrics.fBottom;
272 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
273 bounds.fLeft += pad;
274 bounds.fRight -= pad;
276 GatherPixelRefDevice::drawRect(draw, bounds, paint);
278 virtual void drawTextOnPath(const SkDraw& draw,
279 const void* text,
280 size_t len,
281 const SkPath& path,
282 const SkMatrix* matrix,
283 const SkPaint& paint) SK_OVERRIDE {
284 SkBitmap bitmap;
285 if (!GetBitmapFromPaint(paint, &bitmap))
286 return;
288 // Math is borrowed from SkBBoxRecord
289 SkRect bounds = path.getBounds();
290 SkPaint::FontMetrics metrics;
291 paint.getFontMetrics(&metrics);
293 SkScalar pad = metrics.fTop;
294 bounds.fLeft += pad;
295 bounds.fRight -= pad;
296 bounds.fTop += pad;
297 bounds.fBottom -= pad;
299 GatherPixelRefDevice::drawRect(draw, bounds, paint);
301 virtual void drawVertices(const SkDraw& draw,
302 SkCanvas::VertexMode,
303 int vertex_count,
304 const SkPoint verts[],
305 const SkPoint texs[],
306 const SkColor colors[],
307 SkXfermode* xmode,
308 const uint16_t indices[],
309 int index_count,
310 const SkPaint& paint) SK_OVERRIDE {
311 GatherPixelRefDevice::drawPoints(
312 draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
314 virtual void drawDevice(const SkDraw&,
315 SkBaseDevice*,
316 int x,
317 int y,
318 const SkPaint&) SK_OVERRIDE {}
320 protected:
321 virtual bool onReadPixels(const SkBitmap& bitmap,
322 int x,
323 int y,
324 SkCanvas::Config8888 config8888) SK_OVERRIDE {
325 return false;
328 private:
329 DiscardablePixelRefSet* pixel_ref_set_;
331 void AddBitmap(const SkBitmap& bm, const SkRect& rect) {
332 SkRect canvas_rect = SkRect::MakeWH(width(), height());
333 SkRect paint_rect = SkRect::MakeEmpty();
334 paint_rect.intersect(rect, canvas_rect);
335 pixel_ref_set_->Add(bm.pixelRef(), paint_rect);
338 bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) {
339 SkShader* shader = paint.getShader();
340 if (shader) {
341 // Check whether the shader is a gradient in order to prevent generation
342 // of bitmaps from gradient shaders, which implement asABitmap.
343 if (SkShader::kNone_GradientType == shader->asAGradient(NULL))
344 return shader->asABitmap(bm, NULL, NULL);
346 return false;
350 class NoSaveLayerCanvas : public SkCanvas {
351 public:
352 NoSaveLayerCanvas(SkBaseDevice* device) : INHERITED(device) {}
354 // Turn saveLayer() into save() for speed, should not affect correctness.
355 virtual int saveLayer(const SkRect* bounds,
356 const SkPaint* paint,
357 SaveFlags flags) SK_OVERRIDE {
359 // Like SkPictureRecord, we don't want to create layers, but we do need
360 // to respect the save and (possibly) its rect-clip.
361 int count = this->INHERITED::save(flags);
362 if (bounds) {
363 this->INHERITED::clipRectBounds(bounds, flags, NULL);
365 return count;
368 // Disable aa for speed.
369 virtual bool clipRect(const SkRect& rect, SkRegion::Op op, bool doAA)
370 SK_OVERRIDE {
371 return this->INHERITED::clipRect(rect, op, false);
374 virtual bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA)
375 SK_OVERRIDE {
376 return this->updateClipConservativelyUsingBounds(
377 path.getBounds(), op, path.isInverseFillType());
379 virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA)
380 SK_OVERRIDE {
381 return this->updateClipConservativelyUsingBounds(
382 rrect.getBounds(), op, false);
385 private:
386 typedef SkCanvas INHERITED;
389 } // namespace
391 void PixelRefUtils::GatherDiscardablePixelRefs(
392 SkPicture* picture,
393 std::vector<PositionPixelRef>* pixel_refs) {
394 pixel_refs->clear();
395 DiscardablePixelRefSet pixel_ref_set(pixel_refs);
397 SkBitmap empty_bitmap;
398 empty_bitmap.setConfig(
399 SkBitmap::kNo_Config, picture->width(), picture->height());
401 GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
402 NoSaveLayerCanvas canvas(&device);
404 canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()),
405 SkRegion::kIntersect_Op,
406 false);
407 canvas.drawPicture(*picture);
410 } // namespace skia