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 #include "SkDevice.h" 10 #include "SkCanvas.h" 11 #include "SkReadBuffer.h" 12 #include "SkSurfaceProps.h" 13 #include "SkWriteBuffer.h" 14 #include "SkValidationUtils.h" 15 16 SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture) 17 : INHERITED(0, 0, nullptr) 18 , fPicture(SkSafeRef(picture)) 19 , fCropRect(picture ? picture->cullRect() : SkRect::MakeEmpty()) 20 , fPictureResolution(kDeviceSpace_PictureResolution) 21 , fFilterQuality(kLow_SkFilterQuality) { 22 } 23 24 SkPictureImageFilter::SkPictureImageFilter(const SkPicture* picture, const SkRect& cropRect, 25 PictureResolution pictureResolution, 26 SkFilterQuality filterQuality) 27 : INHERITED(0, 0, nullptr) 28 , fPicture(SkSafeRef(picture)) 29 , fCropRect(cropRect) 30 , fPictureResolution(pictureResolution) 31 , fFilterQuality(filterQuality) { 32 } 33 34 SkPictureImageFilter::~SkPictureImageFilter() { 35 SkSafeUnref(fPicture); 36 } 37 38 SkFlattenable* SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) { 39 SkAutoTUnref<SkPicture> picture; 40 SkRect cropRect; 41 42 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) { 43 buffer.validate(!buffer.readBool()); 44 } else { 45 if (buffer.readBool()) { 46 picture.reset(SkPicture::CreateFromBuffer(buffer)); 47 } 48 } 49 buffer.readRect(&cropRect); 50 PictureResolution pictureResolution; 51 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) { 52 pictureResolution = kDeviceSpace_PictureResolution; 53 } else { 54 pictureResolution = (PictureResolution)buffer.readInt(); 55 } 56 57 if (kLocalSpace_PictureResolution == pictureResolution) { 58 //filterLevel is only serialized if pictureResolution is LocalSpace 59 SkFilterQuality filterQuality; 60 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) { 61 filterQuality = kLow_SkFilterQuality; 62 } else { 63 filterQuality = (SkFilterQuality)buffer.readInt(); 64 } 65 return CreateForLocalSpace(picture, cropRect, filterQuality); 66 } 67 return Create(picture, cropRect); 68 } 69 70 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const { 71 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) { 72 buffer.writeBool(false); 73 } else { 74 bool hasPicture = (fPicture != nullptr); 75 buffer.writeBool(hasPicture); 76 if (hasPicture) { 77 fPicture->flatten(buffer); 78 } 79 } 80 buffer.writeRect(fCropRect); 81 buffer.writeInt(fPictureResolution); 82 if (kLocalSpace_PictureResolution == fPictureResolution) { 83 buffer.writeInt(fFilterQuality); 84 } 85 } 86 87 bool SkPictureImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitmap&, 88 const Context& ctx, 89 SkBitmap* result, SkIPoint* offset) const { 90 if (!fPicture) { 91 offset->fX = offset->fY = 0; 92 return true; 93 } 94 95 SkRect floatBounds; 96 ctx.ctm().mapRect(&floatBounds, fCropRect); 97 SkIRect bounds = floatBounds.roundOut(); 98 if (!bounds.intersect(ctx.clipBounds())) { 99 return false; 100 } 101 102 if (bounds.isEmpty()) { 103 offset->fX = offset->fY = 0; 104 return true; 105 } 106 107 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); 108 if (nullptr == device.get()) { 109 return false; 110 } 111 112 if (kDeviceSpace_PictureResolution == fPictureResolution || 113 0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) { 114 this->drawPictureAtDeviceResolution(device.get(), bounds, ctx); 115 } else { 116 this->drawPictureAtLocalResolution(proxy, device.get(), bounds, ctx); 117 } 118 119 *result = device.get()->accessBitmap(false); 120 offset->fX = bounds.fLeft; 121 offset->fY = bounds.fTop; 122 return true; 123 } 124 125 void SkPictureImageFilter::drawPictureAtDeviceResolution(SkBaseDevice* device, 126 const SkIRect& deviceBounds, 127 const Context& ctx) const { 128 SkCanvas canvas(device); 129 130 canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop)); 131 canvas.concat(ctx.ctm()); 132 canvas.drawPicture(fPicture); 133 } 134 135 void SkPictureImageFilter::drawPictureAtLocalResolution(Proxy* proxy, SkBaseDevice* device, 136 const SkIRect& deviceBounds, 137 const Context& ctx) const { 138 SkMatrix inverseCtm; 139 if (!ctx.ctm().invert(&inverseCtm)) { 140 return; 141 } 142 143 SkRect localBounds = SkRect::Make(ctx.clipBounds()); 144 inverseCtm.mapRect(&localBounds); 145 if (!localBounds.intersect(fCropRect)) { 146 return; 147 } 148 SkIRect localIBounds = localBounds.roundOut(); 149 SkAutoTUnref<SkBaseDevice> localDevice(proxy->createDevice(localIBounds.width(), localIBounds.height())); 150 151 SkCanvas localCanvas(localDevice); 152 localCanvas.translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop)); 153 localCanvas.drawPicture(fPicture); 154 155 SkCanvas canvas(device); 156 157 canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop)); 158 canvas.concat(ctx.ctm()); 159 SkPaint paint; 160 paint.setFilterQuality(fFilterQuality); 161 canvas.drawBitmap(localDevice.get()->accessBitmap(false), SkIntToScalar(localIBounds.fLeft), 162 SkIntToScalar(localIBounds.fTop), &paint); 163 } 164 165 #ifndef SK_IGNORE_TO_STRING 166 void SkPictureImageFilter::toString(SkString* str) const { 167 str->appendf("SkPictureImageFilter: ("); 168 str->appendf("crop: (%f,%f,%f,%f) ", 169 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom); 170 if (fPicture) { 171 str->appendf("picture: (%f,%f,%f,%f)", 172 fPicture->cullRect().fLeft, fPicture->cullRect().fTop, 173 fPicture->cullRect().fRight, fPicture->cullRect().fBottom); 174 } 175 str->append(")"); 176 } 177 #endif 178