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, NULL) 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, NULL) 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 #ifdef SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS 43 if (buffer.isCrossProcess()) { 44 buffer.validate(!buffer.readBool()); 45 } else 46 #endif 47 { 48 if (buffer.readBool()) { 49 picture.reset(SkPicture::CreateFromBuffer(buffer)); 50 } 51 } 52 buffer.readRect(&cropRect); 53 PictureResolution pictureResolution; 54 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) { 55 pictureResolution = kDeviceSpace_PictureResolution; 56 } else { 57 pictureResolution = (PictureResolution)buffer.readInt(); 58 } 59 60 if (kLocalSpace_PictureResolution == pictureResolution) { 61 //filterLevel is only serialized if pictureResolution is LocalSpace 62 SkFilterQuality filterQuality; 63 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) { 64 filterQuality = kLow_SkFilterQuality; 65 } else { 66 filterQuality = (SkFilterQuality)buffer.readInt(); 67 } 68 return CreateForLocalSpace(picture, cropRect, filterQuality); 69 } 70 return Create(picture, cropRect); 71 } 72 73 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const { 74 #ifdef SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS 75 if (buffer.isCrossProcess()) { 76 buffer.writeBool(false); 77 } else 78 #endif 79 { 80 bool hasPicture = (fPicture != NULL); 81 buffer.writeBool(hasPicture); 82 if (hasPicture) { 83 fPicture->flatten(buffer); 84 } 85 } 86 buffer.writeRect(fCropRect); 87 buffer.writeInt(fPictureResolution); 88 if (kLocalSpace_PictureResolution == fPictureResolution) { 89 buffer.writeInt(fFilterQuality); 90 } 91 } 92 93 bool SkPictureImageFilter::onFilterImage(Proxy* proxy, const SkBitmap&, const Context& ctx, 94 SkBitmap* result, SkIPoint* offset) const { 95 if (!fPicture) { 96 offset->fX = offset->fY = 0; 97 return true; 98 } 99 100 SkRect floatBounds; 101 ctx.ctm().mapRect(&floatBounds, fCropRect); 102 SkIRect bounds = floatBounds.roundOut(); 103 if (!bounds.intersect(ctx.clipBounds())) { 104 return false; 105 } 106 107 if (bounds.isEmpty()) { 108 offset->fX = offset->fY = 0; 109 return true; 110 } 111 112 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); 113 if (NULL == device.get()) { 114 return false; 115 } 116 117 if (kDeviceSpace_PictureResolution == fPictureResolution || 118 0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) { 119 drawPictureAtDeviceResolution(proxy, device.get(), bounds, ctx); 120 } else { 121 drawPictureAtLocalResolution(proxy, device.get(), bounds, ctx); 122 } 123 124 *result = device.get()->accessBitmap(false); 125 offset->fX = bounds.fLeft; 126 offset->fY = bounds.fTop; 127 return true; 128 } 129 130 void SkPictureImageFilter::drawPictureAtDeviceResolution(Proxy* proxy, SkBaseDevice* device, 131 const SkIRect& deviceBounds, 132 const Context& ctx) const { 133 // Pass explicit surface props, as the simplified canvas constructor discards device properties. 134 // FIXME: switch back to the public constructor (and unfriend) after 135 // https://code.google.com/p/skia/issues/detail?id=3142 is fixed. 136 SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags); 137 138 canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop)); 139 canvas.concat(ctx.ctm()); 140 canvas.drawPicture(fPicture); 141 } 142 143 void SkPictureImageFilter::drawPictureAtLocalResolution(Proxy* proxy, SkBaseDevice* device, 144 const SkIRect& deviceBounds, 145 const Context& ctx) const { 146 SkMatrix inverseCtm; 147 if (!ctx.ctm().invert(&inverseCtm)) 148 return; 149 SkRect localBounds = SkRect::Make(ctx.clipBounds()); 150 inverseCtm.mapRect(&localBounds); 151 if (!localBounds.intersect(fCropRect)) 152 return; 153 SkIRect localIBounds = localBounds.roundOut(); 154 SkAutoTUnref<SkBaseDevice> localDevice(proxy->createDevice(localIBounds.width(), localIBounds.height())); 155 156 // Pass explicit surface props, as the simplified canvas constructor discards device properties. 157 // FIXME: switch back to the public constructor (and unfriend) after 158 // https://code.google.com/p/skia/issues/detail?id=3142 is fixed. 159 SkCanvas localCanvas(localDevice, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags); 160 localCanvas.translate(-SkIntToScalar(localIBounds.fLeft), -SkIntToScalar(localIBounds.fTop)); 161 localCanvas.drawPicture(fPicture); 162 163 // Pass explicit surface props, as the simplified canvas constructor discards device properties. 164 // FIXME: switch back to the public constructor (and unfriend) after 165 // https://code.google.com/p/skia/issues/detail?id=3142 is fixed. 166 SkCanvas canvas(device, proxy->surfaceProps(), SkCanvas::kDefault_InitFlags); 167 168 canvas.translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop)); 169 canvas.concat(ctx.ctm()); 170 SkPaint paint; 171 paint.setFilterQuality(fFilterQuality); 172 canvas.drawBitmap(localDevice.get()->accessBitmap(false), SkIntToScalar(localIBounds.fLeft), 173 SkIntToScalar(localIBounds.fTop), &paint); 174 //canvas.drawPicture(fPicture); 175 } 176 177 #ifndef SK_IGNORE_TO_STRING 178 void SkPictureImageFilter::toString(SkString* str) const { 179 str->appendf("SkPictureImageFilter: ("); 180 str->appendf("crop: (%f,%f,%f,%f) ", 181 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom); 182 if (fPicture) { 183 str->appendf("picture: (%f,%f,%f,%f)", 184 fPicture->cullRect().fLeft, fPicture->cullRect().fTop, 185 fPicture->cullRect().fRight, fPicture->cullRect().fBottom); 186 } 187 str->append(")"); 188 } 189 #endif 190