From 28ef613184c483fa2206dd220812b93abb973ace Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Thu, 4 Mar 2010 20:30:05 +0100 Subject: [PATCH] Bug 549652: Properly support clearing surfaces. r=jrmuizel --- gfx/cairo/cairo/src/cairo-d2d-private.h | 7 +- gfx/cairo/cairo/src/cairo-d2d-surface.cpp | 96 +++++++++++++++++------ 2 files changed, 78 insertions(+), 25 deletions(-) diff --git a/gfx/cairo/cairo/src/cairo-d2d-private.h b/gfx/cairo/cairo/src/cairo-d2d-private.h index 2d2cbf2e6bcd..16f29bd98fb2 100644 --- a/gfx/cairo/cairo/src/cairo-d2d-private.h +++ b/gfx/cairo/cairo/src/cairo-d2d-private.h @@ -76,8 +76,11 @@ struct _cairo_d2d_surface { ID2D1Layer *clipLayer; /** Mask layer used by surface_mask to push opacity masks */ ID2D1Layer *maskLayer; - /** Layer used for clipping when tiling - lazily initialized */ - ID2D1Layer *tilingLayer; + /** + * Layer used for clipping when tiling, and also for clearing out geometries + * - lazily initialized + */ + ID2D1Layer *helperLayer; /** If this layer currently is clipping, used to prevent excessive push/pops */ bool clipping; /** Brush used for bitmaps */ diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp index dc3a79dad6ad..8cfa9ca1d8ea 100644 --- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp +++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp @@ -846,15 +846,15 @@ _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf, D2DSurfFactory::Instance()->CreateRectangleGeometry(D2D1::RectF(0, 0, (float)width, (float)height), &clipRect); - if (!d2dsurf->tilingLayer) { - d2dsurf->rt->CreateLayer(&d2dsurf->tilingLayer); + if (!d2dsurf->helperLayer) { + d2dsurf->rt->CreateLayer(&d2dsurf->helperLayer); } d2dsurf->rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), clipRect, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, _cairo_d2d_matrix_from_matrix(&mat)), - d2dsurf->tilingLayer); + d2dsurf->helperLayer); *pushed_clip = true; clipRect->Release(); } @@ -1137,6 +1137,27 @@ _cairo_d2d_create_path_geometry_for_path(cairo_path_fixed_t *path, return d2dpath; } +/** + * We use this to clear out a certain geometry on a surface. This will respect + * the existing clip. + * + * \param d2dsurf Surface we clear + * \param geometry Geometry of the area to clear + */ +static void _cairo_d2d_clear_geometry(cairo_d2d_surface_t *d2dsurf, + ID2D1Geometry *geometry) +{ + if (!d2dsurf->helperLayer) { + d2dsurf->rt->CreateLayer(&d2dsurf->helperLayer); + } + + d2dsurf->rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), + geometry), + d2dsurf->helperLayer); + d2dsurf->rt->Clear(D2D1::ColorF(0, 0)); + d2dsurf->rt->PopLayer(); +} + // Implementation static cairo_surface_t* _cairo_d2d_create_similar(void *surface, @@ -1289,8 +1310,8 @@ _cairo_d2d_finish(void *surface) if (d2dsurf->surface) { d2dsurf->surface->Release(); } - if (d2dsurf->tilingLayer) { - d2dsurf->tilingLayer->Release(); + if (d2dsurf->helperLayer) { + d2dsurf->helperLayer->Release(); } if (d2dsurf->bufferTexture) { d2dsurf->bufferTexture->Release(); @@ -1610,10 +1631,7 @@ _cairo_d2d_paint(void *surface, cairo_d2d_surface_t *d2dsurf = static_cast(surface); _begin_draw_state(d2dsurf); if (op == CAIRO_OPERATOR_CLEAR) { - cairo_solid_pattern_t *sourcePattern = - (cairo_solid_pattern_t*)source; - d2dsurf->rt->Clear( - _cairo_d2d_color_from_cairo_color(sourcePattern->color)); + d2dsurf->rt->Clear(D2D1::ColorF(0, 0)); return CAIRO_INT_STATUS_SUCCESS; } @@ -1755,14 +1773,14 @@ _cairo_d2d_stroke(void *surface, { cairo_d2d_surface_t *d2dsurf = static_cast(surface); _begin_draw_state(d2dsurf); - if (op != CAIRO_OPERATOR_OVER && op != CAIRO_OPERATOR_SOURCE && - op != CAIRO_OPERATOR_ADD) { - /** - * We don't really support SOURCE and ADD yet. Source won't be - * too hard, true ADD support requires getting the tesselated - * mesh from D2D, and blending that using D3D which has an add - * operator available. - */ + + if (op != CAIRO_OPERATOR_OVER && op != CAIRO_OPERATOR_ADD && + op != CAIRO_OPERATOR_CLEAR) { + /** + * We don't really support ADD yet. True ADD support requires getting + * the tesselated mesh from D2D, and blending that using D3D which has + * an add operator available. + */ return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -1779,6 +1797,29 @@ _cairo_d2d_stroke(void *surface, D2D1::Matrix3x2F mat = _cairo_d2d_matrix_from_matrix(ctm); _cairo_path_fixed_transform(path, ctm_inverse); + + if (op == CAIRO_OPERATOR_CLEAR) { + ID2D1Geometry *d2dpath = _cairo_d2d_create_path_geometry_for_path(path, + CAIRO_FILL_RULE_WINDING, + D2D1_FIGURE_BEGIN_FILLED); + + ID2D1PathGeometry *strokeGeometry; + D2DSurfFactory::Instance()->CreatePathGeometry(&strokeGeometry); + + ID2D1GeometrySink *sink; + strokeGeometry->Open(&sink); + d2dpath->Widen((FLOAT)style->line_width, strokeStyle, mat, (FLOAT)tolerance, sink); + sink->Close(); + sink->Release(); + + _cairo_d2d_clear_geometry(d2dsurf, strokeGeometry); + + strokeGeometry->Release(); + d2dpath->Release(); + + return CAIRO_INT_STATUS_SUCCESS; + } + d2dsurf->rt->SetTransform(mat); unsigned int runs_remaining = 1; @@ -1862,13 +1903,12 @@ _cairo_d2d_fill(void *surface, cairo_d2d_surface_t *d2dsurf = static_cast(surface); _begin_draw_state(d2dsurf); - if (op != CAIRO_OPERATOR_OVER && op != CAIRO_OPERATOR_SOURCE && - op != CAIRO_OPERATOR_ADD) { + if (op != CAIRO_OPERATOR_OVER && op != CAIRO_OPERATOR_ADD && + op != CAIRO_OPERATOR_CLEAR) { /** - * We don't really support SOURCE and ADD yet. Source won't be - * too hard, true ADD support requires getting the tesselated - * mesh from D2D, and blending that using D3D which has an add - * operator available. + * We don't really support ADD yet. True ADD support requires getting + * the tesselated mesh from D2D, and blending that using D3D which has + * an add operator available. */ return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -1883,6 +1923,16 @@ _cairo_d2d_fill(void *surface, unsigned int last_run = 0; bool pushed_clip = false; + if (op == CAIRO_OPERATOR_CLEAR) { + ID2D1Geometry *d2dpath = _cairo_d2d_create_path_geometry_for_path(path, + fill_rule, + D2D1_FIGURE_BEGIN_FILLED); + _cairo_d2d_clear_geometry(d2dsurf, d2dpath); + + d2dpath->Release(); + return CAIRO_INT_STATUS_SUCCESS; + } + cairo_box_t box; if (_cairo_path_fixed_is_box(path, &box)) { float x1 = _cairo_fixed_to_float(box.p1.x);