blob: 4e52ba07c80c1663438af54f64541ee1868df139 [file] [log] [blame]
robertphillips@google.com56bf6e42014-01-13 13:33:26 +00001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkGatherPixelRefsAndRects_DEFINED
9#define SkGatherPixelRefsAndRects_DEFINED
10
11#include "SkBitmap.h"
12#include "SkDevice.h"
13#include "SkDraw.h"
14#include "SkPictureUtils.h"
15#include "SkRasterClip.h"
16#include "SkRefCnt.h"
17#include "SkRRect.h"
18#include "SkTypes.h"
19
20// This GatherPixelRefs device passes all discovered pixel refs and their
21// device bounds to the user provided SkPixelRefContainer-derived object
22class SkGatherPixelRefsAndRectsDevice : public SkBaseDevice {
23public:
24 SK_DECLARE_INST_COUNT(SkGatherPixelRefsAndRectsDevice)
25
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +000026 SkGatherPixelRefsAndRectsDevice(int width, int height,
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000027 SkPictureUtils::SkPixelRefContainer* prCont) {
28 fSize.set(width, height);
29 fPRCont = prCont;
30 SkSafeRef(fPRCont);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +000031 fEmptyBitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000032 }
33
34 virtual ~SkGatherPixelRefsAndRectsDevice() {
35 SkSafeUnref(fPRCont);
36 }
37
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000038 virtual int width() const SK_OVERRIDE { return fSize.width(); }
39 virtual int height() const SK_OVERRIDE { return fSize.height(); }
40 virtual bool isOpaque() const SK_OVERRIDE { return false; }
41 virtual SkBitmap::Config config() const SK_OVERRIDE {
42 return SkBitmap::kNo_Config;
43 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000044 virtual SkImageInfo imageInfo() const SK_OVERRIDE {
45 return fEmptyBitmap.info();
46 }
47
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000048 virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
49
50protected:
51 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
52 return false;
53 }
54 virtual void clear(SkColor color) SK_OVERRIDE {
55 NothingToDo();
56 }
57 virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
58 SkBitmap bm;
59
60 if (GetBitmapFromPaint(paint, &bm)) {
61 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
62 fPRCont->add(bm.pixelRef(), clipRect);
63 }
64 }
65 virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
66 const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
67 SkBitmap bm;
68 if (!GetBitmapFromPaint(paint, &bm)) {
69 return;
70 }
71
72 if (0 == count) {
73 return;
74 }
75
76 SkPoint min = points[0];
77 SkPoint max = points[0];
78 for (size_t i = 1; i < count; ++i) {
79 const SkPoint& point = points[i];
80
81 min.set(SkMinScalar(min.x(), point.x()), SkMinScalar(min.y(), point.y()));
82 max.set(SkMaxScalar(max.x(), point.x()), SkMaxScalar(max.y(), point.y()));
83 }
84
85 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x()+1, max.y()+1);
86
87 this->drawRect(draw, bounds, paint);
88 }
89 virtual void drawRect(const SkDraw& draw, const SkRect& rect,
90 const SkPaint& paint) SK_OVERRIDE {
91 SkBitmap bm;
92 if (GetBitmapFromPaint(paint, &bm)) {
93 SkRect mappedRect;
94 draw.fMatrix->mapRect(&mappedRect, rect);
95 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
96 mappedRect.intersect(clipRect);
97 fPRCont->add(bm.pixelRef(), mappedRect);
98 }
99 }
100 virtual void drawOval(const SkDraw& draw, const SkRect& rect,
101 const SkPaint& paint) SK_OVERRIDE {
102 this->drawRect(draw, rect, paint);
103 }
104 virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
105 const SkPaint& paint) SK_OVERRIDE {
106 this->drawRect(draw, rrect.rect(), paint);
107 }
108 virtual void drawPath(const SkDraw& draw, const SkPath& path,
109 const SkPaint& paint, const SkMatrix* prePathMatrix,
110 bool pathIsMutable) SK_OVERRIDE {
111 SkBitmap bm;
112 if (!GetBitmapFromPaint(paint, &bm)) {
113 return;
114 }
115
116 SkRect pathBounds = path.getBounds();
117 if (NULL != prePathMatrix) {
118 prePathMatrix->mapRect(&pathBounds);
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000119 }
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000120
121 this->drawRect(draw, pathBounds, paint);
122 }
123 virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
124 const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
125 SkMatrix totMatrix;
126 totMatrix.setConcat(*draw.fMatrix, matrix);
127
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000128 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000129 SkIntToScalar(bitmap.height()));
130 SkRect mappedRect;
131 totMatrix.mapRect(&mappedRect, bitmapRect);
132 fPRCont->add(bitmap.pixelRef(), mappedRect);
133
134 SkBitmap paintBitmap;
135 if (GetBitmapFromPaint(paint, &paintBitmap)) {
136 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
137 }
138 }
139 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
140 int x, int y, const SkPaint& paint) SK_OVERRIDE {
141 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
142 SkMatrix matrix;
143 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
144
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000145 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000146 SkIntToScalar(bitmap.height()));
147 SkRect mappedRect;
148 matrix.mapRect(&mappedRect, bitmapRect);
149 fPRCont->add(bitmap.pixelRef(), mappedRect);
150
151 SkBitmap paintBitmap;
152 if (GetBitmapFromPaint(paint, &paintBitmap)) {
153 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
154 }
155 }
156 virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
157 const SkRect* srcOrNull, const SkRect& dst,
158 const SkPaint& paint,
159 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000160 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000161 SkIntToScalar(bitmap.height()));
162 SkMatrix matrix;
163 matrix.setRectToRect(bitmapRect, dst, SkMatrix::kFill_ScaleToFit);
164 this->drawBitmap(draw, bitmap, matrix, paint);
165 }
166 virtual void drawText(const SkDraw& draw, const void* text, size_t len,
167 SkScalar x, SkScalar y,
168 const SkPaint& paint) SK_OVERRIDE {
169 SkBitmap bitmap;
170 if (!GetBitmapFromPaint(paint, &bitmap)) {
171 return;
172 }
173
174 // Math is borrowed from SkBBoxRecord
175 SkRect bounds;
176 paint.measureText(text, len, &bounds);
177 SkPaint::FontMetrics metrics;
178 paint.getFontMetrics(&metrics);
179
180 if (paint.isVerticalText()) {
181 SkScalar h = bounds.fBottom - bounds.fTop;
182 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
183 bounds.fTop -= h / 2;
184 bounds.fBottom -= h / 2;
185 }
186 bounds.fBottom += metrics.fBottom;
187 bounds.fTop += metrics.fTop;
188 } else {
189 SkScalar w = bounds.fRight - bounds.fLeft;
190 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
191 bounds.fLeft -= w / 2;
192 bounds.fRight -= w / 2;
193 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
194 bounds.fLeft -= w;
195 bounds.fRight -= w;
196 }
197 bounds.fTop = metrics.fTop;
198 bounds.fBottom = metrics.fBottom;
199 }
200
201 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
202 bounds.fLeft -= pad;
203 bounds.fRight += pad;
204 bounds.offset(x, y);
205
206 this->drawRect(draw, bounds, paint);
207 }
208 virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
209 const SkScalar pos[], SkScalar constY,
210 int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
211 SkBitmap bitmap;
212 if (!GetBitmapFromPaint(paint, &bitmap)) {
213 return;
214 }
215
216 if (0 == len) {
217 return;
218 }
219
220 // Similar to SkDraw asserts.
221 SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2);
222
robertphillips@google.comf0a40132014-01-13 14:13:46 +0000223 SkScalar y = scalarsPerPos == 1 ? constY : constY + pos[1];
224
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000225 SkPoint min, max;
robertphillips@google.comf0a40132014-01-13 14:13:46 +0000226 min.set(pos[0], y);
227 max.set(pos[0], y);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000228
229 for (size_t i = 1; i < len; ++i) {
230 SkScalar x = pos[i * scalarsPerPos];
231 SkScalar y = constY;
232 if (2 == scalarsPerPos) {
233 y += pos[i * scalarsPerPos + 1];
234 }
235
236 min.set(SkMinScalar(x, min.x()), SkMinScalar(y, min.y()));
237 max.set(SkMaxScalar(x, max.x()), SkMaxScalar(y, max.y()));
238 }
239
240 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x(), max.y());
241
242 // Math is borrowed from SkBBoxRecord
243 SkPaint::FontMetrics metrics;
244 paint.getFontMetrics(&metrics);
245
246 bounds.fTop += metrics.fTop;
247 bounds.fBottom += metrics.fBottom;
248
249 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
250 bounds.fLeft -= pad;
251 bounds.fRight += pad;
252
253 this->drawRect(draw, bounds, paint);
254 }
255 virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
256 const SkPath& path, const SkMatrix* matrix,
257 const SkPaint& paint) SK_OVERRIDE {
258 SkBitmap bitmap;
259 if (!GetBitmapFromPaint(paint, &bitmap)) {
260 return;
261 }
262
263 // Math is borrowed from SkBBoxRecord
264 SkRect bounds = path.getBounds();
265 SkPaint::FontMetrics metrics;
266 paint.getFontMetrics(&metrics);
267
268 SkScalar pad = metrics.fTop;
269 // TODO: inset?!
270 bounds.fLeft += pad;
271 bounds.fRight -= pad;
272 bounds.fTop += pad;
273 bounds.fBottom -= pad;
274
275 this->drawRect(draw, bounds, paint);
276 }
277 virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
278 const SkPoint verts[], const SkPoint texs[],
279 const SkColor colors[], SkXfermode* xmode,
280 const uint16_t indices[], int indexCount,
281 const SkPaint& paint) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000282 this->drawPoints(draw, SkCanvas::kPolygon_PointMode, vertexCount, verts, paint);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000283 }
284 virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
285 const SkPaint&) SK_OVERRIDE {
286 NothingToDo();
287 }
288 // TODO: allow this call to return failure, or move to SkBitmapDevice only.
289 virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
290 return fEmptyBitmap;
291 }
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000292 virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
293 virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000294 virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
295 virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000296 virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000297 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
298 return false;
299 }
300
301private:
302 SkPictureUtils::SkPixelRefContainer* fPRCont;
303 SkISize fSize;
304
305 SkBitmap fEmptyBitmap; // legacy -- need to remove
306
307 static bool GetBitmapFromPaint(const SkPaint &paint, SkBitmap* bitmap) {
308 SkShader* shader = paint.getShader();
309 if (NULL != shader) {
310 if (SkShader::kNone_GradientType == shader->asAGradient(NULL)) {
311 return SkShader::kNone_BitmapType != shader->asABitmap(bitmap, NULL, NULL);
312 }
313 }
314 return false;
315 }
316
317 virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
318 NotSupported();
319 }
320
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000321 virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000322 // we expect to only get called via savelayer, in which case it is fine.
323 SkASSERT(kSaveLayer_Usage == usage);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000324 return SkNEW_ARGS(SkGatherPixelRefsAndRectsDevice,
325 (info.width(), info.height(), fPRCont));
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000326 }
327
328 virtual void flush() SK_OVERRIDE {}
329
330 static void NotSupported() {
331 SkDEBUGFAIL("this method should never be called");
332 }
333
334 static void NothingToDo() {}
335
336 typedef SkBaseDevice INHERITED;
337};
338
339#endif // SkGatherPixelRefsAndRects_DEFINED