michael@0: From: Robert O'Callahan michael@0: 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 michael@0: michael@0: diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp michael@0: --- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp michael@0: +++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp michael@0: @@ -1411,17 +1411,17 @@ static RefPtr michael@0: michael@0: gradient_center.x = _cairo_fixed_to_float(source_pattern->c1.x); michael@0: gradient_center.y = _cairo_fixed_to_float(source_pattern->c1.y); michael@0: michael@0: // Transform surface corners into pattern coordinates. michael@0: cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_left.x, &top_left.y); michael@0: cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_right.x, &top_right.y); michael@0: cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_left.x, &bottom_left.y); michael@0: - cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &top_left.y); michael@0: + cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &bottom_right.y); michael@0: michael@0: // Find the corner furthest away from the gradient center in pattern space. michael@0: double largest = MAX(_cairo_d2d_point_dist(top_left, gradient_center), _cairo_d2d_point_dist(top_right, gradient_center)); michael@0: largest = MAX(largest, _cairo_d2d_point_dist(bottom_left, gradient_center)); michael@0: largest = MAX(largest, _cairo_d2d_point_dist(bottom_right, gradient_center)); michael@0: michael@0: unsigned int minSize = (unsigned int)ceil(largest); michael@0: michael@0: @@ -1531,16 +1531,17 @@ static RefPtr michael@0: stopCollection, michael@0: &brush); michael@0: delete [] stops; michael@0: return brush; michael@0: } michael@0: michael@0: static RefPtr michael@0: _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf, michael@0: + cairo_path_fixed_t *fill_path, michael@0: cairo_linear_pattern_t *source_pattern) michael@0: { michael@0: if (source_pattern->p1.x == source_pattern->p2.x && michael@0: source_pattern->p1.y == source_pattern->p2.y) { michael@0: // Cairo behavior in this situation is to draw a solid color the size of the last stop. michael@0: RefPtr brush; michael@0: d2dsurf->rt->CreateSolidColorBrush( michael@0: _cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[source_pattern->base.n_stops - 1].color), michael@0: @@ -1564,35 +1565,46 @@ static RefPtr michael@0: p1.x = _cairo_fixed_to_float(source_pattern->p1.x); michael@0: p1.y = _cairo_fixed_to_float(source_pattern->p1.y); michael@0: p2.x = _cairo_fixed_to_float(source_pattern->p2.x); michael@0: p2.y = _cairo_fixed_to_float(source_pattern->p2.y); michael@0: michael@0: D2D1_GRADIENT_STOP *stops; michael@0: int num_stops = source_pattern->base.n_stops; michael@0: if (source_pattern->base.base.extend == CAIRO_EXTEND_REPEAT || source_pattern->base.base.extend == CAIRO_EXTEND_REFLECT) { michael@0: - michael@0: - RefPtr surf; michael@0: - d2dsurf->surface->QueryInterface(&surf); michael@0: - DXGI_SURFACE_DESC desc; michael@0: - surf->GetDesc(&desc); michael@0: - michael@0: // Get this when the points are not transformed yet. michael@0: double gradient_length = _cairo_d2d_point_dist(p1, p2); michael@0: - michael@0: - // Calculate the repeat count needed; michael@0: - cairo_point_double_t top_left, top_right, bottom_left, bottom_right; michael@0: - top_left.x = bottom_left.x = top_left.y = top_right.y = 0; michael@0: - top_right.x = bottom_right.x = desc.Width; michael@0: - bottom_right.y = bottom_left.y = desc.Height; michael@0: + cairo_point_double_t top_left, top_right, bottom_left, bottom_right; michael@0: + michael@0: + if (fill_path) { michael@0: + // Calculate the repeat count needed; michael@0: + cairo_box_t fill_extents; michael@0: + _cairo_path_fixed_extents (fill_path, &fill_extents); michael@0: + michael@0: + top_left.x = bottom_left.x = _cairo_fixed_to_double (fill_extents.p1.x); michael@0: + top_left.y = top_right.y = _cairo_fixed_to_double (fill_extents.p1.y); michael@0: + top_right.x = bottom_right.x = _cairo_fixed_to_double (fill_extents.p2.x); michael@0: + bottom_right.y = bottom_left.y = _cairo_fixed_to_double (fill_extents.p2.y); michael@0: + } else { michael@0: + RefPtr surf; michael@0: + d2dsurf->surface->QueryInterface(&surf); michael@0: + DXGI_SURFACE_DESC desc; michael@0: + surf->GetDesc(&desc); michael@0: + michael@0: + top_left.x = bottom_left.x = 0; michael@0: + top_left.y = top_right.y = 0; michael@0: + top_right.x = bottom_right.x = desc.Width; michael@0: + bottom_right.y = bottom_left.y = desc.Height; michael@0: + } michael@0: + michael@0: // Transform the corners of our surface to pattern space. michael@0: cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_left.x, &top_left.y); michael@0: cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_right.x, &top_right.y); michael@0: cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_left.x, &bottom_left.y); michael@0: - cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &top_left.y); michael@0: + cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &bottom_right.y); michael@0: michael@0: cairo_point_double_t u; michael@0: // Unit vector of the gradient direction. michael@0: u = _cairo_d2d_subtract_point(p2, p1); michael@0: _cairo_d2d_normalize_point(&u); michael@0: michael@0: // (corner - p1) . u = |corner - p1| cos(a) where a is the angle between the two vectors. michael@0: // Coincidentally |corner - p1| cos(a) is actually also the distance our gradient needs to cover since michael@0: @@ -1701,17 +1713,18 @@ static RefPtr michael@0: * \param d2dsurf Surface to create a brush for michael@0: * \param pattern The pattern to create a brush for michael@0: * \param unique We cache the bitmap/color brush for speed. If this michael@0: * needs a brush that is unique (i.e. when more than one is needed), michael@0: * this will make the function return a seperate brush. michael@0: * \return A brush object michael@0: */ michael@0: static RefPtr michael@0: -_cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf, michael@0: +_cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf, michael@0: + cairo_path_fixed_t *fill_path, michael@0: const cairo_pattern_t *pattern, michael@0: bool unique = false) michael@0: { michael@0: HRESULT hr; michael@0: michael@0: if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { michael@0: cairo_solid_pattern_t *sourcePattern = michael@0: (cairo_solid_pattern_t*)pattern; michael@0: @@ -1729,17 +1742,17 @@ static RefPtr michael@0: d2dsurf->solidColorBrush->SetColor(color); michael@0: } michael@0: return d2dsurf->solidColorBrush; michael@0: } michael@0: michael@0: } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { michael@0: cairo_linear_pattern_t *source_pattern = michael@0: (cairo_linear_pattern_t*)pattern; michael@0: - return _cairo_d2d_create_linear_gradient_brush(d2dsurf, source_pattern); michael@0: + return _cairo_d2d_create_linear_gradient_brush(d2dsurf, fill_path, source_pattern); michael@0: } else if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) { michael@0: cairo_radial_pattern_t *source_pattern = michael@0: (cairo_radial_pattern_t*)pattern; michael@0: return _cairo_d2d_create_radial_gradient_brush(d2dsurf, source_pattern); michael@0: } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { michael@0: cairo_matrix_t mat = pattern->matrix; michael@0: cairo_matrix_invert(&mat); michael@0: michael@0: @@ -3228,17 +3241,17 @@ static cairo_int_status_t michael@0: michael@0: if (unlikely(status)) michael@0: return status; michael@0: } michael@0: #endif michael@0: michael@0: target_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); michael@0: michael@0: - RefPtr brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, michael@0: + RefPtr brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, michael@0: source); michael@0: michael@0: if (!brush) { michael@0: return CAIRO_INT_STATUS_UNSUPPORTED; michael@0: } michael@0: michael@0: D2D1_SIZE_F size = target_rt->GetSize(); michael@0: target_rt->FillRectangle(D2D1::RectF((FLOAT)0, michael@0: @@ -3349,17 +3362,17 @@ static cairo_int_status_t michael@0: source->filter, michael@0: solidAlphaValue); michael@0: if (rv != CAIRO_INT_STATUS_UNSUPPORTED) { michael@0: return rv; michael@0: } michael@0: } michael@0: } michael@0: michael@0: - RefPtr brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, source); michael@0: + RefPtr brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, source); michael@0: if (!brush) { michael@0: return CAIRO_INT_STATUS_UNSUPPORTED; michael@0: } michael@0: michael@0: RefPtr target_rt = d2dsurf->rt; michael@0: #ifndef ALWAYS_MANUAL_COMPOSITE michael@0: if (op != CAIRO_OPERATOR_OVER) { michael@0: #endif michael@0: @@ -3389,17 +3402,17 @@ static cairo_int_status_t michael@0: brush->SetOpacity(1.0); michael@0: michael@0: if (target_rt.get() != d2dsurf->rt.get()) { michael@0: return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip); michael@0: } michael@0: return CAIRO_INT_STATUS_SUCCESS; michael@0: } michael@0: michael@0: - RefPtr opacityBrush = _cairo_d2d_create_brush_for_pattern(d2dsurf, mask, true); michael@0: + RefPtr opacityBrush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, mask, true); michael@0: if (!opacityBrush) { michael@0: return CAIRO_INT_STATUS_UNSUPPORTED; michael@0: } michael@0: michael@0: if (!d2dsurf->maskLayer) { michael@0: d2dsurf->rt->CreateLayer(&d2dsurf->maskLayer); michael@0: } michael@0: target_rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), michael@0: @@ -3475,17 +3488,17 @@ static cairo_int_status_t michael@0: D2D1_FIGURE_BEGIN_FILLED); michael@0: michael@0: bool transformed = true; michael@0: michael@0: if (_cairo_matrix_is_identity(ctm)) { michael@0: transformed = false; michael@0: } michael@0: michael@0: - RefPtr brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, michael@0: + RefPtr brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, michael@0: source); michael@0: if (!brush) { michael@0: return CAIRO_INT_STATUS_UNSUPPORTED; michael@0: } michael@0: michael@0: D2D1::Matrix3x2F mat; michael@0: if (transformed) { michael@0: // If we are transformed we will draw the geometry multiplied by the michael@0: @@ -3602,31 +3615,31 @@ static cairo_int_status_t michael@0: } michael@0: michael@0: if (is_box) { michael@0: float x1 = _cairo_fixed_to_float(box.p1.x); michael@0: float y1 = _cairo_fixed_to_float(box.p1.y); michael@0: float x2 = _cairo_fixed_to_float(box.p2.x); michael@0: float y2 = _cairo_fixed_to_float(box.p2.y); michael@0: RefPtr brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, michael@0: - source); michael@0: + path, source); michael@0: if (!brush) { michael@0: return CAIRO_INT_STATUS_UNSUPPORTED; michael@0: } michael@0: michael@0: target_rt->FillRectangle(D2D1::RectF(x1, michael@0: y1, michael@0: x2, michael@0: y2), michael@0: brush); michael@0: } else { michael@0: RefPtr d2dpath = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED); michael@0: michael@0: RefPtr brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, michael@0: - source); michael@0: + path, source); michael@0: if (!brush) { michael@0: return CAIRO_INT_STATUS_UNSUPPORTED; michael@0: } michael@0: target_rt->FillGeometry(d2dpath, brush); michael@0: } michael@0: michael@0: if (target_rt.get() != d2dsurf->rt.get()) { michael@0: double x1, y1, x2, y2; michael@0: @@ -4138,17 +4151,17 @@ static cairo_int_status_t michael@0: DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1, michael@0: &bounds); michael@0: fontArea.x = bounds.left; michael@0: fontArea.y = bounds.top; michael@0: fontArea.width = bounds.right - bounds.left; michael@0: fontArea.height = bounds.bottom - bounds.top; michael@0: } michael@0: michael@0: - RefPtr brush = _cairo_d2d_create_brush_for_pattern(dst, michael@0: + RefPtr brush = _cairo_d2d_create_brush_for_pattern(dst, NULL, michael@0: source); michael@0: michael@0: if (!brush) { michael@0: return CAIRO_INT_STATUS_UNSUPPORTED; michael@0: } michael@0: michael@0: if (transform) { michael@0: D2D1::Matrix3x2F mat_inverse = _cairo_d2d_matrix_from_matrix(&dwritesf->mat_inverse);