Matan Lurey 8ec1692298 Do not convert an open path to a closed rect. (flutter/engine#45903)
Fixes https://github.com/flutter/flutter/issues/134816.

---

Confirmed this only happens when utilizing `DisplayListBuilder`.
Consider:

```cc
TEST_P(DisplayListTest, CanDrawAnOpenPath) {
  flutter::DisplayListBuilder builder;
  flutter::DlPaint paint;

  paint.setColor(flutter::DlColor::kRed());
  paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
  paint.setStrokeWidth(10);

  builder.Translate(300, 300);

  // Move to (50, 50) and draw lines from:
  // 1. (50, height)
  // 2. (width, height)
  // 3. (width, 50)
  SkPath path;
  path.moveTo(50, 50);
  path.lineTo(50, 100);
  path.lineTo(100, 100);
  path.lineTo(100, 50);
  builder.DrawPath(path, paint);

  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
```

![Screenshot 2023-09-15 at 2 06 53
PM](https://github.com/flutter/flutter/assets/168174/3a3868e1-f1d1-4e29-affa-4bd32d26ccdc)

---

The bug is in `dl_dispatcher.cc`:

```cc
// |flutter::DlOpReceiver|
void DlDispatcher::drawPath(const SkPath& path) {
  SkRect rect;
  SkRRect rrect;
  SkRect oval;

  if (path.isRect(&rect)) {
    canvas_.DrawRect(skia_conversions::ToRect(rect), paint_);
  } else if (path.isRRect(&rrect) && rrect.isSimple()) {
    canvas_.DrawRRect(skia_conversions::ToRect(rrect.rect()),
                      rrect.getSimpleRadii().fX, paint_);
  } else if (path.isOval(&oval) && oval.width() == oval.height()) {
    canvas_.DrawCircle(skia_conversions::ToPoint(oval.center()),
                       oval.width() * 0.5, paint_);
  } else {
    canvas_.DrawPath(skia_conversions::ToPath(path), paint_);
  }
}
```

Note the documentation for `isRect`:

```cc
/** Returns true if SkPath is equivalent to SkRect when filled.
    If false: rect, isClosed, and direction are unchanged.
    If true: rect, isClosed, and direction are written to if not nullptr.

    rect may be smaller than the SkPath bounds. SkPath bounds may include kMove_Verb points
    that do not alter the area drawn by the returned rect.

    @param rect       storage for bounds of SkRect; may be nullptr
    @param isClosed   storage set to true if SkPath is closed; may be nullptr
    @param direction  storage set to SkRect direction; may be nullptr
    @return           true if SkPath contains SkRect

    example: https://fiddle.skia.org/c/@Path_isRect
*/
bool isRect(SkRect* rect, bool* isClosed = nullptr, SkPathDirection* direction = nullptr) const;
```

... the `isClosed` is critical, without checking that we're doing an
incorrect optimization.

I'll send a fix and test.
2023-09-15 15:29:13 -07:00
Languages
Dart 75%
C++ 16.5%
Objective-C++ 2.9%
Java 2.8%
Objective-C 0.7%
Other 1.9%