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