SkAlphaThresholdFilter.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright 2013 Google Inc.
  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. #include "include/effects/SkAlphaThresholdFilter.h"
  8. #include "include/core/SkBitmap.h"
  9. #include "include/core/SkRegion.h"
  10. #include "src/core/SkImageFilterPriv.h"
  11. #include "src/core/SkReadBuffer.h"
  12. #include "src/core/SkSpecialImage.h"
  13. #include "src/core/SkWriteBuffer.h"
  14. #if SK_SUPPORT_GPU
  15. #include "include/gpu/GrContext.h"
  16. #include "include/private/GrRecordingContext.h"
  17. #include "src/gpu/GrCaps.h"
  18. #include "src/gpu/GrColorSpaceXform.h"
  19. #include "src/gpu/GrFixedClip.h"
  20. #include "src/gpu/GrRecordingContextPriv.h"
  21. #include "src/gpu/GrRenderTargetContext.h"
  22. #include "src/gpu/GrTextureProxy.h"
  23. #include "src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h"
  24. #include "src/gpu/effects/generated/GrSimpleTextureEffect.h"
  25. #endif
  26. class SkAlphaThresholdFilterImpl : public SkImageFilter {
  27. public:
  28. SkAlphaThresholdFilterImpl(const SkRegion& region, SkScalar innerThreshold,
  29. SkScalar outerThreshold, sk_sp<SkImageFilter> input,
  30. const CropRect* cropRect = nullptr);
  31. friend void SkAlphaThresholdFilter::RegisterFlattenables();
  32. protected:
  33. void flatten(SkWriteBuffer&) const override;
  34. sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
  35. SkIPoint* offset) const override;
  36. #if SK_SUPPORT_GPU
  37. sk_sp<GrTextureProxy> createMaskTexture(GrRecordingContext*,
  38. const SkMatrix&,
  39. const SkIRect& bounds) const;
  40. #endif
  41. private:
  42. SK_FLATTENABLE_HOOKS(SkAlphaThresholdFilterImpl)
  43. SkRegion fRegion;
  44. SkScalar fInnerThreshold;
  45. SkScalar fOuterThreshold;
  46. typedef SkImageFilter INHERITED;
  47. };
  48. void SkAlphaThresholdFilter::RegisterFlattenables() {
  49. SK_REGISTER_FLATTENABLE(SkAlphaThresholdFilterImpl);
  50. }
  51. static SkScalar pin_0_1(SkScalar x) {
  52. return SkMinScalar(SkMaxScalar(x, 0), 1);
  53. }
  54. sk_sp<SkImageFilter> SkAlphaThresholdFilter::Make(const SkRegion& region,
  55. SkScalar innerThreshold,
  56. SkScalar outerThreshold,
  57. sk_sp<SkImageFilter> input,
  58. const SkImageFilter::CropRect* cropRect) {
  59. innerThreshold = pin_0_1(innerThreshold);
  60. outerThreshold = pin_0_1(outerThreshold);
  61. if (!SkScalarIsFinite(innerThreshold) || !SkScalarIsFinite(outerThreshold)) {
  62. return nullptr;
  63. }
  64. return sk_sp<SkImageFilter>(new SkAlphaThresholdFilterImpl(region, innerThreshold,
  65. outerThreshold,
  66. std::move(input),
  67. cropRect));
  68. }
  69. sk_sp<SkFlattenable> SkAlphaThresholdFilterImpl::CreateProc(SkReadBuffer& buffer) {
  70. SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
  71. SkScalar inner = buffer.readScalar();
  72. SkScalar outer = buffer.readScalar();
  73. SkRegion rgn;
  74. buffer.readRegion(&rgn);
  75. return SkAlphaThresholdFilter::Make(rgn, inner, outer, common.getInput(0),
  76. &common.cropRect());
  77. }
  78. SkAlphaThresholdFilterImpl::SkAlphaThresholdFilterImpl(const SkRegion& region,
  79. SkScalar innerThreshold,
  80. SkScalar outerThreshold,
  81. sk_sp<SkImageFilter> input,
  82. const CropRect* cropRect)
  83. : INHERITED(&input, 1, cropRect)
  84. , fRegion(region)
  85. , fInnerThreshold(innerThreshold)
  86. , fOuterThreshold(outerThreshold) {
  87. }
  88. #if SK_SUPPORT_GPU
  89. sk_sp<GrTextureProxy> SkAlphaThresholdFilterImpl::createMaskTexture(GrRecordingContext* context,
  90. const SkMatrix& inMatrix,
  91. const SkIRect& bounds) const {
  92. sk_sp<GrRenderTargetContext> rtContext(
  93. context->priv().makeDeferredRenderTargetContextWithFallback(
  94. SkBackingFit::kApprox, bounds.width(), bounds.height(), GrColorType::kAlpha_8,
  95. nullptr));
  96. if (!rtContext) {
  97. return nullptr;
  98. }
  99. SkRegion::Iterator iter(fRegion);
  100. rtContext->clear(nullptr, SK_PMColor4fTRANSPARENT,
  101. GrRenderTargetContext::CanClearFullscreen::kYes);
  102. GrFixedClip clip(SkIRect::MakeWH(bounds.width(), bounds.height()));
  103. while (!iter.done()) {
  104. GrPaint paint;
  105. paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
  106. SkRect rect = SkRect::Make(iter.rect());
  107. rtContext->drawRect(clip, std::move(paint), GrAA::kNo, inMatrix, rect);
  108. iter.next();
  109. }
  110. return rtContext->asTextureProxyRef();
  111. }
  112. #endif
  113. void SkAlphaThresholdFilterImpl::flatten(SkWriteBuffer& buffer) const {
  114. this->INHERITED::flatten(buffer);
  115. buffer.writeScalar(fInnerThreshold);
  116. buffer.writeScalar(fOuterThreshold);
  117. buffer.writeRegion(fRegion);
  118. }
  119. sk_sp<SkSpecialImage> SkAlphaThresholdFilterImpl::onFilterImage(SkSpecialImage* source,
  120. const Context& ctx,
  121. SkIPoint* offset) const {
  122. SkIPoint inputOffset = SkIPoint::Make(0, 0);
  123. sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
  124. if (!input) {
  125. return nullptr;
  126. }
  127. const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
  128. input->width(), input->height());
  129. SkIRect bounds;
  130. if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
  131. return nullptr;
  132. }
  133. #if SK_SUPPORT_GPU
  134. if (source->isTextureBacked()) {
  135. auto context = source->getContext();
  136. sk_sp<GrTextureProxy> inputProxy(input->asTextureProxyRef(context));
  137. SkASSERT(inputProxy);
  138. const bool isProtected = inputProxy->isProtected();
  139. offset->fX = bounds.left();
  140. offset->fY = bounds.top();
  141. bounds.offset(-inputOffset);
  142. SkMatrix matrix(ctx.ctm());
  143. matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
  144. sk_sp<GrTextureProxy> maskProxy(this->createMaskTexture(context, matrix, bounds));
  145. if (!maskProxy) {
  146. return nullptr;
  147. }
  148. const OutputProperties& outProps = ctx.outputProperties();
  149. auto textureFP = GrSimpleTextureEffect::Make(std::move(inputProxy),
  150. SkMatrix::MakeTrans(input->subset().x(),
  151. input->subset().y()));
  152. textureFP = GrColorSpaceXformEffect::Make(std::move(textureFP), input->getColorSpace(),
  153. input->alphaType(), outProps.colorSpace());
  154. if (!textureFP) {
  155. return nullptr;
  156. }
  157. auto thresholdFP = GrAlphaThresholdFragmentProcessor::Make(std::move(maskProxy),
  158. fInnerThreshold,
  159. fOuterThreshold,
  160. bounds);
  161. if (!thresholdFP) {
  162. return nullptr;
  163. }
  164. std::unique_ptr<GrFragmentProcessor> fpSeries[] = { std::move(textureFP),
  165. std::move(thresholdFP) };
  166. auto fp = GrFragmentProcessor::RunInSeries(fpSeries, 2);
  167. return DrawWithFP(context, std::move(fp), bounds, outProps,
  168. isProtected ? GrProtected::kYes : GrProtected::kNo);
  169. }
  170. #endif
  171. SkBitmap inputBM;
  172. if (!input->getROPixels(&inputBM)) {
  173. return nullptr;
  174. }
  175. if (inputBM.colorType() != kN32_SkColorType) {
  176. return nullptr;
  177. }
  178. if (!inputBM.getPixels() || inputBM.width() <= 0 || inputBM.height() <= 0) {
  179. return nullptr;
  180. }
  181. SkMatrix localInverse;
  182. if (!ctx.ctm().invert(&localInverse)) {
  183. return nullptr;
  184. }
  185. SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(),
  186. kPremul_SkAlphaType);
  187. SkBitmap dst;
  188. if (!dst.tryAllocPixels(info)) {
  189. return nullptr;
  190. }
  191. U8CPU innerThreshold = (U8CPU)(fInnerThreshold * 0xFF);
  192. U8CPU outerThreshold = (U8CPU)(fOuterThreshold * 0xFF);
  193. SkColor* dptr = dst.getAddr32(0, 0);
  194. int dstWidth = dst.width(), dstHeight = dst.height();
  195. SkIPoint srcOffset = { bounds.fLeft - inputOffset.fX, bounds.fTop - inputOffset.fY };
  196. for (int y = 0; y < dstHeight; ++y) {
  197. const SkColor* sptr = inputBM.getAddr32(srcOffset.fX, srcOffset.fY+y);
  198. for (int x = 0; x < dstWidth; ++x) {
  199. const SkColor& source = sptr[x];
  200. SkColor outputColor(source);
  201. SkPoint position;
  202. localInverse.mapXY((SkScalar)x + bounds.fLeft, (SkScalar)y + bounds.fTop, &position);
  203. if (fRegion.contains((int32_t)position.x(), (int32_t)position.y())) {
  204. if (SkColorGetA(source) < innerThreshold) {
  205. U8CPU alpha = SkColorGetA(source);
  206. if (alpha == 0) {
  207. alpha = 1;
  208. }
  209. float scale = (float)innerThreshold / alpha;
  210. outputColor = SkColorSetARGB(innerThreshold,
  211. (U8CPU)(SkColorGetR(source) * scale),
  212. (U8CPU)(SkColorGetG(source) * scale),
  213. (U8CPU)(SkColorGetB(source) * scale));
  214. }
  215. } else {
  216. if (SkColorGetA(source) > outerThreshold) {
  217. float scale = (float)outerThreshold / SkColorGetA(source);
  218. outputColor = SkColorSetARGB(outerThreshold,
  219. (U8CPU)(SkColorGetR(source) * scale),
  220. (U8CPU)(SkColorGetG(source) * scale),
  221. (U8CPU)(SkColorGetB(source) * scale));
  222. }
  223. }
  224. dptr[y * dstWidth + x] = outputColor;
  225. }
  226. }
  227. offset->fX = bounds.left();
  228. offset->fY = bounds.top();
  229. return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
  230. dst);
  231. }