1 /*
2 * Copyright 2015 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 #include "SkAndroidSDKCanvas.h"
9
10 #include "SkColorFilter.h"
11 #include "SkPaint.h"
12 #include "SkPathEffect.h"
13 #include "SkShader.h"
14 #include "SkTLazy.h"
15
16 namespace {
17
18 /** Discard SkShaders not exposed by the Android Java API. */
19
CheckShader(SkPaint * paint)20 void CheckShader(SkPaint* paint) {
21 SkShader* shader = paint->getShader();
22 if (!shader) {
23 return;
24 }
25
26 if (shader->isABitmap()) {
27 return;
28 }
29 if (shader->asACompose(nullptr)) {
30 return;
31 }
32 SkShader::GradientType gtype = shader->asAGradient(nullptr);
33 if (gtype == SkShader::kLinear_GradientType ||
34 gtype == SkShader::kRadial_GradientType ||
35 gtype == SkShader::kSweep_GradientType) {
36 return;
37 }
38 paint->setShader(nullptr);
39 }
40
Filter(SkPaint * paint)41 void Filter(SkPaint* paint) {
42
43 uint32_t flags = paint->getFlags();
44 flags &= ~SkPaint::kLCDRenderText_Flag;
45 paint->setFlags(flags);
46
47 // Android doesn't support Xfermodes above kLighten_Mode
48 SkXfermode::Mode mode;
49 SkXfermode::AsMode(paint->getXfermode(), &mode);
50 if (mode > SkXfermode::kLighten_Mode) {
51 paint->setXfermode(nullptr);
52 }
53
54 // Force bilinear scaling or none
55 if (paint->getFilterQuality() != kNone_SkFilterQuality) {
56 paint->setFilterQuality(kLow_SkFilterQuality);
57 }
58
59 CheckShader(paint);
60
61 // Android SDK only supports mode & matrix color filters
62 // (and, again, no modes above kLighten_Mode).
63 SkColorFilter* cf = paint->getColorFilter();
64 if (cf) {
65 SkColor color;
66 SkXfermode::Mode mode;
67 SkScalar srcColorMatrix[20];
68 bool isMode = cf->asColorMode(&color, &mode);
69 if (isMode && mode > SkXfermode::kLighten_Mode) {
70 paint->setColorFilter(
71 SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcOver_Mode));
72 } else if (!isMode && !cf->asColorMatrix(srcColorMatrix)) {
73 paint->setColorFilter(nullptr);
74 }
75 }
76
77 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
78 SkPathEffect* pe = paint->getPathEffect();
79 if (pe && !pe->exposedInAndroidJavaAPI()) {
80 paint->setPathEffect(nullptr);
81 }
82 #endif
83
84 // TODO: Android doesn't support all the flags that can be passed to
85 // blur filters; we need plumbing to get them out.
86
87 paint->setImageFilter(nullptr);
88 paint->setLooper(nullptr);
89 };
90
91 } // namespace
92
93 #define FILTER(p) \
94 SkPaint filteredPaint(p); \
95 Filter(&filteredPaint);
96
97 #define FILTER_PTR(p) \
98 SkTLazy<SkPaint> lazyPaint; \
99 SkPaint* filteredPaint = (SkPaint*) p; \
100 if (p) { \
101 filteredPaint = lazyPaint.set(*p); \
102 Filter(filteredPaint); \
103 }
104
105
SkAndroidSDKCanvas()106 SkAndroidSDKCanvas::SkAndroidSDKCanvas() : fProxyTarget(nullptr) { }
107
reset(SkCanvas * newTarget)108 void SkAndroidSDKCanvas::reset(SkCanvas* newTarget) { fProxyTarget = newTarget; }
109
onDrawPaint(const SkPaint & paint)110 void SkAndroidSDKCanvas::onDrawPaint(const SkPaint& paint) {
111 FILTER(paint);
112 fProxyTarget->drawPaint(filteredPaint);
113 }
onDrawPoints(PointMode pMode,size_t count,const SkPoint pts[],const SkPaint & paint)114 void SkAndroidSDKCanvas::onDrawPoints(PointMode pMode,
115 size_t count,
116 const SkPoint pts[],
117 const SkPaint& paint) {
118 FILTER(paint);
119 fProxyTarget->drawPoints(pMode, count, pts, filteredPaint);
120 }
onDrawOval(const SkRect & r,const SkPaint & paint)121 void SkAndroidSDKCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) {
122 FILTER(paint);
123 fProxyTarget->drawOval(r, filteredPaint);
124 }
onDrawRect(const SkRect & r,const SkPaint & paint)125 void SkAndroidSDKCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
126 FILTER(paint);
127 fProxyTarget->drawRect(r, filteredPaint);
128 }
onDrawRRect(const SkRRect & r,const SkPaint & paint)129 void SkAndroidSDKCanvas::onDrawRRect(const SkRRect& r, const SkPaint& paint) {
130 FILTER(paint);
131 fProxyTarget->drawRRect(r, filteredPaint);
132 }
onDrawPath(const SkPath & path,const SkPaint & paint)133 void SkAndroidSDKCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
134 FILTER(paint);
135 fProxyTarget->drawPath(path, filteredPaint);
136 }
onDrawBitmap(const SkBitmap & bitmap,SkScalar left,SkScalar top,const SkPaint * paint)137 void SkAndroidSDKCanvas::onDrawBitmap(const SkBitmap& bitmap,
138 SkScalar left,
139 SkScalar top,
140 const SkPaint* paint) {
141 FILTER_PTR(paint);
142 fProxyTarget->drawBitmap(bitmap, left, top, filteredPaint);
143 }
onDrawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SkCanvas::SrcRectConstraint constraint)144 void SkAndroidSDKCanvas::onDrawBitmapRect(const SkBitmap& bitmap,
145 const SkRect* src,
146 const SkRect& dst,
147 const SkPaint* paint,
148 SkCanvas::SrcRectConstraint constraint) {
149 FILTER_PTR(paint);
150 fProxyTarget->legacy_drawBitmapRect(bitmap, src, dst, filteredPaint, constraint);
151 }
onDrawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)152 void SkAndroidSDKCanvas::onDrawBitmapNine(const SkBitmap& bitmap,
153 const SkIRect& center,
154 const SkRect& dst,
155 const SkPaint* paint) {
156 FILTER_PTR(paint);
157 fProxyTarget->drawBitmapNine(bitmap, center, dst, filteredPaint);
158 }
onDrawVertices(VertexMode vMode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode * xMode,const uint16_t indices[],int indexCount,const SkPaint & paint)159 void SkAndroidSDKCanvas::onDrawVertices(VertexMode vMode,
160 int vertexCount,
161 const SkPoint vertices[],
162 const SkPoint texs[], const SkColor colors[], SkXfermode* xMode,
163 const uint16_t indices[], int indexCount,
164 const SkPaint& paint) {
165 FILTER(paint);
166 fProxyTarget->drawVertices(vMode, vertexCount, vertices, texs, colors,
167 xMode, indices, indexCount, filteredPaint);
168 }
169
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)170 void SkAndroidSDKCanvas::onDrawDRRect(const SkRRect& outer,
171 const SkRRect& inner,
172 const SkPaint& paint) {
173 FILTER(paint);
174 fProxyTarget->drawDRRect(outer, inner, filteredPaint);
175 }
176
onDrawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)177 void SkAndroidSDKCanvas::onDrawText(const void* text,
178 size_t byteLength,
179 SkScalar x,
180 SkScalar y,
181 const SkPaint& paint) {
182 FILTER(paint);
183 fProxyTarget->drawText(text, byteLength, x, y, filteredPaint);
184 }
onDrawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)185 void SkAndroidSDKCanvas::onDrawPosText(const void* text,
186 size_t byteLength,
187 const SkPoint pos[],
188 const SkPaint& paint) {
189 FILTER(paint);
190 fProxyTarget->drawPosText(text, byteLength, pos, filteredPaint);
191 }
onDrawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)192 void SkAndroidSDKCanvas::onDrawPosTextH(const void* text,
193 size_t byteLength,
194 const SkScalar xpos[],
195 SkScalar constY,
196 const SkPaint& paint) {
197 FILTER(paint);
198 fProxyTarget->drawPosTextH(text, byteLength, xpos, constY, filteredPaint);
199 }
onDrawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)200 void SkAndroidSDKCanvas::onDrawTextOnPath(const void* text,
201 size_t byteLength,
202 const SkPath& path,
203 const SkMatrix* matrix,
204 const SkPaint& paint) {
205 FILTER(paint);
206 fProxyTarget->drawTextOnPath(text, byteLength, path, matrix, filteredPaint);
207 }
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)208 void SkAndroidSDKCanvas::onDrawTextBlob(const SkTextBlob* blob,
209 SkScalar x,
210 SkScalar y,
211 const SkPaint& paint) {
212 FILTER(paint);
213 fProxyTarget->drawTextBlob(blob, x, y, filteredPaint);
214 }
215
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkXfermode * xmode,const SkPaint & paint)216 void SkAndroidSDKCanvas::onDrawPatch(const SkPoint cubics[12],
217 const SkColor colors[4],
218 const SkPoint texCoords[4],
219 SkXfermode* xmode,
220 const SkPaint& paint) {
221 FILTER(paint);
222 fProxyTarget->drawPatch(cubics, colors, texCoords, xmode, filteredPaint);
223 }
224
225
onDrawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint * paint)226 void SkAndroidSDKCanvas::onDrawImage(const SkImage* image,
227 SkScalar x,
228 SkScalar y,
229 const SkPaint* paint) {
230 FILTER_PTR(paint);
231 fProxyTarget->drawImage(image, x, y, filteredPaint);
232 }
233
onDrawImageRect(const SkImage * image,const SkRect * in,const SkRect & out,const SkPaint * paint,SrcRectConstraint constraint)234 void SkAndroidSDKCanvas::onDrawImageRect(const SkImage* image,
235 const SkRect* in,
236 const SkRect& out,
237 const SkPaint* paint,
238 SrcRectConstraint constraint) {
239 FILTER_PTR(paint);
240 fProxyTarget->legacy_drawImageRect(image, in, out, filteredPaint, constraint);
241 }
242
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)243 void SkAndroidSDKCanvas::onDrawPicture(const SkPicture* picture,
244 const SkMatrix* matrix,
245 const SkPaint* paint) {
246 FILTER_PTR(paint);
247 fProxyTarget->drawPicture(picture, matrix, filteredPaint);
248 }
249
onDrawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkXfermode::Mode mode,const SkRect * cullRect,const SkPaint * paint)250 void SkAndroidSDKCanvas::onDrawAtlas(const SkImage* atlas,
251 const SkRSXform xform[],
252 const SkRect tex[],
253 const SkColor colors[],
254 int count,
255 SkXfermode::Mode mode,
256 const SkRect* cullRect,
257 const SkPaint* paint) {
258 FILTER_PTR(paint);
259 fProxyTarget->drawAtlas(atlas, xform, tex, colors, count, mode, cullRect,
260 filteredPaint);
261 }
262
onDrawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint * paint)263 void SkAndroidSDKCanvas::onDrawImageNine(const SkImage* image,
264 const SkIRect& center,
265 const SkRect& dst,
266 const SkPaint* paint) {
267 FILTER_PTR(paint);
268 fProxyTarget->drawImageNine(image, center, dst, filteredPaint);
269 }
270
271
onDrawDrawable(SkDrawable * drawable,const SkMatrix * matrix)272 void SkAndroidSDKCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
273 fProxyTarget->drawDrawable(drawable, matrix);
274 }
275
getBaseLayerSize() const276 SkISize SkAndroidSDKCanvas::getBaseLayerSize() const {
277 return fProxyTarget->getBaseLayerSize();
278 }
getClipBounds(SkRect * rect) const279 bool SkAndroidSDKCanvas::getClipBounds(SkRect* rect) const {
280 return fProxyTarget->getClipBounds(rect);
281 }
getClipDeviceBounds(SkIRect * rect) const282 bool SkAndroidSDKCanvas::getClipDeviceBounds(SkIRect* rect) const {
283 return fProxyTarget->getClipDeviceBounds(rect);
284 }
285
isClipEmpty() const286 bool SkAndroidSDKCanvas::isClipEmpty() const { return fProxyTarget->isClipEmpty(); }
isClipRect() const287 bool SkAndroidSDKCanvas::isClipRect() const { return fProxyTarget->isClipRect(); }
288
onNewSurface(const SkImageInfo & info,const SkSurfaceProps & props)289 SkSurface* SkAndroidSDKCanvas::onNewSurface(const SkImageInfo& info,
290 const SkSurfaceProps& props) {
291 return fProxyTarget->newSurface(info, &props);
292 }
293
onPeekPixels(SkPixmap * pmap)294 bool SkAndroidSDKCanvas::onPeekPixels(SkPixmap* pmap) {
295 SkASSERT(pmap);
296 SkImageInfo info;
297 size_t rowBytes;
298 const void* addr = fProxyTarget->peekPixels(&info, &rowBytes);
299 if (addr) {
300 pmap->reset(info, addr, rowBytes);
301 return true;
302 }
303 return false;
304 }
305
onAccessTopLayerPixels(SkPixmap * pmap)306 bool SkAndroidSDKCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
307 SkASSERT(pmap);
308 SkImageInfo info;
309 size_t rowBytes;
310 const void* addr = fProxyTarget->accessTopLayerPixels(&info, &rowBytes, nullptr);
311 if (addr) {
312 pmap->reset(info, addr, rowBytes);
313 return true;
314 }
315 return false;
316 }
317
willSave()318 void SkAndroidSDKCanvas::willSave() {
319 fProxyTarget->save();
320 }
321
getSaveLayerStrategy(const SaveLayerRec & rec)322 SkCanvas::SaveLayerStrategy SkAndroidSDKCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
323 fProxyTarget->saveLayer(rec);
324 return SkCanvas::kNoLayer_SaveLayerStrategy;
325 }
326
willRestore()327 void SkAndroidSDKCanvas::willRestore() {
328 fProxyTarget->restore();
329 }
330
didRestore()331 void SkAndroidSDKCanvas::didRestore() { }
332
didConcat(const SkMatrix & m)333 void SkAndroidSDKCanvas::didConcat(const SkMatrix& m) {
334 fProxyTarget->concat(m);
335 }
336
didSetMatrix(const SkMatrix & m)337 void SkAndroidSDKCanvas::didSetMatrix(const SkMatrix& m) {
338 fProxyTarget->setMatrix(m);
339 }
340
onClipRect(const SkRect & rect,SkRegion::Op op,ClipEdgeStyle style)341 void SkAndroidSDKCanvas::onClipRect(const SkRect& rect,
342 SkRegion::Op op,
343 ClipEdgeStyle style) {
344 fProxyTarget->clipRect(rect, op, style);
345 }
346
onClipRRect(const SkRRect & rrect,SkRegion::Op op,ClipEdgeStyle style)347 void SkAndroidSDKCanvas::onClipRRect(const SkRRect& rrect,
348 SkRegion::Op op,
349 ClipEdgeStyle style) {
350 fProxyTarget->clipRRect(rrect, op, style);
351 }
352
onClipPath(const SkPath & path,SkRegion::Op op,ClipEdgeStyle style)353 void SkAndroidSDKCanvas::onClipPath(const SkPath& path,
354 SkRegion::Op op,
355 ClipEdgeStyle style) {
356 fProxyTarget->clipPath(path, op, style);
357 }
358
onClipRegion(const SkRegion & region,SkRegion::Op op)359 void SkAndroidSDKCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
360 fProxyTarget->clipRegion(region, op);
361 }
362
onDiscard()363 void SkAndroidSDKCanvas::onDiscard() { fProxyTarget->discard(); }
364
365
366