Bug 573942. Adjust transform matrix in RenderDocument to ensure that components close to integers become actual integers. r=jrmuizel,sr=vlad
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 16 Jul 2010 09:08:08 +1200
changeset 47758 df85fba385ca63974f6be9ad1d89f9f7f9467125
parent 47757 41143b03b5a141fcd77e4aed43bb7a29af2e9d17
child 47759 51dc121aa5258a9d1f27586020490bdab8937a4c
push id14413
push userrocallahan@mozilla.com
push dateThu, 15 Jul 2010 21:12:02 +0000
treeherderautoland@e1d7fd5255fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, vlad
bugs573942
milestone2.0b2pre
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 573942. Adjust transform matrix in RenderDocument to ensure that components close to integers become actual integers. r=jrmuizel,sr=vlad
gfx/thebes/gfxContext.cpp
gfx/thebes/gfxContext.h
layout/base/nsPresShell.cpp
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -313,16 +313,39 @@ gfxContext::IdentityMatrix()
 gfxMatrix
 gfxContext::CurrentMatrix() const
 {
     cairo_matrix_t mat;
     cairo_get_matrix(mCairo, &mat);
     return gfxMatrix(*reinterpret_cast<gfxMatrix*>(&mat));
 }
 
+static void NudgeToInteger(double *aVal)
+{
+    float f = float(*aVal);
+    float r = NS_roundf(f);
+    if (f == r) {
+        *aVal = r;
+    }
+}
+
+void
+gfxContext::NudgeCurrentMatrixToIntegers()
+{
+    cairo_matrix_t mat;
+    cairo_get_matrix(mCairo, &mat);
+    NudgeToInteger(&mat.xx);
+    NudgeToInteger(&mat.xy);
+    NudgeToInteger(&mat.yx);
+    NudgeToInteger(&mat.yy);
+    NudgeToInteger(&mat.x0);
+    NudgeToInteger(&mat.y0);
+    cairo_set_matrix(mCairo, &mat);
+}
+
 gfxPoint
 gfxContext::DeviceToUser(const gfxPoint& point) const
 {
     gfxPoint ret = point;
     cairo_device_to_user(mCairo, &ret.x, &ret.y);
     return ret;
 }
 
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -284,16 +284,23 @@ public:
     void IdentityMatrix();
 
     /**
      * Returns the current transformation matrix.
      */
     gfxMatrix CurrentMatrix() const;
 
     /**
+     * Snap components of the current matrix that are close to integers
+     * to integers. In particular, components that are integral when
+     * converted to single precision are set to those integers.
+     */
+    void NudgeCurrentMatrixToIntegers();
+
+    /**
      * Converts a point from device to user coordinates using the inverse
      * transformation matrix.
      */
     gfxPoint DeviceToUser(const gfxPoint& point) const;
 
     /**
      * Converts a size from device to user coordinates. This does not apply
      * translation components of the matrix.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5271,17 +5271,22 @@ PresShell::RenderDocument(const nsRect& 
   }
 
   aThebesContext->Translate(gfxPoint(-nsPresContext::AppUnitsToFloatCSSPixels(aRect.x),
                                      -nsPresContext::AppUnitsToFloatCSSPixels(aRect.y)));
 
   nsIDeviceContext* devCtx = mPresContext->DeviceContext();
   gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
   aThebesContext->Scale(scale, scale);
-  
+
+  // Since canvas APIs use floats to set up their matrices, we may have
+  // some slight inaccuracy here. Adjust matrix components that are
+  // integers up to the accuracy of floats to be those integers.
+  aThebesContext->NudgeCurrentMatrixToIntegers();
+
   nsCOMPtr<nsIRenderingContext> rc;
   devCtx->CreateRenderingContextInstance(*getter_AddRefs(rc));
   rc->Init(devCtx, aThebesContext);
 
   PRUint32 flags = nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES |
     nsLayoutUtils::PAINT_IGNORE_SUPPRESSION;
   if (aFlags & RENDER_USE_WIDGET_LAYERS) {
     flags |= nsLayoutUtils::PAINT_WIDGET_LAYERS;