gfx/cairo/d2d-repeating-gradients.patch

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/cairo/d2d-repeating-gradients.patch	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,271 @@
     1.4 +From: Robert O'Callahan <robert@ocallahan.org>
     1.5 +Bug 768775. Improve the precision of the calculation of the number of stops that need to be added to handle 'repeat' and 'reflect', when we're filling a path. r=bas
     1.6 +
     1.7 +diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
     1.8 +--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
     1.9 ++++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
    1.10 +@@ -1411,17 +1411,17 @@ static RefPtr<ID2D1Brush>
    1.11 + 
    1.12 + 	gradient_center.x = _cairo_fixed_to_float(source_pattern->c1.x);
    1.13 + 	gradient_center.y = _cairo_fixed_to_float(source_pattern->c1.y);
    1.14 + 
    1.15 + 	// Transform surface corners into pattern coordinates.
    1.16 + 	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_left.x, &top_left.y);
    1.17 + 	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_right.x, &top_right.y);
    1.18 + 	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_left.x, &bottom_left.y);
    1.19 +-	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &top_left.y);
    1.20 ++	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &bottom_right.y);
    1.21 + 
    1.22 + 	// Find the corner furthest away from the gradient center in pattern space.
    1.23 + 	double largest = MAX(_cairo_d2d_point_dist(top_left, gradient_center), _cairo_d2d_point_dist(top_right, gradient_center));
    1.24 + 	largest = MAX(largest, _cairo_d2d_point_dist(bottom_left, gradient_center));
    1.25 + 	largest = MAX(largest, _cairo_d2d_point_dist(bottom_right, gradient_center));
    1.26 + 
    1.27 + 	unsigned int minSize = (unsigned int)ceil(largest);
    1.28 + 
    1.29 +@@ -1531,16 +1531,17 @@ static RefPtr<ID2D1Brush>
    1.30 + 					   stopCollection,
    1.31 + 					   &brush);
    1.32 +     delete [] stops;
    1.33 +     return brush;
    1.34 + }
    1.35 + 
    1.36 + static RefPtr<ID2D1Brush>
    1.37 + _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf,
    1.38 ++					cairo_path_fixed_t *fill_path,
    1.39 + 					cairo_linear_pattern_t *source_pattern)
    1.40 + {
    1.41 +     if (source_pattern->p1.x == source_pattern->p2.x &&
    1.42 + 	source_pattern->p1.y == source_pattern->p2.y) {
    1.43 + 	// Cairo behavior in this situation is to draw a solid color the size of the last stop.
    1.44 + 	RefPtr<ID2D1SolidColorBrush> brush;
    1.45 + 	d2dsurf->rt->CreateSolidColorBrush(
    1.46 + 	    _cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[source_pattern->base.n_stops - 1].color),
    1.47 +@@ -1564,35 +1565,46 @@ static RefPtr<ID2D1Brush>
    1.48 +     p1.x = _cairo_fixed_to_float(source_pattern->p1.x);
    1.49 +     p1.y = _cairo_fixed_to_float(source_pattern->p1.y);
    1.50 +     p2.x = _cairo_fixed_to_float(source_pattern->p2.x);
    1.51 +     p2.y = _cairo_fixed_to_float(source_pattern->p2.y);
    1.52 + 
    1.53 +     D2D1_GRADIENT_STOP *stops;
    1.54 +     int num_stops = source_pattern->base.n_stops;
    1.55 +     if (source_pattern->base.base.extend == CAIRO_EXTEND_REPEAT || source_pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
    1.56 +-
    1.57 +-	RefPtr<IDXGISurface> surf;
    1.58 +-	d2dsurf->surface->QueryInterface(&surf);
    1.59 +-	DXGI_SURFACE_DESC desc;
    1.60 +-	surf->GetDesc(&desc);
    1.61 +-
    1.62 + 	// Get this when the points are not transformed yet.
    1.63 + 	double gradient_length = _cairo_d2d_point_dist(p1, p2);
    1.64 +-
    1.65 +-	// Calculate the repeat count needed;
    1.66 +-	cairo_point_double_t top_left, top_right, bottom_left, bottom_right;
    1.67 +-	top_left.x = bottom_left.x = top_left.y = top_right.y = 0;
    1.68 +-	top_right.x = bottom_right.x = desc.Width;
    1.69 +-	bottom_right.y = bottom_left.y = desc.Height;
    1.70 ++        cairo_point_double_t top_left, top_right, bottom_left, bottom_right;
    1.71 ++
    1.72 ++        if (fill_path) {
    1.73 ++            // Calculate the repeat count needed;
    1.74 ++            cairo_box_t fill_extents;
    1.75 ++            _cairo_path_fixed_extents (fill_path, &fill_extents);
    1.76 ++
    1.77 ++	    top_left.x = bottom_left.x = _cairo_fixed_to_double (fill_extents.p1.x);
    1.78 ++	    top_left.y = top_right.y = _cairo_fixed_to_double (fill_extents.p1.y);
    1.79 ++	    top_right.x = bottom_right.x = _cairo_fixed_to_double (fill_extents.p2.x);
    1.80 ++	    bottom_right.y = bottom_left.y = _cairo_fixed_to_double (fill_extents.p2.y);
    1.81 ++        } else {
    1.82 ++            RefPtr<IDXGISurface> surf;
    1.83 ++            d2dsurf->surface->QueryInterface(&surf);
    1.84 ++            DXGI_SURFACE_DESC desc;
    1.85 ++            surf->GetDesc(&desc);
    1.86 ++
    1.87 ++            top_left.x = bottom_left.x = 0;
    1.88 ++            top_left.y = top_right.y = 0;
    1.89 ++            top_right.x = bottom_right.x = desc.Width;
    1.90 ++            bottom_right.y = bottom_left.y = desc.Height;
    1.91 ++        }
    1.92 ++
    1.93 + 	// Transform the corners of our surface to pattern space.
    1.94 + 	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_left.x, &top_left.y);
    1.95 + 	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_right.x, &top_right.y);
    1.96 + 	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_left.x, &bottom_left.y);
    1.97 +-	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &top_left.y);
    1.98 ++	cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &bottom_right.y);
    1.99 + 
   1.100 + 	cairo_point_double_t u;
   1.101 + 	// Unit vector of the gradient direction.
   1.102 + 	u = _cairo_d2d_subtract_point(p2, p1);
   1.103 + 	_cairo_d2d_normalize_point(&u);
   1.104 + 
   1.105 + 	// (corner - p1) . u = |corner - p1| cos(a) where a is the angle between the two vectors.
   1.106 + 	// Coincidentally |corner - p1| cos(a) is actually also the distance our gradient needs to cover since
   1.107 +@@ -1701,17 +1713,18 @@ static RefPtr<ID2D1Brush>
   1.108 +  * \param d2dsurf Surface to create a brush for
   1.109 +  * \param pattern The pattern to create a brush for
   1.110 +  * \param unique We cache the bitmap/color brush for speed. If this
   1.111 +  * needs a brush that is unique (i.e. when more than one is needed),
   1.112 +  * this will make the function return a seperate brush.
   1.113 +  * \return A brush object
   1.114 +  */
   1.115 + static RefPtr<ID2D1Brush>
   1.116 +-_cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf, 
   1.117 ++_cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
   1.118 ++				    cairo_path_fixed_t *fill_path,
   1.119 + 				    const cairo_pattern_t *pattern,
   1.120 + 				    bool unique = false)
   1.121 + {
   1.122 +     HRESULT hr;
   1.123 + 
   1.124 +     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
   1.125 + 	cairo_solid_pattern_t *sourcePattern =
   1.126 + 	    (cairo_solid_pattern_t*)pattern;
   1.127 +@@ -1729,17 +1742,17 @@ static RefPtr<ID2D1Brush>
   1.128 + 		d2dsurf->solidColorBrush->SetColor(color);
   1.129 + 	    }
   1.130 + 	    return d2dsurf->solidColorBrush;
   1.131 + 	}
   1.132 + 
   1.133 +     } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
   1.134 + 	cairo_linear_pattern_t *source_pattern =
   1.135 + 	    (cairo_linear_pattern_t*)pattern;
   1.136 +-	return _cairo_d2d_create_linear_gradient_brush(d2dsurf, source_pattern);
   1.137 ++	return _cairo_d2d_create_linear_gradient_brush(d2dsurf, fill_path, source_pattern);
   1.138 +     } else if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
   1.139 + 	cairo_radial_pattern_t *source_pattern =
   1.140 + 	    (cairo_radial_pattern_t*)pattern;
   1.141 + 	return _cairo_d2d_create_radial_gradient_brush(d2dsurf, source_pattern);
   1.142 +     } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
   1.143 + 	cairo_matrix_t mat = pattern->matrix;
   1.144 + 	cairo_matrix_invert(&mat);
   1.145 + 
   1.146 +@@ -3228,17 +3241,17 @@ static cairo_int_status_t
   1.147 + 
   1.148 + 	if (unlikely(status))
   1.149 + 	    return status;
   1.150 +     }
   1.151 + #endif
   1.152 + 
   1.153 +     target_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
   1.154 + 
   1.155 +-    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
   1.156 ++    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL,
   1.157 + 								   source);
   1.158 +     
   1.159 +     if (!brush) {
   1.160 + 	return CAIRO_INT_STATUS_UNSUPPORTED;
   1.161 +     }
   1.162 + 
   1.163 +     D2D1_SIZE_F size = target_rt->GetSize();
   1.164 +     target_rt->FillRectangle(D2D1::RectF((FLOAT)0,
   1.165 +@@ -3349,17 +3362,17 @@ static cairo_int_status_t
   1.166 + 							    source->filter,
   1.167 + 							    solidAlphaValue);
   1.168 + 	    if (rv != CAIRO_INT_STATUS_UNSUPPORTED) {
   1.169 + 		return rv;
   1.170 + 	    }
   1.171 + 	}
   1.172 +     }
   1.173 + 
   1.174 +-    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, source);
   1.175 ++    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, source);
   1.176 +     if (!brush) {
   1.177 + 	return CAIRO_INT_STATUS_UNSUPPORTED;
   1.178 +     }
   1.179 + 
   1.180 +     RefPtr<ID2D1RenderTarget> target_rt = d2dsurf->rt;
   1.181 + #ifndef ALWAYS_MANUAL_COMPOSITE
   1.182 +     if (op != CAIRO_OPERATOR_OVER) {
   1.183 + #endif
   1.184 +@@ -3389,17 +3402,17 @@ static cairo_int_status_t
   1.185 + 	brush->SetOpacity(1.0);
   1.186 + 
   1.187 + 	if (target_rt.get() != d2dsurf->rt.get()) {
   1.188 + 	    return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip);
   1.189 + 	}
   1.190 + 	return CAIRO_INT_STATUS_SUCCESS;
   1.191 +     }
   1.192 + 
   1.193 +-    RefPtr<ID2D1Brush> opacityBrush = _cairo_d2d_create_brush_for_pattern(d2dsurf, mask, true);
   1.194 ++    RefPtr<ID2D1Brush> opacityBrush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, mask, true);
   1.195 +     if (!opacityBrush) {
   1.196 + 	return CAIRO_INT_STATUS_UNSUPPORTED;
   1.197 +     }
   1.198 + 
   1.199 +     if (!d2dsurf->maskLayer) {
   1.200 + 	d2dsurf->rt->CreateLayer(&d2dsurf->maskLayer);
   1.201 +     }
   1.202 +     target_rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(),
   1.203 +@@ -3475,17 +3488,17 @@ static cairo_int_status_t
   1.204 + 									     D2D1_FIGURE_BEGIN_FILLED);
   1.205 +     
   1.206 +     bool transformed = true;
   1.207 + 
   1.208 +     if (_cairo_matrix_is_identity(ctm)) {
   1.209 +       transformed = false;
   1.210 +     }
   1.211 + 
   1.212 +-    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
   1.213 ++    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL,
   1.214 + 								   source);
   1.215 +     if (!brush) {
   1.216 + 	return CAIRO_INT_STATUS_UNSUPPORTED;
   1.217 +     }
   1.218 + 
   1.219 +     D2D1::Matrix3x2F mat;
   1.220 +     if (transformed) {
   1.221 +       // If we are transformed we will draw the geometry multiplied by the
   1.222 +@@ -3602,31 +3615,31 @@ static cairo_int_status_t
   1.223 +     }
   1.224 + 
   1.225 +     if (is_box) {
   1.226 + 	float x1 = _cairo_fixed_to_float(box.p1.x);
   1.227 + 	float y1 = _cairo_fixed_to_float(box.p1.y);    
   1.228 + 	float x2 = _cairo_fixed_to_float(box.p2.x);    
   1.229 + 	float y2 = _cairo_fixed_to_float(box.p2.y);
   1.230 + 	RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
   1.231 +-								       source);
   1.232 ++	    path, source);
   1.233 + 	if (!brush) {
   1.234 + 	    return CAIRO_INT_STATUS_UNSUPPORTED;
   1.235 + 	}
   1.236 + 
   1.237 + 	target_rt->FillRectangle(D2D1::RectF(x1,
   1.238 + 					     y1,
   1.239 + 					     x2,
   1.240 + 					     y2),
   1.241 + 				 brush);
   1.242 +     } else {
   1.243 + 	RefPtr<ID2D1Geometry> d2dpath = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED);
   1.244 + 
   1.245 + 	RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
   1.246 +-								       source);
   1.247 ++            path, source);
   1.248 + 	if (!brush) {
   1.249 + 	    return CAIRO_INT_STATUS_UNSUPPORTED;
   1.250 + 	}
   1.251 + 	target_rt->FillGeometry(d2dpath, brush);
   1.252 +     }
   1.253 + 
   1.254 +     if (target_rt.get() != d2dsurf->rt.get()) {
   1.255 + 	double x1, y1, x2, y2;
   1.256 +@@ -4138,17 +4151,17 @@ static cairo_int_status_t
   1.257 + 					DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1,
   1.258 + 					&bounds);
   1.259 + 	fontArea.x = bounds.left;
   1.260 + 	fontArea.y = bounds.top;
   1.261 + 	fontArea.width = bounds.right - bounds.left;
   1.262 + 	fontArea.height = bounds.bottom - bounds.top;
   1.263 +     }
   1.264 + 
   1.265 +-    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(dst,
   1.266 ++    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(dst, NULL,
   1.267 + 								   source);
   1.268 + 
   1.269 +     if (!brush) {
   1.270 + 	return CAIRO_INT_STATUS_UNSUPPORTED;
   1.271 +     }
   1.272 +     
   1.273 +     if (transform) {
   1.274 + 	D2D1::Matrix3x2F mat_inverse = _cairo_d2d_matrix_from_matrix(&dwritesf->mat_inverse);

mercurial