1#[cfg(not(feature = "std"))]
4use alloc::{string::String, vec::Vec};
5
6use core::{cmp, fmt};
7
8#[cfg(not(feature = "std"))]
9use core_maths::CoreFloat;
10use unicode_segmentation::UnicodeSegmentation;
11
12use crate::{
13 render_decoration, Affinity, Align, Attrs, AttrsList, BidiParagraphs, BorrowedWithFontSystem,
14 BufferLine, Color, Cursor, DecorationSpan, Ellipsize, FontSystem, Hinting, LayoutCursor,
15 LayoutGlyph, LayoutLine, LineEnding, LineIter, Motion, Renderer, Scroll, ShapeLine, Shaping,
16 Wrap,
17};
18
19bitflags::bitflags! {
20 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
22 struct DirtyFlags: u8 {
23 const RELAYOUT = 0b0001;
25 const TAB_SHAPE = 0b0010;
27 const TEXT_SET = 0b0100;
29 const SCROLL = 0b1000;
31 }
32}
33
34#[derive(Debug)]
36pub struct LayoutRun<'a> {
37 pub line_i: usize,
39 pub text: &'a str,
41 pub rtl: bool,
43 pub glyphs: &'a [LayoutGlyph],
45 pub decorations: &'a [DecorationSpan],
47 pub line_y: f32,
49 pub line_top: f32,
51 pub line_height: f32,
53 pub line_w: f32,
55}
56
57impl LayoutRun<'_> {
58 pub fn highlight(
67 &self,
68 cursor_start: Cursor,
69 cursor_end: Cursor,
70 ) -> impl Iterator<Item = (f32, f32)> {
71 let line_i = self.line_i;
72 let mut results = Vec::new();
73 let mut range_opt: Option<(f32, f32)> = None;
74
75 for glyph in self.glyphs {
76 let cluster = &self.text[glyph.start..glyph.end];
77 let total = cluster.grapheme_indices(true).count().max(1);
78 let c_w = glyph.w / total as f32;
79 let mut c_x = glyph.x;
80
81 for (i, c) in cluster.grapheme_indices(true) {
82 let c_start = glyph.start + i;
83 let c_end = glyph.start + i + c.len();
84
85 let is_selected = (cursor_start.line != line_i || c_end > cursor_start.index)
86 && (cursor_end.line != line_i || c_start < cursor_end.index);
87
88 if is_selected {
89 range_opt = Some(match range_opt {
90 Some((min, max)) => (min.min(c_x), max.max(c_x + c_w)),
91 None => (c_x, c_x + c_w),
92 });
93 } else if let Some((min_x, max_x)) = range_opt.take() {
94 let width = max_x - min_x;
95 if width > 0.0 {
96 results.push((min_x, width));
97 }
98 }
99
100 c_x += c_w;
101 }
102 }
103
104 if let Some((min_x, max_x)) = range_opt {
106 let width = max_x - min_x;
107 if width > 0.0 {
108 results.push((min_x, width));
109 }
110 }
111
112 results.into_iter()
113 }
114
115 pub fn cursor_position(&self, cursor: &Cursor) -> Option<f32> {
121 let (glyph_idx, glyph_offset) = self.cursor_glyph(cursor)?;
122 let x = self.glyphs.get(glyph_idx).map_or_else(
123 || {
124 self.glyphs.last().map_or(0.0, |glyph| {
126 if glyph.level.is_rtl() {
127 glyph.x
128 } else {
129 glyph.x + glyph.w
130 }
131 })
132 },
133 |glyph| {
134 if glyph.level.is_rtl() {
135 glyph.x + glyph.w - glyph_offset
136 } else {
137 glyph.x + glyph_offset
138 }
139 },
140 );
141 Some(x)
142 }
143
144 pub fn cursor_glyph(&self, cursor: &Cursor) -> Option<(usize, f32)> {
148 if cursor.line != self.line_i {
149 return None;
150 }
151 for (glyph_i, glyph) in self.glyphs.iter().enumerate() {
152 if cursor.index == glyph.start {
153 return Some((glyph_i, 0.0));
154 } else if cursor.index > glyph.start && cursor.index < glyph.end {
155 let cluster = &self.text[glyph.start..glyph.end];
157 let mut before = 0;
158 let mut total = 0;
159 for (i, _) in cluster.grapheme_indices(true) {
160 if glyph.start + i < cursor.index {
161 before += 1;
162 }
163 total += 1;
164 }
165 let offset = glyph.w * (before as f32) / (total as f32);
166 return Some((glyph_i, offset));
167 }
168 }
169 for (glyph_i, glyph) in self.glyphs.iter().enumerate() {
171 if cursor.index == glyph.end {
172 return Some((glyph_i, glyph.w));
173 }
174 }
175 if self.glyphs.is_empty() {
176 return Some((0, 0.0));
177 }
178 None
179 }
180
181 pub const fn cursor_from_glyph_left(&self, glyph: &LayoutGlyph) -> Cursor {
183 if self.rtl {
184 Cursor::new_with_affinity(self.line_i, glyph.end, Affinity::Before)
185 } else {
186 Cursor::new_with_affinity(self.line_i, glyph.start, Affinity::After)
187 }
188 }
189
190 pub const fn cursor_from_glyph_right(&self, glyph: &LayoutGlyph) -> Cursor {
192 if self.rtl {
193 Cursor::new_with_affinity(self.line_i, glyph.start, Affinity::After)
194 } else {
195 Cursor::new_with_affinity(self.line_i, glyph.end, Affinity::Before)
196 }
197 }
198}
199
200#[derive(Debug)]
202pub struct LayoutRunIter<'b> {
203 lines: &'b [BufferLine],
204 height_opt: Option<f32>,
205 line_height: f32,
206 scroll: f32,
207 line_i: usize,
208 layout_i: usize,
209 total_height: f32,
210 line_top: f32,
211}
212
213impl<'b> LayoutRunIter<'b> {
214 pub const fn new(buffer: &'b Buffer) -> Self {
215 Self::from_lines(
216 buffer.lines.as_slice(),
217 buffer.height_opt,
218 buffer.metrics.line_height,
219 buffer.scroll.vertical,
220 buffer.scroll.line,
221 )
222 }
223
224 pub const fn from_lines(
225 lines: &'b [BufferLine],
226 height_opt: Option<f32>,
227 line_height: f32,
228 scroll: f32,
229 start: usize,
230 ) -> Self {
231 Self {
232 lines,
233 height_opt,
234 line_height,
235 scroll,
236 line_i: start,
237 layout_i: 0,
238 total_height: 0.0,
239 line_top: 0.0,
240 }
241 }
242}
243
244impl<'b> Iterator for LayoutRunIter<'b> {
245 type Item = LayoutRun<'b>;
246
247 fn next(&mut self) -> Option<Self::Item> {
248 while let Some(line) = self.lines.get(self.line_i) {
249 let shape = line.shape_opt()?;
250 let layout = line.layout_opt()?;
251 while let Some(layout_line) = layout.get(self.layout_i) {
252 self.layout_i += 1;
253
254 let line_height = layout_line.line_height_opt.unwrap_or(self.line_height);
255 self.total_height += line_height;
256
257 let line_top = self.line_top - self.scroll;
258 let glyph_height = layout_line.max_ascent + layout_line.max_descent;
259 let centering_offset = (line_height - glyph_height) / 2.0;
260 let line_y = line_top + centering_offset + layout_line.max_ascent;
261 if let Some(height) = self.height_opt {
262 if line_y - layout_line.max_ascent > height {
263 return None;
264 }
265 }
266 self.line_top += line_height;
267 if line_y + layout_line.max_descent < 0.0 {
268 continue;
269 }
270
271 return Some(LayoutRun {
272 line_i: self.line_i,
273 text: line.text(),
274 rtl: shape.rtl,
275 glyphs: &layout_line.glyphs,
276 decorations: &layout_line.decorations,
277 line_y,
278 line_top,
279 line_height,
280 line_w: layout_line.w,
281 });
282 }
283 self.line_i += 1;
284 self.layout_i = 0;
285 }
286
287 None
288 }
289}
290
291#[derive(Clone, Copy, Debug, Default, PartialEq)]
293pub struct Metrics {
294 pub font_size: f32,
296 pub line_height: f32,
298}
299
300impl Metrics {
301 pub const fn new(font_size: f32, line_height: f32) -> Self {
303 Self {
304 font_size,
305 line_height,
306 }
307 }
308
309 pub fn relative(font_size: f32, line_height_scale: f32) -> Self {
311 Self {
312 font_size,
313 line_height: font_size * line_height_scale,
314 }
315 }
316
317 pub fn scale(self, scale: f32) -> Self {
319 Self {
320 font_size: self.font_size * scale,
321 line_height: self.line_height * scale,
322 }
323 }
324}
325
326impl fmt::Display for Metrics {
327 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
328 write!(f, "{}px / {}px", self.font_size, self.line_height)
329 }
330}
331
332#[derive(Debug)]
334pub struct Buffer {
335 pub lines: Vec<BufferLine>,
337 metrics: Metrics,
338 width_opt: Option<f32>,
339 height_opt: Option<f32>,
340 scroll: Scroll,
341 redraw: bool,
343 wrap: Wrap,
344 ellipsize: Ellipsize,
345 monospace_width: Option<f32>,
346 tab_width: u16,
347 hinting: Hinting,
348 dirty: DirtyFlags,
350}
351
352impl Clone for Buffer {
353 fn clone(&self) -> Self {
354 Self {
355 lines: self.lines.clone(),
356 metrics: self.metrics,
357 width_opt: self.width_opt,
358 height_opt: self.height_opt,
359 scroll: self.scroll,
360 redraw: self.redraw,
361 wrap: self.wrap,
362 ellipsize: self.ellipsize,
363 monospace_width: self.monospace_width,
364 tab_width: self.tab_width,
365 hinting: self.hinting,
366 dirty: self.dirty,
367 }
368 }
369}
370
371impl Buffer {
372 pub fn new_empty(metrics: Metrics) -> Self {
384 assert_ne!(metrics.line_height, 0.0, "line height cannot be 0");
385 Self {
386 lines: Vec::new(),
387 metrics,
388 width_opt: None,
389 height_opt: None,
390 scroll: Scroll::default(),
391 redraw: false,
392 wrap: Wrap::WordOrGlyph,
393 ellipsize: Ellipsize::None,
394 monospace_width: None,
395 tab_width: 8,
396 hinting: Hinting::default(),
397 dirty: DirtyFlags::empty(),
398 }
399 }
400
401 pub fn new(font_system: &mut FontSystem, metrics: Metrics) -> Self {
407 let mut buffer = Self::new_empty(metrics);
408 buffer.set_text("", &Attrs::new(), Shaping::Advanced, None);
409 buffer.shape_until_scroll(font_system, false);
410 buffer
411 }
412
413 pub fn borrow_with<'a>(
415 &'a mut self,
416 font_system: &'a mut FontSystem,
417 ) -> BorrowedWithFontSystem<'a, Self> {
418 BorrowedWithFontSystem {
419 inner: self,
420 font_system,
421 }
422 }
423
424 fn resolve_dirty(&mut self) -> bool {
427 let dirty = self.dirty;
428 if dirty.is_empty() {
429 if self.lines.iter().any(|line| line.needs_reshaping()) {
431 self.redraw = true;
432 return true;
433 }
434 return false;
435 }
436
437 if dirty.contains(DirtyFlags::TEXT_SET) {
438 } else {
440 if dirty.contains(DirtyFlags::TAB_SHAPE) {
441 for line in &mut self.lines {
442 if line.shape_opt().is_some() && line.text().contains('\t') {
443 line.reset_shaping();
444 }
445 }
446 }
447 if dirty.contains(DirtyFlags::RELAYOUT) {
448 for line in &mut self.lines {
449 if line.shape_opt().is_some() {
450 line.reset_layout();
451 }
452 }
453 }
454 }
455
456 self.redraw = true;
457 self.dirty = DirtyFlags::empty();
458 true
459 }
460
461 #[allow(clippy::missing_panics_doc)]
463 pub fn shape_until_cursor(
464 &mut self,
465 font_system: &mut FontSystem,
466 cursor: Cursor,
467 prune: bool,
468 ) {
469 self.shape_until_scroll(font_system, prune);
470 let metrics = self.metrics;
471 let old_scroll = self.scroll;
472
473 let layout_cursor = self
474 .layout_cursor(font_system, cursor)
475 .expect("shape_until_cursor invalid cursor");
476
477 let mut layout_y = 0.0;
478 let mut total_height = {
479 let layout = self
480 .line_layout(font_system, layout_cursor.line)
481 .expect("shape_until_cursor failed to scroll forwards");
482 (0..layout_cursor.layout).for_each(|layout_i| {
483 layout_y += layout[layout_i]
484 .line_height_opt
485 .unwrap_or(metrics.line_height);
486 });
487 layout_y
488 + layout[layout_cursor.layout]
489 .line_height_opt
490 .unwrap_or(metrics.line_height)
491 };
492
493 if self.scroll.line > layout_cursor.line
494 || (self.scroll.line == layout_cursor.line && self.scroll.vertical > layout_y)
495 {
496 self.scroll.line = layout_cursor.line;
498 self.scroll.vertical = layout_y;
499 } else if let Some(height) = self.height_opt {
500 let mut line_i = layout_cursor.line;
502 if line_i <= self.scroll.line {
503 if total_height > height + self.scroll.vertical {
505 self.scroll.vertical = total_height - height;
506 }
507 } else {
508 while line_i > self.scroll.line {
509 line_i -= 1;
510 let layout = self
511 .line_layout(font_system, line_i)
512 .expect("shape_until_cursor failed to scroll forwards");
513 for layout_line in layout {
514 total_height += layout_line.line_height_opt.unwrap_or(metrics.line_height);
515 }
516 if total_height > height + self.scroll.vertical {
517 self.scroll.line = line_i;
518 self.scroll.vertical = total_height - height;
519 }
520 }
521 }
522 }
523
524 if old_scroll != self.scroll {
525 self.dirty |= DirtyFlags::SCROLL;
526 }
527
528 self.shape_until_scroll(font_system, prune);
529
530 if let Some(layout_cursor) = self.layout_cursor(font_system, cursor) {
532 if let Some(layout_lines) = self.line_layout(font_system, layout_cursor.line) {
533 if let Some(layout_line) = layout_lines.get(layout_cursor.layout) {
534 let (x_min, x_max) = layout_line
535 .glyphs
536 .get(layout_cursor.glyph)
537 .or_else(|| layout_line.glyphs.last())
538 .map_or((0.0, 0.0), |glyph| {
539 let x_a = glyph.x;
541 let x_b = glyph.x + glyph.w;
542 (x_a.min(x_b), x_a.max(x_b))
543 });
544 if x_min < self.scroll.horizontal {
545 self.scroll.horizontal = x_min;
546 self.redraw = true;
547 }
548 if let Some(width) = self.width_opt {
549 if x_max > self.scroll.horizontal + width {
550 self.scroll.horizontal = x_max - width;
551 self.redraw = true;
552 }
553 }
554 }
555 }
556 }
557 }
558
559 #[allow(clippy::missing_panics_doc)]
571 pub fn shape_until_scroll(&mut self, font_system: &mut FontSystem, prune: bool) {
572 if !self.resolve_dirty() {
573 return;
574 }
575 let metrics = self.metrics;
576
577 if self.scroll.line >= self.lines.len() {
579 self.scroll.line = self.lines.len().saturating_sub(1);
580 self.scroll.vertical = 0.0;
581 }
582
583 let old_scroll = self.scroll;
584
585 loop {
586 while self.scroll.vertical < 0.0 {
588 if self.scroll.line > 0 {
589 let line_i = self.scroll.line - 1;
590 if let Some(layout) = self.line_layout(font_system, line_i) {
591 let mut layout_height = 0.0;
592 for layout_line in layout {
593 layout_height +=
594 layout_line.line_height_opt.unwrap_or(metrics.line_height);
595 }
596 self.scroll.line = line_i;
597 self.scroll.vertical += layout_height;
598 } else {
599 self.scroll.line = line_i;
601 self.scroll.vertical += metrics.line_height;
602 }
603 } else {
604 self.scroll.vertical = 0.0;
605 break;
606 }
607 }
608
609 let scroll_start = self.scroll.vertical;
610 let scroll_end = scroll_start + self.height_opt.unwrap_or(f32::INFINITY);
611
612 if prune {
613 for line_i in 0..self.scroll.line {
614 self.lines[line_i].reset_shaping();
615 }
616 }
617 let mut total_height = 0.0;
618 for line_i in self.scroll.line..self.lines.len() {
619 if total_height > scroll_end {
620 if prune {
621 self.lines[line_i].reset_shaping();
622 continue;
623 }
624 break;
625 }
626
627 let mut layout_height = 0.0;
628 let layout = self
629 .line_layout(font_system, line_i)
630 .expect("shape_until_scroll invalid line");
631 for layout_line in layout {
632 let line_height = layout_line.line_height_opt.unwrap_or(metrics.line_height);
633 layout_height += line_height;
634 total_height += line_height;
635 }
636
637 if line_i == self.scroll.line && layout_height <= self.scroll.vertical {
639 self.scroll.line += 1;
640 self.scroll.vertical -= layout_height;
641 }
642 }
643
644 if total_height < scroll_end && self.scroll.line > 0 {
645 self.scroll.vertical -= scroll_end - total_height;
647 } else {
648 break;
650 }
651 }
652
653 if old_scroll != self.scroll {
654 self.redraw = true;
655 }
656 }
657
658 pub fn layout_cursor(
660 &mut self,
661 font_system: &mut FontSystem,
662 cursor: Cursor,
663 ) -> Option<LayoutCursor> {
664 let layout = self.line_layout(font_system, cursor.line)?;
665 for (layout_i, layout_line) in layout.iter().enumerate() {
666 for (glyph_i, glyph) in layout_line.glyphs.iter().enumerate() {
667 let cursor_end =
668 Cursor::new_with_affinity(cursor.line, glyph.end, Affinity::Before);
669 let cursor_start =
670 Cursor::new_with_affinity(cursor.line, glyph.start, Affinity::After);
671 let (cursor_left, cursor_right) = if glyph.level.is_ltr() {
672 (cursor_start, cursor_end)
673 } else {
674 (cursor_end, cursor_start)
675 };
676 if cursor == cursor_left {
677 return Some(LayoutCursor::new(cursor.line, layout_i, glyph_i));
678 }
679 if cursor == cursor_right {
680 return Some(LayoutCursor::new(cursor.line, layout_i, glyph_i + 1));
681 }
682 }
683 }
684
685 Some(LayoutCursor::new(cursor.line, 0, 0))
688 }
689
690 pub fn line_shape(
692 &mut self,
693 font_system: &mut FontSystem,
694 line_i: usize,
695 ) -> Option<&ShapeLine> {
696 let line = self.lines.get_mut(line_i)?;
697 Some(line.shape(font_system, self.tab_width))
698 }
699
700 pub fn line_layout(
702 &mut self,
703 font_system: &mut FontSystem,
704 line_i: usize,
705 ) -> Option<&[LayoutLine]> {
706 let line = self.lines.get_mut(line_i)?;
707 Some(line.layout(
708 font_system,
709 self.metrics.font_size,
710 self.width_opt,
711 self.wrap,
712 self.ellipsize,
713 self.monospace_width,
714 self.tab_width,
715 self.hinting,
716 ))
717 }
718
719 pub const fn metrics(&self) -> Metrics {
721 self.metrics
722 }
723
724 pub fn set_metrics(&mut self, metrics: Metrics) {
730 if metrics != self.metrics {
731 assert_ne!(metrics.font_size, 0.0, "font size cannot be 0");
732 assert_ne!(metrics.line_height, 0.0, "line height cannot be 0");
733 self.metrics = metrics;
734 self.dirty |= DirtyFlags::RELAYOUT;
735 self.redraw = true;
736 }
737 }
738
739 pub const fn hinting(&self) -> Hinting {
741 self.hinting
742 }
743
744 pub fn set_hinting(&mut self, hinting: Hinting) {
746 if hinting != self.hinting {
747 self.hinting = hinting;
748 self.dirty |= DirtyFlags::RELAYOUT;
749 self.redraw = true;
750 }
751 }
752
753 pub const fn wrap(&self) -> Wrap {
755 self.wrap
756 }
757
758 pub fn set_wrap(&mut self, wrap: Wrap) {
760 if wrap != self.wrap {
761 self.wrap = wrap;
762 self.dirty |= DirtyFlags::RELAYOUT;
763 self.redraw = true;
764 }
765 }
766
767 pub const fn ellipsize(&self) -> Ellipsize {
769 self.ellipsize
770 }
771
772 pub fn set_ellipsize(&mut self, ellipsize: Ellipsize) {
774 if ellipsize != self.ellipsize {
775 self.ellipsize = ellipsize;
776 self.dirty |= DirtyFlags::RELAYOUT;
777 self.redraw = true;
778 }
779 }
780
781 pub const fn monospace_width(&self) -> Option<f32> {
783 self.monospace_width
784 }
785
786 pub fn set_monospace_width(&mut self, monospace_width: Option<f32>) {
788 if monospace_width != self.monospace_width {
789 self.monospace_width = monospace_width;
790 self.dirty |= DirtyFlags::RELAYOUT;
791 self.redraw = true;
792 }
793 }
794
795 pub const fn tab_width(&self) -> u16 {
797 self.tab_width
798 }
799
800 pub fn set_tab_width(&mut self, tab_width: u16) {
802 if tab_width == 0 {
803 return;
804 }
805 if tab_width != self.tab_width {
806 self.tab_width = tab_width;
807 self.dirty |= DirtyFlags::TAB_SHAPE | DirtyFlags::RELAYOUT;
808 self.redraw = true;
809 }
810 }
811
812 pub const fn size(&self) -> (Option<f32>, Option<f32>) {
814 (self.width_opt, self.height_opt)
815 }
816
817 pub fn set_size(&mut self, width_opt: Option<f32>, height_opt: Option<f32>) {
819 let width_clamped = width_opt.map(|v| v.max(0.0));
820 let height_clamped = height_opt.map(|v| v.max(0.0));
821 if width_clamped != self.width_opt {
822 self.width_opt = width_clamped;
823 self.dirty |= DirtyFlags::RELAYOUT;
824 self.redraw = true;
825 }
826 if height_clamped != self.height_opt {
827 self.height_opt = height_clamped;
828 self.dirty |= DirtyFlags::RELAYOUT;
829 self.redraw = true;
830 }
831 }
832
833 pub fn set_metrics_and_size(
839 &mut self,
840 metrics: Metrics,
841 width_opt: Option<f32>,
842 height_opt: Option<f32>,
843 ) {
844 self.set_metrics(metrics);
845 self.set_size(width_opt, height_opt);
846 }
847
848 pub const fn scroll(&self) -> Scroll {
850 self.scroll
851 }
852
853 pub fn set_scroll(&mut self, scroll: Scroll) {
855 if scroll != self.scroll {
856 self.scroll = scroll;
857 self.dirty |= DirtyFlags::SCROLL;
858 self.redraw = true;
859 }
860 }
861
862 fn set_text_impl(
866 &mut self,
867 text: &str,
868 attrs: &Attrs,
869 shaping: Shaping,
870 alignment: Option<Align>,
871 ) {
872 let mut line_count = 0;
873 for (range, ending) in LineIter::new(text) {
874 let line_text = &text[range];
875 if line_count < self.lines.len() {
876 let mut reused_text = self.lines[line_count].reclaim_text();
878 reused_text.push_str(line_text);
879 let reused_attrs = self.lines[line_count].reclaim_attrs().reset(attrs);
880 self.lines[line_count].reset_new(reused_text, ending, reused_attrs, shaping);
881 } else {
882 self.lines.push(BufferLine::new(
883 line_text,
884 ending,
885 AttrsList::new(attrs),
886 shaping,
887 ));
888 }
889 line_count += 1;
890 }
891
892 let last_ending = if line_count > 0 {
896 self.lines[line_count - 1].ending()
897 } else {
898 LineEnding::default()
899 };
900 if last_ending != LineEnding::None {
901 if line_count < self.lines.len() {
902 let reused_text = self.lines[line_count].reclaim_text();
903 let reused_attrs = self.lines[line_count].reclaim_attrs().reset(attrs);
904 self.lines[line_count].reset_new(
905 reused_text,
906 LineEnding::None,
907 reused_attrs,
908 shaping,
909 );
910 } else {
911 self.lines.push(BufferLine::new(
912 "",
913 LineEnding::None,
914 AttrsList::new(attrs),
915 shaping,
916 ));
917 }
918 line_count += 1;
919 }
920
921 self.lines.truncate(line_count);
923
924 if alignment.is_some() {
925 self.lines.iter_mut().for_each(|line| {
926 line.set_align(alignment);
927 });
928 }
929
930 self.scroll = Scroll::default();
931 }
932
933 pub fn set_text(
935 &mut self,
936 text: &str,
937 attrs: &Attrs,
938 shaping: Shaping,
939 alignment: Option<Align>,
940 ) {
941 self.set_text_impl(text, attrs, shaping, alignment);
942 self.dirty |= DirtyFlags::TEXT_SET;
943 self.redraw = true;
944 }
945
946 fn set_rich_text_impl<'r, 's, I>(
950 &mut self,
951 spans: I,
952 default_attrs: &Attrs,
953 shaping: Shaping,
954 alignment: Option<Align>,
955 ) where
956 I: IntoIterator<Item = (&'s str, Attrs<'r>)>,
957 {
958 let mut end = 0;
959 let (string, spans_data): (String, Vec<_>) = spans
961 .into_iter()
962 .map(|(s, attrs)| {
963 let start = end;
964 end += s.len();
965 (s, (attrs, start..end))
966 })
967 .unzip();
968
969 let mut spans_iter = spans_data.into_iter();
970 let mut maybe_span = spans_iter.next();
971
972 let string_start = string.as_ptr() as usize;
974 let mut lines_iter = BidiParagraphs::new(&string).map(|line: &str| {
975 let start = line.as_ptr() as usize - string_start;
976 let end = start + line.len();
977 start..end
978 });
979 let mut maybe_line = lines_iter.next();
980 let line_ending = LineEnding::default();
982
983 let mut line_count = 0;
984 let mut attrs_list = self
985 .lines
986 .get_mut(line_count)
987 .map_or_else(|| AttrsList::new(&Attrs::new()), BufferLine::reclaim_attrs)
988 .reset(default_attrs);
989 let mut line_string = self
990 .lines
991 .get_mut(line_count)
992 .map(BufferLine::reclaim_text)
993 .unwrap_or_default();
994
995 loop {
996 let (Some(line_range), Some((attrs, span_range))) = (&maybe_line, &maybe_span) else {
997 if self.lines.len() == line_count {
999 self.lines.push(BufferLine::empty());
1000 }
1001 self.lines[line_count].reset_new(
1002 String::new(),
1003 line_ending,
1004 AttrsList::new(default_attrs),
1005 shaping,
1006 );
1007 line_count += 1;
1008 break;
1009 };
1010
1011 let start = line_range.start.max(span_range.start);
1013 let end = line_range.end.min(span_range.end);
1014 if start < end {
1015 let text = &string[start..end];
1016 let text_start = line_string.len();
1017 line_string.push_str(text);
1018 let text_end = line_string.len();
1019 if *attrs != attrs_list.defaults() {
1021 attrs_list.add_span(text_start..text_end, attrs);
1022 }
1023 } else if line_string.is_empty() && attrs.metrics_opt.is_some() {
1024 attrs_list = attrs_list.reset(attrs);
1028 }
1029
1030 if span_range.end < line_range.end {
1036 maybe_span = spans_iter.next();
1037 } else {
1038 maybe_line = lines_iter.next();
1039 if maybe_line.is_some() {
1040 let next_attrs_list = self
1042 .lines
1043 .get_mut(line_count + 1)
1044 .map_or_else(|| AttrsList::new(&Attrs::new()), BufferLine::reclaim_attrs)
1045 .reset(default_attrs);
1046 let next_line_string = self
1047 .lines
1048 .get_mut(line_count + 1)
1049 .map(BufferLine::reclaim_text)
1050 .unwrap_or_default();
1051 let prev_attrs_list = core::mem::replace(&mut attrs_list, next_attrs_list);
1052 let prev_line_string = core::mem::replace(&mut line_string, next_line_string);
1053 if self.lines.len() == line_count {
1054 self.lines.push(BufferLine::empty());
1055 }
1056 self.lines[line_count].reset_new(
1057 prev_line_string,
1058 line_ending,
1059 prev_attrs_list,
1060 shaping,
1061 );
1062 line_count += 1;
1063 } else {
1064 if self.lines.len() == line_count {
1066 self.lines.push(BufferLine::empty());
1067 }
1068 self.lines[line_count].reset_new(line_string, line_ending, attrs_list, shaping);
1069 line_count += 1;
1070 break;
1071 }
1072 }
1073 }
1074
1075 self.lines.truncate(line_count);
1077
1078 self.lines.iter_mut().for_each(|line| {
1079 line.set_align(alignment);
1080 });
1081
1082 self.scroll = Scroll::default();
1083 }
1084
1085 pub fn set_rich_text<'r, 's, I>(
1103 &mut self,
1104 spans: I,
1105 default_attrs: &Attrs,
1106 shaping: Shaping,
1107 alignment: Option<Align>,
1108 ) where
1109 I: IntoIterator<Item = (&'s str, Attrs<'r>)>,
1110 {
1111 self.set_rich_text_impl(spans, default_attrs, shaping, alignment);
1112 self.dirty |= DirtyFlags::TEXT_SET;
1113 self.redraw = true;
1114 }
1115
1116 pub const fn redraw(&self) -> bool {
1118 self.redraw
1119 }
1120
1121 pub fn set_redraw(&mut self, redraw: bool) {
1123 self.redraw = redraw;
1124 }
1125
1126 pub fn layout_runs(&self) -> LayoutRunIter<'_> {
1135 LayoutRunIter::new(self)
1136 }
1137
1138 pub fn hit(&self, x: f32, y: f32) -> Option<Cursor> {
1145 #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
1146 let instant = std::time::Instant::now();
1147
1148 let mut new_cursor_opt = None;
1149
1150 let mut runs = self.layout_runs().peekable();
1151 let mut first_run = true;
1152 while let Some(run) = runs.next() {
1153 let line_top = run.line_top;
1154 let line_height = run.line_height;
1155
1156 if first_run && y < line_top {
1157 first_run = false;
1158 let new_cursor = Cursor::new(run.line_i, 0);
1159 new_cursor_opt = Some(new_cursor);
1160 } else if y >= line_top && y < line_top + line_height {
1161 let mut new_cursor_glyph = run.glyphs.len();
1162 let mut new_cursor_char = 0;
1163 let mut new_cursor_affinity = Affinity::After;
1164
1165 let mut first_glyph = true;
1166
1167 'hit: for (glyph_i, glyph) in run.glyphs.iter().enumerate() {
1168 if first_glyph {
1169 first_glyph = false;
1170 if (run.rtl && x > glyph.x) || (!run.rtl && x < 0.0) {
1171 new_cursor_glyph = 0;
1172 new_cursor_char = 0;
1173 }
1174 }
1175 if x >= glyph.x && x <= glyph.x + glyph.w {
1176 new_cursor_glyph = glyph_i;
1177
1178 let cluster = &run.text[glyph.start..glyph.end];
1179 let total = cluster.grapheme_indices(true).count();
1180 let mut egc_x = glyph.x;
1181 let egc_w = glyph.w / (total as f32);
1182 for (egc_i, egc) in cluster.grapheme_indices(true) {
1183 if x >= egc_x && x <= egc_x + egc_w {
1184 new_cursor_char = egc_i;
1185
1186 let right_half = x >= egc_x + egc_w / 2.0;
1187 if right_half != glyph.level.is_rtl() {
1188 new_cursor_char += egc.len();
1190 new_cursor_affinity = Affinity::Before;
1191 }
1192 break 'hit;
1193 }
1194 egc_x += egc_w;
1195 }
1196
1197 let right_half = x >= glyph.x + glyph.w / 2.0;
1198 if right_half != glyph.level.is_rtl() {
1199 new_cursor_char = cluster.len();
1201 new_cursor_affinity = Affinity::Before;
1202 }
1203 break 'hit;
1204 }
1205 }
1206
1207 let mut new_cursor = Cursor::new(run.line_i, 0);
1208
1209 match run.glyphs.get(new_cursor_glyph) {
1210 Some(glyph) => {
1211 new_cursor.index = glyph.start + new_cursor_char;
1213 new_cursor.affinity = new_cursor_affinity;
1214 }
1215 None => {
1216 let run_end = run.glyphs.iter().map(|g| g.end).max().unwrap_or(0);
1221 new_cursor.index = run_end;
1222 new_cursor.affinity = Affinity::Before;
1223 }
1224 }
1225
1226 new_cursor_opt = Some(new_cursor);
1227
1228 break;
1229 } else if runs.peek().is_none() && y > run.line_y {
1230 let new_cursor =
1233 Cursor::new_with_affinity(run.line_i, run.text.len(), Affinity::Before);
1234 new_cursor_opt = Some(new_cursor);
1235 }
1236 }
1237
1238 #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
1239 log::trace!("click({}, {}): {:?}", x, y, instant.elapsed());
1240
1241 new_cursor_opt
1242 }
1243
1244 pub fn cursor_position(&self, cursor: &Cursor) -> Option<(f32, f32)> {
1248 self.layout_runs()
1249 .filter(|run| run.line_i == cursor.line)
1250 .find_map(|run| run.cursor_position(cursor).map(|x| (x, run.line_top)))
1251 }
1252
1253 pub fn is_rtl(&self, line: usize) -> Option<bool> {
1256 self.lines.get(line)?.shape_opt().map(|shape| shape.rtl)
1257 }
1258
1259 pub fn cursor_motion(
1261 &mut self,
1262 font_system: &mut FontSystem,
1263 mut cursor: Cursor,
1264 mut cursor_x_opt: Option<i32>,
1265 motion: Motion,
1266 ) -> Option<(Cursor, Option<i32>)> {
1267 match motion {
1268 Motion::LayoutCursor(layout_cursor) => {
1269 let layout = self.line_layout(font_system, layout_cursor.line)?;
1270
1271 let layout_line = match layout.get(layout_cursor.layout) {
1272 Some(some) => some,
1273 None => match layout.last() {
1274 Some(some) => some,
1275 None => {
1276 return None;
1277 }
1278 },
1279 };
1280
1281 let (new_index, new_affinity) =
1282 layout_line.glyphs.get(layout_cursor.glyph).map_or_else(
1283 || {
1284 layout_line
1285 .glyphs
1286 .last()
1287 .map_or((0, Affinity::After), |glyph| (glyph.end, Affinity::Before))
1288 },
1289 |glyph| (glyph.start, Affinity::After),
1290 );
1291
1292 if cursor.line != layout_cursor.line
1293 || cursor.index != new_index
1294 || cursor.affinity != new_affinity
1295 {
1296 cursor.line = layout_cursor.line;
1297 cursor.index = new_index;
1298 cursor.affinity = new_affinity;
1299 }
1300 }
1301 Motion::Previous => {
1302 let line = self.lines.get(cursor.line)?;
1303 if cursor.index > 0 {
1304 let mut prev_index = 0;
1306 for (i, _) in line.text().grapheme_indices(true) {
1307 if i < cursor.index {
1308 prev_index = i;
1309 } else {
1310 break;
1311 }
1312 }
1313
1314 cursor.index = prev_index;
1315 cursor.affinity = Affinity::After;
1316 } else if cursor.line > 0 {
1317 cursor.line -= 1;
1318 cursor.index = self.lines.get(cursor.line)?.text().len();
1319 cursor.affinity = Affinity::After;
1320 }
1321 cursor_x_opt = None;
1322 }
1323 Motion::Next => {
1324 let line = self.lines.get(cursor.line)?;
1325 if cursor.index < line.text().len() {
1326 for (i, c) in line.text().grapheme_indices(true) {
1327 if i == cursor.index {
1328 cursor.index += c.len();
1329 cursor.affinity = Affinity::Before;
1330 break;
1331 }
1332 }
1333 } else if cursor.line + 1 < self.lines.len() {
1334 cursor.line += 1;
1335 cursor.index = 0;
1336 cursor.affinity = Affinity::Before;
1337 }
1338 cursor_x_opt = None;
1339 }
1340 Motion::Left => {
1341 let rtl_opt = self
1342 .line_shape(font_system, cursor.line)
1343 .map(|shape| shape.rtl);
1344 if let Some(rtl) = rtl_opt {
1345 if rtl {
1346 (cursor, cursor_x_opt) =
1347 self.cursor_motion(font_system, cursor, cursor_x_opt, Motion::Next)?;
1348 } else {
1349 (cursor, cursor_x_opt) = self.cursor_motion(
1350 font_system,
1351 cursor,
1352 cursor_x_opt,
1353 Motion::Previous,
1354 )?;
1355 }
1356 }
1357 }
1358 Motion::Right => {
1359 let rtl_opt = self
1360 .line_shape(font_system, cursor.line)
1361 .map(|shape| shape.rtl);
1362 if let Some(rtl) = rtl_opt {
1363 if rtl {
1364 (cursor, cursor_x_opt) = self.cursor_motion(
1365 font_system,
1366 cursor,
1367 cursor_x_opt,
1368 Motion::Previous,
1369 )?;
1370 } else {
1371 (cursor, cursor_x_opt) =
1372 self.cursor_motion(font_system, cursor, cursor_x_opt, Motion::Next)?;
1373 }
1374 }
1375 }
1376 Motion::Up => {
1377 let mut layout_cursor = self.layout_cursor(font_system, cursor)?;
1378
1379 if cursor_x_opt.is_none() {
1380 cursor_x_opt = Some(
1381 layout_cursor.glyph as i32, );
1383 }
1384
1385 if layout_cursor.layout > 0 {
1386 layout_cursor.layout -= 1;
1387 } else if layout_cursor.line > 0 {
1388 layout_cursor.line -= 1;
1389 layout_cursor.layout = usize::MAX;
1390 }
1391
1392 if let Some(cursor_x) = cursor_x_opt {
1393 layout_cursor.glyph = cursor_x as usize; }
1395
1396 (cursor, cursor_x_opt) = self.cursor_motion(
1397 font_system,
1398 cursor,
1399 cursor_x_opt,
1400 Motion::LayoutCursor(layout_cursor),
1401 )?;
1402 }
1403 Motion::Down => {
1404 let mut layout_cursor = self.layout_cursor(font_system, cursor)?;
1405
1406 let layout_len = self.line_layout(font_system, layout_cursor.line)?.len();
1407
1408 if cursor_x_opt.is_none() {
1409 cursor_x_opt = Some(
1410 layout_cursor.glyph as i32, );
1412 }
1413
1414 if layout_cursor.layout + 1 < layout_len {
1415 layout_cursor.layout += 1;
1416 } else if layout_cursor.line + 1 < self.lines.len() {
1417 layout_cursor.line += 1;
1418 layout_cursor.layout = 0;
1419 }
1420
1421 if let Some(cursor_x) = cursor_x_opt {
1422 layout_cursor.glyph = cursor_x as usize; }
1424
1425 (cursor, cursor_x_opt) = self.cursor_motion(
1426 font_system,
1427 cursor,
1428 cursor_x_opt,
1429 Motion::LayoutCursor(layout_cursor),
1430 )?;
1431 }
1432 Motion::Home => {
1433 cursor.index = 0;
1434 cursor_x_opt = None;
1435 }
1436 Motion::SoftHome => {
1437 let line = self.lines.get(cursor.line)?;
1438 cursor.index = line
1439 .text()
1440 .char_indices()
1441 .find_map(|(i, c)| if c.is_whitespace() { None } else { Some(i) })
1442 .unwrap_or(0);
1443 cursor_x_opt = None;
1444 }
1445 Motion::End => {
1446 let line = self.lines.get(cursor.line)?;
1447 cursor.index = line.text().len();
1448 cursor_x_opt = None;
1449 }
1450 Motion::ParagraphStart => {
1451 cursor.index = 0;
1452 cursor_x_opt = None;
1453 }
1454 Motion::ParagraphEnd => {
1455 cursor.index = self.lines.get(cursor.line)?.text().len();
1456 cursor_x_opt = None;
1457 }
1458 Motion::PageUp => {
1459 if let Some(height) = self.height_opt {
1460 (cursor, cursor_x_opt) = self.cursor_motion(
1461 font_system,
1462 cursor,
1463 cursor_x_opt,
1464 Motion::Vertical(-height as i32),
1465 )?;
1466 }
1467 }
1468 Motion::PageDown => {
1469 if let Some(height) = self.height_opt {
1470 (cursor, cursor_x_opt) = self.cursor_motion(
1471 font_system,
1472 cursor,
1473 cursor_x_opt,
1474 Motion::Vertical(height as i32),
1475 )?;
1476 }
1477 }
1478 Motion::Vertical(px) => {
1479 let lines = px / self.metrics().line_height as i32;
1481 match lines.cmp(&0) {
1482 cmp::Ordering::Less => {
1483 for _ in 0..-lines {
1484 (cursor, cursor_x_opt) =
1485 self.cursor_motion(font_system, cursor, cursor_x_opt, Motion::Up)?;
1486 }
1487 }
1488 cmp::Ordering::Greater => {
1489 for _ in 0..lines {
1490 (cursor, cursor_x_opt) = self.cursor_motion(
1491 font_system,
1492 cursor,
1493 cursor_x_opt,
1494 Motion::Down,
1495 )?;
1496 }
1497 }
1498 cmp::Ordering::Equal => {}
1499 }
1500 }
1501 Motion::PreviousWord => {
1502 let line = self.lines.get(cursor.line)?;
1503 if cursor.index > 0 {
1504 cursor.index = line
1505 .text()
1506 .unicode_word_indices()
1507 .rev()
1508 .map(|(i, _)| i)
1509 .find(|&i| i < cursor.index)
1510 .unwrap_or(0);
1511 } else if cursor.line > 0 {
1512 cursor.line -= 1;
1513 cursor.index = self.lines.get(cursor.line)?.text().len();
1514 }
1515 cursor_x_opt = None;
1516 }
1517 Motion::NextWord => {
1518 let line = self.lines.get(cursor.line)?;
1519 if cursor.index < line.text().len() {
1520 cursor.index = line
1521 .text()
1522 .unicode_word_indices()
1523 .map(|(i, word)| i + word.len())
1524 .find(|&i| i > cursor.index)
1525 .unwrap_or_else(|| line.text().len());
1526 } else if cursor.line + 1 < self.lines.len() {
1527 cursor.line += 1;
1528 cursor.index = 0;
1529 }
1530 cursor_x_opt = None;
1531 }
1532 Motion::LeftWord => {
1533 let rtl_opt = self
1534 .line_shape(font_system, cursor.line)
1535 .map(|shape| shape.rtl);
1536 if let Some(rtl) = rtl_opt {
1537 if rtl {
1538 (cursor, cursor_x_opt) = self.cursor_motion(
1539 font_system,
1540 cursor,
1541 cursor_x_opt,
1542 Motion::NextWord,
1543 )?;
1544 } else {
1545 (cursor, cursor_x_opt) = self.cursor_motion(
1546 font_system,
1547 cursor,
1548 cursor_x_opt,
1549 Motion::PreviousWord,
1550 )?;
1551 }
1552 }
1553 }
1554 Motion::RightWord => {
1555 let rtl_opt = self
1556 .line_shape(font_system, cursor.line)
1557 .map(|shape| shape.rtl);
1558 if let Some(rtl) = rtl_opt {
1559 if rtl {
1560 (cursor, cursor_x_opt) = self.cursor_motion(
1561 font_system,
1562 cursor,
1563 cursor_x_opt,
1564 Motion::PreviousWord,
1565 )?;
1566 } else {
1567 (cursor, cursor_x_opt) = self.cursor_motion(
1568 font_system,
1569 cursor,
1570 cursor_x_opt,
1571 Motion::NextWord,
1572 )?;
1573 }
1574 }
1575 }
1576 Motion::BufferStart => {
1577 cursor.line = 0;
1578 cursor.index = 0;
1579 cursor_x_opt = None;
1580 }
1581 Motion::BufferEnd => {
1582 cursor.line = self.lines.len().saturating_sub(1);
1583 cursor.index = self.lines.get(cursor.line)?.text().len();
1584 cursor_x_opt = None;
1585 }
1586 Motion::GotoLine(line) => {
1587 let mut layout_cursor = self.layout_cursor(font_system, cursor)?;
1588 layout_cursor.line = line;
1589 (cursor, cursor_x_opt) = self.cursor_motion(
1590 font_system,
1591 cursor,
1592 cursor_x_opt,
1593 Motion::LayoutCursor(layout_cursor),
1594 )?;
1595 }
1596 }
1597 Some((cursor, cursor_x_opt))
1598 }
1599
1600 #[cfg(feature = "swash")]
1604 pub fn draw<F>(
1605 &mut self,
1606 font_system: &mut FontSystem,
1607 cache: &mut crate::SwashCache,
1608 color: Color,
1609 callback: F,
1610 ) where
1611 F: FnMut(i32, i32, u32, u32, Color),
1612 {
1613 self.shape_until_scroll(font_system, false);
1614 let mut renderer = crate::LegacyRenderer {
1615 font_system,
1616 cache,
1617 callback,
1618 };
1619 for run in self.layout_runs() {
1620 for glyph in run.glyphs {
1621 let physical_glyph = glyph.physical((0., run.line_y), 1.0);
1622 let glyph_color = glyph.color_opt.map_or(color, |some| some);
1623 renderer.glyph(physical_glyph, glyph_color);
1624 }
1625 render_decoration(&mut renderer, &run, color);
1626 }
1627 }
1628
1629 pub fn render<R: Renderer>(
1633 &mut self,
1634 font_system: &mut FontSystem,
1635 renderer: &mut R,
1636 color: Color,
1637 ) {
1638 self.shape_until_scroll(font_system, false);
1639 for run in self.layout_runs() {
1640 for glyph in run.glyphs {
1641 let physical_glyph = glyph.physical((0., run.line_y), 1.0);
1642 let glyph_color = glyph.color_opt.map_or(color, |some| some);
1643 renderer.glyph(physical_glyph, glyph_color);
1644 }
1645 render_decoration(renderer, &run, color);
1647 }
1648 }
1649}
1650
1651impl BorrowedWithFontSystem<'_, Buffer> {
1652 pub fn shape_until_cursor(&mut self, cursor: Cursor, prune: bool) {
1654 self.inner
1655 .shape_until_cursor(self.font_system, cursor, prune);
1656 }
1657
1658 pub fn line_shape(&mut self, line_i: usize) -> Option<&ShapeLine> {
1660 self.inner.line_shape(self.font_system, line_i)
1661 }
1662
1663 pub fn line_layout(&mut self, line_i: usize) -> Option<&[LayoutLine]> {
1665 self.inner.line_layout(self.font_system, line_i)
1666 }
1667
1668 pub fn set_metrics(&mut self, metrics: Metrics) {
1674 self.inner.set_metrics(metrics);
1675 }
1676
1677 pub fn set_hinting(&mut self, hinting: Hinting) {
1679 self.inner.set_hinting(hinting);
1680 }
1681
1682 pub fn set_wrap(&mut self, wrap: Wrap) {
1684 self.inner.set_wrap(wrap);
1685 }
1686
1687 pub fn set_ellipsize(&mut self, ellipsize: Ellipsize) {
1689 self.inner.set_ellipsize(ellipsize);
1690 }
1691
1692 pub fn set_size(&mut self, width_opt: Option<f32>, height_opt: Option<f32>) {
1694 self.inner.set_size(width_opt, height_opt);
1695 }
1696
1697 pub fn set_metrics_and_size(
1703 &mut self,
1704 metrics: Metrics,
1705 width_opt: Option<f32>,
1706 height_opt: Option<f32>,
1707 ) {
1708 self.inner
1709 .set_metrics_and_size(metrics, width_opt, height_opt);
1710 }
1711
1712 pub fn set_tab_width(&mut self, tab_width: u16) {
1716 self.inner.set_tab_width(tab_width);
1717 }
1718
1719 pub fn set_monospace_width(&mut self, monospace_width: Option<f32>) {
1721 self.inner.set_monospace_width(monospace_width);
1722 }
1723
1724 pub fn set_text(
1726 &mut self,
1727 text: &str,
1728 attrs: &Attrs,
1729 shaping: Shaping,
1730 alignment: Option<Align>,
1731 ) {
1732 self.inner.set_text(text, attrs, shaping, alignment);
1733 }
1734
1735 pub fn set_rich_text<'r, 's, I>(
1737 &mut self,
1738 spans: I,
1739 default_attrs: &Attrs,
1740 shaping: Shaping,
1741 alignment: Option<Align>,
1742 ) where
1743 I: IntoIterator<Item = (&'s str, Attrs<'r>)>,
1744 {
1745 self.inner
1746 .set_rich_text(spans, default_attrs, shaping, alignment);
1747 }
1748
1749 pub fn shape_until_scroll(&mut self, prune: bool) {
1753 self.inner.shape_until_scroll(self.font_system, prune);
1754 }
1755
1756 pub fn layout_runs(&mut self) -> LayoutRunIter<'_> {
1760 self.inner.shape_until_scroll(self.font_system, false);
1761 self.inner.layout_runs()
1762 }
1763
1764 pub fn hit(&mut self, x: f32, y: f32) -> Option<Cursor> {
1768 self.inner.shape_until_scroll(self.font_system, false);
1769 self.inner.hit(x, y)
1770 }
1771
1772 pub fn cursor_motion(
1774 &mut self,
1775 cursor: Cursor,
1776 cursor_x_opt: Option<i32>,
1777 motion: Motion,
1778 ) -> Option<(Cursor, Option<i32>)> {
1779 self.inner
1780 .cursor_motion(self.font_system, cursor, cursor_x_opt, motion)
1781 }
1782
1783 #[cfg(feature = "swash")]
1787 pub fn draw<F>(&mut self, cache: &mut crate::SwashCache, color: Color, f: F)
1788 where
1789 F: FnMut(i32, i32, u32, u32, Color),
1790 {
1791 self.inner.draw(self.font_system, cache, color, f);
1792 }
1793}