1use {
2 super::{
3 color::Color,
4 font::{Font, FontId, GlyphId},
5 font_family::{FontFamily, FontFamilyId},
6 geom::{Point, Rect, Size},
7 loader::{self, FontDefinition, FontFamilyDefinition, Loader},
8 rasterizer::{self, RasterizedGlyph, Rasterizer},
9 sdfer,
10 selection::{Cursor, CursorPosition, Selection},
11 shaper::{self, ShapedText},
12 substr::Substr,
13 },
14 std::{
15 borrow::Borrow,
16 cell::RefCell,
17 collections::{HashMap, VecDeque},
18 hash::{Hash, Hasher},
19 rc::Rc,
20 },
21 unicode_segmentation::UnicodeSegmentation,
22};
23
24const LPXS_PER_INCH: f32 = 96.0;
25const PTS_PER_INCH: f32 = 72.0;
26
27#[derive(Debug)]
28pub struct Layouter {
29 loader: Loader,
30 cache_size: usize,
31 cached_params: VecDeque<OwnedLayoutParams>,
32 cached_results: HashMap<OwnedLayoutParams, Rc<LaidoutText>>,
33}
34
35impl Layouter {
36 pub fn new(settings: Settings) -> Self {
37 Self {
38 loader: Loader::new(settings.loader),
39 cache_size: settings.cache_size,
40 cached_params: VecDeque::with_capacity(settings.cache_size),
41 cached_results: HashMap::with_capacity(settings.cache_size),
42 }
43 }
44
45 pub fn rasterizer(&self) -> &Rc<RefCell<Rasterizer>> {
46 self.loader.rasterizer()
47 }
48
49 pub fn is_font_family_known(&self, id: FontFamilyId) -> bool {
50 self.loader.is_font_family_known(id)
51 }
52
53 pub fn is_font_known(&self, id: FontId) -> bool {
54 self.loader.is_font_known(id)
55 }
56
57 pub fn define_font_family(&mut self, id: FontFamilyId, definition: FontFamilyDefinition) {
58 self.loader.define_font_family(id, definition);
59 }
60
61 pub fn define_font(&mut self, id: FontId, definition: FontDefinition) {
62 self.loader.define_font(id, definition);
63 }
64
65 pub fn get_or_layout(&mut self, params: impl LayoutParams) -> Rc<LaidoutText> {
66 if let Some(result) = self.cached_results.get(¶ms as &dyn LayoutParams) {
67 return result.clone();
68 }
69 if self.cached_params.len() == self.cache_size {
70 let params = self.cached_params.pop_front().unwrap();
71 self.cached_results.remove(¶ms);
72 }
73 let params = params.to_owned();
74 let result = Rc::new(self.layout(params.clone()));
75 self.cached_params.push_back(params.clone());
76 self.cached_results.insert(params, result.clone());
77 result
78 }
79
80 fn layout(&mut self, params: OwnedLayoutParams) -> LaidoutText {
81 LayoutContext::new(&mut self.loader, params.text, params.options).layout(¶ms.spans)
82 }
83}
84
85#[derive(Clone, Copy, Debug)]
86pub struct Settings {
87 pub loader: loader::Settings,
88 pub cache_size: usize,
89}
90
91impl Default for Settings {
92 fn default() -> Self {
93 let r = Self {
94 loader: loader::Settings {
95 shaper: shaper::Settings { cache_size: 4096 },
96 rasterizer: rasterizer::Settings {
97 sdfer: sdfer::Settings {
98 padding: 4,
99 radius: 8.0,
100 cutoff: 0.25,
101 },
102 grayscale_atlas_size: Size::new(4096, 4096),
103 color_atlas_size: Size::new(2048, 2048),
104 },
105 },
106 cache_size: 4096,
107 };
108 r
109 }
110}
111
112#[derive(Debug)]
113struct LayoutContext<'a> {
114 loader: &'a mut Loader,
115 text: Substr,
116 options: LayoutOptions,
117 current_point_in_lpxs: Point<f32>,
118 current_row_start: usize,
119 current_row_end: usize,
120 rows: Vec<LaidoutRow>,
121 glyphs: Vec<LaidoutGlyph>,
122}
123
124impl<'a> LayoutContext<'a> {
125 fn new(loader: &'a mut Loader, text: Substr, options: LayoutOptions) -> Self {
126 Self {
127 loader,
128 text,
129 options,
130 current_point_in_lpxs: Point::new(options.first_row_indent_in_lpxs, 0.0),
131 current_row_start: 0,
132 current_row_end: 0,
133 rows: Vec::new(),
134 glyphs: Vec::new(),
135 }
136 }
137
138 fn current_row_is_first(&self) -> bool {
139 self.rows.is_empty()
140 }
141
142 fn current_row_is_continuation(&self) -> bool {
143 self.current_row_is_first() && self.options.first_row_indent_in_lpxs > 0.0
144 }
145
146 fn current_row_is_empty(&self) -> bool {
147 self.current_row_start == self.current_row_end
148 }
149
150 fn current_row_len(&self) -> usize {
151 self.current_row_end - self.current_row_start
152 }
153
154 fn span_text(&self, len: usize) -> Substr {
155 self.text
156 .substr(self.current_row_end..self.current_row_end + len)
157 }
158
159 fn remaining_width_in_lpxs(&self) -> Option<f32> {
160 if self.options.wrap {
161 self.options
162 .max_width_in_lpxs
163 .map(|max_width_in_lpxs| max_width_in_lpxs - self.current_point_in_lpxs.x)
164 } else {
165 None
166 }
167 }
168
169 fn layout(mut self, spans: &[Span]) -> LaidoutText {
170 for (span_index, span) in spans.iter().enumerate() {
171 self.layout_span_multiline(span, span_index == spans.len() - 1);
172 }
173 self.finish()
174 }
175
176 fn layout_span_multiline(&mut self, span: &Span, is_last: bool) {
177 let font_family = self
178 .loader
179 .get_or_load_font_family(span.style.font_family_id)
180 .clone();
181 for (line_index, len) in self
182 .span_text(span.len)
183 .split('\n')
184 .map(|line| line.len())
185 .enumerate()
186 {
187 if line_index != 0 {
188 self.finish_current_row(&font_family, span.style, true);
189 }
190 self.layout_span(&font_family, span.style, len);
191 }
192 if is_last {
193 self.finish_current_row(&font_family, span.style, false);
194 }
195 }
196
197 fn layout_span(&mut self, font_family: &Rc<FontFamily>, style: Style, len: usize) {
198 if self.remaining_width_in_lpxs().is_none() {
199 self.layout_span_directly(font_family, style, len);
200 } else {
201 self.layout_span_by_word(font_family, style, len);
202 }
203 }
204
205 fn layout_span_by_word(&mut self, font_family: &Rc<FontFamily>, style: Style, len: usize) {
206 let mut fitter = Fitter::new(
207 self.span_text(len),
208 font_family.clone(),
209 style.font_size_in_lpxs(),
210 SegmentKind::Word,
211 );
212 while !fitter.is_empty() {
213 match fitter.fit(self.remaining_width_in_lpxs().unwrap()) {
214 Some(text) => self.append_text(style, &text),
215 None => {
216 if self.current_row_is_empty() && !self.current_row_is_continuation() {
217 self.layout_span_by_grapheme(font_family, style, fitter.pop());
218 } else {
219 self.finish_current_row(font_family, style, false);
220 }
221 }
222 }
223 }
224 }
225
226 fn layout_span_by_grapheme(&mut self, font_family: &Rc<FontFamily>, style: Style, len: usize) {
227 let mut fitter = Fitter::new(
228 self.span_text(len),
229 font_family.clone(),
230 style.font_size_in_lpxs(),
231 SegmentKind::Grapheme,
232 );
233 while !fitter.is_empty() {
234 match fitter.fit(self.remaining_width_in_lpxs().unwrap()) {
235 Some(text) => self.append_text(style, &text),
236 None => {
237 if self.current_row_is_empty() {
238 self.layout_span_directly(font_family, style, fitter.pop());
239 } else {
240 self.finish_current_row(font_family, style, false);
241 }
242 }
243 }
244 }
245 }
246
247 fn layout_span_directly(&mut self, font_family: &FontFamily, style: Style, len: usize) {
248 self.append_text(
249 style,
250 &font_family.get_or_shape(
251 self.text
252 .substr(self.current_row_end..self.current_row_end + len),
253 ),
254 );
255 }
256
257 fn append_text(&mut self, style: Style, text: &ShapedText) {
258 use super::num::Zero;
259
260 for glyph in &text.glyphs {
261 let mut glyph = LaidoutGlyph {
262 origin_in_lpxs: Point::ZERO,
263 font: glyph.font.clone(),
264 font_size_in_lpxs: style.font_size_in_lpxs(),
265 color: style.color,
266 id: glyph.id,
267 cluster: self.current_row_len() + glyph.cluster,
268 advance_in_ems: glyph.advance_in_ems,
269 offset_in_ems: glyph.offset_in_ems,
270 };
271 glyph.origin_in_lpxs.x = self.current_point_in_lpxs.x;
272 self.current_point_in_lpxs.x += glyph.advance_in_lpxs();
273 self.glyphs.push(glyph);
274 }
275 self.current_row_end += text.text.len();
276 }
277
278 fn finish_current_row(
279 &mut self,
280 fallback_font_family: &FontFamily,
281 fallback_style: Style,
282 newline: bool,
283 ) {
284 use {super::num::Zero, std::mem};
285
286 let glyphs = mem::take(&mut self.glyphs);
287 let fallback_font = fallback_font_family.fonts().get(0);
288 let fallback_font_size_in_lpxs = fallback_style.font_size_in_lpxs();
289 let fallback_ascender_in_lpxs =
290 fallback_font.map_or(0.0, |font| font.ascender_in_ems()) * fallback_font_size_in_lpxs;
291 let fallback_descender_in_lpxs =
292 fallback_font.map_or(0.0, |font| font.descender_in_ems()) * fallback_font_size_in_lpxs;
293 let fallback_line_gap_in_lpxs =
294 fallback_font.map_or(0.0, |font| font.line_gap_in_ems()) * fallback_font_size_in_lpxs;
295
296 let text = self
297 .text
298 .substr(self.current_row_start..self.current_row_end);
299 let width_in_lpxs = self.current_point_in_lpxs.x;
300 let ascender_in_lpxs = glyphs
301 .iter()
302 .map(|glyph| glyph.ascender_in_lpxs())
303 .reduce(f32::max)
304 .unwrap_or(fallback_ascender_in_lpxs);
305 let descender_in_lpxs = glyphs
306 .iter()
307 .map(|glyph| glyph.descender_in_lpxs())
308 .reduce(f32::min)
309 .unwrap_or(fallback_descender_in_lpxs);
310 let line_gap_in_lpxs = glyphs
311 .iter()
312 .map(|glyph| glyph.line_gap_in_lpxs())
313 .reduce(f32::max)
314 .unwrap_or(fallback_line_gap_in_lpxs);
315 let line_spacing_scale = self.options.line_spacing_scale;
316 let line_spacing_above_in_lpxs = ascender_in_lpxs * line_spacing_scale;
317 let line_spacing_below_in_lpxs =
318 (-descender_in_lpxs + line_gap_in_lpxs) * line_spacing_scale;
319 let line_spacing_below_in_lpxs =
320 line_spacing_below_in_lpxs.max(if self.current_row_is_first() {
321 self.options.first_row_min_line_spacing_below_in_lpxs - line_spacing_above_in_lpxs
322 } else {
323 0.0
324 });
325 let mut row = LaidoutRow {
326 origin_in_lpxs: Point::ZERO,
327 text,
328 newline,
329 width_in_lpxs,
330 ascender_in_lpxs,
331 descender_in_lpxs,
332 line_gap_in_lpxs,
333 line_spacing_above_in_lpxs,
334 line_spacing_below_in_lpxs,
335 glyphs,
336 };
337
338 self.current_point_in_lpxs.x = 0.0;
339 self.current_point_in_lpxs.y += self.rows.last().map_or(row.ascender_in_lpxs, |prev_row| {
340 prev_row.line_spacing_in_lpxs(&row)
341 });
342 let max_width_in_lpxs = self.options.max_width_in_lpxs.unwrap_or(row.width_in_lpxs);
343 let remaining_width_in_lpxs = max_width_in_lpxs - row.width_in_lpxs;
344 row.origin_in_lpxs.x = self.options.align * remaining_width_in_lpxs;
345 row.origin_in_lpxs.y = self.current_point_in_lpxs.y;
346 self.current_row_start = self.current_row_end;
347 if newline {
348 self.current_row_start += 1;
349 self.current_row_end += 1;
350 }
351 self.rows.push(row);
352 }
353
354 fn finish(self) -> LaidoutText {
355 LaidoutText {
356 text: self.text,
357 size_in_lpxs: Size::new(
358 self.rows
359 .iter()
360 .map(|row| row.width_in_lpxs)
361 .reduce(f32::max)
362 .unwrap_or(0.0),
363 self.current_point_in_lpxs.y - self.rows.last().unwrap().descender_in_lpxs,
364 ),
365 rows: self.rows,
366 }
367 }
368}
369
370#[derive(Debug)]
371struct Fitter {
372 text: Substr,
373 font_family: Rc<FontFamily>,
374 font_size_in_lpxs: f32,
375 lens: Vec<usize>,
376 widths_in_lpxs: Vec<f32>,
377}
378
379impl Fitter {
380 fn new(
381 text: Substr,
382 font_family: Rc<FontFamily>,
383 font_size_in_lpxs: f32,
384 segment_kind: SegmentKind,
385 ) -> Self {
386 let lens: Vec<_> = match segment_kind {
387 SegmentKind::Word => text
388 .split_word_bounds()
389 .map(|segment| segment.len())
390 .collect(),
391 SegmentKind::Grapheme => text.graphemes(true).map(|segment| segment.len()).collect(),
392 };
393 let widths_in_lpxs: Vec<_> = lens
394 .iter()
395 .copied()
396 .scan(0, |state, len| {
397 let start = *state;
398 let end = start + len;
399 let segment = font_family.get_or_shape(text.substr(start..end));
400 let width_in_lpxs = segment.width_in_ems * font_size_in_lpxs;
401 *state = end;
402 Some(width_in_lpxs)
403 })
404 .collect();
405 Self {
406 text,
407 font_family,
408 font_size_in_lpxs,
409 lens,
410 widths_in_lpxs,
411 }
412 }
413
414 fn is_empty(&self) -> bool {
415 self.text.is_empty()
416 }
417
418 fn fit(&mut self, wrap_width_in_lpxs: f32) -> Option<Rc<ShapedText>> {
419 let mut min_count = 1;
420 let mut max_count = self.lens.len() + 1;
421 let mut best_count = None;
422 while min_count < max_count {
423 let mid_count = (min_count + max_count) / 2;
424 if self.can_fit(mid_count, wrap_width_in_lpxs) {
425 best_count = Some(mid_count);
426 min_count = mid_count + 1;
427 } else {
428 max_count = mid_count;
429 }
430 }
431 if let Some(best_count) = best_count {
432 let best_len = self.lens[..best_count].iter().sum();
433 let best_text = self.font_family.get_or_shape(self.text.substr(0..best_len));
434 self.lens.drain(..best_count);
435 self.widths_in_lpxs.drain(..best_count);
436 self.text = self.text.substr(best_len..);
437 Some(best_text)
438 } else {
439 None
440 }
441 }
442
443 fn can_fit(&self, count: usize, wrap_width_in_lpxs: f32) -> bool {
444 let len = self.lens[..count].iter().sum();
445 let estimated_width_in_lpxs: f32 = self.widths_in_lpxs[..count].iter().sum();
446 if 0.5 * estimated_width_in_lpxs > wrap_width_in_lpxs {
447 return false;
448 }
449 let text = self.font_family.get_or_shape(self.text.substr(0..len));
450 let actual_width_in_lpxs = text.width_in_ems * self.font_size_in_lpxs;
451 if actual_width_in_lpxs > wrap_width_in_lpxs {
452 return false;
453 }
454 true
455 }
456
457 fn pop(&mut self) -> usize {
458 let len = self.lens.remove(0);
459 self.widths_in_lpxs.remove(0);
460 self.text = self.text.substr(len..);
461 len
462 }
463}
464
465#[derive(Clone, Copy, Debug)]
466enum SegmentKind {
467 Word,
468 Grapheme,
469}
470
471pub trait LayoutParams {
472 fn to_owned(self) -> OwnedLayoutParams;
473 fn text(&self) -> &str;
474 fn spans(&self) -> &[Span];
475 fn options(&self) -> LayoutOptions;
476}
477
478impl Eq for dyn LayoutParams + '_ {}
479
480impl Hash for dyn LayoutParams + '_ {
481 fn hash<H>(&self, hasher: &mut H)
482 where
483 H: Hasher,
484 {
485 self.text().hash(hasher);
486 self.spans().hash(hasher);
487 self.options().hash(hasher);
488 }
489}
490
491impl PartialEq for dyn LayoutParams + '_ {
492 fn eq(&self, other: &Self) -> bool {
493 if self.text() != other.text() {
494 return false;
495 }
496 if self.spans() != other.spans() {
497 return false;
498 }
499 if self.options() != other.options() {
500 return false;
501 }
502 true
503 }
504}
505
506#[derive(Clone, Debug, Eq, Hash, PartialEq)]
507pub struct OwnedLayoutParams {
508 pub text: Substr,
509 pub spans: Rc<[Span]>,
510 pub options: LayoutOptions,
511}
512
513impl<'a> Borrow<dyn LayoutParams + 'a> for OwnedLayoutParams {
514 fn borrow(&self) -> &(dyn LayoutParams + 'a) {
515 self
516 }
517}
518
519impl LayoutParams for OwnedLayoutParams {
520 fn to_owned(self) -> Self {
521 self
522 }
523
524 fn text(&self) -> &str {
525 &self.text
526 }
527
528 fn spans(&self) -> &[Span] {
529 &self.spans
530 }
531
532 fn options(&self) -> LayoutOptions {
533 self.options
534 }
535}
536
537#[derive(Clone, Copy, Debug)]
538pub struct BorrowedLayoutParams<'a> {
539 pub text: &'a str,
540 pub spans: &'a [Span],
541 pub options: LayoutOptions,
542}
543
544impl<'a> Borrow<dyn LayoutParams + 'a> for BorrowedLayoutParams<'a> {
545 fn borrow(&self) -> &(dyn LayoutParams + 'a) {
546 self
547 }
548}
549
550impl<'a> LayoutParams for BorrowedLayoutParams<'a> {
551 fn to_owned(self) -> OwnedLayoutParams {
552 OwnedLayoutParams {
553 text: self.text.into(),
554 spans: self.spans.into(),
555 options: self.options,
556 }
557 }
558
559 fn text(&self) -> &str {
560 self.text
561 }
562
563 fn spans(&self) -> &[Span] {
564 self.spans
565 }
566
567 fn options(&self) -> LayoutOptions {
568 self.options
569 }
570}
571
572#[derive(Clone, Debug, Eq, Hash, PartialEq)]
573pub struct Span {
574 pub style: Style,
575 pub len: usize,
576}
577
578#[derive(Clone, Copy, Debug)]
579pub struct Style {
580 pub font_family_id: FontFamilyId,
581 pub font_size_in_pts: f32,
582 pub color: Option<Color>,
583}
584
585impl Style {
586 fn font_size_in_lpxs(&self) -> f32 {
587 self.font_size_in_pts * LPXS_PER_INCH / PTS_PER_INCH
588 }
589}
590
591impl Eq for Style {}
592
593impl Hash for Style {
594 fn hash<H>(&self, hasher: &mut H)
595 where
596 H: Hasher,
597 {
598 self.font_family_id.hash(hasher);
599 self.font_size_in_pts.to_bits().hash(hasher);
600 self.color.hash(hasher);
601 }
602}
603
604impl PartialEq for Style {
605 fn eq(&self, other: &Self) -> bool {
606 if self.font_family_id != other.font_family_id {
607 return false;
608 }
609 if self.font_size_in_lpxs().to_bits() != other.font_size_in_lpxs().to_bits() {
610 return false;
611 }
612 if self.color != other.color {
613 return false;
614 }
615 true
616 }
617}
618
619#[derive(Clone, Copy, Debug)]
620pub struct LayoutOptions {
621 pub first_row_indent_in_lpxs: f32,
622 pub first_row_min_line_spacing_below_in_lpxs: f32,
623 pub max_width_in_lpxs: Option<f32>,
624 pub wrap: bool,
625 pub align: f32,
626 pub line_spacing_scale: f32,
627}
628
629impl Default for LayoutOptions {
630 fn default() -> Self {
631 Self {
632 first_row_indent_in_lpxs: 0.0,
633 first_row_min_line_spacing_below_in_lpxs: 0.0,
634 max_width_in_lpxs: None,
635 wrap: false,
636 align: 0.0,
637 line_spacing_scale: 1.0,
638 }
639 }
640}
641
642impl Eq for LayoutOptions {}
643
644impl Hash for LayoutOptions {
645 fn hash<H>(&self, hasher: &mut H)
646 where
647 H: Hasher,
648 {
649 self.first_row_indent_in_lpxs.to_bits().hash(hasher);
650 self.first_row_min_line_spacing_below_in_lpxs
651 .to_bits()
652 .hash(hasher);
653 self.max_width_in_lpxs.map(f32::to_bits).hash(hasher);
654 self.align.to_bits().hash(hasher);
655 self.line_spacing_scale.to_bits().hash(hasher);
656 }
657}
658
659impl PartialEq for LayoutOptions {
660 fn eq(&self, other: &Self) -> bool {
661 if self.first_row_indent_in_lpxs.to_bits() != other.first_row_indent_in_lpxs.to_bits() {
662 return false;
663 }
664 if self.first_row_min_line_spacing_below_in_lpxs.to_bits()
665 != other.first_row_min_line_spacing_below_in_lpxs.to_bits()
666 {
667 return false;
668 }
669 if self.max_width_in_lpxs.map(f32::to_bits) != other.max_width_in_lpxs.map(f32::to_bits) {
670 return false;
671 }
672 if self.align != other.align {
673 return false;
674 }
675 true
676 }
677}
678
679#[derive(Clone, Debug)]
680pub struct LaidoutText {
681 pub text: Substr,
682 pub size_in_lpxs: Size<f32>,
683 pub rows: Vec<LaidoutRow>,
684}
685
686impl LaidoutText {
687 pub fn cursor_to_position(&self, cursor: Cursor) -> CursorPosition {
688 let row_index = self.cursor_to_row_index(cursor);
689 let row = &self.rows[row_index];
690 let x_in_lpxs = row.index_to_x_in_lpxs(cursor.index - row.text.start_in_parent());
691 CursorPosition {
692 row_index,
693 x_in_lpxs,
694 }
695 }
696
697 fn cursor_to_row_index(&self, cursor: Cursor) -> usize {
698 for (row_index, row) in self.rows.iter().enumerate() {
699 if cursor.index < row.text.end_in_parent() {
700 return row_index;
701 }
702 if cursor.index == row.text.end_in_parent() {
703 if row.newline || !cursor.prefer_next_row {
704 return row_index;
705 }
706 }
707 }
708 self.rows.len() - 1
709 }
710
711 pub fn point_in_lpxs_to_cursor(&self, point_in_lpxs: Point<f32>) -> Cursor {
712 let row_index = self.y_in_lpxs_to_row_index(point_in_lpxs.y);
713 self.position_to_cursor(CursorPosition {
714 row_index,
715 x_in_lpxs: point_in_lpxs.x,
716 })
717 }
718
719 fn y_in_lpxs_to_row_index(&self, y_in_lpxs: f32) -> usize {
720 if y_in_lpxs < 0.0 {
721 return 0;
722 }
723 for (row_index, row) in self.rows.iter().enumerate() {
724 let line_spacing_in_lpxs = self
725 .rows
726 .get(row_index + 1)
727 .map_or(0.0, |next_row| row.line_spacing_in_lpxs(next_row));
728 if y_in_lpxs < row.origin_in_lpxs.y + 0.5 * line_spacing_in_lpxs {
729 return row_index;
730 }
731 }
732 self.rows.len() - 1
733 }
734
735 pub fn position_to_cursor(&self, position: CursorPosition) -> Cursor {
736 let row = &self.rows[position.row_index];
737 let index = row.x_in_lpxs_to_index(position.x_in_lpxs);
738 Cursor {
739 index: row.text.start_in_parent() + index,
740 prefer_next_row: if index == 0 { true } else { false },
741 }
742 }
743
744 pub fn selection_rects_in_lpxs(&self, selection: Selection) -> Vec<Rect<f32>> {
745 let CursorPosition {
746 row_index: start_row_index,
747 x_in_lpxs: start_x_in_lpxs,
748 } = self.cursor_to_position(selection.start());
749 let CursorPosition {
750 row_index: end_row_index,
751 x_in_lpxs: end_x_in_lpxs,
752 } = self.cursor_to_position(selection.end());
753 let mut rects_in_lpxs = Vec::new();
754 if start_row_index == end_row_index {
755 let row = &self.rows[start_row_index];
756 rects_in_lpxs.push(Rect::new(
757 Point::new(start_x_in_lpxs, row.origin_in_lpxs.y - row.ascender_in_lpxs),
758 Size::new(
759 end_x_in_lpxs - start_x_in_lpxs,
760 row.ascender_in_lpxs - row.descender_in_lpxs,
761 ),
762 ));
763 } else {
764 let start_row = &self.rows[start_row_index];
765 let end_row = &self.rows[end_row_index];
766 rects_in_lpxs.push(Rect::new(
767 Point::new(
768 start_x_in_lpxs,
769 start_row.origin_in_lpxs.y - start_row.ascender_in_lpxs,
770 ),
771 Size::new(
772 start_row.width_in_lpxs - start_x_in_lpxs,
773 start_row.ascender_in_lpxs - start_row.descender_in_lpxs,
774 ),
775 ));
776 for row_index in start_row_index + 1..end_row_index {
777 let row = &self.rows[row_index];
778 rects_in_lpxs.push(Rect::new(
779 Point::new(
780 row.origin_in_lpxs.x,
781 row.origin_in_lpxs.y - row.ascender_in_lpxs,
782 ),
783 Size::new(
784 row.width_in_lpxs,
785 row.ascender_in_lpxs - row.descender_in_lpxs,
786 ),
787 ));
788 }
789 rects_in_lpxs.push(Rect::new(
790 Point::new(0.0, end_row.origin_in_lpxs.y - end_row.ascender_in_lpxs),
791 Size::new(
792 end_x_in_lpxs,
793 end_row.ascender_in_lpxs - end_row.descender_in_lpxs,
794 ),
795 ));
796 }
797 rects_in_lpxs
798 }
799}
800
801#[derive(Clone, Debug)]
802pub struct LaidoutRow {
803 pub origin_in_lpxs: Point<f32>,
804 pub text: Substr,
805 pub newline: bool,
806 pub width_in_lpxs: f32,
807 pub ascender_in_lpxs: f32,
808 pub descender_in_lpxs: f32,
809 pub line_gap_in_lpxs: f32,
810 pub line_spacing_above_in_lpxs: f32,
811 pub line_spacing_below_in_lpxs: f32,
812 pub glyphs: Vec<LaidoutGlyph>,
813}
814
815impl LaidoutRow {
816 pub fn line_spacing_in_lpxs(&self, next_row: &LaidoutRow) -> f32 {
817 self.line_spacing_below_in_lpxs + next_row.line_spacing_above_in_lpxs
818 }
819
820 pub fn x_in_lpxs_to_index(&self, x_in_lpxs: f32) -> usize {
821 use {super::slice::SliceExt, unicode_segmentation::UnicodeSegmentation};
822
823 let mut glyph_groups = self
824 .glyphs
825 .group_by(|glyph_0, glyph_1| glyph_0.cluster == glyph_1.cluster)
826 .peekable();
827 while let Some(glyph_group) = glyph_groups.next() {
828 let start = glyph_group[0].cluster;
829 let start_x_in_lpxs = glyph_group[0].origin_in_lpxs.x;
830 let next_glyph_group = glyph_groups.peek();
831 let end = next_glyph_group.map_or(self.text.len(), |next_glyph_group| {
832 next_glyph_group[0].cluster
833 });
834 let end_x_in_lpxs = next_glyph_group.map_or(self.width_in_lpxs, |next_glyph_group| {
835 next_glyph_group[0].origin_in_lpxs.x
836 });
837 let width_in_lpxs = end_x_in_lpxs - start_x_in_lpxs;
838 let grapheme_count = self.text[start..end].graphemes(true).count();
839 let grapheme_width_in_lpxs = width_in_lpxs / grapheme_count as f32;
840 let mut current_x_in_lpxs = start_x_in_lpxs;
841 for (grapheme_start, _) in self.text[start..end].grapheme_indices(true) {
842 if x_in_lpxs < current_x_in_lpxs + 0.5 * grapheme_width_in_lpxs {
843 return start + grapheme_start;
844 }
845 current_x_in_lpxs += grapheme_width_in_lpxs;
846 }
847 }
848 self.text.len()
849 }
850
851 pub fn index_to_x_in_lpxs(&self, index: usize) -> f32 {
852 use {super::slice::SliceExt, unicode_segmentation::UnicodeSegmentation};
853
854 let mut glyph_groups = self
855 .glyphs
856 .group_by(|glyph_0, glyph_1| glyph_0.cluster == glyph_1.cluster)
857 .peekable();
858 while let Some(glyph_group) = glyph_groups.next() {
859 let start = glyph_group[0].cluster;
860 let start_x_in_lpxs = glyph_group[0].origin_in_lpxs.x;
861 let end = glyph_groups
862 .peek()
863 .map_or(self.text.len(), |next_glyph_group| {
864 next_glyph_group[0].cluster
865 });
866 let end_x_in_lpxs = glyph_groups
867 .peek()
868 .map_or(self.width_in_lpxs, |next_glyph_group| {
869 next_glyph_group[0].origin_in_lpxs.x
870 });
871 let width_in_lpxs = end_x_in_lpxs - start_x_in_lpxs;
872 let grapheme_count = self.text[start..end].graphemes(true).count();
873 let grapheme_width_in_lpxs = width_in_lpxs / grapheme_count as f32;
874 let mut current_x_in_lpxs = start_x_in_lpxs;
875 for (grapheme_start, _) in self.text[start..end].grapheme_indices(true) {
876 let grapheme_start = start + grapheme_start;
877 if index == grapheme_start {
878 return current_x_in_lpxs;
879 }
880 current_x_in_lpxs += grapheme_width_in_lpxs;
881 }
882 }
883 self.width_in_lpxs
884 }
885}
886
887#[derive(Clone, Debug)]
888pub struct LaidoutGlyph {
889 pub origin_in_lpxs: Point<f32>,
890 pub font: Rc<Font>,
891 pub font_size_in_lpxs: f32,
892 pub color: Option<Color>,
893 pub id: GlyphId,
894 pub cluster: usize,
895 pub advance_in_ems: f32,
896 pub offset_in_ems: f32,
897}
898
899impl LaidoutGlyph {
900 pub fn advance_in_lpxs(&self) -> f32 {
901 self.advance_in_ems * self.font_size_in_lpxs
902 }
903
904 pub fn offset_in_lpxs(&self) -> f32 {
905 self.offset_in_ems * self.font_size_in_lpxs
906 }
907
908 pub fn ascender_in_lpxs(&self) -> f32 {
909 self.font.ascender_in_ems() * self.font_size_in_lpxs
910 }
911
912 pub fn descender_in_lpxs(&self) -> f32 {
913 self.font.descender_in_ems() * self.font_size_in_lpxs
914 }
915
916 pub fn line_gap_in_lpxs(&self) -> f32 {
917 self.font.line_gap_in_ems() * self.font_size_in_lpxs
918 }
919
920 pub fn rasterize(&self, dpx_per_em: f32) -> Option<RasterizedGlyph> {
921 self.font.rasterize_glyph(self.id, dpx_per_em)
922 }
923}