18
18
19
19
#include < algorithm>
20
20
#include < numeric>
21
+ #include " fml/logging.h"
21
22
22
23
namespace txt {
23
24
@@ -45,27 +46,29 @@ txt::FontStyle GetTxtFontStyle(SkFontStyle::Slant font_slant) {
45
46
46
47
class DisplayListParagraphPainter : public skt ::ParagraphPainter {
47
48
public:
49
+ // ----------------------------------------------------------------------------
50
+ // / @brief Creates a |skt::ParagraphPainter| that draws to DisplayList.
51
+ // /
52
+ // / @param builder The display list builder.
53
+ // / @param[in] dl_paints The paints referenced by ID in the `drawX` methods.
54
+ // / @param[in] draw_path_effect If true, draw path effects directly by
55
+ // / drawing multiple lines instead of providing
56
+ // a path effect to the paint.
57
+ // /
58
+ // / @note Impeller does not (and will not) support path effects, but the
59
+ // / Skia backend does. That means that if we want to draw dashed
60
+ // / and dotted lines, we need to draw them directly using the
61
+ // / `drawLine` API instead of using a path effect.
62
+ // /
63
+ // / See https://github.com/flutter/flutter/issues/126673. It
64
+ // / probably makes sense to eventually make this a compile-time
65
+ // / decision (i.e. with `#ifdef`) instead of a runtime option.
48
66
DisplayListParagraphPainter (DisplayListBuilder* builder,
49
- const std::vector<DlPaint>& dl_paints)
50
- : builder_(builder), dl_paints_(dl_paints) {}
51
-
52
- DlPaint toDlPaint (const DecorationStyle& decor_style,
53
- DlDrawStyle draw_style = DlDrawStyle::kStroke ) {
54
- DlPaint paint;
55
- paint.setDrawStyle (draw_style);
56
- paint.setAntiAlias (true );
57
- paint.setColor (decor_style.getColor ());
58
- paint.setStrokeWidth (decor_style.getStrokeWidth ());
59
- std::optional<DashPathEffect> dash_path_effect =
60
- decor_style.getDashPathEffect ();
61
- if (dash_path_effect) {
62
- std::array<SkScalar, 2 > intervals{dash_path_effect->fOnLength ,
63
- dash_path_effect->fOffLength };
64
- paint.setPathEffect (
65
- DlDashPathEffect::Make (intervals.data (), intervals.size (), 0 ));
66
- }
67
- return paint;
68
- }
67
+ const std::vector<DlPaint>& dl_paints,
68
+ bool draw_path_effect)
69
+ : builder_(builder),
70
+ dl_paints_ (dl_paints),
71
+ draw_path_effect_(draw_path_effect) {}
69
72
70
73
void drawTextBlob (const sk_sp<SkTextBlob>& blob,
71
74
SkScalar x,
@@ -118,8 +121,25 @@ class DisplayListParagraphPainter : public skt::ParagraphPainter {
118
121
SkScalar x1,
119
122
SkScalar y1,
120
123
const DecorationStyle& decor_style) override {
121
- builder_->DrawLine (SkPoint::Make (x0, y0), SkPoint::Make (x1, y1),
122
- toDlPaint (decor_style));
124
+ // We only support horizontal lines.
125
+ FML_DCHECK (y0 == y1);
126
+
127
+ // This function is called for both solid and dashed lines. If we're drawing
128
+ // a dashed line, and we're using the Impeller backend, then we need to draw
129
+ // the line directly using the `drawLine` API instead of using a path effect
130
+ // (because Impeller does not support path effects).
131
+ auto dash_path_effect = decor_style.getDashPathEffect ();
132
+ if (draw_path_effect_ && dash_path_effect) {
133
+ auto path = dashedLine (x0, x1, y0, *dash_path_effect);
134
+ builder_->DrawPath (path, toDlPaint (decor_style));
135
+ return ;
136
+ }
137
+
138
+ auto paint = toDlPaint (decor_style);
139
+ if (dash_path_effect) {
140
+ setPathEffect (paint, *dash_path_effect);
141
+ }
142
+ builder_->DrawLine (SkPoint::Make (x0, y0), SkPoint::Make (x1, y1), paint);
123
143
}
124
144
125
145
void clipRect (const SkRect& rect) override {
@@ -135,15 +155,64 @@ class DisplayListParagraphPainter : public skt::ParagraphPainter {
135
155
void restore () override { builder_->Restore (); }
136
156
137
157
private:
158
+ SkPath dashedLine (SkScalar x0,
159
+ SkScalar x1,
160
+ SkScalar y0,
161
+ const DashPathEffect& dash_path_effect) {
162
+ auto dx = 0.0 ;
163
+ auto path = SkPath ();
164
+ auto on = true ;
165
+ auto length = x1 - x0;
166
+ while (dx < length) {
167
+ if (on) {
168
+ // Draw the on part of the dash.
169
+ path.moveTo (x0 + dx, y0);
170
+ dx += dash_path_effect.fOnLength ;
171
+ path.lineTo (x0 + dx, y0);
172
+ } else {
173
+ // Skip the off part of the dash.
174
+ dx += dash_path_effect.fOffLength ;
175
+ }
176
+ on = !on;
177
+ }
178
+
179
+ path.close ();
180
+ return path;
181
+ }
182
+
183
+ DlPaint toDlPaint (const DecorationStyle& decor_style,
184
+ DlDrawStyle draw_style = DlDrawStyle::kStroke ) {
185
+ DlPaint paint;
186
+ paint.setDrawStyle (draw_style);
187
+ paint.setAntiAlias (true );
188
+ paint.setColor (decor_style.getColor ());
189
+ paint.setStrokeWidth (decor_style.getStrokeWidth ());
190
+ return paint;
191
+ }
192
+
193
+ void setPathEffect (DlPaint& paint, const DashPathEffect& dash_path_effect) {
194
+ // Impeller does not support path effects, so we should never be setting.
195
+ FML_DCHECK (!draw_path_effect_);
196
+
197
+ std::array<SkScalar, 2 > intervals{dash_path_effect.fOnLength ,
198
+ dash_path_effect.fOffLength };
199
+ auto effect = DlDashPathEffect::Make (intervals.data (), intervals.size (), 0 );
200
+ paint.setPathEffect (effect);
201
+ }
202
+
138
203
DisplayListBuilder* builder_;
139
204
const std::vector<DlPaint>& dl_paints_;
205
+ bool draw_path_effect_;
140
206
};
141
207
142
208
} // anonymous namespace
143
209
144
210
ParagraphSkia::ParagraphSkia (std::unique_ptr<skt::Paragraph> paragraph,
145
- std::vector<flutter::DlPaint>&& dl_paints)
146
- : paragraph_(std::move(paragraph)), dl_paints_(dl_paints) {}
211
+ std::vector<flutter::DlPaint>&& dl_paints,
212
+ bool impeller_enabled)
213
+ : paragraph_(std::move(paragraph)),
214
+ dl_paints_(dl_paints),
215
+ impeller_enabled_(impeller_enabled) {}
147
216
148
217
double ParagraphSkia::GetMaxWidth () {
149
218
return SkScalarToDouble (paragraph_->getMaxWidth ());
@@ -223,7 +292,7 @@ void ParagraphSkia::Layout(double width) {
223
292
}
224
293
225
294
bool ParagraphSkia::Paint (DisplayListBuilder* builder, double x, double y) {
226
- DisplayListParagraphPainter painter (builder, dl_paints_);
295
+ DisplayListParagraphPainter painter (builder, dl_paints_, impeller_enabled_ );
227
296
paragraph_->paint (&painter, x, y);
228
297
return true ;
229
298
}
0 commit comments