• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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