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 "SkReadBuffer.h" 14 #include "SkSpecialImage.h" 15 #include "SkSpecialSurface.h" 16 #include "SkWriteBuffer.h" 17 #include "SkValidationUtils.h" 18 19 sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture) { 20 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture))); 21 } 22 23 sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture, 24 const SkRect& cropRect) { 25 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture), 26 cropRect, 27 kDeviceSpace_PictureResolution, 28 kLow_SkFilterQuality, 29 nullptr)); 30 } 31 32 sk_sp<SkImageFilter> SkPictureImageFilter::MakeForLocalSpace(sk_sp<SkPicture> picture, 33 const SkRect& cropRect, 34 SkFilterQuality filterQuality) { 35 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture), 36 cropRect, 37 kLocalSpace_PictureResolution, 38 filterQuality, 39 nullptr)); 40 } 41 42 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture) 43 : INHERITED(nullptr, 0, nullptr) 44 , fPicture(std::move(picture)) 45 , fCropRect(fPicture ? fPicture->cullRect() : SkRect::MakeEmpty()) 46 , fPictureResolution(kDeviceSpace_PictureResolution) 47 , fFilterQuality(kLow_SkFilterQuality) { 48 } 49 50 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cropRect, 51 PictureResolution pictureResolution, 52 SkFilterQuality filterQuality, 53 sk_sp<SkColorSpace> colorSpace) 54 : INHERITED(nullptr, 0, nullptr) 55 , fPicture(std::move(picture)) 56 , fCropRect(cropRect) 57 , fPictureResolution(pictureResolution) 58 , fFilterQuality(filterQuality) 59 , fColorSpace(std::move(colorSpace)) { 60 } 61 62 sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) { 63 sk_sp<SkPicture> picture; 64 SkRect cropRect; 65 66 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) { 67 buffer.validate(!buffer.readBool()); 68 } else { 69 if (buffer.readBool()) { 70 picture = SkPicture::MakeFromBuffer(buffer); 71 } 72 } 73 buffer.readRect(&cropRect); 74 PictureResolution pictureResolution = (PictureResolution)buffer.readInt(); 75 76 if (kLocalSpace_PictureResolution == pictureResolution) { 77 //filterLevel is only serialized if pictureResolution is LocalSpace 78 SkFilterQuality filterQuality = (SkFilterQuality)buffer.readInt(); 79 return MakeForLocalSpace(picture, cropRect, filterQuality); 80 } 81 return Make(picture, cropRect); 82 } 83 84 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const { 85 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) { 86 buffer.writeBool(false); 87 } else { 88 bool hasPicture = (fPicture != nullptr); 89 buffer.writeBool(hasPicture); 90 if (hasPicture) { 91 fPicture->flatten(buffer); 92 } 93 } 94 buffer.writeRect(fCropRect); 95 buffer.writeInt(fPictureResolution); 96 if (kLocalSpace_PictureResolution == fPictureResolution) { 97 buffer.writeInt(fFilterQuality); 98 } 99 } 100 101 sk_sp<SkSpecialImage> SkPictureImageFilter::onFilterImage(SkSpecialImage* source, 102 const Context& ctx, 103 SkIPoint* offset) const { 104 if (!fPicture) { 105 return nullptr; 106 } 107 108 SkRect floatBounds; 109 ctx.ctm().mapRect(&floatBounds, fCropRect); 110 SkIRect bounds = floatBounds.roundOut(); 111 if (!bounds.intersect(ctx.clipBounds())) { 112 return nullptr; 113 } 114 115 SkASSERT(!bounds.isEmpty()); 116 117 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size())); 118 if (!surf) { 119 return nullptr; 120 } 121 122 SkCanvas* canvas = surf->getCanvas(); 123 SkASSERT(canvas); 124 canvas->clear(0x0); 125 126 if (kDeviceSpace_PictureResolution == fPictureResolution || 127 0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) { 128 this->drawPictureAtDeviceResolution(canvas, bounds, ctx); 129 } else { 130 this->drawPictureAtLocalResolution(source, canvas, bounds, ctx); 131 } 132 133 offset->fX = bounds.fLeft; 134 offset->fY = bounds.fTop; 135 return surf->makeImageSnapshot(); 136 } 137 138 sk_sp<SkImageFilter> SkPictureImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 139 sk_sp<SkColorSpace> dstCS = xformer->dst(); 140 if (SkColorSpace::Equals(dstCS.get(), fColorSpace.get())) { 141 return this->refMe(); 142 } 143 144 return sk_sp<SkImageFilter>(new SkPictureImageFilter(fPicture, fCropRect, fPictureResolution, 145 fFilterQuality, std::move(dstCS))); 146 } 147 148 void SkPictureImageFilter::drawPictureAtDeviceResolution(SkCanvas* canvas, 149 const SkIRect& deviceBounds, 150 const Context& ctx) const { 151 std::unique_ptr<SkCanvas> xformCanvas = nullptr; 152 if (fColorSpace) { 153 // Only non-null in the case where onMakeColorSpace() was called. This instructs 154 // us to do the color space xform on playback. 155 xformCanvas = SkCreateColorSpaceXformCanvas(canvas, fColorSpace); 156 canvas = xformCanvas.get(); 157 } 158 canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop)); 159 canvas->concat(ctx.ctm()); 160 canvas->drawPicture(fPicture); 161 } 162 163 void SkPictureImageFilter::drawPictureAtLocalResolution(SkSpecialImage* source, 164 SkCanvas* canvas, 165 const SkIRect& deviceBounds, 166 const Context& ctx) const { 167 SkMatrix inverseCtm; 168 if (!ctx.ctm().invert(&inverseCtm)) { 169 return; 170 } 171 172 SkRect localBounds = SkRect::Make(ctx.clipBounds()); 173 inverseCtm.mapRect(&localBounds); 174 if (!localBounds.intersect(fCropRect)) { 175 return; 176 } 177 SkIRect localIBounds = localBounds.roundOut(); 178 179 sk_sp<SkSpecialImage> localImg; 180 { 181 sk_sp<SkSpecialSurface> localSurface(source->makeSurface(ctx.outputProperties(), 182 localIBounds.size())); 183 if (!localSurface) { 184 return; 185 } 186 187 SkCanvas* localCanvas = localSurface->getCanvas(); 188 SkASSERT(localCanvas); 189 std::unique_ptr<SkCanvas> xformCanvas = nullptr; 190 if (fColorSpace) { 191 // Only non-null in the case where onMakeColorSpace() was called. This instructs 192 // us to do the color space xform on playback. 193 xformCanvas = SkCreateColorSpaceXformCanvas(localCanvas, fColorSpace); 194 localCanvas = xformCanvas.get(); 195 } 196 197 localCanvas->clear(0x0); 198 199 localCanvas->translate(-SkIntToScalar(localIBounds.fLeft), 200 -SkIntToScalar(localIBounds.fTop)); 201 localCanvas->drawPicture(fPicture); 202 203 localImg = localSurface->makeImageSnapshot(); 204 SkASSERT(localImg); 205 } 206 207 { 208 canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop)); 209 canvas->concat(ctx.ctm()); 210 SkPaint paint; 211 paint.setFilterQuality(fFilterQuality); 212 213 localImg->draw(canvas, 214 SkIntToScalar(localIBounds.fLeft), 215 SkIntToScalar(localIBounds.fTop), 216 &paint); 217 } 218 } 219 220 #ifndef SK_IGNORE_TO_STRING 221 void SkPictureImageFilter::toString(SkString* str) const { 222 str->appendf("SkPictureImageFilter: ("); 223 str->appendf("crop: (%f,%f,%f,%f) ", 224 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom); 225 if (fPicture) { 226 str->appendf("picture: (%f,%f,%f,%f)", 227 fPicture->cullRect().fLeft, fPicture->cullRect().fTop, 228 fPicture->cullRect().fRight, fPicture->cullRect().fBottom); 229 } 230 str->append(")"); 231 } 232 #endif 233