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;
MaybePaint__anonc585eb570111::MaybePaint25        MaybePaint(const SkPaint* p, SkColorSpaceXformer* xformer) {
26            if (p) { fPaint = fStorage.set(xformer->apply(*p)); }
27        }
operator const SkPaint*__anonc585eb570111::MaybePaint28        operator const SkPaint*() const { return fPaint; }
29     };
30 };
31 
32 class SkColorSpaceXformCanvas : public SkNoDrawCanvas {
33 public:
SkColorSpaceXformCanvas(SkCanvas * target,sk_sp<SkColorSpace> targetCS,std::unique_ptr<SkColorSpaceXformer> xformer)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 
onImageInfo() const48     SkImageInfo onImageInfo() const override {
49         return fTarget->imageInfo().makeColorSpace(fTargetCS);
50     }
51 
onDrawPaint(const SkPaint & paint)52     void onDrawPaint(const SkPaint& paint) override {
53         fTarget->drawPaint(fXformer->apply(paint));
54     }
55 
onDrawRect(const SkRect & rect,const SkPaint & paint)56     void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
57         fTarget->drawRect(rect, fXformer->apply(paint));
58     }
onDrawOval(const SkRect & oval,const SkPaint & paint)59     void onDrawOval(const SkRect& oval, const SkPaint& paint) override {
60         fTarget->drawOval(oval, fXformer->apply(paint));
61     }
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)62     void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
63         fTarget->drawRRect(rrect, fXformer->apply(paint));
64     }
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)65     void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override {
66         fTarget->drawDRRect(outer, inner, fXformer->apply(paint));
67     }
onDrawPath(const SkPath & path,const SkPaint & paint)68     void onDrawPath(const SkPath& path, const SkPaint& paint) override {
69         fTarget->drawPath(path, fXformer->apply(paint));
70     }
onDrawArc(const SkRect & oval,SkScalar start,SkScalar sweep,bool useCenter,const SkPaint & paint)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     }
onDrawRegion(const SkRegion & region,const SkPaint & paint)75     void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
76         fTarget->drawRegion(region, fXformer->apply(paint));
77     }
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texs[4],SkBlendMode mode,const SkPaint & paint)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     }
onDrawPoints(PointMode mode,size_t count,const SkPoint * pts,const SkPaint & paint)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     }
onDrawVerticesObject(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)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 
onDrawText(const void * ptr,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)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     }
onDrawPosText(const void * ptr,size_t len,const SkPoint * xys,const SkPaint & paint)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     }
onDrawPosTextH(const void * ptr,size_t len,const SkScalar * xs,SkScalar y,const SkPaint & paint)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     }
onDrawTextOnPath(const void * ptr,size_t len,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)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     }
onDrawTextRSXform(const void * ptr,size_t len,const SkRSXform * xforms,const SkRect * cull,const SkPaint & paint)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     }
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)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 
onDrawImage(const SkImage * img,SkScalar l,SkScalar t,const SkPaint * paint)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     }
onDrawImageRect(const SkImage * img,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)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     }
onDrawImageNine(const SkImage * img,const SkIRect & center,const SkRect & dst,const SkPaint * paint)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     }
onDrawImageLattice(const SkImage * img,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)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     }
onDrawAtlas(const SkImage * atlas,const SkRSXform * xforms,const SkRect * tex,const SkColor * colors,int count,SkBlendMode mode,const SkRect * cull,const SkPaint * paint)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?
onDrawBitmap(const SkBitmap & bitmap,SkScalar l,SkScalar t,const SkPaint * paint)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     }
onDrawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)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     }
onDrawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)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     }
onDrawBitmapLattice(const SkBitmap & bitmap,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)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     }
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)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     }
onDrawPicture(const SkPicture * pic,const SkMatrix * matrix,const SkPaint * paint)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     }
onDrawDrawable(SkDrawable * drawable,const SkMatrix * matrix)250     void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
251         SkCanvas::onDrawDrawable(drawable, matrix);
252     }
253 
getSaveLayerStrategy(const SaveLayerRec & rec)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
setDrawFilter(SkDrawFilter * filter)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.
willSave()276     void willSave()    override { fTarget->save(); }
willRestore()277     void willRestore() override { fTarget->restore(); }
278 
didConcat(const SkMatrix & m)279     void didConcat   (const SkMatrix& m) override { fTarget->concat   (m); }
didSetMatrix(const SkMatrix & m)280     void didSetMatrix(const SkMatrix& m) override { fTarget->setMatrix(m); }
281 
onClipRect(const SkRect & clip,SkClipOp op,ClipEdgeStyle style)282     void onClipRect(const SkRect& clip, SkClipOp op, ClipEdgeStyle style) override {
283         SkCanvas::onClipRect(clip, op, style);
284         fTarget->clipRect(clip, op, style);
285     }
onClipRRect(const SkRRect & clip,SkClipOp op,ClipEdgeStyle style)286     void onClipRRect(const SkRRect& clip, SkClipOp op, ClipEdgeStyle style) override {
287         SkCanvas::onClipRRect(clip, op, style);
288         fTarget->clipRRect(clip, op, style);
289     }
onClipPath(const SkPath & clip,SkClipOp op,ClipEdgeStyle style)290     void onClipPath(const SkPath& clip, SkClipOp op, ClipEdgeStyle style) override {
291         SkCanvas::onClipPath(clip, op, style);
292         fTarget->clipPath(clip, op, style);
293     }
onClipRegion(const SkRegion & clip,SkClipOp op)294     void onClipRegion(const SkRegion& clip, SkClipOp op) override {
295         SkCanvas::onClipRegion(clip, op);
296         fTarget->clipRegion(clip, op);
297     }
298 
onDrawAnnotation(const SkRect & rect,const char * key,SkData * val)299     void onDrawAnnotation(const SkRect& rect, const char* key, SkData* val) override {
300         fTarget->drawAnnotation(rect, key, val);
301     }
302 
onNewSurface(const SkImageInfo & info,const SkSurfaceProps & props)303     sk_sp<SkSurface> onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) override {
304         return fTarget->makeSurface(info, &props);
305     }
306 
getBaseLayerSize() const307     SkISize getBaseLayerSize() const override { return fTarget->getBaseLayerSize(); }
isClipEmpty() const308     bool isClipEmpty() const override { return fTarget->isClipEmpty(); }
isClipRect() const309     bool isClipRect() const override { return fTarget->isClipRect(); }
onPeekPixels(SkPixmap * pixmap)310     bool onPeekPixels(SkPixmap* pixmap) override { return fTarget->peekPixels(pixmap); }
onAccessTopLayerPixels(SkPixmap * 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 
getGrContext()323     GrContext* getGrContext() override { return fTarget->getGrContext(); }
onGetProps(SkSurfaceProps * props) const324     bool onGetProps(SkSurfaceProps* props) const override { return fTarget->getProps(props); }
onFlush()325     void onFlush() override { return fTarget->flush(); }
internal_private_accessTopLayerRenderTargetContext()326     GrRenderTargetContext* internal_private_accessTopLayerRenderTargetContext() override {
327         return fTarget->internal_private_accessTopLayerRenderTargetContext();
328     }
329 
330 private:
prepareImage(const SkImage * image)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 
skipXform(const SkBitmap & bitmap)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 
SkCreateColorSpaceXformCanvas(SkCanvas * target,sk_sp<SkColorSpace> targetCS)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