blob: 6f1e1b5e469c1febc5b911935d27678ab6880cf9 [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
mtklein72c9faa2015-01-09 10:06:39 -080038 SkImageInfo imageInfo() const SK_OVERRIDE {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000039 return fEmptyBitmap.info();
40 }
41
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000042protected:
mtklein72c9faa2015-01-09 10:06:39 -080043 void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000044 SkBitmap bm;
45
46 if (GetBitmapFromPaint(paint, &bm)) {
47 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
48 fPRCont->add(bm.pixelRef(), clipRect);
49 }
50 }
51 virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
52 const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
53 SkBitmap bm;
54 if (!GetBitmapFromPaint(paint, &bm)) {
55 return;
56 }
57
58 if (0 == count) {
59 return;
60 }
61
62 SkPoint min = points[0];
63 SkPoint max = points[0];
64 for (size_t i = 1; i < count; ++i) {
65 const SkPoint& point = points[i];
66
67 min.set(SkMinScalar(min.x(), point.x()), SkMinScalar(min.y(), point.y()));
68 max.set(SkMaxScalar(max.x(), point.x()), SkMaxScalar(max.y(), point.y()));
69 }
70
71 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x()+1, max.y()+1);
72
73 this->drawRect(draw, bounds, paint);
74 }
75 virtual void drawRect(const SkDraw& draw, const SkRect& rect,
76 const SkPaint& paint) SK_OVERRIDE {
77 SkBitmap bm;
78 if (GetBitmapFromPaint(paint, &bm)) {
79 SkRect mappedRect;
80 draw.fMatrix->mapRect(&mappedRect, rect);
81 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
robertphillipsf4e59952015-01-07 12:16:10 -080082 if (mappedRect.intersect(clipRect)) {
83 fPRCont->add(bm.pixelRef(), mappedRect);
84 }
robertphillips@google.com56bf6e42014-01-13 13:33:26 +000085 }
86 }
87 virtual void drawOval(const SkDraw& draw, const SkRect& rect,
88 const SkPaint& paint) SK_OVERRIDE {
89 this->drawRect(draw, rect, paint);
90 }
91 virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
92 const SkPaint& paint) SK_OVERRIDE {
93 this->drawRect(draw, rrect.rect(), paint);
94 }
95 virtual void drawPath(const SkDraw& draw, const SkPath& path,
96 const SkPaint& paint, const SkMatrix* prePathMatrix,
97 bool pathIsMutable) SK_OVERRIDE {
98 SkBitmap bm;
99 if (!GetBitmapFromPaint(paint, &bm)) {
100 return;
101 }
102
103 SkRect pathBounds = path.getBounds();
bsalomon49f085d2014-09-05 13:34:00 -0700104 if (prePathMatrix) {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000105 prePathMatrix->mapRect(&pathBounds);
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000106 }
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000107
108 this->drawRect(draw, pathBounds, paint);
109 }
110 virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
111 const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
112 SkMatrix totMatrix;
113 totMatrix.setConcat(*draw.fMatrix, matrix);
114
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000115 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000116 SkIntToScalar(bitmap.height()));
117 SkRect mappedRect;
118 totMatrix.mapRect(&mappedRect, bitmapRect);
119 fPRCont->add(bitmap.pixelRef(), mappedRect);
120
121 SkBitmap paintBitmap;
122 if (GetBitmapFromPaint(paint, &paintBitmap)) {
123 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
124 }
125 }
126 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
127 int x, int y, const SkPaint& paint) SK_OVERRIDE {
128 // Sprites aren't affected by current matrix, so we can't reuse drawRect.
129 SkMatrix matrix;
130 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
131
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000132 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000133 SkIntToScalar(bitmap.height()));
134 SkRect mappedRect;
135 matrix.mapRect(&mappedRect, bitmapRect);
136 fPRCont->add(bitmap.pixelRef(), mappedRect);
137
138 SkBitmap paintBitmap;
139 if (GetBitmapFromPaint(paint, &paintBitmap)) {
140 fPRCont->add(paintBitmap.pixelRef(), mappedRect);
141 }
142 }
143 virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
144 const SkRect* srcOrNull, const SkRect& dst,
145 const SkPaint& paint,
146 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000147 SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000148 SkIntToScalar(bitmap.height()));
149 SkMatrix matrix;
150 matrix.setRectToRect(bitmapRect, dst, SkMatrix::kFill_ScaleToFit);
151 this->drawBitmap(draw, bitmap, matrix, paint);
152 }
153 virtual void drawText(const SkDraw& draw, const void* text, size_t len,
154 SkScalar x, SkScalar y,
155 const SkPaint& paint) SK_OVERRIDE {
156 SkBitmap bitmap;
157 if (!GetBitmapFromPaint(paint, &bitmap)) {
158 return;
159 }
160
161 // Math is borrowed from SkBBoxRecord
162 SkRect bounds;
163 paint.measureText(text, len, &bounds);
164 SkPaint::FontMetrics metrics;
165 paint.getFontMetrics(&metrics);
166
167 if (paint.isVerticalText()) {
168 SkScalar h = bounds.fBottom - bounds.fTop;
169 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
170 bounds.fTop -= h / 2;
171 bounds.fBottom -= h / 2;
172 }
173 bounds.fBottom += metrics.fBottom;
174 bounds.fTop += metrics.fTop;
175 } else {
176 SkScalar w = bounds.fRight - bounds.fLeft;
177 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
178 bounds.fLeft -= w / 2;
179 bounds.fRight -= w / 2;
180 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
181 bounds.fLeft -= w;
182 bounds.fRight -= w;
183 }
184 bounds.fTop = metrics.fTop;
185 bounds.fBottom = metrics.fBottom;
186 }
187
188 SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
189 bounds.fLeft -= pad;
190 bounds.fRight += pad;
191 bounds.offset(x, y);
192
193 this->drawRect(draw, bounds, paint);
194 }
195 virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
fmalita05c4a432014-09-29 06:29:53 -0700196 const SkScalar pos[], int scalarsPerPos,
197 const SkPoint& offset, const SkPaint& paint) SK_OVERRIDE {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000198 SkBitmap bitmap;
199 if (!GetBitmapFromPaint(paint, &bitmap)) {
200 return;
201 }
202
203 if (0 == len) {
204 return;
205 }
206
207 // Similar to SkDraw asserts.
208 SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2);
209
fmalita05c4a432014-09-29 06:29:53 -0700210 SkPoint min = SkPoint::Make(offset.x() + pos[0],
211 offset.y() + (2 == scalarsPerPos ? pos[1] : 0));
212 SkPoint max = min;
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000213
214 for (size_t i = 1; i < len; ++i) {
fmalita05c4a432014-09-29 06:29:53 -0700215 SkScalar x = offset.x() + pos[i * scalarsPerPos];
216 SkScalar y = offset.y() + (2 == scalarsPerPos ? pos[i * 2 + 1] : 0);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000217
218 min.set(SkMinScalar(x, min.x()), SkMinScalar(y, min.y()));
219 max.set(SkMaxScalar(x, max.x()), SkMaxScalar(y, max.y()));
220 }
221
222 SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x(), max.y());
223
224 // Math is borrowed from SkBBoxRecord
225 SkPaint::FontMetrics metrics;
226 paint.getFontMetrics(&metrics);
227
228 bounds.fTop += metrics.fTop;
229 bounds.fBottom += metrics.fBottom;
230
231 SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
232 bounds.fLeft -= pad;
233 bounds.fRight += pad;
234
235 this->drawRect(draw, bounds, paint);
236 }
237 virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
238 const SkPath& path, const SkMatrix* matrix,
239 const SkPaint& paint) SK_OVERRIDE {
240 SkBitmap bitmap;
241 if (!GetBitmapFromPaint(paint, &bitmap)) {
242 return;
243 }
244
245 // Math is borrowed from SkBBoxRecord
246 SkRect bounds = path.getBounds();
247 SkPaint::FontMetrics metrics;
248 paint.getFontMetrics(&metrics);
249
250 SkScalar pad = metrics.fTop;
251 // TODO: inset?!
252 bounds.fLeft += pad;
253 bounds.fRight -= pad;
254 bounds.fTop += pad;
255 bounds.fBottom -= pad;
256
257 this->drawRect(draw, bounds, paint);
258 }
259 virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
260 const SkPoint verts[], const SkPoint texs[],
261 const SkColor colors[], SkXfermode* xmode,
262 const uint16_t indices[], int indexCount,
263 const SkPaint& paint) SK_OVERRIDE {
skia.committer@gmail.com2e9a7152014-01-14 07:01:42 +0000264 this->drawPoints(draw, SkCanvas::kPolygon_PointMode, vertexCount, verts, paint);
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000265 }
266 virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
267 const SkPaint&) SK_OVERRIDE {
268 NothingToDo();
269 }
270 // TODO: allow this call to return failure, or move to SkBitmapDevice only.
mtklein72c9faa2015-01-09 10:06:39 -0800271 const SkBitmap& onAccessBitmap() SK_OVERRIDE {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000272 return fEmptyBitmap;
273 }
mtklein72c9faa2015-01-09 10:06:39 -0800274 void lockPixels() SK_OVERRIDE { NothingToDo(); }
275 void unlockPixels() SK_OVERRIDE { NothingToDo(); }
276 bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
277 bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000278 virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000279 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
280 return false;
281 }
282
283private:
284 SkPictureUtils::SkPixelRefContainer* fPRCont;
285 SkISize fSize;
286
287 SkBitmap fEmptyBitmap; // legacy -- need to remove
288
289 static bool GetBitmapFromPaint(const SkPaint &paint, SkBitmap* bitmap) {
290 SkShader* shader = paint.getShader();
bsalomon49f085d2014-09-05 13:34:00 -0700291 if (shader) {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000292 if (SkShader::kNone_GradientType == shader->asAGradient(NULL)) {
293 return SkShader::kNone_BitmapType != shader->asABitmap(bitmap, NULL, NULL);
294 }
295 }
296 return false;
297 }
298
mtklein72c9faa2015-01-09 10:06:39 -0800299 void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000300 NotSupported();
301 }
302
mtklein72c9faa2015-01-09 10:06:39 -0800303 SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info) SK_OVERRIDE {
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000304 // we expect to only get called via savelayer, in which case it is fine.
fmalita6987dca2014-11-13 08:33:37 -0800305 SkASSERT(kSaveLayer_Usage == info.fUsage);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000306 return SkNEW_ARGS(SkGatherPixelRefsAndRectsDevice,
fmalita6987dca2014-11-13 08:33:37 -0800307 (info.fInfo.width(), info.fInfo.height(), fPRCont));
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000308 }
309
robertphillips@google.com56bf6e42014-01-13 13:33:26 +0000310 static void NotSupported() {
311 SkDEBUGFAIL("this method should never be called");
312 }
313
314 static void NothingToDo() {}
315
316 typedef SkBaseDevice INHERITED;
317};
318
319#endif // SkGatherPixelRefsAndRects_DEFINED