blob: 90ab0f6cffcae0c84fc73fcc9a022cbfc106c4ea [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.org15a14052014-02-16 00:59:25 +000031 fEmptyBitmap.setConfig(SkImageInfo::Make(width, height,
32 kUnknown_SkColorType,
33 kIgnore_SkAlphaType));
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000034 }
35
36 virtual ~SkGatherPixelRefsAndRectsDevice() {
37 SkSafeUnref(fPRCont);
38 }
39
40 virtual uint32_t getDeviceCapabilities() SK_OVERRIDE { return 0; }
41
42 virtual int width() const SK_OVERRIDE { return fSize.width(); }
43 virtual int height() const SK_OVERRIDE { return fSize.height(); }
44 virtual bool isOpaque() const SK_OVERRIDE { return false; }
45 virtual SkBitmap::Config config() const SK_OVERRIDE {
46 return SkBitmap::kNo_Config;
47 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000048 virtual SkImageInfo imageInfo() const SK_OVERRIDE {
49 return fEmptyBitmap.info();
50 }
51
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000052 virtual void writePixels(const SkBitmap& bitmap, int x, int y,
53 SkCanvas::Config8888 config8888) SK_OVERRIDE {
54 NotSupported();
55 }
56 virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
57
58protected:
59 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
60 return false;
61 }
62 virtual void clear(SkColor color) SK_OVERRIDE {
63 NothingToDo();
64 }
65 virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
66 SkBitmap bm;
67
68 if (GetBitmapFromPaint(paint, &bm)) {
69 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
70 fPRCont->add(bm.pixelRef(), clipRect);
71 }
72 }
73 virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
74 const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
75 SkBitmap bm;
76 if (!GetBitmapFromPaint(paint, &bm)) {
77 return;
78 }
79
80 if (0 == count) {
81 return;
82 }
83
84 SkPoint min = points[0];
85 SkPoint max = points[0];
86 for (size_t i = 1; i < count; ++i) {
87 const SkPoint& point = points[i];
88
89 min.set(SkMinScalar(min.x(), point.x()), SkMinScalar(min.y(), point.y()));
90 max.set(SkMaxScalar(max.x(), point.x()), SkMaxScalar(max.y(), point.y()));
91 }
92
93 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x()+1, max.y()+1);
94
95 this->drawRect(draw, bounds, paint);
96 }
97 virtual void drawRect(const SkDraw& draw, const SkRect& rect,
98 const SkPaint& paint) SK_OVERRIDE {
99 SkBitmap bm;
100 if (GetBitmapFromPaint(paint, &bm)) {
101 SkRect mappedRect;
102 draw.fMatrix->mapRect(&mappedRect, rect);
103 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
104 mappedRect.intersect(clipRect);
105 fPRCont->add(bm.pixelRef(), mappedRect);
106 }
107 }
108 virtual void drawOval(const SkDraw& draw, const SkRect& rect,
109 const SkPaint& paint) SK_OVERRIDE {
110 this->drawRect(draw, rect, paint);
111 }
112 virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
113 const SkPaint& paint) SK_OVERRIDE {
114 this->drawRect(draw, rrect.rect(), paint);
115 }
116 virtual void drawPath(const SkDraw& draw, const SkPath& path,
117 const SkPaint& paint, const SkMatrix* prePathMatrix,
118 bool pathIsMutable) SK_OVERRIDE {
119 SkBitmap bm;
120 if (!GetBitmapFromPaint(paint, &bm)) {
121 return;
122 }
123
124 SkRect pathBounds = path.getBounds();
125 if (NULL != prePathMatrix) {
126 prePathMatrix->mapRect(&pathBounds);
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000127 }
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000128
129 this->drawRect(draw, pathBounds, paint);
130 }
131 virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
132 const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
133 SkMatrix totMatrix;
134 totMatrix.setConcat(*draw.fMatrix, matrix);
135
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000136 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000137 SkIntToScalar(bitmap.height()));
138 SkRect mappedRect;
139 totMatrix.mapRect(&mappedRect, bitmapRect);
140 fPRCont->add(bitmap.pixelRef(), mappedRect);
141
142 SkBitmap paintBitmap;
143 if (GetBitmapFromPaint(paint, &paintBitmap)) {
144 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
145 }
146 }
147 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
148 int x, int y, const SkPaint& paint) SK_OVERRIDE {
149 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
150 SkMatrix matrix;
151 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
152
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000153 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000154 SkIntToScalar(bitmap.height()));
155 SkRect mappedRect;
156 matrix.mapRect(&mappedRect, bitmapRect);
157 fPRCont->add(bitmap.pixelRef(), mappedRect);
158
159 SkBitmap paintBitmap;
160 if (GetBitmapFromPaint(paint, &paintBitmap)) {
161 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
162 }
163 }
164 virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
165 const SkRect* srcOrNull, const SkRect& dst,
166 const SkPaint& paint,
167 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000168 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000169 SkIntToScalar(bitmap.height()));
170 SkMatrix matrix;
171 matrix.setRectToRect(bitmapRect, dst, SkMatrix::kFill_ScaleToFit);
172 this->drawBitmap(draw, bitmap, matrix, paint);
173 }
174 virtual void drawText(const SkDraw& draw, const void* text, size_t len,
175 SkScalar x, SkScalar y,
176 const SkPaint& paint) SK_OVERRIDE {
177 SkBitmap bitmap;
178 if (!GetBitmapFromPaint(paint, &bitmap)) {
179 return;
180 }
181
182 // Math is borrowed from SkBBoxRecord
183 SkRect bounds;
184 paint.measureText(text, len, &bounds);
185 SkPaint::FontMetrics metrics;
186 paint.getFontMetrics(&metrics);
187
188 if (paint.isVerticalText()) {
189 SkScalar h = bounds.fBottom - bounds.fTop;
190 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
191 bounds.fTop -= h / 2;
192 bounds.fBottom -= h / 2;
193 }
194 bounds.fBottom += metrics.fBottom;
195 bounds.fTop += metrics.fTop;
196 } else {
197 SkScalar w = bounds.fRight - bounds.fLeft;
198 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
199 bounds.fLeft -= w / 2;
200 bounds.fRight -= w / 2;
201 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
202 bounds.fLeft -= w;
203 bounds.fRight -= w;
204 }
205 bounds.fTop = metrics.fTop;
206 bounds.fBottom = metrics.fBottom;
207 }
208
209 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
210 bounds.fLeft -= pad;
211 bounds.fRight += pad;
212 bounds.offset(x, y);
213
214 this->drawRect(draw, bounds, paint);
215 }
216 virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
217 const SkScalar pos[], SkScalar constY,
218 int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
219 SkBitmap bitmap;
220 if (!GetBitmapFromPaint(paint, &bitmap)) {
221 return;
222 }
223
224 if (0 == len) {
225 return;
226 }
227
228 // Similar to SkDraw asserts.
229 SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2);
230
robertphillips@google.comf0a40132014-01-13 14:13:46 +0000231 SkScalar y = scalarsPerPos == 1 ? constY : constY + pos[1];
232
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000233 SkPoint min, max;
robertphillips@google.comf0a40132014-01-13 14:13:46 +0000234 min.set(pos[0], y);
235 max.set(pos[0], y);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000236
237 for (size_t i = 1; i < len; ++i) {
238 SkScalar x = pos[i * scalarsPerPos];
239 SkScalar y = constY;
240 if (2 == scalarsPerPos) {
241 y += pos[i * scalarsPerPos + 1];
242 }
243
244 min.set(SkMinScalar(x, min.x()), SkMinScalar(y, min.y()));
245 max.set(SkMaxScalar(x, max.x()), SkMaxScalar(y, max.y()));
246 }
247
248 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x(), max.y());
249
250 // Math is borrowed from SkBBoxRecord
251 SkPaint::FontMetrics metrics;
252 paint.getFontMetrics(&metrics);
253
254 bounds.fTop += metrics.fTop;
255 bounds.fBottom += metrics.fBottom;
256
257 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
258 bounds.fLeft -= pad;
259 bounds.fRight += pad;
260
261 this->drawRect(draw, bounds, paint);
262 }
263 virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
264 const SkPath& path, const SkMatrix* matrix,
265 const SkPaint& paint) SK_OVERRIDE {
266 SkBitmap bitmap;
267 if (!GetBitmapFromPaint(paint, &bitmap)) {
268 return;
269 }
270
271 // Math is borrowed from SkBBoxRecord
272 SkRect bounds = path.getBounds();
273 SkPaint::FontMetrics metrics;
274 paint.getFontMetrics(&metrics);
275
276 SkScalar pad = metrics.fTop;
277 // TODO: inset?!
278 bounds.fLeft += pad;
279 bounds.fRight -= pad;
280 bounds.fTop += pad;
281 bounds.fBottom -= pad;
282
283 this->drawRect(draw, bounds, paint);
284 }
285 virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
286 const SkPoint verts[], const SkPoint texs[],
287 const SkColor colors[], SkXfermode* xmode,
288 const uint16_t indices[], int indexCount,
289 const SkPaint& paint) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000290 this->drawPoints(draw, SkCanvas::kPolygon_PointMode, vertexCount, verts, paint);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000291 }
292 virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
293 const SkPaint&) SK_OVERRIDE {
294 NothingToDo();
295 }
296 // TODO: allow this call to return failure, or move to SkBitmapDevice only.
297 virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
298 return fEmptyBitmap;
299 }
300 virtual bool onReadPixels(const SkBitmap& bitmap,
301 int x, int y,
302 SkCanvas::Config8888 config8888) SK_OVERRIDE {
303 NotSupported();
304 return false;
305 }
306 virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
307 virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000308 virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
309 virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
310 virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkMatrix&,
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000311 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
312 return false;
313 }
314
315private:
316 SkPictureUtils::SkPixelRefContainer* fPRCont;
317 SkISize fSize;
318
319 SkBitmap fEmptyBitmap; // legacy -- need to remove
320
321 static bool GetBitmapFromPaint(const SkPaint &paint, SkBitmap* bitmap) {
322 SkShader* shader = paint.getShader();
323 if (NULL != shader) {
324 if (SkShader::kNone_GradientType == shader->asAGradient(NULL)) {
325 return SkShader::kNone_BitmapType != shader->asABitmap(bitmap, NULL, NULL);
326 }
327 }
328 return false;
329 }
330
331 virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
332 NotSupported();
333 }
334
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000335 virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000336 // we expect to only get called via savelayer, in which case it is fine.
337 SkASSERT(kSaveLayer_Usage == usage);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000338 return SkNEW_ARGS(SkGatherPixelRefsAndRectsDevice,
339 (info.width(), info.height(), fPRCont));
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000340 }
341
342 virtual void flush() SK_OVERRIDE {}
343
344 static void NotSupported() {
345 SkDEBUGFAIL("this method should never be called");
346 }
347
348 static void NothingToDo() {}
349
350 typedef SkBaseDevice INHERITED;
351};
352
353#endif // SkGatherPixelRefsAndRects_DEFINED