@@ -31,6 +31,7 @@ class TextLine extends StatefulWidget {
3131    required  this .controller,
3232    required  this .onLaunchUrl,
3333    required  this .linkActionPicker,
34+     required  this .composingRange,
3435    this .textDirection,
3536    this .customStyleBuilder,
3637    this .customRecognizerBuilder,
@@ -49,6 +50,7 @@ class TextLine extends StatefulWidget {
4950  final  ValueChanged <String >?  onLaunchUrl;
5051  final  LinkActionPicker  linkActionPicker;
5152  final  List <String > customLinkPrefixes;
53+   final  TextRange  composingRange;
5254
5355  @override 
5456  State <TextLine > createState () =>  _TextLineState ();
@@ -267,14 +269,70 @@ class _TextLineState extends State<TextLine> {
267269    if  (nodes.isEmpty &&  kIsWeb) {
268270      nodes =  LinkedList <Node >()..add (leaf.QuillText ('\u {200B}' ));
269271    }
270-     final  children =  nodes
271-         .map ((node) => 
272-             _getTextSpanFromNode (defaultStyles, node, widget.line.style))
273-         .toList (growable:  false );
272+ 
273+     final  isComposingRangeOutOfLine =  ! widget.composingRange.isValid || 
274+         widget.composingRange.isCollapsed || 
275+         (widget.composingRange.start <  widget.line.documentOffset || 
276+             widget.composingRange.end > 
277+                 widget.line.documentOffset +  widget.line.length);
278+ 
279+     if  (isComposingRangeOutOfLine) {
280+       final  children =  nodes
281+           .map ((node) => 
282+               _getTextSpanFromNode (defaultStyles, node, widget.line.style))
283+           .toList (growable:  false );
284+       return  TextSpan (children:  children, style:  lineStyle);
285+     }
286+ 
287+     final  children =  nodes.expand ((node) {
288+       final  child = 
289+           _getTextSpanFromNode (defaultStyles, node, widget.line.style);
290+       final  isNodeInComposingRange = 
291+           node.documentOffset <=  widget.composingRange.start && 
292+               widget.composingRange.end <=  node.documentOffset +  node.length;
293+       if  (isNodeInComposingRange) {
294+         return  _splitAndApplyComposingStyle (node, child);
295+       } else  {
296+         return  [child];
297+       }
298+     }).toList (growable:  false );
274299
275300    return  TextSpan (children:  children, style:  lineStyle);
276301  }
277302
303+   // split the text nodes into composing and non-composing nodes 
304+   // and apply the composing style to the composing nodes 
305+   List <InlineSpan > _splitAndApplyComposingStyle (Node  node, InlineSpan  child) {
306+     assert (widget.composingRange.isValid &&  ! widget.composingRange.isCollapsed);
307+ 
308+     final  composingStart =  widget.composingRange.start -  node.documentOffset;
309+     final  composingEnd =  widget.composingRange.end -  node.documentOffset;
310+     final  text =  child.toPlainText ();
311+ 
312+     final  textBefore =  text.substring (0 , composingStart);
313+     final  textComposing =  text.substring (composingStart, composingEnd);
314+     final  textAfter =  text.substring (composingEnd);
315+ 
316+     final  composingStyle =  child.style
317+             ? .merge (const  TextStyle (decoration:  TextDecoration .underline)) ?? 
318+         const  TextStyle (decoration:  TextDecoration .underline);
319+ 
320+     return  [
321+       TextSpan (
322+         text:  textBefore,
323+         style:  child.style,
324+       ),
325+       TextSpan (
326+         text:  textComposing,
327+         style:  composingStyle,
328+       ),
329+       TextSpan (
330+         text:  textAfter,
331+         style:  child.style,
332+       ),
333+     ];
334+   }
335+ 
278336  TextStyle  _getLineStyle (DefaultStyles  defaultStyles) {
279337    var  textStyle =  const  TextStyle ();
280338
@@ -643,8 +701,6 @@ class EditableTextLine extends RenderObjectWidget {
643701      this .devicePixelRatio,
644702      this .cursorCont,
645703      this .inlineCodeStyle,
646-       this .composingRange,
647-       this .composingColor,
648704      {super .key});
649705
650706  final  Line  line;
@@ -660,8 +716,6 @@ class EditableTextLine extends RenderObjectWidget {
660716  final  double  devicePixelRatio;
661717  final  CursorCont  cursorCont;
662718  final  InlineCodeStyle  inlineCodeStyle;
663-   final  TextRange  composingRange;
664-   final  Color  composingColor;
665719
666720  @override 
667721  RenderObjectElement  createElement () {
@@ -680,9 +734,7 @@ class EditableTextLine extends RenderObjectWidget {
680734        _getPadding (),
681735        color,
682736        cursorCont,
683-         inlineCodeStyle,
684-         composingRange,
685-         composingColor);
737+         inlineCodeStyle);
686738  }
687739
688740  @override 
@@ -698,8 +750,7 @@ class EditableTextLine extends RenderObjectWidget {
698750      ..hasFocus =  hasFocus
699751      ..setDevicePixelRatio (devicePixelRatio)
700752      ..setCursorCont (cursorCont)
701-       ..setInlineCodeStyle (inlineCodeStyle)
702-       ..setComposingRange (composingRange);
753+       ..setInlineCodeStyle (inlineCodeStyle);
703754  }
704755
705756  EdgeInsetsGeometry  _getPadding () {
@@ -726,8 +777,6 @@ class RenderEditableTextLine extends RenderEditableBox {
726777    this .color,
727778    this .cursorCont,
728779    this .inlineCodeStyle,
729-     this .composingRange,
730-     this .composingColor,
731780  );
732781
733782  RenderBox ?  _leading;
@@ -746,8 +795,6 @@ class RenderEditableTextLine extends RenderEditableBox {
746795  List <TextBox >?  _selectedRects;
747796  late  Rect  _caretPrototype;
748797  InlineCodeStyle  inlineCodeStyle;
749-   TextRange  composingRange;
750-   Color  composingColor;
751798  final  Map <TextLineSlot , RenderBox > children =  < TextLineSlot , RenderBox > {};
752799
753800  Iterable <RenderBox > get  _children sync *  {
@@ -863,12 +910,6 @@ class RenderEditableTextLine extends RenderEditableBox {
863910    markNeedsLayout ();
864911  }
865912
866-   void  setComposingRange (TextRange  newComposingRange) {
867-     if  (composingRange ==  newComposingRange) return ;
868-     composingRange =  newComposingRange;
869-     markNeedsLayout ();
870-   }
871- 
872913  // Start selection implementation 
873914
874915  bool  containsTextSelection () {
@@ -1351,11 +1392,6 @@ class RenderEditableTextLine extends RenderEditableBox {
13511392
13521393        _paintSelection (context, effectiveOffset);
13531394      }
1354- 
1355-       // Paints an underline to indicate the text being composed by the IME. 
1356-       if  (composingRange.isValid) {
1357-         _paintComposing (context);
1358-       }
13591395    }
13601396  }
13611397
@@ -1387,34 +1423,6 @@ class RenderEditableTextLine extends RenderEditableBox {
13871423    );
13881424  }
13891425
1390-   // Paints a line below the composing text. 
1391-   void  _paintComposing (PaintingContext  context) {
1392-     assert (composingRange.isValid);
1393-     final  composingStart =  composingRange.start -  line.documentOffset;
1394-     final  composingEnd =  composingRange.end -  line.documentOffset;
1395-     if  (composingStart <  0  ||  composingEnd <  0 ) {
1396-       return ;
1397-     }
1398-     final  composingRects =  _body! .getBoxesForSelection (
1399-       TextSelection (
1400-         baseOffset:  composingStart,
1401-         extentOffset:  composingEnd,
1402-       ),
1403-     );
1404-     final  paint =  Paint ()
1405-       ..color =  composingColor
1406-       ..style =  PaintingStyle .stroke
1407-       ..strokeWidth =  1 ;
1408-     for  (final  box in  composingRects) {
1409-       final  rect =  box.toRect ();
1410-       context.canvas.drawLine (
1411-         rect.bottomLeft.translate (0 , - 5 ),
1412-         rect.bottomRight.translate (0 , - 5 ),
1413-         paint,
1414-       );
1415-     }
1416-   }
1417- 
14181426  @override 
14191427  bool  hitTestChildren (BoxHitTestResult  result, {required  Offset  position}) {
14201428    if  (_leading !=  null ) {
0 commit comments