1b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// found in the LICENSE file.
4b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include <algorithm>
6b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include <cmath>
7b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include <vector>
8b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/logging.h"
10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "skia/ext/recursive_gaussian_convolution.h"
11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace skia {
13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace {
15b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Takes the value produced by accumulating element-wise product of image with
17b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// a kernel and brings it back into range.
18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// All of the filter scaling factors are in fixed point with kShiftBits bits of
19b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// fractional part.
20b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)template<bool take_absolute>
21b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)inline unsigned char FloatTo8(float f) {
22b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  int a = static_cast<int>(f + 0.5f);
23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (take_absolute)
24b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    a = std::abs(a);
25b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  else if (a < 0)
26b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return 0;
27b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (a < 256)
28b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return a;
29b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return 255;
30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
31b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)template<RecursiveFilter::Order order>
33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)inline float ForwardFilter(float in_n_1,
34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                           float in_n,
35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                           float in_n1,
36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                           const std::vector<float>& w,
37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                           int n,
38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                           const float* b) {
39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  switch (order) {
40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    case RecursiveFilter::FUNCTION:
41b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return b[0] * in_n + b[1] * w[n-1] + b[2] * w[n-2] + b[3] * w[n-3];
42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    case RecursiveFilter::FIRST_DERIVATIVE:
43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return b[0] * 0.5f * (in_n1 - in_n_1) +
44b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          b[1] * w[n-1] + b[2] * w[n-2] + b[3] * w[n-3];
45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    case RecursiveFilter::SECOND_DERIVATIVE:
46b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return b[0] * (in_n - in_n_1)  +
47b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          b[1] * w[n-1] + b[2] * w[n-2] + b[3] * w[n-3];
48b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NOTREACHED();
51b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return 0.0f;
52b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
53b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
54b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)template<RecursiveFilter::Order order>
55b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)inline float BackwardFilter(const std::vector<float>& out,
56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                            int n,
57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                            float w_n,
58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                            float w_n1,
59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                            const float* b) {
60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  switch (order) {
61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    case RecursiveFilter::FUNCTION:
62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    case RecursiveFilter::FIRST_DERIVATIVE:
63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return b[0] * w_n +
64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          b[1] * out[n + 1] + b[2] * out[n + 2] + b[3] * out[n + 3];
65b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    case RecursiveFilter::SECOND_DERIVATIVE:
66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return b[0] * (w_n1 - w_n)  +
67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          b[1] * out[n + 1] + b[2] * out[n + 2] + b[3] * out[n + 3];
68b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
69b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NOTREACHED();
70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return 0.0f;
71b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)template<RecursiveFilter::Order order, bool absolute_values>
74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)unsigned char SingleChannelRecursiveFilter(
75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const unsigned char* const source_data,
76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int source_pixel_stride,
77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int source_row_stride,
78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int row_width,
79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int row_count,
80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    unsigned char* const output,
81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int output_pixel_stride,
82b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int output_row_stride,
83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const float* b) {
84b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const int intermediate_buffer_size = row_width + 6;
85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  std::vector<float> w(intermediate_buffer_size);
86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const unsigned char* in = source_data;
87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  unsigned char* out = output;
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  unsigned char max_output = 0;
89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (int r = 0; r < row_count;
90b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       ++r, in += source_row_stride, out += output_row_stride) {
91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Compute forward filter.
92b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // First initialize start of the w (temporary) vector.
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (order == RecursiveFilter::FUNCTION)
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      w[0] = w[1] = w[2] = in[0];
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    else
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      w[0] = w[1] = w[2] = 0.0f;
97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Note that special-casing of w[3] is needed because of derivatives.
98b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    w[3] = ForwardFilter<order>(
99b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        in[0], in[0], in[source_pixel_stride], w, 3, b);
100b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int n = 4;
101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int c = 1;
102b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int byte_index = source_pixel_stride;
103b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    for (; c < row_width - 1; ++c, ++n, byte_index += source_pixel_stride) {
104b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      w[n] = ForwardFilter<order>(in[byte_index - source_pixel_stride],
105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                  in[byte_index],
106b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                  in[byte_index + source_pixel_stride],
107b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                  w, n, b);
108b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
109b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
110b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // The value of w corresponding to the last image pixel needs to be computed
111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // separately, again because of derivatives.
112b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    w[n] = ForwardFilter<order>(in[byte_index - source_pixel_stride],
113b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                in[byte_index],
114b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                in[byte_index],
115b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                w, n, b);
116b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Now three trailing bytes set to the same value as current w[n].
117b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    w[n + 1] = w[n];
118b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    w[n + 2] = w[n];
119b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    w[n + 3] = w[n];
120b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Now apply the back filter.
122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    float w_n1 = w[n + 1];
123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int output_index = (row_width - 1) * output_pixel_stride;
124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    for (; c >= 0; output_index -= output_pixel_stride, --c, --n) {
125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      float w_n = BackwardFilter<order>(w, n, w[n], w_n1, b);
126b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      w_n1 = w[n];
127b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      w[n] = w_n;
128b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      out[output_index] = FloatTo8<absolute_values>(w_n);
129b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      max_output = std::max(max_output, out[output_index]);
130b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
131b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return max_output;
133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
134b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
135b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)unsigned char SingleChannelRecursiveFilter(
136b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const unsigned char* const source_data,
137b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int source_pixel_stride,
138b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int source_row_stride,
139b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int row_width,
140b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int row_count,
141b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    unsigned char* const output,
142b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int output_pixel_stride,
143b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int output_row_stride,
144b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const float* b,
145b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecursiveFilter::Order order,
146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    bool absolute_values) {
147b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (absolute_values) {
148b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)   switch (order) {
149b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)     case RecursiveFilter::FUNCTION:
150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       return SingleChannelRecursiveFilter<RecursiveFilter::FUNCTION, true>(
151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)           source_data, source_pixel_stride, source_row_stride,
152b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)           row_width, row_count,
153b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)           output, output_pixel_stride, output_row_stride, b);
154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)     case RecursiveFilter::FIRST_DERIVATIVE:
155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       return SingleChannelRecursiveFilter<
156b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)         RecursiveFilter::FIRST_DERIVATIVE, true>(
157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             source_data, source_pixel_stride, source_row_stride,
158b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             row_width, row_count,
159b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             output, output_pixel_stride, output_row_stride, b);
160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)     case RecursiveFilter::SECOND_DERIVATIVE:
161b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       return SingleChannelRecursiveFilter<
162b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)         RecursiveFilter::SECOND_DERIVATIVE, true>(
163b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             source_data, source_pixel_stride, source_row_stride,
164b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             row_width, row_count,
165b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             output, output_pixel_stride, output_row_stride, b);
166b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)   }
167b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  } else {
168b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    switch (order) {
169b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)     case RecursiveFilter::FUNCTION:
170b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       return SingleChannelRecursiveFilter<RecursiveFilter::FUNCTION, false>(
171b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)           source_data, source_pixel_stride, source_row_stride,
172b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)           row_width, row_count,
173b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)           output, output_pixel_stride, output_row_stride, b);
174b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)     case RecursiveFilter::FIRST_DERIVATIVE:
175b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       return SingleChannelRecursiveFilter<
176b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)         RecursiveFilter::FIRST_DERIVATIVE, false>(
177b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             source_data, source_pixel_stride, source_row_stride,
178b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             row_width, row_count,
179b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             output, output_pixel_stride, output_row_stride, b);
180b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)     case RecursiveFilter::SECOND_DERIVATIVE:
181b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       return SingleChannelRecursiveFilter<
182b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)         RecursiveFilter::SECOND_DERIVATIVE, false>(
183b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             source_data, source_pixel_stride, source_row_stride,
184b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             row_width, row_count,
185b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             output, output_pixel_stride, output_row_stride, b);
186b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)   }
187b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
188b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
189b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NOTREACHED();
190b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return 0;
191b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
192b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
193b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
195b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)float RecursiveFilter::qFromSigma(float sigma) {
196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK_GE(sigma, 0.5f);
197b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (sigma <= 2.5f)
198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return 3.97156f - 4.14554f * std::sqrt(1.0f - 0.26891f * sigma);
199b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return 0.98711f * sigma - 0.96330f;
200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void RecursiveFilter::computeCoefficients(float q, float b[4]) {
203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  b[0] = 1.57825f + 2.44413f * q + 1.4281f * q * q + 0.422205f * q * q * q;
204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  b[1] = 2.4413f * q + 2.85619f * q * q + 1.26661f * q * q * q;
205b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  b[2] = - 1.4281f * q * q - 1.26661f * q * q * q;
206b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  b[3] = 0.422205f * q * q * q;
207b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
208b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // The above is exactly like in the paper. To cut down on computations,
209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // we can fix up these numbers a bit now.
210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  float b_norm = 1.0f - (b[1] + b[2] + b[3]) / b[0];
211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  b[1] /= b[0];
212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  b[2] /= b[0];
213b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  b[3] /= b[0];
214b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  b[0] = b_norm;
215b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
216b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
217b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)RecursiveFilter::RecursiveFilter(float sigma, Order order)
218b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    : order_(order), q_(qFromSigma(sigma)) {
219b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  computeCoefficients(q_, b_);
220b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
221b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)unsigned char SingleChannelRecursiveGaussianX(const unsigned char* source_data,
223b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              int source_byte_row_stride,
224b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              int input_channel_index,
225b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              int input_channel_count,
226b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              const RecursiveFilter& filter,
227b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              const SkISize& image_size,
228b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              unsigned char* output,
229b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              int output_byte_row_stride,
230b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              int output_channel_index,
231b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              int output_channel_count,
232b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                              bool absolute_values) {
233b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return SingleChannelRecursiveFilter(source_data + input_channel_index,
234b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      input_channel_count,
235b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      source_byte_row_stride,
236b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      image_size.width(),
237b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      image_size.height(),
238b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      output + output_channel_index,
239b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      output_channel_count,
240b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      output_byte_row_stride,
241b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      filter.b(),
242b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      filter.order(),
243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      absolute_values);
244b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
245b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
246b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)unsigned char  SingleChannelRecursiveGaussianY(const unsigned char* source_data,
247b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               int source_byte_row_stride,
248b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               int input_channel_index,
249b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               int input_channel_count,
250b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               const RecursiveFilter& filter,
251b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               const SkISize& image_size,
252b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               unsigned char* output,
253b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               int output_byte_row_stride,
254b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               int output_channel_index,
255b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               int output_channel_count,
256b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                               bool absolute_values) {
257b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return SingleChannelRecursiveFilter(source_data + input_channel_index,
258b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      source_byte_row_stride,
259b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      input_channel_count,
260b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      image_size.height(),
261b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      image_size.width(),
262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      output + output_channel_index,
263b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      output_byte_row_stride,
264b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      output_channel_count,
265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      filter.b(),
266b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      filter.order(),
267b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                      absolute_values);
268b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
269b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace skia
271