Bug 513395: Make sure the Cairo/Quartz backend returns the first stop for negative positions on the gradient line of a nonrepeating linear gradient. r=jrmuizel

--HG--
extra : rebase_source : 2b4fbf1602dbaac5f3bba2ac0c8465236546bfe7
This commit is contained in:
Robert O'Callahan 2009-11-02 09:20:40 -08:00
parent ee08301769
commit 894942d61e
3 changed files with 81 additions and 2 deletions

View File

@ -60,6 +60,8 @@ quartz-const-globals.patch: make some Quartz color function data const globals i
quartz-minimze-gradient-repeat.patch: reduce the number of gradient stop repetitions we use, to improve quality of Quartz's gradient rendering
quartz-first-stop.patch: return the first stop for negative positions on the gradient line of a nonrepeating linear gradient
==== pixman patches ====
pixman-neon.patch: add ARM NEON optimized compositing functions

View File

@ -695,12 +695,32 @@ static const float gradient_output_value_ranges[8] = {
static const CGFunctionCallbacks gradient_callbacks = {
0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy
};
/* Quartz will clamp input values to the input range.
Our stops are all in the range 0.0 to 1.0. However, the color before the
beginning of the gradient line is obtained by Quartz computing a negative
position on the gradient line, clamping it to the input range we specified
for our color function, and then calling our color function (actually it
pre-samples the color function into an array, but that doesn't matter just
here). Therefore if we set the lower bound to 0.0, a negative position
on the gradient line will pass 0.0 to ComputeGradientValue, which will
select the last color stop with position 0, although it should select
the first color stop (this matters when there are multiple color stops with
position 0).
Therefore we pass a small negative number as the lower bound of the input
range, so this value gets passed into ComputeGradientValue, which will
return the color of the first stop. The number should be small because
as far as I can tell, Quartz pre-samples the entire input range of the color
function into an array of fixed size, so if the input range is larger
than needed, the resolution of the gradient will be unnecessarily low.
*/
static const float nonrepeating_gradient_input_value_range[2] = { -0.001f, 1.f };
static CGFunctionRef
CreateGradientFunction (const cairo_gradient_pattern_t *gpat)
{
cairo_pattern_t *pat;
float input_value_range[2] = { 0.f, 1.f };
if (_cairo_pattern_create_copy (&pat, &gpat->base))
/* quartz doesn't deal very well with malloc failing, so there's
@ -709,7 +729,7 @@ CreateGradientFunction (const cairo_gradient_pattern_t *gpat)
return CGFunctionCreate (pat,
1,
input_value_range,
nonrepeating_gradient_input_value_range,
4,
gradient_output_value_ranges,
&gradient_callbacks);

View File

@ -0,0 +1,57 @@
diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
@@ -690,31 +690,51 @@ ComputeGradientValue (void *info, const
}
static const float gradient_output_value_ranges[8] = {
0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f
};
static const CGFunctionCallbacks gradient_callbacks = {
0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy
};
+/* Quartz will clamp input values to the input range.
+
+ Our stops are all in the range 0.0 to 1.0. However, the color before the
+ beginning of the gradient line is obtained by Quartz computing a negative
+ position on the gradient line, clamping it to the input range we specified
+ for our color function, and then calling our color function (actually it
+ pre-samples the color function into an array, but that doesn't matter just
+ here). Therefore if we set the lower bound to 0.0, a negative position
+ on the gradient line will pass 0.0 to ComputeGradientValue, which will
+ select the last color stop with position 0, although it should select
+ the first color stop (this matters when there are multiple color stops with
+ position 0).
+
+ Therefore we pass a small negative number as the lower bound of the input
+ range, so this value gets passed into ComputeGradientValue, which will
+ return the color of the first stop. The number should be small because
+ as far as I can tell, Quartz pre-samples the entire input range of the color
+ function into an array of fixed size, so if the input range is larger
+ than needed, the resolution of the gradient will be unnecessarily low.
+*/
+static const float nonrepeating_gradient_input_value_range[2] = { -0.001f, 1.f };
static CGFunctionRef
CreateGradientFunction (const cairo_gradient_pattern_t *gpat)
{
cairo_pattern_t *pat;
- float input_value_range[2] = { 0.f, 1.f };
if (_cairo_pattern_create_copy (&pat, &gpat->base))
/* quartz doesn't deal very well with malloc failing, so there's
* not much point in us trying either */
return NULL;
return CGFunctionCreate (pat,
1,
- input_value_range,
+ nonrepeating_gradient_input_value_range,
4,
gradient_output_value_ranges,
&gradient_callbacks);
}
static void
UpdateLinearParametersToIncludePoint(double *min_t, double *max_t, CGPoint *start,
double dx, double dy,