1#![allow(clippy::collapsible_else_if)]
9#![allow(clippy::or_fun_call)]
10#![allow(clippy::never_loop)]
11#![allow(clippy::needless_range_loop)]
12
13use super::{Line, TextDisplay};
14use crate::conv::to_usize;
15use crate::fonts::{self, FaceId};
16use crate::{shaper, Glyph, Range, Vec2};
17
18#[derive(Clone, Debug, Default, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct Effect {
22 pub start: u32,
27 pub e: u16,
29 pub flags: EffectFlags,
31}
32
33bitflags::bitflags! {
34 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
36 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37 pub struct EffectFlags: u16 {
38 const UNDERLINE = 1 << 0;
40 const STRIKETHROUGH = 1 << 1;
42 }
43}
44
45#[derive(Copy, Clone, Debug, Default, PartialEq)]
47pub struct MarkerPos {
48 pub pos: Vec2,
50 pub ascent: f32,
52 pub descent: f32,
54 level: u8,
55}
56
57impl MarkerPos {
58 #[inline]
64 pub fn embedding_level(&self) -> u8 {
65 self.level
66 }
67
68 #[inline]
70 pub fn is_ltr(&self) -> bool {
71 self.level % 2 == 0
72 }
73
74 #[inline]
76 pub fn is_rtl(&self) -> bool {
77 self.level % 2 == 1
78 }
79}
80
81pub struct MarkerPosIter {
82 v: [MarkerPos; 2],
83 a: usize,
84 b: usize,
85}
86
87impl MarkerPosIter {
88 pub fn as_slice(&self) -> &[MarkerPos] {
92 &self.v[self.a..self.b]
93 }
94}
95
96impl Iterator for MarkerPosIter {
97 type Item = MarkerPos;
98
99 #[inline]
100 fn next(&mut self) -> Option<Self::Item> {
101 if self.a < self.b {
102 let i = self.a;
103 self.a = i + 1;
104 Some(self.v[i])
105 } else {
106 None
107 }
108 }
109
110 #[inline]
111 fn size_hint(&self) -> (usize, Option<usize>) {
112 let len = self.b - self.a;
113 (len, Some(len))
114 }
115}
116
117impl DoubleEndedIterator for MarkerPosIter {
118 #[inline]
119 fn next_back(&mut self) -> Option<Self::Item> {
120 if self.a < self.b {
121 let i = self.b - 1;
122 self.b = i;
123 Some(self.v[i])
124 } else {
125 None
126 }
127 }
128}
129
130impl ExactSizeIterator for MarkerPosIter {}
131
132pub struct GlyphRun<'a> {
136 run: &'a shaper::GlyphRun,
137 range: Range,
138 offset: Vec2,
139 effects: &'a [Effect],
140}
141
142impl<'a> GlyphRun<'a> {
143 #[inline]
145 pub fn face_id(&self) -> FaceId {
146 self.run.face_id
147 }
148
149 #[inline]
153 pub fn dpem(&self) -> f32 {
154 self.run.dpem
155 }
156
157 pub fn glyphs(&self) -> impl Iterator<Item = Glyph> + '_ {
162 self.run.glyphs[self.range.to_std()]
163 .iter()
164 .map(|glyph| Glyph {
165 index: glyph.index,
166 id: glyph.id,
167 position: glyph.position + self.offset,
168 })
169 }
170
171 pub fn glyphs_with_effects<F, G>(&self, mut f: F, mut g: G)
186 where
187 F: FnMut(Glyph, u16),
188 G: FnMut(f32, f32, f32, f32, u16),
189 {
190 let sf = fonts::library()
191 .get_face(self.run.face_id)
192 .scale_by_dpu(self.run.dpu);
193
194 let ltr = self.run.level.is_ltr();
195
196 let mut underline = None;
197 let mut strikethrough = None;
198
199 let mut effect_cur = usize::MAX;
200 let mut effect_next = 0;
201
202 let left_index = self.run.glyphs[self.range.start()].index;
205 while self
206 .effects
207 .get(effect_next)
208 .map(|e| e.start <= left_index)
209 .unwrap_or(false)
210 {
211 effect_cur = effect_next;
212 effect_next += 1;
213 }
214
215 let mut next_start = self
216 .effects
217 .get(effect_next)
218 .map(|e| e.start)
219 .unwrap_or(u32::MAX);
220
221 let mut fmt = self
222 .effects
223 .get(effect_cur)
224 .cloned()
225 .unwrap_or(Effect::default());
226
227 if !fmt.flags.is_empty() {
230 let glyph = &self.run.glyphs[self.range.start()];
231 let position = glyph.position + self.offset;
232 if fmt.flags.contains(EffectFlags::UNDERLINE) {
233 if let Some(metrics) = sf.underline_metrics() {
234 let y_top = position.1 - metrics.position;
235 let h = metrics.thickness;
236 let x1 = position.0;
237 underline = Some((x1, y_top, h, fmt.e));
238 }
239 }
240 if fmt.flags.contains(EffectFlags::STRIKETHROUGH) {
241 if let Some(metrics) = sf.strikethrough_metrics() {
242 let y_top = position.1 - metrics.position;
243 let h = metrics.thickness;
244 let x1 = position.0;
245 strikethrough = Some((x1, y_top, h, fmt.e));
246 }
247 }
248 }
249
250 for mut glyph in self.run.glyphs[self.range.to_std()].iter().cloned() {
252 glyph.position += self.offset;
253
254 if (ltr && next_start <= glyph.index) || (!ltr && fmt.start > glyph.index) {
256 if ltr {
257 loop {
259 effect_cur = effect_next;
260 effect_next += 1;
261 if self
262 .effects
263 .get(effect_next)
264 .map(|e| e.start > glyph.index)
265 .unwrap_or(true)
266 {
267 break;
268 }
269 }
270 next_start = self
271 .effects
272 .get(effect_next)
273 .map(|e| e.start)
274 .unwrap_or(u32::MAX);
275 } else {
276 loop {
278 effect_cur = effect_cur.wrapping_sub(1);
279 if self.effects.get(effect_cur).map(|e| e.start).unwrap_or(0) <= glyph.index
280 {
281 break;
282 }
283 }
284 }
285 fmt = self
286 .effects
287 .get(effect_cur)
288 .cloned()
289 .unwrap_or(Effect::default());
290
291 if underline.is_some() != fmt.flags.contains(EffectFlags::UNDERLINE) {
292 if let Some((x1, y_top, h, e)) = underline {
293 let x2 = glyph.position.0;
294 g(x1, x2, y_top, h, e);
295 underline = None;
296 } else if let Some(metrics) = sf.underline_metrics() {
297 let y_top = glyph.position.1 - metrics.position;
298 let h = metrics.thickness;
299 let x1 = glyph.position.0;
300 underline = Some((x1, y_top, h, fmt.e));
301 }
302 }
303 if strikethrough.is_some() != fmt.flags.contains(EffectFlags::STRIKETHROUGH) {
304 if let Some((x1, y_top, h, e)) = strikethrough {
305 let x2 = glyph.position.0;
306 g(x1, x2, y_top, h, e);
307 strikethrough = None;
308 } else if let Some(metrics) = sf.strikethrough_metrics() {
309 let y_top = glyph.position.1 - metrics.position;
310 let h = metrics.thickness;
311 let x1 = glyph.position.0;
312 strikethrough = Some((x1, y_top, h, fmt.e));
313 }
314 }
315 }
316
317 f(glyph, fmt.e);
318 }
319
320 if let Some((x1, y_top, h, e)) = underline {
322 let x2 = if self.range.end() < self.run.glyphs.len() {
323 self.run.glyphs[self.range.end()].position.0
324 } else {
325 self.run.caret
326 } + self.offset.0;
327 g(x1, x2, y_top, h, e);
328 }
329 if let Some((x1, y_top, h, e)) = strikethrough {
330 let x2 = if self.range.end() < self.run.glyphs.len() {
331 self.run.glyphs[self.range.end()].position.0
332 } else {
333 self.run.caret
334 } + self.offset.0;
335 g(x1, x2, y_top, h, e);
336 }
337 }
338}
339
340impl TextDisplay {
341 pub fn text_glyph_pos(&self, index: usize) -> MarkerPosIter {
362 let mut v: [MarkerPos; 2] = Default::default();
363 let (a, mut b) = (0, 0);
364 let mut push_result = |pos, ascent, descent, level| {
365 v[b] = MarkerPos {
366 pos,
367 ascent,
368 descent,
369 level,
370 };
371 b += 1;
372 };
373
374 'a: for run_part in &self.wrapped_runs {
376 if index > to_usize(run_part.text_end) {
377 continue;
378 }
379
380 let glyph_run = &self.runs[to_usize(run_part.glyph_run)];
381 let sf = fonts::library()
382 .get_face(glyph_run.face_id)
383 .scale_by_dpu(glyph_run.dpu);
384
385 if index == to_usize(run_part.text_end) {
387 let i = if glyph_run.level.is_ltr() {
388 run_part.glyph_range.end()
389 } else {
390 run_part.glyph_range.start()
391 };
392 let pos = if i < glyph_run.glyphs.len() {
393 glyph_run.glyphs[i].position
394 } else {
395 Vec2(glyph_run.caret, 0.0)
397 };
398
399 let pos = run_part.offset + pos;
400 push_result(pos, sf.ascent(), sf.descent(), glyph_run.level.number());
401 continue;
402 }
403
404 let pos = 'b: loop {
406 if glyph_run.level.is_ltr() {
407 for glyph in glyph_run.glyphs[run_part.glyph_range.to_std()].iter().rev() {
408 if to_usize(glyph.index) <= index {
409 break 'b glyph.position;
410 }
411 }
412 } else {
413 for glyph in glyph_run.glyphs[run_part.glyph_range.to_std()].iter() {
414 if to_usize(glyph.index) <= index {
415 let mut pos = glyph.position;
416 pos.0 += sf.h_advance(glyph.id);
417 break 'b pos;
418 }
419 }
420 }
421 break 'a;
422 };
423
424 let pos = run_part.offset + pos;
425 push_result(pos, sf.ascent(), sf.descent(), glyph_run.level.number());
426 break;
427 }
428
429 MarkerPosIter { v, a, b }
430 }
431
432 #[inline]
438 #[cfg(feature = "num_glyphs")]
439 pub fn num_glyphs(&self) -> usize {
440 to_usize(self.num_glyphs)
441 }
442
443 pub fn runs<'a>(
458 &'a self,
459 offset: Vec2,
460 effects: &'a [Effect],
461 ) -> impl Iterator<Item = GlyphRun<'a>> + 'a {
462 self.wrapped_runs
463 .iter()
464 .filter(|part| !part.glyph_range.is_empty())
465 .map(move |part| GlyphRun {
466 run: &self.runs[to_usize(part.glyph_run)],
467 range: part.glyph_range,
468 offset: offset + part.offset,
469 effects,
470 })
471 }
472
473 pub fn highlight_range(&self, range: std::ops::Range<usize>, f: &mut dyn FnMut(Vec2, Vec2)) {
480 for line in &self.lines {
481 let line_range: std::ops::Range<usize> = line.text_range.into();
482 if line_range.end <= range.start {
483 continue;
484 } else if range.end <= line_range.start {
485 break;
486 } else if range.start <= line_range.start && line_range.end <= range.end {
487 let tl = Vec2(self.l_bound, line.top);
488 let br = Vec2(self.r_bound, line.bottom);
489 f(tl, br);
490 } else {
491 self.highlight_line(line.clone(), range.clone(), f);
492 }
493 }
494 }
495
496 fn highlight_line(
504 &self,
505 line: Line,
506 range: std::ops::Range<usize>,
507 f: &mut dyn FnMut(Vec2, Vec2),
508 ) {
509 let fonts = fonts::library();
510
511 let mut a;
512
513 let mut i = line.run_range.start();
514 let line_range_end = line.run_range.end();
515 'b: loop {
516 if i >= line_range_end {
517 return;
518 }
519 let run_part = &self.wrapped_runs[i];
520 if range.start >= to_usize(run_part.text_end) {
521 i += 1;
522 continue;
523 }
524
525 let glyph_run = &self.runs[to_usize(run_part.glyph_run)];
526
527 if glyph_run.level.is_ltr() {
528 for glyph in glyph_run.glyphs[run_part.glyph_range.to_std()].iter().rev() {
529 if to_usize(glyph.index) <= range.start {
530 a = glyph.position.0;
531 break 'b;
532 }
533 }
534 a = 0.0;
535 } else {
536 let sf = fonts
537 .get_face(glyph_run.face_id)
538 .scale_by_dpu(glyph_run.dpu);
539 for glyph in glyph_run.glyphs[run_part.glyph_range.to_std()].iter() {
540 if to_usize(glyph.index) <= range.start {
541 a = glyph.position.0;
542 a += sf.h_advance(glyph.id);
543 break 'b;
544 }
545 }
546 a = glyph_run.caret;
547 }
548 break 'b;
549 }
550
551 let mut first = true;
552 'a: while i < line_range_end {
553 let run_part = &self.wrapped_runs[i];
554 let offset = run_part.offset.0;
555 let glyph_run = &self.runs[to_usize(run_part.glyph_run)];
556
557 if !first {
558 a = if glyph_run.level.is_ltr() {
559 if run_part.glyph_range.start() < glyph_run.glyphs.len() {
560 glyph_run.glyphs[run_part.glyph_range.start()].position.0
561 } else {
562 0.0
563 }
564 } else {
565 if run_part.glyph_range.end() < glyph_run.glyphs.len() {
566 glyph_run.glyphs[run_part.glyph_range.end()].position.0
567 } else {
568 glyph_run.caret
569 }
570 };
571 }
572 first = false;
573
574 if range.end >= to_usize(run_part.text_end) {
575 let b;
576 if glyph_run.level.is_ltr() {
577 if run_part.glyph_range.end() < glyph_run.glyphs.len() {
578 b = glyph_run.glyphs[run_part.glyph_range.end()].position.0;
579 } else {
580 b = glyph_run.caret;
581 }
582 } else {
583 let p = if run_part.glyph_range.start() < glyph_run.glyphs.len() {
584 glyph_run.glyphs[run_part.glyph_range.start()].position.0
585 } else {
586 glyph_run.caret
588 };
589 b = a;
590 a = p;
591 };
592
593 f(Vec2(a + offset, line.top), Vec2(b + offset, line.bottom));
594 i += 1;
595 continue;
596 }
597
598 let sf = fonts
599 .get_face(glyph_run.face_id)
600 .scale_by_dpu(glyph_run.dpu);
601
602 let b;
603 'c: loop {
604 if glyph_run.level.is_ltr() {
605 for glyph in glyph_run.glyphs[run_part.glyph_range.to_std()].iter().rev() {
606 if to_usize(glyph.index) <= range.end {
607 b = glyph.position.0;
608 break 'c;
609 }
610 }
611 } else {
612 for glyph in glyph_run.glyphs[run_part.glyph_range.to_std()].iter() {
613 if to_usize(glyph.index) <= range.end {
614 b = a;
615 a = glyph.position.0 + sf.h_advance(glyph.id);
616 break 'c;
617 }
618 }
619 }
620 break 'a;
621 }
622
623 f(Vec2(a + offset, line.top), Vec2(b + offset, line.bottom));
624 break;
625 }
626 }
627}