LCOV - code coverage report
Current view: top level - gfx/2d - ConvolutionFilter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 66 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "2D.h"
       6             : #include "ConvolutionFilter.h"
       7             : #include "skia/src/core/SkBitmapFilter.h"
       8             : #include "skia/src/core/SkConvolver.h"
       9             : #include "skia/src/core/SkOpts.h"
      10             : #include <algorithm>
      11             : #include <cmath>
      12             : #include "mozilla/Vector.h"
      13             : 
      14             : namespace mozilla {
      15             : namespace gfx {
      16             : 
      17           0 : ConvolutionFilter::ConvolutionFilter()
      18           0 :   : mFilter(MakeUnique<SkConvolutionFilter1D>())
      19             : {
      20           0 : }
      21             : 
      22           0 : ConvolutionFilter::~ConvolutionFilter()
      23             : {
      24           0 : }
      25             : 
      26             : int32_t
      27           0 : ConvolutionFilter::MaxFilter() const
      28             : {
      29           0 :   return mFilter->maxFilter();
      30             : }
      31             : 
      32             : int32_t
      33           0 : ConvolutionFilter::NumValues() const
      34             : {
      35           0 :   return mFilter->numValues();
      36             : }
      37             : 
      38             : bool
      39           0 : ConvolutionFilter::GetFilterOffsetAndLength(int32_t aRowIndex, int32_t* aResultOffset, int32_t* aResultLength)
      40             : {
      41           0 :   if (aRowIndex >= mFilter->numValues()) {
      42           0 :     return false;
      43             :   }
      44           0 :   mFilter->FilterForValue(aRowIndex, aResultOffset, aResultLength);
      45           0 :   return true;
      46             : }
      47             : 
      48             : void
      49           0 : ConvolutionFilter::ConvolveHorizontally(const uint8_t* aSrc, uint8_t* aDst, bool aHasAlpha)
      50             : {
      51           0 :   SkOpts::convolve_horizontally(aSrc, *mFilter, aDst, aHasAlpha);
      52           0 : }
      53             : 
      54             : void
      55           0 : ConvolutionFilter::ConvolveVertically(uint8_t* const* aSrc, uint8_t* aDst, int32_t aRowIndex, int32_t aRowSize, bool aHasAlpha)
      56             : {
      57           0 :   MOZ_ASSERT(aRowIndex < mFilter->numValues());
      58             : 
      59             :   int32_t filterOffset;
      60             :   int32_t filterLength;
      61           0 :   auto filterValues = mFilter->FilterForValue(aRowIndex, &filterOffset, &filterLength);
      62           0 :   SkOpts::convolve_vertically(filterValues, filterLength, aSrc, aRowSize, aDst, aHasAlpha);
      63           0 : }
      64             : 
      65             : /* ConvolutionFilter::ComputeResizeFactor is derived from Skia's SkBitmapScaler/SkResizeFilter::computeFactors.
      66             :  * It is governed by Skia's BSD-style license (see gfx/skia/LICENSE) and the following copyright:
      67             :  * Copyright (c) 2015 Google Inc.
      68             :  */
      69             : bool
      70           0 : ConvolutionFilter::ComputeResizeFilter(ResizeMethod aResizeMethod, int32_t aSrcSize, int32_t aDstSize)
      71             : {
      72             :   typedef SkConvolutionFilter1D::ConvolutionFixed Fixed;
      73             : 
      74           0 :   UniquePtr<SkBitmapFilter> bitmapFilter;
      75           0 :   switch (aResizeMethod) {
      76             :   case ResizeMethod::BOX:
      77           0 :     bitmapFilter = MakeUnique<SkBoxFilter>();
      78           0 :     break;
      79             :   case ResizeMethod::TRIANGLE:
      80           0 :     bitmapFilter = MakeUnique<SkTriangleFilter>();
      81           0 :     break;
      82             :   case ResizeMethod::LANCZOS3:
      83           0 :     bitmapFilter = MakeUnique<SkLanczosFilter>();
      84           0 :     break;
      85             :   case ResizeMethod::HAMMING:
      86           0 :     bitmapFilter = MakeUnique<SkHammingFilter>();
      87           0 :     break;
      88             :   case ResizeMethod::MITCHELL:
      89           0 :     bitmapFilter = MakeUnique<SkMitchellFilter>();
      90           0 :     break;
      91             :   default:
      92           0 :     return false;
      93             :   }
      94             : 
      95             :   // When we're doing a magnification, the scale will be larger than one. This
      96             :   // means the destination pixels are much smaller than the source pixels, and
      97             :   // that the range covered by the filter won't necessarily cover any source
      98             :   // pixel boundaries. Therefore, we use these clamped values (max of 1) for
      99             :   // some computations.
     100           0 :   float scale = float(aDstSize) / float(aSrcSize);
     101           0 :   float clampedScale = std::min(1.0f, scale);
     102             :   // This is how many source pixels from the center we need to count
     103             :   // to support the filtering function.
     104           0 :   float srcSupport = bitmapFilter->width() / clampedScale;
     105           0 :   float invScale = 1.0f / scale;
     106             : 
     107           0 :   Vector<float, 64> filterValues;
     108           0 :   Vector<Fixed, 64> fixedFilterValues;
     109             : 
     110             :   // Loop over all pixels in the output range. We will generate one set of
     111             :   // filter values for each one. Those values will tell us how to blend the
     112             :   // source pixels to compute the destination pixel.
     113             : 
     114             :   // This is the pixel in the source directly under the pixel in the dest.
     115             :   // Note that we base computations on the "center" of the pixels. To see
     116             :   // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
     117             :   // downscale should "cover" the pixels around the pixel with *its center*
     118             :   // at coordinates (2.5, 2.5) in the source, not those around (0, 0).
     119             :   // Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
     120           0 :   float srcPixel = 0.5f * invScale;
     121           0 :   mFilter->reserveAdditional(aDstSize, int32_t(ceil(aDstSize * srcSupport * 2)));
     122           0 :   for (int32_t destI = 0; destI < aDstSize; destI++) {
     123             :     // Compute the (inclusive) range of source pixels the filter covers.
     124           0 :     float srcBegin = std::max(0.0f, floorf(srcPixel - srcSupport));
     125           0 :     float srcEnd = std::min(aSrcSize - 1.0f, ceilf(srcPixel + srcSupport));
     126             : 
     127             :     // Compute the unnormalized filter value at each location of the source
     128             :     // it covers.
     129             : 
     130             :     // Sum of the filter values for normalizing.
     131             :     // Distance from the center of the filter, this is the filter coordinate
     132             :     // in source space. We also need to consider the center of the pixel
     133             :     // when comparing distance against 'srcPixel'. In the 5x downscale
     134             :     // example used above the distance from the center of the filter to
     135             :     // the pixel with coordinates (2, 2) should be 0, because its center
     136             :     // is at (2.5, 2.5).
     137           0 :     float destFilterDist = (srcBegin + 0.5f - srcPixel) * clampedScale;
     138           0 :     int32_t filterCount = int32_t(srcEnd - srcBegin) + 1;
     139           0 :     if (filterCount <= 0 ||
     140           0 :         !filterValues.resize(filterCount) ||
     141           0 :         !fixedFilterValues.resize(filterCount)) {
     142           0 :       return false;
     143             :     }
     144           0 :     float filterSum = bitmapFilter->evaluate_n(destFilterDist, clampedScale, filterCount,
     145           0 :                                                filterValues.begin());
     146             : 
     147             :     // The filter must be normalized so that we don't affect the brightness of
     148             :     // the image. Convert to normalized fixed point.
     149           0 :     Fixed fixedSum = 0;
     150           0 :     float invFilterSum = 1.0f / filterSum;
     151           0 :     for (int32_t fixedI = 0; fixedI < filterCount; fixedI++) {
     152           0 :       Fixed curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] * invFilterSum);
     153           0 :       fixedSum += curFixed;
     154           0 :       fixedFilterValues[fixedI] = curFixed;
     155             :     }
     156             : 
     157             :     // The conversion to fixed point will leave some rounding errors, which
     158             :     // we add back in to avoid affecting the brightness of the image. We
     159             :     // arbitrarily add this to the center of the filter array (this won't always
     160             :     // be the center of the filter function since it could get clipped on the
     161             :     // edges, but it doesn't matter enough to worry about that case).
     162           0 :     Fixed leftovers = SkConvolutionFilter1D::FloatToFixed(1) - fixedSum;
     163           0 :     fixedFilterValues[filterCount / 2] += leftovers;
     164             : 
     165           0 :     mFilter->AddFilter(int32_t(srcBegin), fixedFilterValues.begin(), filterCount);
     166             : 
     167           0 :     srcPixel += invScale;
     168             :   }
     169             : 
     170           0 :   return mFilter->maxFilter() > 0 && mFilter->numValues() == aDstSize;
     171             : }
     172             : 
     173             : } // namespace gfx
     174             : } // namespace mozilla
     175             : 

Generated by: LCOV version 1.13