ConvolutionFilter.cpp (4138B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "ConvolutionFilter.h" 8 #include "HelpersSkia.h" 9 #include "SkConvolver.h" 10 #include "skia/include/core/SkBitmap.h" 11 12 namespace mozilla::gfx { 13 14 ConvolutionFilter::ConvolutionFilter() 15 : mFilter(MakeUnique<skia::SkConvolutionFilter1D>()) {} 16 17 ConvolutionFilter::~ConvolutionFilter() = default; 18 19 int32_t ConvolutionFilter::MaxFilter() const { return mFilter->maxFilter(); } 20 21 int32_t ConvolutionFilter::NumValues() const { return mFilter->numValues(); } 22 23 bool ConvolutionFilter::GetFilterOffsetAndLength(int32_t aRowIndex, 24 int32_t* aResultOffset, 25 int32_t* aResultLength) { 26 if (aRowIndex >= mFilter->numValues()) { 27 return false; 28 } 29 mFilter->FilterForValue(aRowIndex, aResultOffset, aResultLength); 30 return true; 31 } 32 33 void ConvolutionFilter::ConvolveHorizontally(const uint8_t* aSrc, uint8_t* aDst, 34 SurfaceFormat aFormat) { 35 skia::convolve_horizontally(aSrc, *mFilter, aDst, aFormat); 36 } 37 38 void ConvolutionFilter::ConvolveVertically(uint8_t* const* aSrc, uint8_t* aDst, 39 int32_t aRowIndex, int32_t aRowSize, 40 SurfaceFormat aFormat) { 41 MOZ_ASSERT(aRowIndex < mFilter->numValues()); 42 43 int32_t filterOffset; 44 int32_t filterLength; 45 auto filterValues = 46 mFilter->FilterForValue(aRowIndex, &filterOffset, &filterLength); 47 skia::convolve_vertically(filterValues, filterLength, aSrc, aRowSize, aDst, 48 aFormat); 49 } 50 51 bool ConvolutionFilter::ComputeResizeFilter(ResizeMethod aResizeMethod, 52 int32_t aSrcSize, 53 int32_t aDstSize) { 54 if (aSrcSize < 0 || aDstSize < 0) { 55 return false; 56 } 57 58 switch (aResizeMethod) { 59 case ResizeMethod::BOX: 60 return mFilter->ComputeFilterValues(skia::SkBoxFilter(), aSrcSize, 61 aDstSize); 62 case ResizeMethod::LANCZOS3: 63 return mFilter->ComputeFilterValues(skia::SkLanczosFilter(), aSrcSize, 64 aDstSize); 65 default: 66 return false; 67 } 68 } 69 70 bool Scale(uint8_t* srcData, int32_t srcWidth, int32_t srcHeight, 71 int32_t srcStride, uint8_t* dstData, int32_t dstWidth, 72 int32_t dstHeight, int32_t dstStride, SurfaceFormat format) { 73 if (!srcData || !dstData || srcWidth < 1 || srcHeight < 1 || dstWidth < 1 || 74 dstHeight < 1) { 75 return false; 76 } 77 78 switch (format) { 79 case SurfaceFormat::B8G8R8A8: 80 case SurfaceFormat::B8G8R8X8: 81 case SurfaceFormat::R8G8B8A8: 82 case SurfaceFormat::R8G8B8X8: 83 // 4 byte formats with alpha at last byte are supported. 84 break; 85 case SurfaceFormat::A8: 86 // 1 byte formats are supported. 87 break; 88 default: 89 return false; 90 } 91 92 SkPixmap srcPixmap(MakeSkiaImageInfo(IntSize(srcWidth, srcHeight), format), 93 srcData, srcStride); 94 95 ConvolutionFilter xFilter; 96 ConvolutionFilter yFilter; 97 ConvolutionFilter* xOrYFilter = &xFilter; 98 bool isSquare = srcWidth == srcHeight && dstWidth == dstHeight; 99 if (!xFilter.ComputeResizeFilter(ConvolutionFilter::ResizeMethod::LANCZOS3, 100 srcWidth, dstWidth)) { 101 return false; 102 } 103 if (!isSquare) { 104 if (!yFilter.ComputeResizeFilter(ConvolutionFilter::ResizeMethod::LANCZOS3, 105 srcHeight, dstHeight)) { 106 return false; 107 } 108 xOrYFilter = &yFilter; 109 } 110 111 return skia::BGRAConvolve2D( 112 static_cast<const uint8_t*>(srcPixmap.addr()), int(srcPixmap.rowBytes()), 113 format, xFilter.GetSkiaFilter(), xOrYFilter->GetSkiaFilter(), 114 int(dstStride), dstData); 115 } 116 117 } // namespace mozilla::gfx