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);