Bug 606372: Properly inverse transform the brushes in D2D. r=jrmuizel a=blocking-final
authorBas Schouten <bschouten@mozilla.com>
Wed, 01 Dec 2010 02:17:05 +0100
changeset 58397 824f8a023254f117c0f6bc54a95223d5a658c665
parent 58396 8777ed85c5ac544eb8aa74b226bf710315ba5f14
child 58398 c46083e1b190c18435ee4241bdf37c5245eb7800
push id17283
push userbschouten@mozilla.com
push dateWed, 01 Dec 2010 01:17:33 +0000
treeherdermozilla-central@824f8a023254 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, blocking-final
bugs606372
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 606372: Properly inverse transform the brushes in D2D. r=jrmuizel a=blocking-final
gfx/cairo/cairo/src/cairo-d2d-surface.cpp
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -3272,40 +3272,66 @@ static cairo_int_status_t
     } else {
 	target_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
     }
     RefPtr<ID2D1StrokeStyle> strokeStyle = _cairo_d2d_create_strokestyle_for_stroke_style(style);
 
     if (!strokeStyle) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
-    D2D1::Matrix3x2F mat = _cairo_d2d_matrix_from_matrix(ctm);
     RefPtr<ID2D1Geometry> d2dpath = _cairo_d2d_create_path_geometry_for_path(path, 
 		    							     CAIRO_FILL_RULE_WINDING, 
 									     D2D1_FIGURE_BEGIN_FILLED);
-    D2D1::Matrix3x2F inverse_mat = _cairo_d2d_invert_matrix(mat);
     
-    RefPtr<ID2D1TransformedGeometry> trans_geom;
-    sD2DFactory->CreateTransformedGeometry(d2dpath, &inverse_mat, &trans_geom);
-
-    target_rt->SetTransform(mat);
+    bool transformed = true;
+
+    if (_cairo_matrix_is_identity(ctm)) {
+      transformed = false;
+    }
 
     RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
 								   source);
     if (!brush) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    target_rt->DrawGeometry(trans_geom, brush, (FLOAT)style->line_width, strokeStyle);
-
-    target_rt->SetTransform(D2D1::Matrix3x2F::Identity());
+    D2D1::Matrix3x2F mat;
+    if (transformed) {
+      // If we are transformed we will draw the geometry multiplied by the
+      // inverse transformation and apply the transform to our render target.
+      // This way the transformation will also be applied to the strokestyle.
+      mat = _cairo_d2d_matrix_from_matrix(ctm);
+      D2D1::Matrix3x2F inverse_mat = _cairo_d2d_invert_matrix(mat);
+    
+      RefPtr<ID2D1TransformedGeometry> trans_geom;
+      sD2DFactory->CreateTransformedGeometry(d2dpath, &inverse_mat, &trans_geom);
+
+      // If we are setting a transform on the render target, we've multiplied
+      // the geometry by the inverse transform, we should also multiply the
+      // brush matrix by this inverse transform then to map the brush to the
+      // correct place.
+      D2D1_MATRIX_3X2_F brushMatrix;
+      brush->GetTransform(&brushMatrix);
+      brushMatrix = brushMatrix * inverse_mat;
+      brush->SetTransform(brushMatrix);
+      target_rt->SetTransform(mat);
+      d2dpath = trans_geom;
+    } else {
+      mat = D2D1::Matrix3x2F::Identity();
+    }
+
+    target_rt->DrawGeometry(d2dpath, brush, (FLOAT)style->line_width, strokeStyle);
+
+    if (transformed) {
+      target_rt->SetTransform(D2D1::Matrix3x2F::Identity());
+    }
 
     if (target_rt.get() != d2dsurf->rt.get()) {
 	D2D1_RECT_F bounds;
-	trans_geom->GetWidenedBounds((FLOAT)style->line_width, strokeStyle, mat, &bounds);
+	d2dpath->GetWidenedBounds((FLOAT)style->line_width, strokeStyle, mat, &bounds);
 	cairo_rectangle_int_t bound_rect;
 	_cairo_d2d_round_out_to_int_rect(&bound_rect, bounds.left, bounds.top, bounds.right, bounds.bottom);
 	return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip, &bound_rect);
     }
 
     return CAIRO_INT_STATUS_SUCCESS;
 }