blob: 5d980aaf5fd44080560899763a7fddb05ea4f2ec [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
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000038 virtual SkImageInfo imageInfo() const SK_OVERRIDE {
39 return fEmptyBitmap.info();
40 }
41
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000042protected:
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000043 virtual void clear(SkColor color) SK_OVERRIDE {
44 NothingToDo();
45 }
46 virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
47 SkBitmap bm;
48
49 if (GetBitmapFromPaint(paint, &bm)) {
50 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
51 fPRCont->add(bm.pixelRef(), clipRect);
52 }
53 }
54 virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
55 const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
56 SkBitmap bm;
57 if (!GetBitmapFromPaint(paint, &bm)) {
58 return;
59 }
60
61 if (0 == count) {
62 return;
63 }
64
65 SkPoint min = points[0];
66 SkPoint max = points[0];
67 for (size_t i = 1; i < count; ++i) {
68 const SkPoint& point = points[i];
69
70 min.set(SkMinScalar(min.x(), point.x()), SkMinScalar(min.y(), point.y()));
71 max.set(SkMaxScalar(max.x(), point.x()), SkMaxScalar(max.y(), point.y()));
72 }
73
74 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x()+1, max.y()+1);
75
76 this->drawRect(draw, bounds, paint);
77 }
78 virtual void drawRect(const SkDraw& draw, const SkRect& rect,
79 const SkPaint& paint) SK_OVERRIDE {
80 SkBitmap bm;
81 if (GetBitmapFromPaint(paint, &bm)) {
82 SkRect mappedRect;
83 draw.fMatrix->mapRect(&mappedRect, rect);
84 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
85 mappedRect.intersect(clipRect);
86 fPRCont->add(bm.pixelRef(), mappedRect);
87 }
88 }
89 virtual void drawOval(const SkDraw& draw, const SkRect& rect,
90 const SkPaint& paint) SK_OVERRIDE {
91 this->drawRect(draw, rect, paint);
92 }
93 virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
94 const SkPaint& paint) SK_OVERRIDE {
95 this->drawRect(draw, rrect.rect(), paint);
96 }
97 virtual void drawPath(const SkDraw& draw, const SkPath& path,
98 const SkPaint& paint, const SkMatrix* prePathMatrix,
99 bool pathIsMutable) SK_OVERRIDE {
100 SkBitmap bm;
101 if (!GetBitmapFromPaint(paint, &bm)) {
102 return;
103 }
104
105 SkRect pathBounds = path.getBounds();
106 if (NULL != prePathMatrix) {
107 prePathMatrix->mapRect(&pathBounds);
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000108 }
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000109
110 this->drawRect(draw, pathBounds, paint);
111 }
112 virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
113 const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
114 SkMatrix totMatrix;
115 totMatrix.setConcat(*draw.fMatrix, matrix);
116
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000117 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000118 SkIntToScalar(bitmap.height()));
119 SkRect mappedRect;
120 totMatrix.mapRect(&mappedRect, bitmapRect);
121 fPRCont->add(bitmap.pixelRef(), mappedRect);
122
123 SkBitmap paintBitmap;
124 if (GetBitmapFromPaint(paint, &paintBitmap)) {
125 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
126 }
127 }
128 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
129 int x, int y, const SkPaint& paint) SK_OVERRIDE {
130 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
131 SkMatrix matrix;
132 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
133
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000134 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000135 SkIntToScalar(bitmap.height()));
136 SkRect mappedRect;
137 matrix.mapRect(&mappedRect, bitmapRect);
138 fPRCont->add(bitmap.pixelRef(), mappedRect);
139
140 SkBitmap paintBitmap;
141 if (GetBitmapFromPaint(paint, &paintBitmap)) {
142 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
143 }
144 }
145 virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
146 const SkRect* srcOrNull, const SkRect& dst,
147 const SkPaint& paint,
148 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000149 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000150 SkIntToScalar(bitmap.height()));
151 SkMatrix matrix;
152 matrix.setRectToRect(bitmapRect, dst, SkMatrix::kFill_ScaleToFit);
153 this->drawBitmap(draw, bitmap, matrix, paint);
154 }
155 virtual void drawText(const SkDraw& draw, const void* text, size_t len,
156 SkScalar x, SkScalar y,
157 const SkPaint& paint) SK_OVERRIDE {
158 SkBitmap bitmap;
159 if (!GetBitmapFromPaint(paint, &bitmap)) {
160 return;
161 }
162
163 // Math is borrowed from SkBBoxRecord
164 SkRect bounds;
165 paint.measureText(text, len, &bounds);
166 SkPaint::FontMetrics metrics;
167 paint.getFontMetrics(&metrics);
168
169 if (paint.isVerticalText()) {
170 SkScalar h = bounds.fBottom - bounds.fTop;
171 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
172 bounds.fTop -= h / 2;
173 bounds.fBottom -= h / 2;
174 }
175 bounds.fBottom += metrics.fBottom;
176 bounds.fTop += metrics.fTop;
177 } else {
178 SkScalar w = bounds.fRight - bounds.fLeft;
179 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
180 bounds.fLeft -= w / 2;
181 bounds.fRight -= w / 2;
182 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
183 bounds.fLeft -= w;
184 bounds.fRight -= w;
185 }
186 bounds.fTop = metrics.fTop;
187 bounds.fBottom = metrics.fBottom;
188 }
189
190 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
191 bounds.fLeft -= pad;
192 bounds.fRight += pad;
193 bounds.offset(x, y);
194
195 this->drawRect(draw, bounds, paint);
196 }
197 virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
198 const SkScalar pos[], SkScalar constY,
199 int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
200 SkBitmap bitmap;
201 if (!GetBitmapFromPaint(paint, &bitmap)) {
202 return;
203 }
204
205 if (0 == len) {
206 return;
207 }
208
209 // Similar to SkDraw asserts.
210 SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2);
211
robertphillips@google.comf0a40132014-01-13 14:13:46 +0000212 SkScalar y = scalarsPerPos == 1 ? constY : constY + pos[1];
213
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000214 SkPoint min, max;
robertphillips@google.comf0a40132014-01-13 14:13:46 +0000215 min.set(pos[0], y);
216 max.set(pos[0], y);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000217
218 for (size_t i = 1; i < len; ++i) {
219 SkScalar x = pos[i * scalarsPerPos];
220 SkScalar y = constY;
221 if (2 == scalarsPerPos) {
222 y += pos[i * scalarsPerPos + 1];
223 }
224
225 min.set(SkMinScalar(x, min.x()), SkMinScalar(y, min.y()));
226 max.set(SkMaxScalar(x, max.x()), SkMaxScalar(y, max.y()));
227 }
228
229 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x(), max.y());
230
231 // Math is borrowed from SkBBoxRecord
232 SkPaint::FontMetrics metrics;
233 paint.getFontMetrics(&metrics);
234
235 bounds.fTop += metrics.fTop;
236 bounds.fBottom += metrics.fBottom;
237
238 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
239 bounds.fLeft -= pad;
240 bounds.fRight += pad;
241
242 this->drawRect(draw, bounds, paint);
243 }
244 virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
245 const SkPath& path, const SkMatrix* matrix,
246 const SkPaint& paint) SK_OVERRIDE {
247 SkBitmap bitmap;
248 if (!GetBitmapFromPaint(paint, &bitmap)) {
249 return;
250 }
251
252 // Math is borrowed from SkBBoxRecord
253 SkRect bounds = path.getBounds();
254 SkPaint::FontMetrics metrics;
255 paint.getFontMetrics(&metrics);
256
257 SkScalar pad = metrics.fTop;
258 // TODO: inset?!
259 bounds.fLeft += pad;
260 bounds.fRight -= pad;
261 bounds.fTop += pad;
262 bounds.fBottom -= pad;
263
264 this->drawRect(draw, bounds, paint);
265 }
266 virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
267 const SkPoint verts[], const SkPoint texs[],
268 const SkColor colors[], SkXfermode* xmode,
269 const uint16_t indices[], int indexCount,
270 const SkPaint& paint) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000271 this->drawPoints(draw, SkCanvas::kPolygon_PointMode, vertexCount, verts, paint);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000272 }
273 virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
274 const SkPaint&) SK_OVERRIDE {
275 NothingToDo();
276 }
277 // TODO: allow this call to return failure, or move to SkBitmapDevice only.
278 virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
279 return fEmptyBitmap;
280 }
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000281 virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
282 virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000283 virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
284 virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000285 virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000286 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
287 return false;
288 }
289
290private:
291 SkPictureUtils::SkPixelRefContainer* fPRCont;
292 SkISize fSize;
293
294 SkBitmap fEmptyBitmap; // legacy -- need to remove
295
296 static bool GetBitmapFromPaint(const SkPaint &paint, SkBitmap* bitmap) {
297 SkShader* shader = paint.getShader();
298 if (NULL != shader) {
299 if (SkShader::kNone_GradientType == shader->asAGradient(NULL)) {
300 return SkShader::kNone_BitmapType != shader->asABitmap(bitmap, NULL, NULL);
301 }
302 }
303 return false;
304 }
305
306 virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
307 NotSupported();
308 }
309
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000310 virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000311 // we expect to only get called via savelayer, in which case it is fine.
312 SkASSERT(kSaveLayer_Usage == usage);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000313 return SkNEW_ARGS(SkGatherPixelRefsAndRectsDevice,
314 (info.width(), info.height(), fPRCont));
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000315 }
316
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000317 static void NotSupported() {
318 SkDEBUGFAIL("this method should never be called");
319 }
320
321 static void NothingToDo() {}
322
323 typedef SkBaseDevice INHERITED;
324};
325
326#endif // SkGatherPixelRefsAndRects_DEFINED