1 /* 2 * Copyright 2012 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 "SkMagnifierImageFilter.h" 9 10 #include "SkBitmap.h" 11 #include "SkColorData.h" 12 #include "SkColorSpaceXformer.h" 13 #include "SkImageFilterPriv.h" 14 #include "SkReadBuffer.h" 15 #include "SkSpecialImage.h" 16 #include "SkWriteBuffer.h" 17 #include "SkValidationUtils.h" 18 19 //////////////////////////////////////////////////////////////////////////////// 20 #if SK_SUPPORT_GPU 21 #include "../private/GrGLSL.h" 22 #include "GrColorSpaceXform.h" 23 #include "GrContext.h" 24 #include "GrCoordTransform.h" 25 #include "GrTexture.h" 26 #include "effects/GrMagnifierEffect.h" 27 #include "glsl/GrGLSLFragmentProcessor.h" 28 #include "glsl/GrGLSLFragmentShaderBuilder.h" 29 #include "glsl/GrGLSLProgramDataManager.h" 30 #include "glsl/GrGLSLUniformHandler.h" 31 #endif 32 33 sk_sp<SkImageFilter> SkMagnifierImageFilter::Make(const SkRect& srcRect, SkScalar inset, 34 sk_sp<SkImageFilter> input, 35 const CropRect* cropRect) { 36 if (!SkScalarIsFinite(inset) || !SkIsValidRect(srcRect)) { 37 return nullptr; 38 } 39 if (inset < 0) { 40 return nullptr; 41 } 42 // Negative numbers in src rect are not supported 43 if (srcRect.fLeft < 0 || srcRect.fTop < 0) { 44 return nullptr; 45 } 46 return sk_sp<SkImageFilter>(new SkMagnifierImageFilter(srcRect, inset, 47 std::move(input), 48 cropRect)); 49 } 50 51 //////////////////////////////////////////////////////////////////////////////// 52 53 SkMagnifierImageFilter::SkMagnifierImageFilter(const SkRect& srcRect, 54 SkScalar inset, 55 sk_sp<SkImageFilter> input, 56 const CropRect* cropRect) 57 : INHERITED(&input, 1, cropRect) 58 , fSrcRect(srcRect) 59 , fInset(inset) { 60 SkASSERT(srcRect.left() >= 0 && srcRect.top() >= 0 && inset >= 0); 61 } 62 63 sk_sp<SkFlattenable> SkMagnifierImageFilter::CreateProc(SkReadBuffer& buffer) { 64 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 65 SkRect src; 66 buffer.readRect(&src); 67 return Make(src, buffer.readScalar(), common.getInput(0), &common.cropRect()); 68 } 69 70 void SkMagnifierImageFilter::flatten(SkWriteBuffer& buffer) const { 71 this->INHERITED::flatten(buffer); 72 buffer.writeRect(fSrcRect); 73 buffer.writeScalar(fInset); 74 } 75 76 sk_sp<SkSpecialImage> SkMagnifierImageFilter::onFilterImage(SkSpecialImage* source, 77 const Context& ctx, 78 SkIPoint* offset) const { 79 SkIPoint inputOffset = SkIPoint::Make(0, 0); 80 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); 81 if (!input) { 82 return nullptr; 83 } 84 85 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(), 86 input->width(), input->height()); 87 88 SkIRect bounds; 89 if (!this->applyCropRect(ctx, inputBounds, &bounds)) { 90 return nullptr; 91 } 92 93 SkScalar invInset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1; 94 95 SkScalar invXZoom = fSrcRect.width() / bounds.width(); 96 SkScalar invYZoom = fSrcRect.height() / bounds.height(); 97 98 99 #if SK_SUPPORT_GPU 100 if (source->isTextureBacked()) { 101 GrContext* context = source->getContext(); 102 103 sk_sp<GrTextureProxy> inputProxy(input->asTextureProxyRef(context)); 104 SkASSERT(inputProxy); 105 106 offset->fX = bounds.left(); 107 offset->fY = bounds.top(); 108 bounds.offset(-inputOffset); 109 110 GrPixelConfig inputConfig = inputProxy->config(); 111 auto fp = GrMagnifierEffect::Make(std::move(inputProxy), 112 bounds, 113 fSrcRect, 114 invXZoom, 115 invYZoom, 116 bounds.width() * invInset, 117 bounds.height() * invInset); 118 fp = GrColorSpaceXformEffect::Make(std::move(fp), input->getColorSpace(), 119 inputConfig, ctx.outputProperties().colorSpace()); 120 if (!fp) { 121 return nullptr; 122 } 123 124 return DrawWithFP(context, std::move(fp), bounds, ctx.outputProperties()); 125 } 126 #endif 127 128 SkBitmap inputBM; 129 130 if (!input->getROPixels(&inputBM)) { 131 return nullptr; 132 } 133 134 if ((inputBM.colorType() != kN32_SkColorType) || 135 (fSrcRect.width() >= inputBM.width()) || (fSrcRect.height() >= inputBM.height())) { 136 return nullptr; 137 } 138 139 SkASSERT(inputBM.getPixels()); 140 if (!inputBM.getPixels() || inputBM.width() <= 0 || inputBM.height() <= 0) { 141 return nullptr; 142 } 143 144 const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()); 145 146 SkBitmap dst; 147 if (!dst.tryAllocPixels(info)) { 148 return nullptr; 149 } 150 151 SkColor* dptr = dst.getAddr32(0, 0); 152 int dstWidth = dst.width(), dstHeight = dst.height(); 153 for (int y = 0; y < dstHeight; ++y) { 154 for (int x = 0; x < dstWidth; ++x) { 155 SkScalar x_dist = SkMin32(x, dstWidth - x - 1) * invInset; 156 SkScalar y_dist = SkMin32(y, dstHeight - y - 1) * invInset; 157 SkScalar weight = 0; 158 159 static const SkScalar kScalar2 = SkScalar(2); 160 161 // To create a smooth curve at the corners, we need to work on 162 // a square twice the size of the inset. 163 if (x_dist < kScalar2 && y_dist < kScalar2) { 164 x_dist = kScalar2 - x_dist; 165 y_dist = kScalar2 - y_dist; 166 167 SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) + 168 SkScalarSquare(y_dist)); 169 dist = SkMaxScalar(kScalar2 - dist, 0); 170 weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1); 171 } else { 172 SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist), 173 SkScalarSquare(y_dist)); 174 weight = SkMinScalar(sqDist, SK_Scalar1); 175 } 176 177 SkScalar x_interp = weight * (fSrcRect.x() + x * invXZoom) + (1 - weight) * x; 178 SkScalar y_interp = weight * (fSrcRect.y() + y * invYZoom) + (1 - weight) * y; 179 180 int x_val = SkTPin(bounds.x() + SkScalarFloorToInt(x_interp), 0, inputBM.width() - 1); 181 int y_val = SkTPin(bounds.y() + SkScalarFloorToInt(y_interp), 0, inputBM.height() - 1); 182 183 *dptr = *inputBM.getAddr32(x_val, y_val); 184 dptr++; 185 } 186 } 187 188 offset->fX = bounds.left(); 189 offset->fY = bounds.top(); 190 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), 191 dst); 192 } 193 194 sk_sp<SkImageFilter> SkMagnifierImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 195 SkASSERT(1 == this->countInputs()); 196 auto input = xformer->apply(this->getInput(0)); 197 if (input.get() != this->getInput(0)) { 198 return SkMagnifierImageFilter::Make(fSrcRect, fInset, std::move(input), 199 this->getCropRectIfSet()); 200 } 201 return this->refMe(); 202 } 203 204 #ifndef SK_IGNORE_TO_STRING 205 void SkMagnifierImageFilter::toString(SkString* str) const { 206 str->appendf("SkMagnifierImageFilter: ("); 207 str->appendf("src: (%f,%f,%f,%f) ", 208 fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom); 209 str->appendf("inset: %f", fInset); 210 str->append(")"); 211 } 212 #endif 213