Fix metrics on Windows.
With this change, Skia's metrics are much better in general, and
specifically can be made to match the metrics produced by current
Blink code. This allows Blink to use Skia's metrics.
This change will require a number of rebaselines in Skia, since
previous metrics were quite different. This will require about five
rebaslines in Blink, as the new code may cause GDI's matrix to differ
in the low bits.
Review URL: https://codereview.chromium.org/20585004
git-svn-id: http://skia.googlecode.com/svn/trunk@10399 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tools/generate_fir_coeff.py b/tools/generate_fir_coeff.py
new file mode 100644
index 0000000..70f521f
--- /dev/null
+++ b/tools/generate_fir_coeff.py
@@ -0,0 +1,119 @@
+#!/usr/bin/python
+
+'''
+Copyright 2013 Google Inc.
+
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+'''
+
+import math
+import pprint
+
+def withinStdDev(n):
+ """Returns the percent of samples within n std deviations of the normal."""
+ return math.erf(n / math.sqrt(2))
+
+def withinStdDevRange(a, b):
+ """Returns the percent of samples within the std deviation range a, b"""
+ if b < a:
+ return 0;
+
+ if a < 0:
+ if b < 0:
+ return (withinStdDev(-a) - withinStdDev(-b)) / 2;
+ else:
+ return (withinStdDev(-a) + withinStdDev(b)) / 2;
+ else:
+ return (withinStdDev(b) - withinStdDev(a)) / 2;
+
+
+#We have a bunch of smudged samples which represent the average coverage of a range.
+#We have a 'center' which may not line up with those samples.
+#From the 'center' we want to make a normal approximation where '5' sample width out we're at '3' std deviations.
+#The first and last samples may not be fully covered.
+
+#This is the sub-sample shift for each set of FIR coefficients (the centers of the lcds in the samples)
+#Each subpxl takes up 1/3 of a pixel, so they are centered at x=(i/n+1/2n), or 1/6, 3/6, 5/6 of a pixel.
+#Each sample takes up 1/4 of a pixel, so the results fall at (x*4)%1, or 2/3, 0, 1/3 of a sample.
+samples_per_pixel = 4
+subpxls_per_pixel = 3
+#sample_offsets is (frac, int) in sample units.
+sample_offsets = [math.modf((float(subpxl_index)/subpxls_per_pixel + 1.0/(2.0*subpxls_per_pixel))*samples_per_pixel) for subpxl_index in range(subpxls_per_pixel)]
+
+#How many samples to consider to the left and right of the subpxl center.
+sample_units_width = 5
+
+#The std deviation at sample_units_width.
+std_dev_max = 3
+
+#The target sum is in some fixed point representation.
+#Values larger the 1 in fixed point simulate ink spread.
+target_sum = 0x110
+
+for sample_offset, sample_align in sample_offsets:
+ coeffs = []
+ coeffs_rounded = []
+
+ #We start at sample_offset - sample_units_width
+ current_sample_left = sample_offset - sample_units_width
+ current_std_dev_left = -std_dev_max
+
+ done = False
+ while not done:
+ current_sample_right = math.floor(current_sample_left + 1)
+ if current_sample_right > sample_offset + sample_units_width:
+ done = True
+ current_sample_right = sample_offset + sample_units_width
+ current_std_dev_right = current_std_dev_left + ((current_sample_right - current_sample_left) / sample_units_width) * std_dev_max
+
+ coverage = withinStdDevRange(current_std_dev_left, current_std_dev_right)
+ coeffs.append(coverage * target_sum)
+ coeffs_rounded.append(int(round(coverage * target_sum)))
+
+ current_sample_left = current_sample_right
+ current_std_dev_left = current_std_dev_right
+
+ # Now we have the numbers we want, but our rounding needs to add up to target_sum.
+ delta = 0
+ coeffs_rounded_sum = sum(coeffs_rounded)
+ if coeffs_rounded_sum > target_sum:
+ # The coeffs add up to too much. Subtract 1 from the ones which were rounded up the most.
+ delta = -1
+
+ if coeffs_rounded_sum < target_sum:
+ # The coeffs add up to too little. Add 1 to the ones which were rounded down the most.
+ delta = 1
+
+ if delta:
+ print "Initial sum is 0x%0.2X, adjusting." % (coeffs_rounded_sum,)
+ coeff_diff = [(coeff_rounded - coeff) * delta
+ for coeff, coeff_rounded in zip(coeffs, coeffs_rounded)]
+
+ class IndexTracker:
+ def __init__(self, index, item):
+ self.index = index
+ self.item = item
+ def __lt__(self, other):
+ return self.item < other.item
+ def __repr__(self):
+ return "arr[%d] == %s" % (self.index, repr(self.item))
+
+ coeff_pkg = [IndexTracker(i, diff) for i, diff in enumerate(coeff_diff)]
+ coeff_pkg.sort()
+
+ # num_elements_to_force_round had better be < (2 * sample_units_width + 1) or
+ # * our math was wildy wrong
+ # * an awful lot of the curve is out side our sample
+ # either is pretty bad, and probably means the results will not be useful.
+ num_elements_to_force_round = abs(coeffs_rounded_sum - target_sum)
+ for i in xrange(num_elements_to_force_round):
+ print "Adding %d to index %d to force round %f." % (delta, coeff_pkg[i].index, coeffs[coeff_pkg[i].index])
+ coeffs_rounded[coeff_pkg[i].index] += delta
+
+ print "Prepending %d 0x00 for allignment." % (sample_align,)
+ coeffs_rounded_aligned = ([0] * int(sample_align)) + coeffs_rounded
+
+ print ', '.join(["0x%0.2X" % coeff_rounded for coeff_rounded in coeffs_rounded_aligned])
+ print sum(coeffs), hex(sum(coeffs_rounded))
+ print