Bug 1178971 - Changed line snapping behaviour depending on even/odd-ness of stroke width. r=mstange
authorKyle <kfung@mozilla.com>
Tue, 07 Jul 2015 14:56:23 -0400
changeset 283694 4823385c1005f6da054cf58677ecef77514b2ae6
parent 283693 7bffe6c8fd4d04d8f4564458943aff27c5206fd1
child 283695 c1c2fe57cf9146928ae2f1ac32c6da81623c1aad
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1178971
milestone42.0a1
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 1178971 - Changed line snapping behaviour depending on even/odd-ness of stroke width. r=mstange
gfx/2d/PathHelpers.cpp
gfx/2d/PathHelpers.h
layout/base/nsLayoutUtils.cpp
layout/generic/nsImageMap.cpp
layout/xul/tree/nsTreeBodyFrame.cpp
--- a/gfx/2d/PathHelpers.cpp
+++ b/gfx/2d/PathHelpers.cpp
@@ -179,70 +179,82 @@ AppendEllipseToPath(PathBuilder* aPathBu
   Rect rect(aCenter - Point(halfDim.width, halfDim.height), aDimensions);
   RectCornerRadii radii(halfDim.width, halfDim.height);
 
   AppendRoundedRectToPath(aPathBuilder, rect, radii);
 }
 
 bool
 SnapLineToDevicePixelsForStroking(Point& aP1, Point& aP2,
-                                  const DrawTarget& aDrawTarget)
+                                  const DrawTarget& aDrawTarget,
+                                  Float aLineWidth)
 {
   Matrix mat = aDrawTarget.GetTransform();
   if (mat.HasNonTranslation()) {
     return false;
   }
   if (aP1.x != aP2.x && aP1.y != aP2.y) {
     return false; // not a horizontal or vertical line
   }
   Point p1 = aP1 + mat.GetTranslation(); // into device space
   Point p2 = aP2 + mat.GetTranslation();
   p1.Round();
   p2.Round();
   p1 -= mat.GetTranslation(); // back into user space
   p2 -= mat.GetTranslation();
-  if (aP1.x == aP2.x) {
-    // snap vertical line, adding 0.5 to align it to be mid-pixel:
-    aP1 = p1 + Point(0.5, 0);
-    aP2 = p2 + Point(0.5, 0);
-  } else {
-    // snap horizontal line, adding 0.5 to align it to be mid-pixel:
-    aP1 = p1 + Point(0, 0.5);
-    aP2 = p2 + Point(0, 0.5);
+
+  aP1 = p1;
+  aP2 = p2;
+
+  bool lineWidthIsOdd = (int(aLineWidth) % 2) == 1;
+  if (lineWidthIsOdd) {
+    if (aP1.x == aP2.x) {
+      // snap vertical line, adding 0.5 to align it to be mid-pixel:
+      aP1 += Point(0.5, 0);
+      aP2 += Point(0.5, 0);
+    } else {
+      // snap horizontal line, adding 0.5 to align it to be mid-pixel:
+      aP1 += Point(0, 0.5);
+      aP2 += Point(0, 0.5);
+    }
   }
   return true;
 }
 
 void
 StrokeSnappedEdgesOfRect(const Rect& aRect, DrawTarget& aDrawTarget,
                         const ColorPattern& aColor,
                         const StrokeOptions& aStrokeOptions)
 {
   if (aRect.IsEmpty()) {
     return;
   }
 
   Point p1 = aRect.TopLeft();
   Point p2 = aRect.BottomLeft();
-  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
+  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget,
+                                    aStrokeOptions.mLineWidth);
   aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
 
   p1 = aRect.BottomLeft();
   p2 = aRect.BottomRight();
-  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
+  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget,
+                                    aStrokeOptions.mLineWidth);
   aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
 
   p1 = aRect.TopLeft();
   p2 = aRect.TopRight();
-  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
+  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget,
+                                    aStrokeOptions.mLineWidth);
   aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
 
   p1 = aRect.TopRight();
   p2 = aRect.BottomRight();
-  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
+  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget,
+                                    aStrokeOptions.mLineWidth);
   aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
 }
 
 // The logic for this comes from _cairo_stroke_style_max_distance_from_path
 Margin
 MaxStrokeExtents(const StrokeOptions& aStrokeOptions,
                  const Matrix& aTransform)
 {
--- a/gfx/2d/PathHelpers.h
+++ b/gfx/2d/PathHelpers.h
@@ -271,17 +271,18 @@ inline already_AddRefed<Path> MakePathFo
  * to align with the device pixel grid so that stroking the line with a one
  * pixel wide stroke will result in a crisp line that is not antialiased over
  * two pixels across its width.
  *
  * @return Returns true if this function snaps aRect's vertices, else returns
  *   false.
  */
 GFX2D_API bool SnapLineToDevicePixelsForStroking(Point& aP1, Point& aP2,
-                                                 const DrawTarget& aDrawTarget);
+                                                 const DrawTarget& aDrawTarget,
+                                                 Float aLineWidth);
 
 /**
  * This function paints each edge of aRect separately, snapping the edges using
  * SnapLineToDevicePixelsForStroking. Stroking the edges as separate paths
  * helps ensure not only that the stroke spans a single row of device pixels if
  * possible, but also that the ends of stroke dashes start and end on device
  * pixels too.
  */
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -8044,17 +8044,18 @@ void StrokeLineWithSnapping(const nsPoin
                             int32_t aAppUnitsPerDevPixel,
                             DrawTarget& aDrawTarget,
                             const Pattern& aPattern,
                             const StrokeOptions& aStrokeOptions,
                             const DrawOptions& aDrawOptions)
 {
   Point p1 = NSPointToPoint(aP1, aAppUnitsPerDevPixel);
   Point p2 = NSPointToPoint(aP2, aAppUnitsPerDevPixel);
-  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
+  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget,
+                                    aStrokeOptions.mLineWidth);
   aDrawTarget.StrokeLine(p1, p2, aPattern, aStrokeOptions, aDrawOptions);
 }
 
 namespace layout {
 
   
 void
 MaybeSetupTransactionIdAllocator(layers::LayerManager* aManager, nsView* aView)
--- a/layout/generic/nsImageMap.cpp
+++ b/layout/generic/nsImageMap.cpp
@@ -530,25 +530,27 @@ void PolyArea::Draw(nsIFrame* aFrame, Dr
       Point p1(pc->CSSPixelsToDevPixels(mCoords[0]),
                pc->CSSPixelsToDevPixels(mCoords[1]));
       Point p2, p1snapped, p2snapped;
       for (int32_t i = 2; i < mNumCoords; i += 2) {
         p2.x = pc->CSSPixelsToDevPixels(mCoords[i]);
         p2.y = pc->CSSPixelsToDevPixels(mCoords[i+1]);
         p1snapped = p1;
         p2snapped = p2;
-        SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget);
+        SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget,
+                                          aStrokeOptions.mLineWidth);
         aDrawTarget.StrokeLine(p1snapped, p2snapped, aColor, aStrokeOptions);
         p1 = p2;
       }
       p2.x = pc->CSSPixelsToDevPixels(mCoords[0]);
       p2.y = pc->CSSPixelsToDevPixels(mCoords[1]);
       p1snapped = p1;
       p2snapped = p2;
-      SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget);
+      SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget,
+                                        aStrokeOptions.mLineWidth);
       aDrawTarget.StrokeLine(p1snapped, p2snapped, aColor, aStrokeOptions);
     }
   }
 }
 
 void PolyArea::GetRect(nsIFrame* aFrame, nsRect& aRect)
 {
   if (mNumCoords >= 6) {
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -3249,17 +3249,18 @@ nsTreeBodyFrame::PaintCell(int32_t      
         if (isRTL) {
           srcX = currX + remainingWidth - (srcX - cellRect.x);
           destX = currX + remainingWidth - (destX - cellRect.x);
         }
         Point p1(pc->AppUnitsToGfxUnits(srcX),
                  pc->AppUnitsToGfxUnits(lineY + mRowHeight / 2));
         Point p2(pc->AppUnitsToGfxUnits(destX),
                  pc->AppUnitsToGfxUnits(lineY + mRowHeight / 2));
-        SnapLineToDevicePixelsForStroking(p1, p2, *drawTarget);
+        SnapLineToDevicePixelsForStroking(p1, p2, *drawTarget,
+                                          strokeOptions.mLineWidth);
         drawTarget->StrokeLine(p1, p2, colorPatt, strokeOptions);
       }
 
       int32_t currentParent = aRowIndex;
       for (int32_t i = level; i > 0; i--) {
         if (srcX <= cellRect.x + cellRect.width) {
           // Paint full vertical line only if we have next sibling.
           bool hasNextSibling;
@@ -3270,17 +3271,18 @@ nsTreeBodyFrame::PaintCell(int32_t      
             Point p2;
             p2.x = pc->AppUnitsToGfxUnits(srcX);
 
             if (hasNextSibling)
               p2.y = pc->AppUnitsToGfxUnits(lineY + mRowHeight);
             else if (i == level)
               p2.y = pc->AppUnitsToGfxUnits(lineY + mRowHeight / 2);
 
-            SnapLineToDevicePixelsForStroking(p1, p2, *drawTarget);
+            SnapLineToDevicePixelsForStroking(p1, p2, *drawTarget,
+                                              strokeOptions.mLineWidth);
             drawTarget->StrokeLine(p1, p2, colorPatt, strokeOptions);
           }          
         }
 
         int32_t parent;
         if (NS_FAILED(mView->GetParentIndex(currentParent, &parent)) || parent < 0)
           break;
         currentParent = parent;