|
1 From: Robert O'Callahan <robert@ocallahan.org> |
|
2 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 |
|
3 |
|
4 diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp |
|
5 --- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp |
|
6 +++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp |
|
7 @@ -1411,17 +1411,17 @@ static RefPtr<ID2D1Brush> |
|
8 |
|
9 gradient_center.x = _cairo_fixed_to_float(source_pattern->c1.x); |
|
10 gradient_center.y = _cairo_fixed_to_float(source_pattern->c1.y); |
|
11 |
|
12 // Transform surface corners into pattern coordinates. |
|
13 cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_left.x, &top_left.y); |
|
14 cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_right.x, &top_right.y); |
|
15 cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_left.x, &bottom_left.y); |
|
16 - cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &top_left.y); |
|
17 + cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &bottom_right.y); |
|
18 |
|
19 // Find the corner furthest away from the gradient center in pattern space. |
|
20 double largest = MAX(_cairo_d2d_point_dist(top_left, gradient_center), _cairo_d2d_point_dist(top_right, gradient_center)); |
|
21 largest = MAX(largest, _cairo_d2d_point_dist(bottom_left, gradient_center)); |
|
22 largest = MAX(largest, _cairo_d2d_point_dist(bottom_right, gradient_center)); |
|
23 |
|
24 unsigned int minSize = (unsigned int)ceil(largest); |
|
25 |
|
26 @@ -1531,16 +1531,17 @@ static RefPtr<ID2D1Brush> |
|
27 stopCollection, |
|
28 &brush); |
|
29 delete [] stops; |
|
30 return brush; |
|
31 } |
|
32 |
|
33 static RefPtr<ID2D1Brush> |
|
34 _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf, |
|
35 + cairo_path_fixed_t *fill_path, |
|
36 cairo_linear_pattern_t *source_pattern) |
|
37 { |
|
38 if (source_pattern->p1.x == source_pattern->p2.x && |
|
39 source_pattern->p1.y == source_pattern->p2.y) { |
|
40 // Cairo behavior in this situation is to draw a solid color the size of the last stop. |
|
41 RefPtr<ID2D1SolidColorBrush> brush; |
|
42 d2dsurf->rt->CreateSolidColorBrush( |
|
43 _cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[source_pattern->base.n_stops - 1].color), |
|
44 @@ -1564,35 +1565,46 @@ static RefPtr<ID2D1Brush> |
|
45 p1.x = _cairo_fixed_to_float(source_pattern->p1.x); |
|
46 p1.y = _cairo_fixed_to_float(source_pattern->p1.y); |
|
47 p2.x = _cairo_fixed_to_float(source_pattern->p2.x); |
|
48 p2.y = _cairo_fixed_to_float(source_pattern->p2.y); |
|
49 |
|
50 D2D1_GRADIENT_STOP *stops; |
|
51 int num_stops = source_pattern->base.n_stops; |
|
52 if (source_pattern->base.base.extend == CAIRO_EXTEND_REPEAT || source_pattern->base.base.extend == CAIRO_EXTEND_REFLECT) { |
|
53 - |
|
54 - RefPtr<IDXGISurface> surf; |
|
55 - d2dsurf->surface->QueryInterface(&surf); |
|
56 - DXGI_SURFACE_DESC desc; |
|
57 - surf->GetDesc(&desc); |
|
58 - |
|
59 // Get this when the points are not transformed yet. |
|
60 double gradient_length = _cairo_d2d_point_dist(p1, p2); |
|
61 - |
|
62 - // Calculate the repeat count needed; |
|
63 - cairo_point_double_t top_left, top_right, bottom_left, bottom_right; |
|
64 - top_left.x = bottom_left.x = top_left.y = top_right.y = 0; |
|
65 - top_right.x = bottom_right.x = desc.Width; |
|
66 - bottom_right.y = bottom_left.y = desc.Height; |
|
67 + cairo_point_double_t top_left, top_right, bottom_left, bottom_right; |
|
68 + |
|
69 + if (fill_path) { |
|
70 + // Calculate the repeat count needed; |
|
71 + cairo_box_t fill_extents; |
|
72 + _cairo_path_fixed_extents (fill_path, &fill_extents); |
|
73 + |
|
74 + top_left.x = bottom_left.x = _cairo_fixed_to_double (fill_extents.p1.x); |
|
75 + top_left.y = top_right.y = _cairo_fixed_to_double (fill_extents.p1.y); |
|
76 + top_right.x = bottom_right.x = _cairo_fixed_to_double (fill_extents.p2.x); |
|
77 + bottom_right.y = bottom_left.y = _cairo_fixed_to_double (fill_extents.p2.y); |
|
78 + } else { |
|
79 + RefPtr<IDXGISurface> surf; |
|
80 + d2dsurf->surface->QueryInterface(&surf); |
|
81 + DXGI_SURFACE_DESC desc; |
|
82 + surf->GetDesc(&desc); |
|
83 + |
|
84 + top_left.x = bottom_left.x = 0; |
|
85 + top_left.y = top_right.y = 0; |
|
86 + top_right.x = bottom_right.x = desc.Width; |
|
87 + bottom_right.y = bottom_left.y = desc.Height; |
|
88 + } |
|
89 + |
|
90 // Transform the corners of our surface to pattern space. |
|
91 cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_left.x, &top_left.y); |
|
92 cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_right.x, &top_right.y); |
|
93 cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_left.x, &bottom_left.y); |
|
94 - cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &top_left.y); |
|
95 + cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &bottom_right.y); |
|
96 |
|
97 cairo_point_double_t u; |
|
98 // Unit vector of the gradient direction. |
|
99 u = _cairo_d2d_subtract_point(p2, p1); |
|
100 _cairo_d2d_normalize_point(&u); |
|
101 |
|
102 // (corner - p1) . u = |corner - p1| cos(a) where a is the angle between the two vectors. |
|
103 // Coincidentally |corner - p1| cos(a) is actually also the distance our gradient needs to cover since |
|
104 @@ -1701,17 +1713,18 @@ static RefPtr<ID2D1Brush> |
|
105 * \param d2dsurf Surface to create a brush for |
|
106 * \param pattern The pattern to create a brush for |
|
107 * \param unique We cache the bitmap/color brush for speed. If this |
|
108 * needs a brush that is unique (i.e. when more than one is needed), |
|
109 * this will make the function return a seperate brush. |
|
110 * \return A brush object |
|
111 */ |
|
112 static RefPtr<ID2D1Brush> |
|
113 -_cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf, |
|
114 +_cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf, |
|
115 + cairo_path_fixed_t *fill_path, |
|
116 const cairo_pattern_t *pattern, |
|
117 bool unique = false) |
|
118 { |
|
119 HRESULT hr; |
|
120 |
|
121 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { |
|
122 cairo_solid_pattern_t *sourcePattern = |
|
123 (cairo_solid_pattern_t*)pattern; |
|
124 @@ -1729,17 +1742,17 @@ static RefPtr<ID2D1Brush> |
|
125 d2dsurf->solidColorBrush->SetColor(color); |
|
126 } |
|
127 return d2dsurf->solidColorBrush; |
|
128 } |
|
129 |
|
130 } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { |
|
131 cairo_linear_pattern_t *source_pattern = |
|
132 (cairo_linear_pattern_t*)pattern; |
|
133 - return _cairo_d2d_create_linear_gradient_brush(d2dsurf, source_pattern); |
|
134 + return _cairo_d2d_create_linear_gradient_brush(d2dsurf, fill_path, source_pattern); |
|
135 } else if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) { |
|
136 cairo_radial_pattern_t *source_pattern = |
|
137 (cairo_radial_pattern_t*)pattern; |
|
138 return _cairo_d2d_create_radial_gradient_brush(d2dsurf, source_pattern); |
|
139 } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { |
|
140 cairo_matrix_t mat = pattern->matrix; |
|
141 cairo_matrix_invert(&mat); |
|
142 |
|
143 @@ -3228,17 +3241,17 @@ static cairo_int_status_t |
|
144 |
|
145 if (unlikely(status)) |
|
146 return status; |
|
147 } |
|
148 #endif |
|
149 |
|
150 target_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); |
|
151 |
|
152 - RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, |
|
153 + RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, |
|
154 source); |
|
155 |
|
156 if (!brush) { |
|
157 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
158 } |
|
159 |
|
160 D2D1_SIZE_F size = target_rt->GetSize(); |
|
161 target_rt->FillRectangle(D2D1::RectF((FLOAT)0, |
|
162 @@ -3349,17 +3362,17 @@ static cairo_int_status_t |
|
163 source->filter, |
|
164 solidAlphaValue); |
|
165 if (rv != CAIRO_INT_STATUS_UNSUPPORTED) { |
|
166 return rv; |
|
167 } |
|
168 } |
|
169 } |
|
170 |
|
171 - RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, source); |
|
172 + RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, source); |
|
173 if (!brush) { |
|
174 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
175 } |
|
176 |
|
177 RefPtr<ID2D1RenderTarget> target_rt = d2dsurf->rt; |
|
178 #ifndef ALWAYS_MANUAL_COMPOSITE |
|
179 if (op != CAIRO_OPERATOR_OVER) { |
|
180 #endif |
|
181 @@ -3389,17 +3402,17 @@ static cairo_int_status_t |
|
182 brush->SetOpacity(1.0); |
|
183 |
|
184 if (target_rt.get() != d2dsurf->rt.get()) { |
|
185 return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip); |
|
186 } |
|
187 return CAIRO_INT_STATUS_SUCCESS; |
|
188 } |
|
189 |
|
190 - RefPtr<ID2D1Brush> opacityBrush = _cairo_d2d_create_brush_for_pattern(d2dsurf, mask, true); |
|
191 + RefPtr<ID2D1Brush> opacityBrush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, mask, true); |
|
192 if (!opacityBrush) { |
|
193 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
194 } |
|
195 |
|
196 if (!d2dsurf->maskLayer) { |
|
197 d2dsurf->rt->CreateLayer(&d2dsurf->maskLayer); |
|
198 } |
|
199 target_rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), |
|
200 @@ -3475,17 +3488,17 @@ static cairo_int_status_t |
|
201 D2D1_FIGURE_BEGIN_FILLED); |
|
202 |
|
203 bool transformed = true; |
|
204 |
|
205 if (_cairo_matrix_is_identity(ctm)) { |
|
206 transformed = false; |
|
207 } |
|
208 |
|
209 - RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, |
|
210 + RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, |
|
211 source); |
|
212 if (!brush) { |
|
213 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
214 } |
|
215 |
|
216 D2D1::Matrix3x2F mat; |
|
217 if (transformed) { |
|
218 // If we are transformed we will draw the geometry multiplied by the |
|
219 @@ -3602,31 +3615,31 @@ static cairo_int_status_t |
|
220 } |
|
221 |
|
222 if (is_box) { |
|
223 float x1 = _cairo_fixed_to_float(box.p1.x); |
|
224 float y1 = _cairo_fixed_to_float(box.p1.y); |
|
225 float x2 = _cairo_fixed_to_float(box.p2.x); |
|
226 float y2 = _cairo_fixed_to_float(box.p2.y); |
|
227 RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, |
|
228 - source); |
|
229 + path, source); |
|
230 if (!brush) { |
|
231 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
232 } |
|
233 |
|
234 target_rt->FillRectangle(D2D1::RectF(x1, |
|
235 y1, |
|
236 x2, |
|
237 y2), |
|
238 brush); |
|
239 } else { |
|
240 RefPtr<ID2D1Geometry> d2dpath = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED); |
|
241 |
|
242 RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, |
|
243 - source); |
|
244 + path, source); |
|
245 if (!brush) { |
|
246 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
247 } |
|
248 target_rt->FillGeometry(d2dpath, brush); |
|
249 } |
|
250 |
|
251 if (target_rt.get() != d2dsurf->rt.get()) { |
|
252 double x1, y1, x2, y2; |
|
253 @@ -4138,17 +4151,17 @@ static cairo_int_status_t |
|
254 DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1, |
|
255 &bounds); |
|
256 fontArea.x = bounds.left; |
|
257 fontArea.y = bounds.top; |
|
258 fontArea.width = bounds.right - bounds.left; |
|
259 fontArea.height = bounds.bottom - bounds.top; |
|
260 } |
|
261 |
|
262 - RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(dst, |
|
263 + RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(dst, NULL, |
|
264 source); |
|
265 |
|
266 if (!brush) { |
|
267 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
268 } |
|
269 |
|
270 if (transform) { |
|
271 D2D1::Matrix3x2F mat_inverse = _cairo_d2d_matrix_from_matrix(&dwritesf->mat_inverse); |