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