Bug 1770103 - Handle StrokeLine in DrawTargetWebgl. r=aosmond
authorLee Salzman <lsalzman@mozilla.com>
Thu, 19 May 2022 15:37:34 +0000
changeset 618253 3362d8edea6a2e5f4698aaae706728942004dd9a
parent 618252 88d31f6c458de91707eceffc89c3d1f59d642e37
child 618254 1c7ed4f4e686caa66c0d5e7cc9e5c64b1e197c9e
push id39722
push usernfay@mozilla.com
push dateFri, 20 May 2022 09:31:26 +0000
treeherdermozilla-central@6092ad95d117 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaosmond
bugs1770103
milestone102.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 1770103 - Handle StrokeLine in DrawTargetWebgl. r=aosmond Differential Revision: https://phabricator.services.mozilla.com/D146769
dom/canvas/DrawTargetWebgl.cpp
--- a/dom/canvas/DrawTargetWebgl.cpp
+++ b/dom/canvas/DrawTargetWebgl.cpp
@@ -2233,38 +2233,80 @@ void DrawTargetWebgl::StrokeRect(const R
     DrawPath(path, aPattern, aOptions, &aStrokeOptions);
   }
 }
 
 void DrawTargetWebgl::StrokeLine(const Point& aStart, const Point& aEnd,
                                  const Pattern& aPattern,
                                  const StrokeOptions& aStrokeOptions,
                                  const DrawOptions& aOptions) {
+  if (mWebglValid && SupportsPattern(aPattern) &&
+      (aStrokeOptions.mLineCap == CapStyle::BUTT ||
+       aStrokeOptions.mLineCap == CapStyle::SQUARE) &&
+      aStrokeOptions.mDashPattern == nullptr && aStrokeOptions.mLineWidth > 0) {
+    // Treat the line as a rectangle whose center-line is the supplied line and
+    // for which the height is the supplied line width. Generate a matrix that
+    // maps the X axis to the orientation of the line and the Y axis to the
+    // normal vector to the line. This only works if the line caps are squared,
+    // as rounded rectangles are currently not supported for round line caps.
+    Point start = aStart;
+    Point dirX = aEnd - aStart;
+    float scale = aStrokeOptions.mLineWidth / dirX.Length();
+    Point dirY = Point(-dirX.y, dirX.x) * scale;
+    if (aStrokeOptions.mLineCap == CapStyle::SQUARE) {
+      start -= (dirX * scale) * 0.5f;
+      dirX += dirX * scale;
+    }
+    Matrix lineXform(dirX.x, dirX.y, dirY.x, dirY.y, start.x - 0.5f * dirY.x,
+                     start.y - 0.5f * dirY.y);
+    AutoRestoreTransform restore(this);
+    ConcatTransform(lineXform);
+    if (DrawRect(Rect(0, 0, 1, 1), aPattern, aOptions, Nothing(), nullptr, true,
+                 true, true)) {
+      return;
+    }
+    // If drawing an accelerated rectangle failed, just fall back to Skia's line
+    // rendering.
+  }
   MarkSkiaChanged(aOptions);
   mSkia->StrokeLine(aStart, aEnd, aPattern, aStrokeOptions, aOptions);
 }
 
 void DrawTargetWebgl::Stroke(const Path* aPath, const Pattern& aPattern,
                              const StrokeOptions& aStrokeOptions,
                              const DrawOptions& aOptions) {
   if (!aPath || aPath->GetBackendType() != BackendType::SKIA) {
     return;
   }
   const auto& skiaPath = static_cast<const PathSkia*>(aPath)->GetPath();
   SkRect rect;
-  SkPoint line[2];
   if (!mWebglValid) {
     MarkSkiaChanged(aOptions);
     mSkia->Stroke(aPath, aPattern, aStrokeOptions, aOptions);
   } else if (skiaPath.isRect(&rect)) {
     StrokeRect(SkRectToRect(rect), aPattern, aStrokeOptions, aOptions);
-  } else if (skiaPath.isLine(line)) {
-    StrokeLine(SkPointToPoint(line[0]), SkPointToPoint(line[1]), aPattern,
-               aStrokeOptions, aOptions);
   } else {
+    // Avoid using Skia's isLine here because some paths erroneously include a
+    // closePath at the end, causing isLine to not detect the line. In that case
+    // we just draw a line in reverse right over the original line.
+    int numVerbs = skiaPath.countVerbs();
+    if (numVerbs >= 2 && numVerbs <= 3) {
+      uint8_t verbs[3];
+      skiaPath.getVerbs(verbs, numVerbs);
+      if (verbs[0] == SkPath::kMove_Verb && verbs[1] == SkPath::kLine_Verb &&
+          (numVerbs < 3 || verbs[2] == SkPath::kClose_Verb)) {
+        Point start = SkPointToPoint(skiaPath.getPoint(0));
+        Point end = SkPointToPoint(skiaPath.getPoint(1));
+        StrokeLine(start, end, aPattern, aStrokeOptions, aOptions);
+        if (numVerbs >= 3) {
+          StrokeLine(end, start, aPattern, aStrokeOptions, aOptions);
+        }
+        return;
+      }
+    }
     DrawPath(aPath, aPattern, aOptions, &aStrokeOptions);
   }
 }
 
 void DrawTargetWebgl::StrokeGlyphs(ScaledFont* aFont,
                                    const GlyphBuffer& aBuffer,
                                    const Pattern& aPattern,
                                    const StrokeOptions& aStrokeOptions,