1use core::convert::TryFrom;
2
3use crate::{aat, ot, fallback, normalize, Direction, Face, Feature, GlyphBuffer, UnicodeBuffer};
4use crate::buffer::{
5 glyph_flag, Buffer, BufferClusterLevel, BufferFlags, BufferScratchFlags, GlyphInfo,
6 GlyphPropsFlags,
7};
8use crate::complex::ZeroWidthMarksMode;
9use crate::plan::ShapePlan;
10use crate::unicode::{CharExt, GeneralCategory};
11
12pub fn shape(face: &Face, features: &[Feature], buffer: UnicodeBuffer) -> GlyphBuffer {
17 let mut buffer = buffer.0;
18 buffer.guess_segment_properties();
19
20 if buffer.len > 0 {
21 let plan = ShapePlan::new(
22 face,
23 buffer.direction,
24 buffer.script,
25 buffer.language.as_ref(),
26 features,
27 );
28
29 let target_direction = buffer.direction;
31 shape_internal(&mut ShapeContext {
32 plan: &plan,
33 face,
34 buffer: &mut buffer,
35 user_features: features,
36 target_direction,
37 });
38 }
39
40 GlyphBuffer(buffer)
41}
42
43struct ShapeContext<'a> {
44 plan: &'a ShapePlan,
45 face: &'a Face<'a>,
46 buffer: &'a mut Buffer,
47 user_features: &'a [Feature],
48 target_direction: Direction,
50}
51
52fn shape_internal(ctx: &mut ShapeContext) {
54 ctx.buffer.scratch_flags = BufferScratchFlags::empty();
55
56 if let Some(len) = ctx.buffer.len.checked_mul(Buffer::MAX_LEN_FACTOR) {
57 ctx.buffer.max_len = len.max(Buffer::MAX_LEN_MIN);
58 }
59
60 if let Ok(len) = i32::try_from(ctx.buffer.len) {
61 if let Some(ops) = len.checked_mul(Buffer::MAX_OPS_FACTOR) {
62 ctx.buffer.max_ops = ops.max(Buffer::MAX_OPS_MIN);
63 }
64 }
65
66 ctx.buffer.clear_output();
67
68 initialize_masks(ctx);
69 set_unicode_props(ctx.buffer);
70 insert_dotted_circle(ctx.buffer, ctx.face);
71
72 form_clusters(ctx.buffer);
73
74 ensure_native_direction(ctx.buffer);
75
76 if let Some(func) = ctx.plan.shaper.preprocess_text {
77 func(ctx.plan, ctx.face, ctx.buffer);
78 }
79
80 substitute_pre(ctx);
81 position(ctx);
82 substitute_post(ctx);
83
84 propagate_flags(ctx.buffer);
85
86 ctx.buffer.direction = ctx.target_direction;
87 ctx.buffer.max_len = Buffer::MAX_LEN_DEFAULT;
88 ctx.buffer.max_ops = Buffer::MAX_OPS_DEFAULT;
89}
90
91fn substitute_pre(ctx: &mut ShapeContext) {
92 substitute_default(ctx);
93 substitute_complex(ctx);
94}
95
96fn substitute_post(ctx: &mut ShapeContext) {
97 hide_default_ignorables(ctx.buffer, ctx.face);
98
99 if ctx.plan.apply_morx {
100 aat::remove_deleted_glyphs(ctx.buffer);
101 }
102
103 if let Some(func) = ctx.plan.shaper.postprocess_glyphs {
104 func(ctx.plan, ctx.face, ctx.buffer);
105 }
106}
107
108fn substitute_default(ctx: &mut ShapeContext) {
109 rotate_chars(ctx);
110
111 normalize::normalize(ctx.plan, ctx.face, ctx.buffer);
112
113 setup_masks(ctx);
114
115 if ctx.plan.fallback_mark_positioning {
117 fallback::recategorize_marks(ctx.plan, ctx.face, ctx.buffer);
118 }
119
120 map_glyphs_fast(ctx.buffer);
121}
122
123fn substitute_complex(ctx: &mut ShapeContext) {
124 ot::substitute_start(ctx.face, ctx.buffer);
125
126 if ctx.plan.fallback_glyph_classes {
127 synthesize_glyph_classes(ctx.buffer);
128 }
129
130 substitute_by_plan(ctx.plan, ctx.face, ctx.buffer);
131}
132
133fn substitute_by_plan(plan: &ShapePlan, face: &Face, buffer: &mut Buffer) {
134 if plan.apply_morx {
135 aat::substitute(plan, face, buffer);
136 } else {
137 ot::substitute(plan, face, buffer);
138 }
139}
140
141fn position(ctx: &mut ShapeContext) {
142 ctx.buffer.clear_positions();
143
144 position_default(ctx);
145
146 position_complex(ctx);
147
148 if ctx.buffer.direction.is_backward() {
149 ctx.buffer.reverse();
150 }
151}
152
153fn position_default(ctx: &mut ShapeContext) {
154 let len = ctx.buffer.len;
155
156 if ctx.buffer.direction.is_horizontal() {
157 for (info, pos) in ctx.buffer.info[..len].iter().zip(&mut ctx.buffer.pos[..len]) {
158 pos.x_advance = ctx.face.glyph_h_advance(info.as_glyph());
159 }
160 } else {
161 for (info, pos) in ctx.buffer.info[..len].iter().zip(&mut ctx.buffer.pos[..len]) {
162 let glyph = info.as_glyph();
163 pos.y_advance = ctx.face.glyph_v_advance(glyph);
164 pos.x_offset -= ctx.face.glyph_h_origin(glyph);
165 pos.y_offset -= ctx.face.glyph_v_origin(glyph);
166 }
167 }
168
169 if ctx.buffer.scratch_flags.contains(BufferScratchFlags::HAS_SPACE_FALLBACK) {
170 fallback::adjust_spaces(ctx.plan, ctx.face, ctx.buffer);
171 }
172}
173
174fn position_complex(ctx: &mut ShapeContext) {
175 let adjust_offsets_when_zeroing = ctx.plan.adjust_mark_positioning_when_zeroing
184 && ctx.buffer.direction.is_forward();
185
186 ot::position_start(ctx.face, ctx.buffer);
189
190 if ctx.plan.zero_marks && ctx.plan.shaper.zero_width_marks == Some(ZeroWidthMarksMode::ByGdefEarly) {
191 zero_mark_widths_by_gdef(ctx.buffer, adjust_offsets_when_zeroing);
192 }
193
194 position_by_plan(ctx.plan, ctx.face, ctx.buffer);
195
196 if ctx.plan.zero_marks && ctx.plan.shaper.zero_width_marks == Some(ZeroWidthMarksMode::ByGdefLate) {
197 zero_mark_widths_by_gdef(ctx.buffer, adjust_offsets_when_zeroing);
198 }
199
200 ot::position_finish_advances(ctx.face, ctx.buffer);
202 zero_width_default_ignorables(ctx.buffer);
203
204 if ctx.plan.apply_morx {
205 aat::zero_width_deleted_glyphs(ctx.buffer);
206 }
207
208 ot::position_finish_offsets(ctx.face, ctx.buffer);
209
210 if ctx.plan.fallback_mark_positioning {
211 fallback::position_marks(ctx.plan, ctx.face, ctx.buffer, adjust_offsets_when_zeroing);
212 }
213}
214
215fn position_by_plan(plan: &ShapePlan, face: &Face, buffer: &mut Buffer) {
216 if plan.apply_gpos {
217 ot::position(plan, face, buffer);
218 } else if plan.apply_kerx {
219 aat::position(plan, face, buffer);
220 } else if plan.apply_kern {
221 ot::kern(plan, face, buffer);
222 }
223
224 if plan.apply_trak {
225 aat::track(plan, face, buffer);
226 }
227}
228
229fn initialize_masks(ctx: &mut ShapeContext) {
230 let global_mask = ctx.plan.ot_map.global_mask();
231 ctx.buffer.reset_masks(global_mask);
232}
233
234fn setup_masks(ctx: &mut ShapeContext) {
235 setup_masks_fraction(ctx);
236
237 if let Some(func) = ctx.plan.shaper.setup_masks {
238 func(ctx.plan, ctx.face, ctx.buffer);
239 }
240
241 for feature in ctx.user_features {
242 if !feature.is_global() {
243 let (mask, shift) = ctx.plan.ot_map.mask(feature.tag);
244 ctx.buffer.set_masks(feature.value << shift, mask, feature.start, feature.end);
245 }
246 }
247}
248
249fn setup_masks_fraction(ctx: &mut ShapeContext) {
250 let buffer = &mut ctx.buffer;
251 if !buffer.scratch_flags.contains(BufferScratchFlags::HAS_NON_ASCII) || !ctx.plan.has_frac {
252 return;
253 }
254
255 let (pre_mask, post_mask) = if buffer.direction.is_forward() {
256 (ctx.plan.numr_mask | ctx.plan.frac_mask, ctx.plan.frac_mask | ctx.plan.dnom_mask)
257 } else {
258 (ctx.plan.frac_mask | ctx.plan.dnom_mask, ctx.plan.numr_mask | ctx.plan.frac_mask)
259 };
260
261 let len = buffer.len;
262 let mut i = 0;
263 while i < len {
264 if buffer.info[i].glyph_id == 0x2044 {
266 let mut start = i;
267 while start > 0 && buffer.info[start - 1].general_category() == GeneralCategory::DecimalNumber {
268 start -= 1;
269 }
270
271 let mut end = i + 1;
272 while end < len && buffer.info[end].general_category() == GeneralCategory::DecimalNumber {
273 end += 1;
274 }
275
276 buffer.unsafe_to_break(start, end);
277
278 for info in &mut buffer.info[start..i] {
279 info.mask |= pre_mask;
280 }
281
282 buffer.info[i].mask |= ctx.plan.frac_mask;
283
284 for info in &mut buffer.info[i+1..end] {
285 info.mask |= post_mask;
286 }
287
288 i = end;
289 } else {
290 i += 1;
291 }
292 }
293}
294
295fn set_unicode_props(buffer: &mut Buffer) {
296 let len = buffer.len;
305
306 let mut i = 0;
307 while i < len {
308 let info = &mut buffer.info[i];
309 info.init_unicode_props(&mut buffer.scratch_flags);
310
311 if info.general_category() == GeneralCategory::ModifierSymbol
314 && matches!(info.glyph_id, 0x1F3FB..=0x1F3FF)
315 {
316 info.set_continuation();
317 } else if info.is_zwj() {
318 info.set_continuation();
319 if let Some(next) = buffer.info[..len].get_mut(i + 1) {
320 if next.as_char().is_emoji_extended_pictographic() {
321 next.init_unicode_props(&mut buffer.scratch_flags);
322 next.set_continuation();
323 i += 1;
324 }
325 }
326 } else if matches!(info.glyph_id, 0xE0020..=0xE007F) {
327 info.set_continuation();
339 }
340
341 i += 1;
342 }
343}
344
345fn insert_dotted_circle(buffer: &mut Buffer, face: &Face) {
346 if !buffer.flags.contains(BufferFlags::DO_NOT_INSERT_DOTTED_CIRCLE)
347 && buffer.flags.contains(BufferFlags::BEGINNING_OF_TEXT)
348 && buffer.context_len[0] == 0
349 && buffer.info[0].is_unicode_mark()
350 && face.has_glyph(0x25CC)
351 {
352 let mut info = GlyphInfo {
353 glyph_id: 0x25CC,
354 mask: buffer.cur(0).mask,
355 cluster: buffer.cur(0).cluster,
356 var1: 0,
357 var2: 0,
358 };
359
360 info.init_unicode_props(&mut buffer.scratch_flags);
361 buffer.clear_output();
362 buffer.output_info(info);
363
364 while buffer.idx < buffer.len && buffer.successful {
365 buffer.next_glyph();
366 }
367
368 buffer.swap_buffers();
369 }
370}
371
372fn form_clusters(buffer: &mut Buffer) {
373 if buffer.scratch_flags.contains(BufferScratchFlags::HAS_NON_ASCII) {
374 if buffer.cluster_level == BufferClusterLevel::MonotoneGraphemes {
375 foreach_grapheme!(buffer, start, end, {
376 buffer.merge_clusters(start, end)
377 });
378 } else {
379 foreach_grapheme!(buffer, start, end, {
380 buffer.unsafe_to_break(start, end);
381 });
382 }
383 }
384}
385
386fn ensure_native_direction(buffer: &mut Buffer) {
387 let dir = buffer.direction;
388 let hor = buffer.script.and_then(Direction::from_script).unwrap_or_default();
389
390 if (dir.is_horizontal() && dir != hor && hor != Direction::Invalid)
391 || (dir.is_vertical() && dir != Direction::TopToBottom)
392 {
393 if buffer.cluster_level == BufferClusterLevel::MonotoneCharacters {
394 foreach_grapheme!(buffer, start, end, {
395 buffer.merge_clusters(start, end);
396 buffer.reverse_range(start, end);
397 });
398 } else {
399 foreach_grapheme!(buffer, start, end, {
400 buffer.reverse_range(start, end);
402 })
403 }
404
405 buffer.reverse();
406 buffer.direction = buffer.direction.reverse();
407 }
408}
409
410fn rotate_chars(ctx: &mut ShapeContext) {
411 let len = ctx.buffer.len;
412
413 if ctx.target_direction.is_backward() {
414 let rtlm_mask = ctx.plan.rtlm_mask;
415
416 for info in &mut ctx.buffer.info[..len] {
417 if let Some(c) = info.as_char().mirrored().map(u32::from) {
418 if ctx.face.has_glyph(c) {
419 info.glyph_id = c;
420 continue;
421 }
422 }
423 info.mask |= rtlm_mask;
424 }
425 }
426
427 if ctx.target_direction.is_vertical() && !ctx.plan.has_vert {
428 for info in &mut ctx.buffer.info[..len] {
429 if let Some(c) = info.as_char().vertical().map(u32::from) {
430 if ctx.face.has_glyph(c) {
431 info.glyph_id = c;
432 }
433 }
434 }
435 }
436}
437
438fn map_glyphs_fast(buffer: &mut Buffer) {
439 let len = buffer.len;
441 for info in &mut buffer.info[..len] {
442 info.glyph_id = info.glyph_index();
443 }
444}
445
446fn synthesize_glyph_classes(buffer: &mut Buffer) {
447 let len = buffer.len;
448 for info in &mut buffer.info[..len] {
449 let class = if info.general_category() != GeneralCategory::NonspacingMark
458 || info.is_default_ignorable()
459 {
460 GlyphPropsFlags::BASE_GLYPH
461 } else {
462 GlyphPropsFlags::MARK
463 };
464
465 info.set_glyph_props(class.bits());
466 }
467}
468
469fn zero_width_default_ignorables(buffer: &mut Buffer) {
470 if buffer.scratch_flags.contains(BufferScratchFlags::HAS_DEFAULT_IGNORABLES)
471 && !buffer.flags.contains(BufferFlags::PRESERVE_DEFAULT_IGNORABLES)
472 && !buffer.flags.contains(BufferFlags::REMOVE_DEFAULT_IGNORABLES)
473 {
474 let len = buffer.len;
475 for (info, pos) in buffer.info[..len].iter().zip(&mut buffer.pos[..len]) {
476 if info.is_default_ignorable() {
477 pos.x_advance = 0;
478 pos.y_advance = 0;
479 pos.x_offset = 0;
480 pos.y_offset = 0;
481 }
482 }
483 }
484}
485
486fn zero_mark_widths_by_gdef(buffer: &mut Buffer, adjust_offsets: bool) {
487 let len = buffer.len;
488 for (info, pos) in buffer.info[..len].iter().zip(&mut buffer.pos[..len]) {
489 if info.is_mark() {
490 if adjust_offsets {
491 pos.x_offset -= pos.x_advance;
492 pos.y_offset -= pos.y_advance;
493 }
494
495 pos.x_advance = 0;
496 pos.y_advance = 0;
497 }
498 }
499}
500
501fn hide_default_ignorables(buffer: &mut Buffer, face: &Face) {
502 if buffer.scratch_flags.contains(BufferScratchFlags::HAS_DEFAULT_IGNORABLES)
503 && !buffer.flags.contains(BufferFlags::PRESERVE_DEFAULT_IGNORABLES)
504 {
505 if !buffer.flags.contains(BufferFlags::REMOVE_DEFAULT_IGNORABLES) {
506 if let Some(invisible) = buffer.invisible.or_else(|| face.glyph_index(u32::from(' '))) {
507 let len = buffer.len;
508 for info in &mut buffer.info[..len] {
509 if info.is_default_ignorable() {
510 info.glyph_id = u32::from(invisible.0);
511 }
512 }
513 return;
514 }
515 }
516
517 buffer.delete_glyphs_inplace(GlyphInfo::is_default_ignorable);
518 }
519}
520
521fn propagate_flags(buffer: &mut Buffer) {
522 if buffer.scratch_flags.contains(BufferScratchFlags::HAS_UNSAFE_TO_BREAK) {
525 foreach_cluster!(buffer, start, end, {
526 for info in &buffer.info[start..end] {
527 if info.mask & glyph_flag::UNSAFE_TO_BREAK != 0 {
528 for info in &mut buffer.info[start..end] {
529 info.mask |= glyph_flag::UNSAFE_TO_BREAK;
530 }
531 break;
532 }
533 }
534 });
535 }
536}