Open vargab95 opened 5 days ago
master branch
Have you tried older/other major versions of the project? If yes, can you mention them to ensure if this is a regression.
In my project where I've first detected the jank frames, I'm using 10.8.5. I'll do the same tests with some older versions as well.
It's the same with v9.6.0. The only difference is that flutter devtools have also reported 1 shader compilation jank. I haven't seen it in the latest version.
I've started a pixel 5 emulator and using that even editing the original example document generates jank frames. When I hit a key on the virtual keyboard, it results in a jank frame with 40-70ms duration.
some older versions
Can you also test the latest pre-release? If the migration is too much to test, maybe with the example of the flutter_quill
?
Sure, with the flutter_quill example it's still the same 30-60ms with 1k rows when using v11.0.0-dev.12.
I've enabled tracking widget builds in all code. The result is that a single render of QuillRawEditorMultiChildRenderObject takes 59.5ms.
And another screenshot, where you can see one of the 1k TextLine objects.
Another strange thing. Can it be that the toolbar is also re-rendered on change? I did some more measurements with tracking widget builds in all code and it seems like it takes a measurable proportion of the build time. I guess it's due to the fact that they use the same controller, so when the notifyListeners function is called, then both are rebuilt.
Just an idea, would it be possible to add a Widget cache into the QuillRawEditor? I've simply added a map to the _buildChildren method of QuillRawEditorState which stores the widget by the node.hashCode and only rebuilds it when something has changed in that position. It reduced the build time from 100-120ms to 20-30ms in case of 4k rows and from 200-250ms to 30-40ms in case of 8k rows.
You can see my changes below. It's just a hack in it's current state, but if nodes can have a unique id, like an integer, incremented on each node creation, then it may be doable.
What is your opinion? The problem is that I don't know the flutter_quill code base, so maybe there is a blocker with this approach.
diff --git a/lib/src/controller/quill_controller.dart b/lib/src/controller/quill_controller.dart
index 30c16eae..fd5ed71f 100644
--- a/lib/src/controller/quill_controller.dart
+++ b/lib/src/controller/quill_controller.dart
@@ -264,6 +264,8 @@ class QuillController extends ChangeNotifier {
const TextSelection.collapsed(offset: 0));
}
+ int? changePosition;
+
void replaceText(
int index,
int len,
@@ -278,6 +280,8 @@ class QuillController extends ChangeNotifier {
return;
}
+ changePosition = index;
+
Delta? delta;
Style? style;
if (len > 0 || data is! String || data.isNotEmpty) {
diff --git a/lib/src/editor/raw_editor/raw_editor_state.dart b/lib/src/editor/raw_editor/raw_editor_state.dart
index b3c49ddc..7f351223 100644
--- a/lib/src/editor/raw_editor/raw_editor_state.dart
+++ b/lib/src/editor/raw_editor/raw_editor_state.dart
@@ -576,6 +576,8 @@ class QuillRawEditorState extends EditorState
}
}
+ final Map<int, Directionality> _lines = {};
+
List<Widget> _buildChildren(Document doc, BuildContext context) {
final result = <Widget>[];
final indentLevelCounts = <int, int>{};
@@ -598,9 +600,20 @@ class QuillRawEditorState extends EditorState
prevNodeOl = attrs[Attribute.list.key] == Attribute.ol;
final nodeTextDirection = getDirectionOfNode(node, _textDirection);
if (node is Line) {
- final editableTextLine = _getEditableTextLineFromNode(node, context);
- result.add(Directionality(
- textDirection: nodeTextDirection, child: editableTextLine));
+ if (controller.changePosition != null &&
+ _lines[node.hashCode] != null &&
+ !node.containsOffset(controller.changePosition!)) {
+ result.add(_lines[node.hashCode]!);
+ } else {
+ final editableTextLine = Directionality(
+ textDirection: nodeTextDirection,
+ child: _getEditableTextLineFromNode(node, context),
+ );
+
+ _lines[node.hashCode] = editableTextLine;
+
+ result.add(editableTextLine);
+ }
} else if (node is Block) {
final editableTextBlock = EditableTextBlock(
block: node,
@@ -632,6 +645,7 @@ class QuillRawEditorState extends EditorState
customLinkPrefixes: widget.config.customLinkPrefixes,
composingRange: composingRange.value,
);
+
result.add(
Directionality(
Is there an existing issue for this?
Flutter Quill version
master branch
Steps to reproduce
Expected results
A document with few thousand rows renders at least with 30 FPS when edited.
Actual results
I've tested with a linux desktop PC (AMD Ryzen 5 5600G). With 1k rows, it rendered in 30-60ms, with 2k rows in 60-80ms, with 4k rows in 100-120ms, with 8k it took 200-250ms. It is more or less exactly O(n). Which means that even when a user edits a document with 1k rows, it will generate a jank frame.
Additional Context
I think, having documents with 1k rows are not so rare in case of a rich text editor.
I've searched through the issues and I've found that in https://github.com/singerdmx/flutter-quill/issues/997 it was already described. However, on master I cannot see the rasterization charts, but jank frames are still problematic.