blob: 4b5bb6f9e5b2be6489f9f38e1d15d68395a15354 [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
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +000052#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000053 virtual void writePixels(const SkBitmap& bitmap, int x, int y,
54 SkCanvas::Config8888 config8888) SK_OVERRIDE {
55 NotSupported();
56 }
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +000057#endif
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000058 virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
59
60protected:
61 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
62 return false;
63 }
64 virtual void clear(SkColor color) SK_OVERRIDE {
65 NothingToDo();
66 }
67 virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
68 SkBitmap bm;
69
70 if (GetBitmapFromPaint(paint, &bm)) {
71 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
72 fPRCont->add(bm.pixelRef(), clipRect);
73 }
74 }
75 virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
76 const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
77 SkBitmap bm;
78 if (!GetBitmapFromPaint(paint, &bm)) {
79 return;
80 }
81
82 if (0 == count) {
83 return;
84 }
85
86 SkPoint min = points[0];
87 SkPoint max = points[0];
88 for (size_t i = 1; i < count; ++i) {
89 const SkPoint& point = points[i];
90
91 min.set(SkMinScalar(min.x(), point.x()), SkMinScalar(min.y(), point.y()));
92 max.set(SkMaxScalar(max.x(), point.x()), SkMaxScalar(max.y(), point.y()));
93 }
94
95 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x()+1, max.y()+1);
96
97 this->drawRect(draw, bounds, paint);
98 }
99 virtual void drawRect(const SkDraw& draw, const SkRect& rect,
100 const SkPaint& paint) SK_OVERRIDE {
101 SkBitmap bm;
102 if (GetBitmapFromPaint(paint, &bm)) {
103 SkRect mappedRect;
104 draw.fMatrix->mapRect(&mappedRect, rect);
105 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
106 mappedRect.intersect(clipRect);
107 fPRCont->add(bm.pixelRef(), mappedRect);
108 }
109 }
110 virtual void drawOval(const SkDraw& draw, const SkRect& rect,
111 const SkPaint& paint) SK_OVERRIDE {
112 this->drawRect(draw, rect, paint);
113 }
114 virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
115 const SkPaint& paint) SK_OVERRIDE {
116 this->drawRect(draw, rrect.rect(), paint);
117 }
118 virtual void drawPath(const SkDraw& draw, const SkPath& path,
119 const SkPaint& paint, const SkMatrix* prePathMatrix,
120 bool pathIsMutable) SK_OVERRIDE {
121 SkBitmap bm;
122 if (!GetBitmapFromPaint(paint, &bm)) {
123 return;
124 }
125
126 SkRect pathBounds = path.getBounds();
127 if (NULL != prePathMatrix) {
128 prePathMatrix->mapRect(&pathBounds);
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000129 }
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000130
131 this->drawRect(draw, pathBounds, paint);
132 }
133 virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
134 const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
135 SkMatrix totMatrix;
136 totMatrix.setConcat(*draw.fMatrix, matrix);
137
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000138 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000139 SkIntToScalar(bitmap.height()));
140 SkRect mappedRect;
141 totMatrix.mapRect(&mappedRect, bitmapRect);
142 fPRCont->add(bitmap.pixelRef(), mappedRect);
143
144 SkBitmap paintBitmap;
145 if (GetBitmapFromPaint(paint, &paintBitmap)) {
146 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
147 }
148 }
149 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
150 int x, int y, const SkPaint& paint) SK_OVERRIDE {
151 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
152 SkMatrix matrix;
153 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
154
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000155 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000156 SkIntToScalar(bitmap.height()));
157 SkRect mappedRect;
158 matrix.mapRect(&mappedRect, bitmapRect);
159 fPRCont->add(bitmap.pixelRef(), mappedRect);
160
161 SkBitmap paintBitmap;
162 if (GetBitmapFromPaint(paint, &paintBitmap)) {
163 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
164 }
165 }
166 virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
167 const SkRect* srcOrNull, const SkRect& dst,
168 const SkPaint& paint,
169 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000170 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000171 SkIntToScalar(bitmap.height()));
172 SkMatrix matrix;
173 matrix.setRectToRect(bitmapRect, dst, SkMatrix::kFill_ScaleToFit);
174 this->drawBitmap(draw, bitmap, matrix, paint);
175 }
176 virtual void drawText(const SkDraw& draw, const void* text, size_t len,
177 SkScalar x, SkScalar y,
178 const SkPaint& paint) SK_OVERRIDE {
179 SkBitmap bitmap;
180 if (!GetBitmapFromPaint(paint, &bitmap)) {
181 return;
182 }
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.offset(x, y);
215
216 this->drawRect(draw, bounds, paint);
217 }
218 virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
219 const SkScalar pos[], SkScalar constY,
220 int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
221 SkBitmap bitmap;
222 if (!GetBitmapFromPaint(paint, &bitmap)) {
223 return;
224 }
225
226 if (0 == len) {
227 return;
228 }
229
230 // Similar to SkDraw asserts.
231 SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2);
232
robertphillips@google.comf0a40132014-01-13 14:13:46 +0000233 SkScalar y = scalarsPerPos == 1 ? constY : constY + pos[1];
234
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000235 SkPoint min, max;
robertphillips@google.comf0a40132014-01-13 14:13:46 +0000236 min.set(pos[0], y);
237 max.set(pos[0], y);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000238
239 for (size_t i = 1; i < len; ++i) {
240 SkScalar x = pos[i * scalarsPerPos];
241 SkScalar y = constY;
242 if (2 == scalarsPerPos) {
243 y += pos[i * scalarsPerPos + 1];
244 }
245
246 min.set(SkMinScalar(x, min.x()), SkMinScalar(y, min.y()));
247 max.set(SkMaxScalar(x, max.x()), SkMaxScalar(y, max.y()));
248 }
249
250 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x(), max.y());
251
252 // Math is borrowed from SkBBoxRecord
253 SkPaint::FontMetrics metrics;
254 paint.getFontMetrics(&metrics);
255
256 bounds.fTop += metrics.fTop;
257 bounds.fBottom += metrics.fBottom;
258
259 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
260 bounds.fLeft -= pad;
261 bounds.fRight += pad;
262
263 this->drawRect(draw, bounds, paint);
264 }
265 virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
266 const SkPath& path, const SkMatrix* matrix,
267 const SkPaint& paint) SK_OVERRIDE {
268 SkBitmap bitmap;
269 if (!GetBitmapFromPaint(paint, &bitmap)) {
270 return;
271 }
272
273 // Math is borrowed from SkBBoxRecord
274 SkRect bounds = path.getBounds();
275 SkPaint::FontMetrics metrics;
276 paint.getFontMetrics(&metrics);
277
278 SkScalar pad = metrics.fTop;
279 // TODO: inset?!
280 bounds.fLeft += pad;
281 bounds.fRight -= pad;
282 bounds.fTop += pad;
283 bounds.fBottom -= pad;
284
285 this->drawRect(draw, bounds, paint);
286 }
287 virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
288 const SkPoint verts[], const SkPoint texs[],
289 const SkColor colors[], SkXfermode* xmode,
290 const uint16_t indices[], int indexCount,
291 const SkPaint& paint) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000292 this->drawPoints(draw, SkCanvas::kPolygon_PointMode, vertexCount, verts, paint);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000293 }
294 virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
295 const SkPaint&) SK_OVERRIDE {
296 NothingToDo();
297 }
298 // TODO: allow this call to return failure, or move to SkBitmapDevice only.
299 virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
300 return fEmptyBitmap;
301 }
302 virtual bool onReadPixels(const SkBitmap& bitmap,
303 int x, int y,
304 SkCanvas::Config8888 config8888) SK_OVERRIDE {
305 NotSupported();
306 return false;
307 }
308 virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
309 virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000310 virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
311 virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
312 virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkMatrix&,
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000313 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
314 return false;
315 }
316
317private:
318 SkPictureUtils::SkPixelRefContainer* fPRCont;
319 SkISize fSize;
320
321 SkBitmap fEmptyBitmap; // legacy -- need to remove
322
323 static bool GetBitmapFromPaint(const SkPaint &paint, SkBitmap* bitmap) {
324 SkShader* shader = paint.getShader();
325 if (NULL != shader) {
326 if (SkShader::kNone_GradientType == shader->asAGradient(NULL)) {
327 return SkShader::kNone_BitmapType != shader->asABitmap(bitmap, NULL, NULL);
328 }
329 }
330 return false;
331 }
332
333 virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
334 NotSupported();
335 }
336
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000337 virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000338 // we expect to only get called via savelayer, in which case it is fine.
339 SkASSERT(kSaveLayer_Usage == usage);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000340 return SkNEW_ARGS(SkGatherPixelRefsAndRectsDevice,
341 (info.width(), info.height(), fPRCont));
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000342 }
343
344 virtual void flush() SK_OVERRIDE {}
345
346 static void NotSupported() {
347 SkDEBUGFAIL("this method should never be called");
348 }
349
350 static void NothingToDo() {}
351
352 typedef SkBaseDevice INHERITED;
353};
354
355#endif // SkGatherPixelRefsAndRects_DEFINED