Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2017 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 "SkColorFilter.h"
      9 #include "SkColorSpaceXformCanvas.h"
     10 #include "SkColorSpaceXformer.h"
     11 #include "SkDrawShadowInfo.h"
     12 #include "SkGradientShader.h"
     13 #include "SkImageFilter.h"
     14 #include "SkImagePriv.h"
     15 #include "SkImage_Base.h"
     16 #include "SkMakeUnique.h"
     17 #include "SkNoDrawCanvas.h"
     18 #include "SkSurface.h"
     19 #include "SkTLazy.h"
     20 
     21 namespace {
     22     struct MaybePaint {
     23        SkTLazy<SkPaint> fStorage;
     24        const SkPaint* fPaint = nullptr;
     25        MaybePaint(const SkPaint* p, SkColorSpaceXformer* xformer) {
     26            if (p) { fPaint = fStorage.set(xformer->apply(*p)); }
     27        }
     28        operator const SkPaint*() const { return fPaint; }
     29     };
     30 };
     31 
     32 class SkColorSpaceXformCanvas : public SkNoDrawCanvas {
     33 public:
     34     SkColorSpaceXformCanvas(SkCanvas* target, sk_sp<SkColorSpace> targetCS,
     35                             std::unique_ptr<SkColorSpaceXformer> xformer)
     36         : SkNoDrawCanvas(SkIRect::MakeSize(target->getBaseLayerSize()))
     37         , fTarget(target)
     38         , fTargetCS(targetCS)
     39         , fXformer(std::move(xformer))
     40     {
     41         // Set the matrix and clip to match |fTarget|.  Otherwise, we'll answer queries for
     42         // bounds/matrix differently than |fTarget| would.
     43         SkCanvas::onClipRect(SkRect::Make(fTarget->getDeviceClipBounds()),
     44                              SkClipOp::kIntersect, kHard_ClipEdgeStyle);
     45         SkCanvas::setMatrix(fTarget->getTotalMatrix());
     46     }
     47 
     48     SkImageInfo onImageInfo() const override {
     49         return fTarget->imageInfo().makeColorSpace(fTargetCS);
     50     }
     51 
     52     void onDrawPaint(const SkPaint& paint) override {
     53         fTarget->drawPaint(fXformer->apply(paint));
     54     }
     55 
     56     void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
     57         fTarget->drawRect(rect, fXformer->apply(paint));
     58     }
     59     void onDrawOval(const SkRect& oval, const SkPaint& paint) override {
     60         fTarget->drawOval(oval, fXformer->apply(paint));
     61     }
     62     void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
     63         fTarget->drawRRect(rrect, fXformer->apply(paint));
     64     }
     65     void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override {
     66         fTarget->drawDRRect(outer, inner, fXformer->apply(paint));
     67     }
     68     void onDrawPath(const SkPath& path, const SkPaint& paint) override {
     69         fTarget->drawPath(path, fXformer->apply(paint));
     70     }
     71     void onDrawArc(const SkRect& oval, SkScalar start, SkScalar sweep, bool useCenter,
     72                    const SkPaint& paint) override {
     73         fTarget->drawArc(oval, start, sweep, useCenter, fXformer->apply(paint));
     74     }
     75     void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
     76         fTarget->drawRegion(region, fXformer->apply(paint));
     77     }
     78     void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4],
     79                      SkBlendMode mode, const SkPaint& paint) override {
     80         SkColor xformed[4];
     81         if (colors) {
     82             fXformer->apply(xformed, colors, 4);
     83             colors = xformed;
     84         }
     85 
     86         fTarget->drawPatch(cubics, colors, texs, mode, fXformer->apply(paint));
     87     }
     88     void onDrawPoints(PointMode mode, size_t count, const SkPoint* pts,
     89                       const SkPaint& paint) override {
     90         fTarget->drawPoints(mode, count, pts, fXformer->apply(paint));
     91     }
     92     void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
     93                               const SkPaint& paint) override {
     94         sk_sp<SkVertices> copy;
     95         if (vertices->hasColors()) {
     96             int count = vertices->vertexCount();
     97             SkSTArray<8, SkColor> xformed(count);
     98             fXformer->apply(xformed.begin(), vertices->colors(), count);
     99             copy = SkVertices::MakeCopy(vertices->mode(), count, vertices->positions(),
    100                                         vertices->texCoords(), xformed.begin(),
    101                                         vertices->indexCount(), vertices->indices());
    102             vertices = copy.get();
    103         }
    104 
    105         fTarget->drawVertices(vertices, mode, fXformer->apply(paint));
    106     }
    107 
    108     void onDrawText(const void* ptr, size_t len,
    109                     SkScalar x, SkScalar y,
    110                     const SkPaint& paint) override {
    111         fTarget->drawText(ptr, len, x, y, fXformer->apply(paint));
    112     }
    113     void onDrawPosText(const void* ptr, size_t len,
    114                        const SkPoint* xys,
    115                        const SkPaint& paint) override {
    116         fTarget->drawPosText(ptr, len, xys, fXformer->apply(paint));
    117     }
    118     void onDrawPosTextH(const void* ptr, size_t len,
    119                         const SkScalar* xs, SkScalar y,
    120                         const SkPaint& paint) override {
    121         fTarget->drawPosTextH(ptr, len, xs, y, fXformer->apply(paint));
    122     }
    123     void onDrawTextOnPath(const void* ptr, size_t len,
    124                           const SkPath& path, const SkMatrix* matrix,
    125                           const SkPaint& paint) override {
    126         fTarget->drawTextOnPath(ptr, len, path, matrix, fXformer->apply(paint));
    127     }
    128     void onDrawTextRSXform(const void* ptr, size_t len,
    129                            const SkRSXform* xforms, const SkRect* cull,
    130                            const SkPaint& paint) override {
    131         fTarget->drawTextRSXform(ptr, len, xforms, cull, fXformer->apply(paint));
    132     }
    133     void onDrawTextBlob(const SkTextBlob* blob,
    134                         SkScalar x, SkScalar y,
    135                         const SkPaint& paint) override {
    136         fTarget->drawTextBlob(blob, x, y, fXformer->apply(paint));
    137     }
    138 
    139     void onDrawImage(const SkImage* img,
    140                      SkScalar l, SkScalar t,
    141                      const SkPaint* paint) override {
    142         if (!fTarget->quickReject(SkRect::Make(img->bounds()).makeOffset(l,t))) {
    143             fTarget->drawImage(prepareImage(img).get(), l, t, MaybePaint(paint, fXformer.get()));
    144         }
    145     }
    146     void onDrawImageRect(const SkImage* img,
    147                          const SkRect* src, const SkRect& dst,
    148                          const SkPaint* paint, SrcRectConstraint constraint) override {
    149         if (!fTarget->quickReject(dst)) {
    150             fTarget->drawImageRect(prepareImage(img).get(),
    151                                    src ? *src : SkRect::MakeIWH(img->width(), img->height()), dst,
    152                                    MaybePaint(paint, fXformer.get()), constraint);
    153         }
    154     }
    155     void onDrawImageNine(const SkImage* img,
    156                          const SkIRect& center, const SkRect& dst,
    157                          const SkPaint* paint) override {
    158         if (!fTarget->quickReject(dst)) {
    159             fTarget->drawImageNine(prepareImage(img).get(), center, dst,
    160                                    MaybePaint(paint, fXformer.get()));
    161         }
    162     }
    163     void onDrawImageLattice(const SkImage* img,
    164                             const Lattice& lattice, const SkRect& dst,
    165                             const SkPaint* paint) override {
    166         if (!fTarget->quickReject(dst)) {
    167             SkSTArray<16, SkColor> colorBuffer;
    168             int count = lattice.fRectTypes && lattice.fColors ?
    169                         (lattice.fXCount + 1) * (lattice.fYCount + 1) : 0;
    170             colorBuffer.reset(count);
    171             fTarget->drawImageLattice(prepareImage(img).get(),
    172                                       fXformer->apply(lattice, colorBuffer.begin(), count),
    173                                       dst, MaybePaint(paint, fXformer.get()));
    174         }
    175     }
    176     void onDrawAtlas(const SkImage* atlas, const SkRSXform* xforms, const SkRect* tex,
    177                      const SkColor* colors, int count, SkBlendMode mode,
    178                      const SkRect* cull, const SkPaint* paint) override {
    179         SkSTArray<8, SkColor> xformed;
    180         if (colors) {
    181             xformed.reset(count);
    182             fXformer->apply(xformed.begin(), colors, count);
    183             colors = xformed.begin();
    184         }
    185         fTarget->drawAtlas(prepareImage(atlas).get(), xforms, tex, colors, count, mode, cull,
    186                            MaybePaint(paint, fXformer.get()));
    187     }
    188 
    189     // TODO: quick reject bitmap draw calls before transforming too?
    190     void onDrawBitmap(const SkBitmap& bitmap,
    191                       SkScalar l, SkScalar t,
    192                       const SkPaint* paint) override {
    193         if (this->skipXform(bitmap)) {
    194             return fTarget->drawBitmap(bitmap, l, t, MaybePaint(paint, fXformer.get()));
    195         }
    196 
    197         fTarget->drawImage(fXformer->apply(bitmap).get(), l, t, MaybePaint(paint, fXformer.get()));
    198     }
    199     void onDrawBitmapRect(const SkBitmap& bitmap,
    200                           const SkRect* src, const SkRect& dst,
    201                           const SkPaint* paint, SrcRectConstraint constraint) override {
    202         if (this->skipXform(bitmap)) {
    203             return fTarget->drawBitmapRect(bitmap,
    204                     src ? *src : SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst,
    205                     MaybePaint(paint, fXformer.get()), constraint);
    206         }
    207 
    208         fTarget->drawImageRect(fXformer->apply(bitmap).get(),
    209                                src ? *src : SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst,
    210                                MaybePaint(paint, fXformer.get()), constraint);
    211     }
    212     void onDrawBitmapNine(const SkBitmap& bitmap,
    213                           const SkIRect& center, const SkRect& dst,
    214                           const SkPaint* paint) override {
    215         if (this->skipXform(bitmap)) {
    216             return fTarget->drawBitmapNine(bitmap, center, dst, MaybePaint(paint, fXformer.get()));
    217         }
    218 
    219         fTarget->drawImageNine(fXformer->apply(bitmap).get(), center, dst,
    220                                MaybePaint(paint, fXformer.get()));
    221 
    222     }
    223     void onDrawBitmapLattice(const SkBitmap& bitmap,
    224                              const Lattice& lattice, const SkRect& dst,
    225                              const SkPaint* paint) override {
    226         if (this->skipXform(bitmap)) {
    227             return fTarget->drawBitmapLattice(bitmap, lattice, dst,
    228                                               MaybePaint(paint, fXformer.get()));
    229         }
    230 
    231         SkSTArray<16, SkColor> colorBuffer;
    232         int count = lattice.fRectTypes && lattice.fColors?
    233                     (lattice.fXCount + 1) * (lattice.fYCount + 1) : 0;
    234         colorBuffer.reset(count);
    235         fTarget->drawImageLattice(fXformer->apply(bitmap).get(),
    236                                   fXformer->apply(lattice, colorBuffer.begin(), count), dst,
    237                                   MaybePaint(paint, fXformer.get()));
    238     }
    239     void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override {
    240         SkDrawShadowRec newRec(rec);
    241         newRec.fAmbientColor = fXformer->apply(rec.fAmbientColor);
    242         newRec.fSpotColor = fXformer->apply(rec.fSpotColor);
    243         fTarget->private_draw_shadow_rec(path, newRec);
    244     }
    245     void onDrawPicture(const SkPicture* pic,
    246                        const SkMatrix* matrix,
    247                        const SkPaint* paint) override {
    248         SkCanvas::onDrawPicture(pic, matrix, MaybePaint(paint, fXformer.get()));
    249     }
    250     void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
    251         SkCanvas::onDrawDrawable(drawable, matrix);
    252     }
    253 
    254     SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
    255         sk_sp<SkImageFilter> backdrop = rec.fBackdrop ? fXformer->apply(rec.fBackdrop) : nullptr;
    256         sk_sp<SkImage> clipMask = rec.fClipMask ? fXformer->apply(rec.fClipMask) : nullptr;
    257         fTarget->saveLayer({
    258             rec.fBounds,
    259             MaybePaint(rec.fPaint, fXformer.get()),
    260             backdrop.get(),
    261             clipMask.get(),
    262             rec.fClipMatrix,
    263             rec.fSaveLayerFlags,
    264         });
    265         return kNoLayer_SaveLayerStrategy;
    266     }
    267 
    268 #ifdef SK_SUPPORT_LEGACY_DRAWFILTER
    269     SkDrawFilter* setDrawFilter(SkDrawFilter* filter) override {
    270         SkCanvas::setDrawFilter(filter);
    271         return fTarget->setDrawFilter(filter);
    272     }
    273 #endif
    274 
    275     // Everything from here on should be uninteresting strictly proxied state-change calls.
    276     void willSave()    override { fTarget->save(); }
    277     void willRestore() override { fTarget->restore(); }
    278 
    279     void didConcat   (const SkMatrix& m) override { fTarget->concat   (m); }
    280     void didSetMatrix(const SkMatrix& m) override { fTarget->setMatrix(m); }
    281 
    282     void onClipRect(const SkRect& clip, SkClipOp op, ClipEdgeStyle style) override {
    283         SkCanvas::onClipRect(clip, op, style);
    284         fTarget->clipRect(clip, op, style);
    285     }
    286     void onClipRRect(const SkRRect& clip, SkClipOp op, ClipEdgeStyle style) override {
    287         SkCanvas::onClipRRect(clip, op, style);
    288         fTarget->clipRRect(clip, op, style);
    289     }
    290     void onClipPath(const SkPath& clip, SkClipOp op, ClipEdgeStyle style) override {
    291         SkCanvas::onClipPath(clip, op, style);
    292         fTarget->clipPath(clip, op, style);
    293     }
    294     void onClipRegion(const SkRegion& clip, SkClipOp op) override {
    295         SkCanvas::onClipRegion(clip, op);
    296         fTarget->clipRegion(clip, op);
    297     }
    298 
    299     void onDrawAnnotation(const SkRect& rect, const char* key, SkData* val) override {
    300         fTarget->drawAnnotation(rect, key, val);
    301     }
    302 
    303     sk_sp<SkSurface> onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) override {
    304         return fTarget->makeSurface(info, &props);
    305     }
    306 
    307     SkISize getBaseLayerSize() const override { return fTarget->getBaseLayerSize(); }
    308     bool isClipEmpty() const override { return fTarget->isClipEmpty(); }
    309     bool isClipRect() const override { return fTarget->isClipRect(); }
    310     bool onPeekPixels(SkPixmap* pixmap) override { return fTarget->peekPixels(pixmap); }
    311     bool onAccessTopLayerPixels(SkPixmap* pixmap) override {
    312         SkImageInfo info;
    313         size_t rowBytes;
    314         SkIPoint* origin = nullptr;
    315         void* addr = fTarget->accessTopLayerPixels(&info, &rowBytes, origin);
    316         if (addr) {
    317             *pixmap = SkPixmap(info, addr, rowBytes);
    318             return true;
    319         }
    320         return false;
    321     }
    322 
    323     GrContext* getGrContext() override { return fTarget->getGrContext(); }
    324     bool onGetProps(SkSurfaceProps* props) const override { return fTarget->getProps(props); }
    325     void onFlush() override { return fTarget->flush(); }
    326     GrRenderTargetContext* internal_private_accessTopLayerRenderTargetContext() override {
    327         return fTarget->internal_private_accessTopLayerRenderTargetContext();
    328     }
    329 
    330 private:
    331     sk_sp<SkImage> prepareImage(const SkImage* image) {
    332         GrContext* gr = fTarget->getGrContext();
    333         if (gr) {
    334             // If fTarget is GPU-accelerated, we want to upload to a texture
    335             // before applying the transform. This way, we can get cache hits
    336             // in the texture cache and the transform gets applied on the GPU.
    337             sk_sp<SkImage> textureImage = image->makeTextureImage(gr, nullptr);
    338             if (textureImage)
    339                 return fXformer->apply(textureImage.get());
    340         }
    341         // TODO: Extract a sub image corresponding to the src rect in order
    342         // to xform only the useful part of the image. Sub image could be reduced
    343         // even further by taking into account dst_rect+ctm+clip
    344         return fXformer->apply(image);
    345     }
    346 
    347     bool skipXform(const SkBitmap& bitmap) {
    348         return (!bitmap.colorSpace() && fTargetCS->isSRGB()) ||
    349                (SkColorSpace::Equals(bitmap.colorSpace(), fTargetCS.get())) ||
    350                (kAlpha_8_SkColorType == bitmap.colorType());
    351     }
    352 
    353     SkCanvas*                            fTarget;
    354     sk_sp<SkColorSpace>                  fTargetCS;
    355     std::unique_ptr<SkColorSpaceXformer> fXformer;
    356 };
    357 
    358 std::unique_ptr<SkCanvas> SkCreateColorSpaceXformCanvas(SkCanvas* target,
    359                                                         sk_sp<SkColorSpace> targetCS) {
    360     std::unique_ptr<SkColorSpaceXformer> xformer = SkColorSpaceXformer::Make(targetCS);
    361     if (!xformer) {
    362         return nullptr;
    363     }
    364 
    365     return skstd::make_unique<SkColorSpaceXformCanvas>(target, std::move(targetCS),
    366                                                        std::move(xformer));
    367 }
    368