Home | History | Annotate | Download | only in android
      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 
     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 
     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 
    106 SkAndroidSDKCanvas::SkAndroidSDKCanvas() : fProxyTarget(nullptr) { }
    107 
    108 void SkAndroidSDKCanvas::reset(SkCanvas* newTarget) { fProxyTarget = newTarget; }
    109 
    110 void SkAndroidSDKCanvas::onDrawPaint(const SkPaint& paint) {
    111     FILTER(paint);
    112     fProxyTarget->drawPaint(filteredPaint);
    113 }
    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 }
    121 void SkAndroidSDKCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) {
    122     FILTER(paint);
    123     fProxyTarget->drawOval(r, filteredPaint);
    124 }
    125 void SkAndroidSDKCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
    126     FILTER(paint);
    127     fProxyTarget->drawRect(r, filteredPaint);
    128 }
    129 void SkAndroidSDKCanvas::onDrawRRect(const SkRRect& r, const SkPaint& paint) {
    130     FILTER(paint);
    131     fProxyTarget->drawRRect(r, filteredPaint);
    132 }
    133 void SkAndroidSDKCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
    134     FILTER(paint);
    135     fProxyTarget->drawPath(path, filteredPaint);
    136 }
    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 }
    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 }
    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 }
    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 
    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 
    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 }
    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 }
    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 }
    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 }
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    272 void SkAndroidSDKCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
    273     fProxyTarget->drawDrawable(drawable, matrix);
    274 }
    275 
    276 SkISize SkAndroidSDKCanvas::getBaseLayerSize() const {
    277     return fProxyTarget->getBaseLayerSize();
    278 }
    279 bool SkAndroidSDKCanvas::getClipBounds(SkRect* rect) const {
    280     return fProxyTarget->getClipBounds(rect);
    281 }
    282 bool SkAndroidSDKCanvas::getClipDeviceBounds(SkIRect* rect) const {
    283     return fProxyTarget->getClipDeviceBounds(rect);
    284 }
    285 
    286 bool SkAndroidSDKCanvas::isClipEmpty() const { return fProxyTarget->isClipEmpty(); }
    287 bool SkAndroidSDKCanvas::isClipRect() const { return fProxyTarget->isClipRect(); }
    288 
    289 SkSurface* SkAndroidSDKCanvas::onNewSurface(const SkImageInfo& info,
    290                                                      const SkSurfaceProps& props) {
    291     return fProxyTarget->newSurface(info, &props);
    292 }
    293 
    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 
    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 
    318 void SkAndroidSDKCanvas::willSave() {
    319     fProxyTarget->save();
    320 }
    321 
    322 SkCanvas::SaveLayerStrategy SkAndroidSDKCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
    323     fProxyTarget->saveLayer(rec);
    324     return SkCanvas::kNoLayer_SaveLayerStrategy;
    325 }
    326 
    327 void SkAndroidSDKCanvas::willRestore() {
    328     fProxyTarget->restore();
    329 }
    330 
    331 void SkAndroidSDKCanvas::didRestore() { }
    332 
    333 void SkAndroidSDKCanvas::didConcat(const SkMatrix& m) {
    334     fProxyTarget->concat(m);
    335 }
    336 
    337 void SkAndroidSDKCanvas::didSetMatrix(const SkMatrix& m) {
    338     fProxyTarget->setMatrix(m);
    339 }
    340 
    341 void SkAndroidSDKCanvas::onClipRect(const SkRect& rect,
    342                                              SkRegion::Op op,
    343                                              ClipEdgeStyle style) {
    344     fProxyTarget->clipRect(rect, op, style);
    345 }
    346 
    347 void SkAndroidSDKCanvas::onClipRRect(const SkRRect& rrect,
    348                                               SkRegion::Op op,
    349                                               ClipEdgeStyle style) {
    350     fProxyTarget->clipRRect(rrect, op, style);
    351 }
    352 
    353 void SkAndroidSDKCanvas::onClipPath(const SkPath& path,
    354                                              SkRegion::Op op,
    355                                              ClipEdgeStyle style) {
    356     fProxyTarget->clipPath(path, op, style);
    357 }
    358 
    359 void SkAndroidSDKCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
    360     fProxyTarget->clipRegion(region, op);
    361 }
    362 
    363 void SkAndroidSDKCanvas::onDiscard() { fProxyTarget->discard(); }
    364 
    365 
    366