1 /* 2 * Copyright 2013 The Android Open Source Project 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 "SkPictureImageFilter.h" 9 10 #include "SkCanvas.h" 11 #include "SkColorSpaceXformCanvas.h" 12 #include "SkColorSpaceXformer.h" 13 #include "SkImageSource.h" 14 #include "SkReadBuffer.h" 15 #include "SkSpecialImage.h" 16 #include "SkSpecialSurface.h" 17 #include "SkWriteBuffer.h" 18 #include "SkValidationUtils.h" 19 20 sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture) { 21 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture))); 22 } 23 24 sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture, 25 const SkRect& cropRect) { 26 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture), cropRect, nullptr)); 27 } 28 29 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture) 30 : INHERITED(nullptr, 0, nullptr) 31 , fPicture(std::move(picture)) 32 , fCropRect(fPicture ? fPicture->cullRect() : SkRect::MakeEmpty()) { 33 } 34 35 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cropRect, 36 sk_sp<SkColorSpace> colorSpace) 37 : INHERITED(nullptr, 0, nullptr) 38 , fPicture(std::move(picture)) 39 , fCropRect(cropRect) 40 , fColorSpace(std::move(colorSpace)) { 41 } 42 43 enum PictureResolution { 44 kDeviceSpace_PictureResolution, 45 kLocalSpace_PictureResolution 46 }; 47 static sk_sp<SkImageFilter> make_localspace_filter(sk_sp<SkPicture> pic, const SkRect& cropRect, 48 SkFilterQuality fq) { 49 SkISize dim = { SkScalarRoundToInt(cropRect.width()), SkScalarRoundToInt(cropRect.height()) }; 50 auto img = SkImage::MakeFromPicture(std::move(pic), dim, nullptr, nullptr, 51 SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB()); 52 return SkImageSource::Make(img, cropRect, cropRect, fq); 53 } 54 55 sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) { 56 sk_sp<SkPicture> picture; 57 SkRect cropRect; 58 59 if (buffer.readBool()) { 60 picture = SkPicture::MakeFromBuffer(buffer); 61 } 62 buffer.readRect(&cropRect); 63 64 if (buffer.isVersionLT(SkReadBuffer::kRemovePictureImageFilterLocalSpace)) { 65 PictureResolution pictureResolution = buffer.checkRange<PictureResolution>( 66 kDeviceSpace_PictureResolution, kLocalSpace_PictureResolution); 67 if (kLocalSpace_PictureResolution == pictureResolution) { 68 return make_localspace_filter(std::move(picture), cropRect, 69 buffer.checkFilterQuality()); 70 } 71 } 72 return sk_sp<SkImageFilter>(new SkPictureImageFilter(picture, cropRect, nullptr)); 73 } 74 75 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const { 76 bool hasPicture = (fPicture != nullptr); 77 buffer.writeBool(hasPicture); 78 if (hasPicture) { 79 fPicture->flatten(buffer); 80 } 81 buffer.writeRect(fCropRect); 82 } 83 84 sk_sp<SkSpecialImage> SkPictureImageFilter::onFilterImage(SkSpecialImage* source, 85 const Context& ctx, 86 SkIPoint* offset) const { 87 if (!fPicture) { 88 return nullptr; 89 } 90 91 SkRect floatBounds; 92 ctx.ctm().mapRect(&floatBounds, fCropRect); 93 SkIRect bounds = floatBounds.roundOut(); 94 if (!bounds.intersect(ctx.clipBounds())) { 95 return nullptr; 96 } 97 98 SkASSERT(!bounds.isEmpty()); 99 100 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size())); 101 if (!surf) { 102 return nullptr; 103 } 104 105 SkCanvas* canvas = surf->getCanvas(); 106 SkASSERT(canvas); 107 canvas->clear(0x0); 108 109 std::unique_ptr<SkCanvas> xformCanvas; 110 if (fColorSpace) { 111 // Only non-null in the case where onMakeColorSpace() was called. This instructs 112 // us to do the color space xform on playback. 113 xformCanvas = SkCreateColorSpaceXformCanvas(canvas, fColorSpace); 114 canvas = xformCanvas.get(); 115 } 116 canvas->translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop)); 117 canvas->concat(ctx.ctm()); 118 canvas->drawPicture(fPicture); 119 120 offset->fX = bounds.fLeft; 121 offset->fY = bounds.fTop; 122 return surf->makeImageSnapshot(); 123 } 124 125 sk_sp<SkImageFilter> SkPictureImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 126 sk_sp<SkColorSpace> dstCS = xformer->dst(); 127 if (SkColorSpace::Equals(dstCS.get(), fColorSpace.get())) { 128 return this->refMe(); 129 } 130 131 return sk_sp<SkImageFilter>(new SkPictureImageFilter(fPicture, fCropRect, std::move(dstCS))); 132 } 133 134 #ifndef SK_IGNORE_TO_STRING 135 void SkPictureImageFilter::toString(SkString* str) const { 136 str->appendf("SkPictureImageFilter: ("); 137 str->appendf("crop: (%f,%f,%f,%f) ", 138 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom); 139 if (fPicture) { 140 str->appendf("picture: (%f,%f,%f,%f)", 141 fPicture->cullRect().fLeft, fPicture->cullRect().fTop, 142 fPicture->cullRect().fRight, fPicture->cullRect().fBottom); 143 } 144 str->append(")"); 145 } 146 #endif 147