1#[cfg(not(feature = "std"))]
4use alloc::{string::String, vec::Vec};
5use core::{cmp, fmt};
6use itertools::Itertools;
7use unicode_segmentation::UnicodeSegmentation;
8
9use crate::{
10 Affinity, Attrs, AttrsList, BidiParagraphs, BorrowedWithFontSystem, BufferLine, Color, Cursor,
11 FontSystem, LayoutCursor, LayoutGlyph, LayoutLine, Motion, Scroll, ShapeBuffer, ShapeLine,
12 Shaping, Wrap,
13};
14
15#[derive(Debug)]
17pub struct LayoutRun<'a> {
18 pub line_i: usize,
20 pub text: &'a str,
22 pub rtl: bool,
24 pub glyphs: &'a [LayoutGlyph],
26 pub line_y: f32,
28 pub line_top: f32,
30 pub line_w: f32,
32}
33
34impl<'a> LayoutRun<'a> {
35 pub fn highlight(&self, cursor_start: Cursor, cursor_end: Cursor) -> Option<(f32, f32)> {
40 let mut x_start = None;
41 let mut x_end = None;
42 let rtl_factor = if self.rtl { 1. } else { 0. };
43 let ltr_factor = 1. - rtl_factor;
44 for glyph in self.glyphs.iter() {
45 let cursor = self.cursor_from_glyph_left(glyph);
46 if cursor >= cursor_start && cursor <= cursor_end {
47 if x_start.is_none() {
48 x_start = Some(glyph.x + glyph.w * rtl_factor);
49 }
50 x_end = Some(glyph.x + glyph.w * rtl_factor);
51 }
52 let cursor = self.cursor_from_glyph_right(glyph);
53 if cursor >= cursor_start && cursor <= cursor_end {
54 if x_start.is_none() {
55 x_start = Some(glyph.x + glyph.w * ltr_factor);
56 }
57 x_end = Some(glyph.x + glyph.w * ltr_factor);
58 }
59 }
60 if let Some(x_start) = x_start {
61 let x_end = x_end.expect("end of cursor not found");
62 let (x_start, x_end) = if x_start < x_end {
63 (x_start, x_end)
64 } else {
65 (x_end, x_start)
66 };
67 Some((x_start, x_end - x_start))
68 } else {
69 None
70 }
71 }
72
73 fn cursor_from_glyph_left(&self, glyph: &LayoutGlyph) -> Cursor {
74 if self.rtl {
75 Cursor::new_with_affinity(self.line_i, glyph.end, Affinity::Before)
76 } else {
77 Cursor::new_with_affinity(self.line_i, glyph.start, Affinity::After)
78 }
79 }
80
81 fn cursor_from_glyph_right(&self, glyph: &LayoutGlyph) -> Cursor {
82 if self.rtl {
83 Cursor::new_with_affinity(self.line_i, glyph.start, Affinity::After)
84 } else {
85 Cursor::new_with_affinity(self.line_i, glyph.end, Affinity::Before)
86 }
87 }
88}
89
90#[derive(Debug)]
92pub struct LayoutRunIter<'b> {
93 buffer: &'b Buffer,
94 line_i: usize,
95 layout_i: usize,
96 remaining_len: usize,
97 total_layout: i32,
98}
99
100impl<'b> LayoutRunIter<'b> {
101 pub fn new(buffer: &'b Buffer) -> Self {
102 let total_layout_lines: usize = buffer
103 .lines
104 .iter()
105 .skip(buffer.scroll.line)
106 .map(|line| {
107 line.layout_opt()
108 .as_ref()
109 .map(|layout| layout.len())
110 .unwrap_or_default()
111 })
112 .sum();
113 let top_cropped_layout_lines =
114 total_layout_lines.saturating_sub(buffer.scroll.layout.try_into().unwrap_or_default());
115 let maximum_lines = if buffer.metrics.line_height == 0.0 {
116 0
117 } else {
118 (buffer.height / buffer.metrics.line_height) as i32
119 };
120 let bottom_cropped_layout_lines =
121 if top_cropped_layout_lines > maximum_lines.try_into().unwrap_or_default() {
122 maximum_lines.try_into().unwrap_or_default()
123 } else {
124 top_cropped_layout_lines
125 };
126
127 Self {
128 buffer,
129 line_i: buffer.scroll.line,
130 layout_i: 0,
131 remaining_len: bottom_cropped_layout_lines,
132 total_layout: 0,
133 }
134 }
135}
136
137impl<'b> Iterator for LayoutRunIter<'b> {
138 type Item = LayoutRun<'b>;
139
140 fn size_hint(&self) -> (usize, Option<usize>) {
141 (self.remaining_len, Some(self.remaining_len))
142 }
143
144 fn next(&mut self) -> Option<Self::Item> {
145 while let Some(line) = self.buffer.lines.get(self.line_i) {
146 let shape = line.shape_opt().as_ref()?;
147 let layout = line.layout_opt().as_ref()?;
148 while let Some(layout_line) = layout.get(self.layout_i) {
149 self.layout_i += 1;
150
151 let scrolled = self.total_layout < self.buffer.scroll.layout;
152 self.total_layout += 1;
153 if scrolled {
154 continue;
155 }
156
157 let line_top = self
158 .total_layout
159 .saturating_sub(self.buffer.scroll.layout)
160 .saturating_sub(1) as f32
161 * self.buffer.metrics.line_height;
162 let glyph_height = layout_line.max_ascent + layout_line.max_descent;
163 let centering_offset = (self.buffer.metrics.line_height - glyph_height) / 2.0;
164 let line_y = line_top + centering_offset + layout_line.max_ascent;
165
166 if line_top + centering_offset > self.buffer.height {
167 return None;
168 }
169
170 return self.remaining_len.checked_sub(1).map(|num| {
171 self.remaining_len = num;
172 LayoutRun {
173 line_i: self.line_i,
174 text: line.text(),
175 rtl: shape.rtl,
176 glyphs: &layout_line.glyphs,
177 line_y,
178 line_top,
179 line_w: layout_line.w,
180 }
181 });
182 }
183 self.line_i += 1;
184 self.layout_i = 0;
185 }
186
187 None
188 }
189}
190
191impl<'b> ExactSizeIterator for LayoutRunIter<'b> {}
192
193#[derive(Clone, Copy, Debug, Default, PartialEq)]
195pub struct Metrics {
196 pub font_size: f32,
198 pub line_height: f32,
200}
201
202impl Metrics {
203 pub const fn new(font_size: f32, line_height: f32) -> Self {
204 Self {
205 font_size,
206 line_height,
207 }
208 }
209
210 pub fn scale(self, scale: f32) -> Self {
211 Self {
212 font_size: self.font_size * scale,
213 line_height: self.line_height * scale,
214 }
215 }
216}
217
218impl fmt::Display for Metrics {
219 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220 write!(f, "{}px / {}px", self.font_size, self.line_height)
221 }
222}
223
224#[derive(Debug)]
226pub struct Buffer {
227 pub lines: Vec<BufferLine>,
229 metrics: Metrics,
230 width: f32,
231 height: f32,
232 scroll: Scroll,
233 redraw: bool,
235 wrap: Wrap,
236 monospace_width: Option<f32>,
237
238 scratch: ShapeBuffer,
240}
241
242impl Clone for Buffer {
243 fn clone(&self) -> Self {
244 Self {
245 lines: self.lines.clone(),
246 metrics: self.metrics,
247 width: self.width,
248 height: self.height,
249 scroll: self.scroll,
250 redraw: self.redraw,
251 wrap: self.wrap,
252 monospace_width: self.monospace_width,
253 scratch: ShapeBuffer::default(),
254 }
255 }
256}
257
258impl Buffer {
259 pub fn new_empty(metrics: Metrics) -> Self {
271 assert_ne!(metrics.line_height, 0.0, "line height cannot be 0");
272 Self {
273 lines: Vec::new(),
274 metrics,
275 width: 0.0,
276 height: 0.0,
277 scroll: Scroll::default(),
278 redraw: false,
279 wrap: Wrap::WordOrGlyph,
280 scratch: ShapeBuffer::default(),
281 monospace_width: None,
282 }
283 }
284
285 pub fn new(font_system: &mut FontSystem, metrics: Metrics) -> Self {
291 let mut buffer = Self::new_empty(metrics);
292 buffer.set_text(font_system, "", Attrs::new(), Shaping::Advanced);
293 buffer
294 }
295
296 pub fn borrow_with<'a>(
298 &'a mut self,
299 font_system: &'a mut FontSystem,
300 ) -> BorrowedWithFontSystem<'a, Buffer> {
301 BorrowedWithFontSystem {
302 inner: self,
303 font_system,
304 }
305 }
306
307 fn relayout(&mut self, font_system: &mut FontSystem) {
308 #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
309 let instant = std::time::Instant::now();
310
311 for line in &mut self.lines {
312 if line.shape_opt().is_some() {
313 line.reset_layout();
314 line.layout_in_buffer(
315 &mut self.scratch,
316 font_system,
317 self.metrics.font_size,
318 self.width,
319 self.wrap,
320 self.monospace_width,
321 );
322 }
323 }
324
325 self.redraw = true;
326
327 #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
328 log::debug!("relayout: {:?}", instant.elapsed());
329 }
330
331 pub fn shape_until_cursor(
333 &mut self,
334 font_system: &mut FontSystem,
335 cursor: Cursor,
336 prune: bool,
337 ) {
338 let old_scroll = self.scroll;
339
340 let layout_cursor = self
341 .layout_cursor(font_system, cursor)
342 .expect("shape_until_cursor invalid cursor");
343
344 if self.scroll.line > layout_cursor.line
345 || (self.scroll.line == layout_cursor.line
346 && self.scroll.layout > layout_cursor.layout as i32)
347 {
348 self.scroll.line = layout_cursor.line;
350 self.scroll.layout = layout_cursor.layout as i32;
351 } else {
352 let visible_lines = self.visible_lines();
354 let mut line_i = layout_cursor.line;
355 let mut total_layout = layout_cursor.layout as i32 + 1;
356 while line_i > self.scroll.line {
357 line_i -= 1;
358 let layout = self
359 .line_layout(font_system, line_i)
360 .expect("shape_until_cursor failed to scroll forwards");
361 for layout_i in (0..layout.len()).rev() {
362 total_layout += 1;
363 if total_layout >= visible_lines {
364 self.scroll.line = line_i;
365 self.scroll.layout = layout_i as i32;
366 break;
367 }
368 }
369 }
370 }
371
372 if old_scroll != self.scroll {
373 self.redraw = true;
374 }
375
376 self.shape_until_scroll(font_system, prune);
377 }
378
379 pub fn shape_until_scroll(&mut self, font_system: &mut FontSystem, prune: bool) {
381 let old_scroll = self.scroll;
382
383 loop {
384 while self.scroll.layout < 0 {
386 if self.scroll.line > 0 {
387 self.scroll.line -= 1;
388 if let Some(layout) = self.line_layout(font_system, self.scroll.line) {
389 self.scroll.layout += layout.len() as i32;
390 }
391 } else {
392 self.scroll.layout = 0;
393 break;
394 }
395 }
396
397 let visible_lines = self.visible_lines();
398 let scroll_start = self.scroll.layout;
399 let scroll_end = scroll_start + visible_lines;
400
401 let mut total_layout = 0;
402 for line_i in 0..self.lines.len() {
403 if line_i < self.scroll.line {
404 if prune {
405 self.lines[line_i].reset_shaping();
406 }
407 continue;
408 }
409 if total_layout >= scroll_end {
410 if prune {
411 self.lines[line_i].reset_shaping();
412 continue;
413 } else {
414 break;
415 }
416 }
417
418 let layout = self
419 .line_layout(font_system, line_i)
420 .expect("shape_until_scroll invalid line");
421 for layout_i in 0..layout.len() {
422 if total_layout == scroll_start {
423 self.scroll.line = line_i;
425 self.scroll.layout = layout_i as i32;
426 }
427 total_layout += 1;
428 }
429 }
430
431 if total_layout < scroll_end && self.scroll.line > 0 {
432 self.scroll.layout -= scroll_end - total_layout;
434 } else {
435 break;
437 }
438 }
439
440 if old_scroll != self.scroll {
441 self.redraw = true;
442 }
443 }
444
445 pub fn layout_cursor(
447 &mut self,
448 font_system: &mut FontSystem,
449 cursor: Cursor,
450 ) -> Option<LayoutCursor> {
451 let layout = self.line_layout(font_system, cursor.line)?;
452 for (layout_i, layout_line) in layout.iter().enumerate() {
453 for (glyph_i, glyph) in layout_line.glyphs.iter().enumerate() {
454 let cursor_end =
455 Cursor::new_with_affinity(cursor.line, glyph.end, Affinity::Before);
456 let cursor_start =
457 Cursor::new_with_affinity(cursor.line, glyph.start, Affinity::After);
458 let (cursor_left, cursor_right) = if glyph.level.is_ltr() {
459 (cursor_start, cursor_end)
460 } else {
461 (cursor_end, cursor_start)
462 };
463 if cursor == cursor_left {
464 return Some(LayoutCursor::new(cursor.line, layout_i, glyph_i));
465 }
466 if cursor == cursor_right {
467 return Some(LayoutCursor::new(cursor.line, layout_i, glyph_i + 1));
468 }
469 }
470 }
471
472 Some(LayoutCursor::new(cursor.line, 0, 0))
475 }
476
477 pub fn line_shape(
479 &mut self,
480 font_system: &mut FontSystem,
481 line_i: usize,
482 ) -> Option<&ShapeLine> {
483 let line = self.lines.get_mut(line_i)?;
484 Some(line.shape_in_buffer(&mut self.scratch, font_system))
485 }
486
487 pub fn line_layout(
489 &mut self,
490 font_system: &mut FontSystem,
491 line_i: usize,
492 ) -> Option<&[LayoutLine]> {
493 let line = self.lines.get_mut(line_i)?;
494 Some(line.layout_in_buffer(
495 &mut self.scratch,
496 font_system,
497 self.metrics.font_size,
498 self.width,
499 self.wrap,
500 self.monospace_width,
501 ))
502 }
503
504 pub fn metrics(&self) -> Metrics {
506 self.metrics
507 }
508
509 pub fn set_metrics(&mut self, font_system: &mut FontSystem, metrics: Metrics) {
515 self.set_metrics_and_size(font_system, metrics, self.width, self.height);
516 }
517
518 pub fn wrap(&self) -> Wrap {
520 self.wrap
521 }
522
523 pub fn set_wrap(&mut self, font_system: &mut FontSystem, wrap: Wrap) {
525 if wrap != self.wrap {
526 self.wrap = wrap;
527 self.relayout(font_system);
528 self.shape_until_scroll(font_system, false);
529 }
530 }
531
532 pub fn monospace_width(&self) -> Option<f32> {
534 self.monospace_width
535 }
536
537 pub fn set_monospace_width(
539 &mut self,
540 font_system: &mut FontSystem,
541 monospace_width: Option<f32>,
542 ) {
543 if monospace_width != self.monospace_width {
544 self.monospace_width = monospace_width;
545 self.relayout(font_system);
546 self.shape_until_scroll(font_system, false);
547 }
548 }
549
550 pub fn size(&self) -> (f32, f32) {
552 (self.width, self.height)
553 }
554
555 pub fn set_size(&mut self, font_system: &mut FontSystem, width: f32, height: f32) {
557 self.set_metrics_and_size(font_system, self.metrics, width, height);
558 }
559
560 pub fn set_metrics_and_size(
566 &mut self,
567 font_system: &mut FontSystem,
568 metrics: Metrics,
569 width: f32,
570 height: f32,
571 ) {
572 let clamped_width = width.max(0.0);
573 let clamped_height = height.max(0.0);
574
575 if metrics != self.metrics || clamped_width != self.width || clamped_height != self.height {
576 assert_ne!(metrics.font_size, 0.0, "font size cannot be 0");
577 self.metrics = metrics;
578 self.width = clamped_width;
579 self.height = clamped_height;
580 self.relayout(font_system);
581 self.shape_until_scroll(font_system, false);
582 }
583 }
584
585 pub fn scroll(&self) -> Scroll {
587 self.scroll
588 }
589
590 pub fn set_scroll(&mut self, scroll: Scroll) {
592 if scroll != self.scroll {
593 self.scroll = scroll;
594 self.redraw = true;
595 }
596 }
597
598 pub fn visible_lines(&self) -> i32 {
600 (self.height / self.metrics.line_height) as i32
601 }
602
603 pub fn set_text(
605 &mut self,
606 font_system: &mut FontSystem,
607 text: &str,
608 attrs: Attrs,
609 shaping: Shaping,
610 ) {
611 self.set_rich_text(font_system, [(text, attrs)], attrs, shaping);
612 }
613
614 pub fn set_rich_text<'r, 's, I>(
632 &mut self,
633 font_system: &mut FontSystem,
634 spans: I,
635 default_attrs: Attrs,
636 shaping: Shaping,
637 ) where
638 I: IntoIterator<Item = (&'s str, Attrs<'r>)>,
639 {
640 self.lines.clear();
641
642 let mut attrs_list = AttrsList::new(default_attrs);
643 let mut line_string = String::new();
644 let mut end = 0;
645 let (string, spans_data): (String, Vec<_>) = spans
646 .into_iter()
647 .map(|(s, attrs)| {
648 let start = end;
649 end += s.len();
650 (s, (attrs, start..end))
651 })
652 .unzip();
653
654 let mut spans_iter = spans_data.into_iter();
655 let mut maybe_span = spans_iter.next();
656
657 let string_start = string.as_ptr() as usize;
659 let mut lines_iter = BidiParagraphs::new(&string).map(|line: &str| {
660 let start = line.as_ptr() as usize - string_start;
661 let end = start + line.len();
662 start..end
663 });
664 let mut maybe_line = lines_iter.next();
665
666 loop {
667 let (Some(line_range), Some((attrs, span_range))) = (&maybe_line, &maybe_span) else {
668 self.lines.push(BufferLine::new(
670 String::new(),
671 AttrsList::new(default_attrs),
672 shaping,
673 ));
674 break;
675 };
676
677 let start = line_range.start.max(span_range.start);
679 let end = line_range.end.min(span_range.end);
680 if start < end {
681 let text = &string[start..end];
682 let text_start = line_string.len();
683 line_string.push_str(text);
684 let text_end = line_string.len();
685 if *attrs != attrs_list.defaults() {
687 attrs_list.add_span(text_start..text_end, *attrs);
688 }
689 }
690
691 if span_range.end < line_range.end {
697 maybe_span = spans_iter.next();
698 } else {
699 maybe_line = lines_iter.next();
700 if maybe_line.is_some() {
701 let prev_attrs_list =
703 core::mem::replace(&mut attrs_list, AttrsList::new(default_attrs));
704 let prev_line_string = core::mem::take(&mut line_string);
705 let buffer_line = BufferLine::new(prev_line_string, prev_attrs_list, shaping);
706 self.lines.push(buffer_line);
707 } else {
708 let buffer_line = BufferLine::new(line_string, attrs_list, shaping);
710 self.lines.push(buffer_line);
711 break;
712 }
713 }
714 }
715
716 self.scroll = Scroll::default();
717
718 self.shape_until_scroll(font_system, false);
719 }
720
721 pub fn text_without_preedit(&self) -> String {
723 self.lines
724 .iter()
725 .map(|line| line.text_without_preedit())
726 .join("\n")
727 }
728
729 pub fn redraw(&self) -> bool {
731 self.redraw
732 }
733
734 pub fn set_redraw(&mut self, redraw: bool) {
736 self.redraw = redraw;
737 }
738
739 pub fn layout_runs(&self) -> LayoutRunIter {
741 LayoutRunIter::new(self)
742 }
743
744 pub fn hit(&self, x: f32, y: f32) -> Option<Cursor> {
746 #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
747 let instant = std::time::Instant::now();
748
749 let font_size = self.metrics.font_size;
750 let line_height = self.metrics.line_height;
751
752 let mut new_cursor_opt = None;
753
754 let mut runs = self.layout_runs().peekable();
755 let mut first_run = true;
756 while let Some(run) = runs.next() {
757 let line_y = run.line_y;
758
759 if first_run && y < line_y - font_size {
760 first_run = false;
761 let new_cursor = Cursor::new(run.line_i, 0);
762 new_cursor_opt = Some(new_cursor);
763 } else if y >= line_y - font_size && y < line_y - font_size + line_height {
764 let mut new_cursor_glyph = run.glyphs.len();
765 let mut new_cursor_char = 0;
766 let mut new_cursor_affinity = Affinity::After;
767
768 let mut first_glyph = true;
769
770 'hit: for (glyph_i, glyph) in run.glyphs.iter().enumerate() {
771 if first_glyph {
772 first_glyph = false;
773 if (run.rtl && x > glyph.x) || (!run.rtl && x < 0.0) {
774 new_cursor_glyph = 0;
775 new_cursor_char = 0;
776 }
777 }
778 if x >= glyph.x && x <= glyph.x + glyph.w {
779 new_cursor_glyph = glyph_i;
780
781 let cluster = &run.text[glyph.start..glyph.end];
782 let total = cluster.grapheme_indices(true).count();
783 let mut egc_x = glyph.x;
784 let egc_w = glyph.w / (total as f32);
785 for (egc_i, egc) in cluster.grapheme_indices(true) {
786 if x >= egc_x && x <= egc_x + egc_w {
787 new_cursor_char = egc_i;
788
789 let right_half = x >= egc_x + egc_w / 2.0;
790 if right_half != glyph.level.is_rtl() {
791 new_cursor_char += egc.len();
793 new_cursor_affinity = Affinity::Before;
794 }
795 break 'hit;
796 }
797 egc_x += egc_w;
798 }
799
800 let right_half = x >= glyph.x + glyph.w / 2.0;
801 if right_half != glyph.level.is_rtl() {
802 new_cursor_char = cluster.len();
804 new_cursor_affinity = Affinity::Before;
805 }
806 break 'hit;
807 }
808 }
809
810 let mut new_cursor = Cursor::new(run.line_i, 0);
811
812 match run.glyphs.get(new_cursor_glyph) {
813 Some(glyph) => {
814 new_cursor.index = glyph.start + new_cursor_char;
816 new_cursor.affinity = new_cursor_affinity;
817 }
818 None => {
819 if let Some(glyph) = run.glyphs.last() {
820 new_cursor.index = glyph.end;
822 new_cursor.affinity = Affinity::Before;
823 }
824 }
825 }
826
827 new_cursor_opt = Some(new_cursor);
828
829 break;
830 } else if runs.peek().is_none() && y > run.line_y {
831 let mut new_cursor = Cursor::new(run.line_i, 0);
832 if let Some(glyph) = run.glyphs.last() {
833 new_cursor = run.cursor_from_glyph_right(glyph);
834 }
835 new_cursor_opt = Some(new_cursor);
836 }
837 }
838
839 #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
840 log::trace!("click({}, {}): {:?}", x, y, instant.elapsed());
841
842 new_cursor_opt
843 }
844
845 pub fn cursor_motion(
847 &mut self,
848 font_system: &mut FontSystem,
849 mut cursor: Cursor,
850 mut cursor_x_opt: Option<i32>,
851 motion: Motion,
852 ) -> Option<(Cursor, Option<i32>)> {
853 match motion {
854 Motion::LayoutCursor(layout_cursor) => {
855 let layout = self.line_layout(font_system, layout_cursor.line)?;
856
857 let layout_line = match layout.get(layout_cursor.layout) {
858 Some(some) => some,
859 None => match layout.last() {
860 Some(some) => some,
861 None => {
862 return None;
863 }
864 },
865 };
866
867 let (new_index, new_affinity) = match layout_line.glyphs.get(layout_cursor.glyph) {
868 Some(glyph) => (glyph.start, Affinity::After),
869 None => match layout_line.glyphs.last() {
870 Some(glyph) => (glyph.end, Affinity::Before),
871 None => (0, Affinity::After),
873 },
874 };
875
876 if cursor.line != layout_cursor.line
877 || cursor.index != new_index
878 || cursor.affinity != new_affinity
879 {
880 cursor.line = layout_cursor.line;
881 cursor.index = new_index;
882 cursor.affinity = new_affinity;
883 }
884 }
885 Motion::Previous => {
886 let line = self.lines.get(cursor.line)?;
887 if cursor.index > 0 {
888 let mut prev_index = 0;
890 for (i, _) in line.text().grapheme_indices(true) {
891 if i < cursor.index {
892 prev_index = i;
893 } else {
894 break;
895 }
896 }
897
898 cursor.index = prev_index;
899 cursor.affinity = Affinity::After;
900 } else if cursor.line > 0 {
901 cursor.line -= 1;
902 cursor.index = self.lines.get(cursor.line)?.text().len();
903 cursor.affinity = Affinity::After;
904 }
905 cursor_x_opt = None;
906 }
907 Motion::Next => {
908 let line = self.lines.get(cursor.line)?;
909 if cursor.index < line.text().len() {
910 for (i, c) in line.text().grapheme_indices(true) {
911 if i == cursor.index {
912 cursor.index += c.len();
913 cursor.affinity = Affinity::Before;
914 break;
915 }
916 }
917 } else if cursor.line + 1 < self.lines.len() {
918 cursor.line += 1;
919 cursor.index = 0;
920 cursor.affinity = Affinity::Before;
921 }
922 cursor_x_opt = None;
923 }
924 Motion::Left => {
925 let rtl_opt = self
926 .line_shape(font_system, cursor.line)
927 .map(|shape| shape.rtl);
928 if let Some(rtl) = rtl_opt {
929 if rtl {
930 (cursor, cursor_x_opt) =
931 self.cursor_motion(font_system, cursor, cursor_x_opt, Motion::Next)?;
932 } else {
933 (cursor, cursor_x_opt) = self.cursor_motion(
934 font_system,
935 cursor,
936 cursor_x_opt,
937 Motion::Previous,
938 )?;
939 }
940 }
941 }
942 Motion::Right => {
943 let rtl_opt = self
944 .line_shape(font_system, cursor.line)
945 .map(|shape| shape.rtl);
946 if let Some(rtl) = rtl_opt {
947 if rtl {
948 (cursor, cursor_x_opt) = self.cursor_motion(
949 font_system,
950 cursor,
951 cursor_x_opt,
952 Motion::Previous,
953 )?;
954 } else {
955 (cursor, cursor_x_opt) =
956 self.cursor_motion(font_system, cursor, cursor_x_opt, Motion::Next)?;
957 }
958 }
959 }
960 Motion::Up => {
961 let mut layout_cursor = self.layout_cursor(font_system, cursor)?;
962
963 if cursor_x_opt.is_none() {
964 cursor_x_opt = Some(
965 layout_cursor.glyph as i32, );
967 }
968
969 if layout_cursor.layout > 0 {
970 layout_cursor.layout -= 1;
971 } else if layout_cursor.line > 0 {
972 layout_cursor.line -= 1;
973 layout_cursor.layout = usize::max_value();
974 }
975
976 if let Some(cursor_x) = cursor_x_opt {
977 layout_cursor.glyph = cursor_x as usize; }
979
980 (cursor, cursor_x_opt) = self.cursor_motion(
981 font_system,
982 cursor,
983 cursor_x_opt,
984 Motion::LayoutCursor(layout_cursor),
985 )?;
986 }
987 Motion::Down => {
988 let mut layout_cursor = self.layout_cursor(font_system, cursor)?;
989
990 let layout_len = self.line_layout(font_system, layout_cursor.line)?.len();
991
992 if cursor_x_opt.is_none() {
993 cursor_x_opt = Some(
994 layout_cursor.glyph as i32, );
996 }
997
998 if layout_cursor.layout + 1 < layout_len {
999 layout_cursor.layout += 1;
1000 } else if layout_cursor.line + 1 < self.lines.len() {
1001 layout_cursor.line += 1;
1002 layout_cursor.layout = 0;
1003 }
1004
1005 if let Some(cursor_x) = cursor_x_opt {
1006 layout_cursor.glyph = cursor_x as usize; }
1008
1009 (cursor, cursor_x_opt) = self.cursor_motion(
1010 font_system,
1011 cursor,
1012 cursor_x_opt,
1013 Motion::LayoutCursor(layout_cursor),
1014 )?;
1015 }
1016 Motion::Home => {
1017 let mut layout_cursor = self.layout_cursor(font_system, cursor)?;
1018 layout_cursor.glyph = 0;
1019 #[allow(unused_assignments)]
1020 {
1021 (cursor, cursor_x_opt) = self.cursor_motion(
1022 font_system,
1023 cursor,
1024 cursor_x_opt,
1025 Motion::LayoutCursor(layout_cursor),
1026 )?;
1027 }
1028 cursor_x_opt = None;
1029 }
1030 Motion::SoftHome => {
1031 let line = self.lines.get(cursor.line)?;
1032 cursor.index = line
1033 .text()
1034 .char_indices()
1035 .filter_map(|(i, c)| if c.is_whitespace() { None } else { Some(i) })
1036 .next()
1037 .unwrap_or(0);
1038 cursor_x_opt = None;
1039 }
1040 Motion::End => {
1041 let mut layout_cursor = self.layout_cursor(font_system, cursor)?;
1042 layout_cursor.glyph = usize::max_value();
1043 #[allow(unused_assignments)]
1044 {
1045 (cursor, cursor_x_opt) = self.cursor_motion(
1046 font_system,
1047 cursor,
1048 cursor_x_opt,
1049 Motion::LayoutCursor(layout_cursor),
1050 )?;
1051 }
1052 cursor_x_opt = None;
1053 }
1054 Motion::ParagraphStart => {
1055 cursor.index = 0;
1056 cursor_x_opt = None;
1057 }
1058 Motion::ParagraphEnd => {
1059 cursor.index = self.lines.get(cursor.line)?.text().len();
1060 cursor_x_opt = None;
1061 }
1062 Motion::DocumentStart => {
1063 cursor.line = 0;
1064 cursor.index = 0;
1065 cursor_x_opt = None;
1066 }
1067 Motion::DocumentEnd => {
1068 cursor.line = self.lines.len() - 1;
1069 cursor.index = self.lines.get(cursor.line)?.text().len();
1070 cursor_x_opt = None;
1071 }
1072 Motion::PageUp => {
1073 (cursor, cursor_x_opt) = self.cursor_motion(
1074 font_system,
1075 cursor,
1076 cursor_x_opt,
1077 Motion::Vertical(-self.size().1 as i32),
1078 )?;
1079 }
1080 Motion::PageDown => {
1081 (cursor, cursor_x_opt) = self.cursor_motion(
1082 font_system,
1083 cursor,
1084 cursor_x_opt,
1085 Motion::Vertical(self.size().1 as i32),
1086 )?;
1087 }
1088 Motion::Vertical(px) => {
1089 let lines = px / self.metrics().line_height as i32;
1091 match lines.cmp(&0) {
1092 cmp::Ordering::Less => {
1093 for _ in 0..-lines {
1094 (cursor, cursor_x_opt) =
1095 self.cursor_motion(font_system, cursor, cursor_x_opt, Motion::Up)?;
1096 }
1097 }
1098 cmp::Ordering::Greater => {
1099 for _ in 0..lines {
1100 (cursor, cursor_x_opt) = self.cursor_motion(
1101 font_system,
1102 cursor,
1103 cursor_x_opt,
1104 Motion::Down,
1105 )?;
1106 }
1107 }
1108 cmp::Ordering::Equal => {}
1109 }
1110 }
1111 Motion::PreviousWord => {
1112 let line = self.lines.get(cursor.line)?;
1113 if cursor.index > 0 {
1114 cursor.index = line
1115 .text()
1116 .unicode_word_indices()
1117 .rev()
1118 .map(|(i, _)| i)
1119 .find(|&i| i < cursor.index)
1120 .unwrap_or(0);
1121 } else if cursor.line > 0 {
1122 cursor.line -= 1;
1123 cursor.index = self.lines.get(cursor.line)?.text().len();
1124 }
1125 cursor_x_opt = None;
1126 }
1127 Motion::NextWord => {
1128 let line = self.lines.get(cursor.line)?;
1129 if cursor.index < line.text().len() {
1130 cursor.index = line
1131 .text()
1132 .unicode_word_indices()
1133 .map(|(i, word)| i + word.len())
1134 .find(|&i| i > cursor.index)
1135 .unwrap_or(line.text().len());
1136 } else if cursor.line + 1 < self.lines.len() {
1137 cursor.line += 1;
1138 cursor.index = 0;
1139 }
1140 cursor_x_opt = None;
1141 }
1142 Motion::LeftWord => {
1143 let rtl_opt = self
1144 .line_shape(font_system, cursor.line)
1145 .map(|shape| shape.rtl);
1146 if let Some(rtl) = rtl_opt {
1147 if rtl {
1148 (cursor, cursor_x_opt) = self.cursor_motion(
1149 font_system,
1150 cursor,
1151 cursor_x_opt,
1152 Motion::NextWord,
1153 )?;
1154 } else {
1155 (cursor, cursor_x_opt) = self.cursor_motion(
1156 font_system,
1157 cursor,
1158 cursor_x_opt,
1159 Motion::PreviousWord,
1160 )?;
1161 }
1162 }
1163 }
1164 Motion::RightWord => {
1165 let rtl_opt = self
1166 .line_shape(font_system, cursor.line)
1167 .map(|shape| shape.rtl);
1168 if let Some(rtl) = rtl_opt {
1169 if rtl {
1170 (cursor, cursor_x_opt) = self.cursor_motion(
1171 font_system,
1172 cursor,
1173 cursor_x_opt,
1174 Motion::PreviousWord,
1175 )?;
1176 } else {
1177 (cursor, cursor_x_opt) = self.cursor_motion(
1178 font_system,
1179 cursor,
1180 cursor_x_opt,
1181 Motion::NextWord,
1182 )?;
1183 }
1184 }
1185 }
1186 Motion::BufferStart => {
1187 cursor.line = 0;
1188 cursor.index = 0;
1189 cursor_x_opt = None;
1190 }
1191 Motion::BufferEnd => {
1192 cursor.line = self.lines.len() - 1;
1193 cursor.index = self.lines.get(cursor.line)?.text().len();
1194 cursor_x_opt = None;
1195 }
1196 Motion::GotoLine(line) => {
1197 let mut layout_cursor = self.layout_cursor(font_system, cursor)?;
1198 layout_cursor.line = line;
1199 (cursor, cursor_x_opt) = self.cursor_motion(
1200 font_system,
1201 cursor,
1202 cursor_x_opt,
1203 Motion::LayoutCursor(layout_cursor),
1204 )?;
1205 }
1206 }
1207 Some((cursor, cursor_x_opt))
1208 }
1209
1210 #[cfg(feature = "swash")]
1212 pub fn draw<F>(
1213 &self,
1214 font_system: &mut FontSystem,
1215 cache: &mut crate::SwashCache,
1216 color: Color,
1217 mut f: F,
1218 ) where
1219 F: FnMut(i32, i32, u32, u32, Color),
1220 {
1221 for run in self.layout_runs() {
1222 for glyph in run.glyphs.iter() {
1223 let physical_glyph = glyph.physical((0., 0.), 1.0);
1224
1225 let glyph_color = match glyph.color_opt {
1226 Some(some) => some,
1227 None => color,
1228 };
1229
1230 cache.with_pixels(
1231 font_system,
1232 physical_glyph.cache_key,
1233 glyph_color,
1234 |x, y, color| {
1235 f(
1236 physical_glyph.x + x,
1237 run.line_y as i32 + physical_glyph.y + y,
1238 1,
1239 1,
1240 color,
1241 );
1242 },
1243 );
1244 }
1245 }
1246 }
1247}
1248
1249impl<'a> BorrowedWithFontSystem<'a, Buffer> {
1250 pub fn shape_until_cursor(&mut self, cursor: Cursor, prune: bool) {
1252 self.inner
1253 .shape_until_cursor(self.font_system, cursor, prune);
1254 }
1255
1256 pub fn shape_until_scroll(&mut self, prune: bool) {
1258 self.inner.shape_until_scroll(self.font_system, prune);
1259 }
1260
1261 pub fn line_shape(&mut self, line_i: usize) -> Option<&ShapeLine> {
1263 self.inner.line_shape(self.font_system, line_i)
1264 }
1265
1266 pub fn line_layout(&mut self, line_i: usize) -> Option<&[LayoutLine]> {
1268 self.inner.line_layout(self.font_system, line_i)
1269 }
1270
1271 pub fn set_metrics(&mut self, metrics: Metrics) {
1277 self.inner.set_metrics(self.font_system, metrics);
1278 }
1279
1280 pub fn set_wrap(&mut self, wrap: Wrap) {
1282 self.inner.set_wrap(self.font_system, wrap);
1283 }
1284
1285 pub fn set_size(&mut self, width: f32, height: f32) {
1287 self.inner.set_size(self.font_system, width, height);
1288 }
1289
1290 pub fn set_metrics_and_size(&mut self, metrics: Metrics, width: f32, height: f32) {
1296 self.inner
1297 .set_metrics_and_size(self.font_system, metrics, width, height);
1298 }
1299
1300 pub fn set_text(&mut self, text: &str, attrs: Attrs, shaping: Shaping) {
1302 self.inner.set_text(self.font_system, text, attrs, shaping);
1303 }
1304
1305 pub fn set_rich_text<'r, 's, I>(&mut self, spans: I, default_attrs: Attrs, shaping: Shaping)
1323 where
1324 I: IntoIterator<Item = (&'s str, Attrs<'r>)>,
1325 {
1326 self.inner
1327 .set_rich_text(self.font_system, spans, default_attrs, shaping);
1328 }
1329
1330 pub fn cursor_motion(
1332 &mut self,
1333 cursor: Cursor,
1334 cursor_x_opt: Option<i32>,
1335 motion: Motion,
1336 ) -> Option<(Cursor, Option<i32>)> {
1337 self.inner
1338 .cursor_motion(self.font_system, cursor, cursor_x_opt, motion)
1339 }
1340
1341 #[cfg(feature = "swash")]
1343 pub fn draw<F>(&mut self, cache: &mut crate::SwashCache, color: Color, f: F)
1344 where
1345 F: FnMut(i32, i32, u32, u32, Color),
1346 {
1347 self.inner.draw(self.font_system, cache, color, f);
1348 }
1349}