1use std::f64::consts::PI;
4
5use crate::{
6 euclid::{Point2D, Rect, Size2D, Vector2D},
7 legacy::{
8 glyph::{Shaping, WritingModeType},
9 image::{ImageMap, ImageStretches},
10 image_atlas::ImagePosition,
11 layout::symbol_instance::SymbolContent,
12 shaping::PositionedIcon,
13 style_types::{
14 AlignmentType, SymbolLayoutProperties_Evaluated, SymbolPlacementType, TextRotate,
15 TextRotationAlignment,
16 },
17 util::{
18 constants::ONE_EM,
19 math::{deg2radf, rotate},
20 },
21 TileSpace,
22 },
23};
24
25pub struct SymbolQuad {
27 pub tl: Point2D<f64, TileSpace>,
28 pub tr: Point2D<f64, TileSpace>,
29 pub bl: Point2D<f64, TileSpace>,
30 pub br: Point2D<f64, TileSpace>,
31 pub tex: Rect<u16, TileSpace>,
32 pub pixel_offset_tl: Point2D<f64, TileSpace>,
33 pub pixel_offset_br: Point2D<f64, TileSpace>,
34 pub glyph_offset: Point2D<f64, TileSpace>,
35 pub writing_mode: WritingModeType,
36 pub is_sdf: bool,
37 pub section_index: usize,
38 pub min_font_scale: Point2D<f64, TileSpace>,
39}
40
41pub type SymbolQuads = Vec<SymbolQuad>;
43
44const BORDER: u16 = ImagePosition::PADDING;
45
46fn compute_stretch_sum(stretches: &ImageStretches) -> f64 {
48 let mut sum = 0.;
49 for stretch in stretches {
50 sum += stretch.1 - stretch.0;
51 }
52 sum
53}
54
55fn sum_within_range(stretches: &ImageStretches, min: f64, max: f64) -> f64 {
57 let mut sum = 0.;
58 for stretch in stretches {
59 sum += min.max(max.min(stretch.1)) - min.max(max.min(stretch.0));
60 }
61 sum
62}
63
64fn get_em_offset(stretch_offset: f64, stretch_size: f64, icon_size: f64, icon_offset: f64) -> f64 {
66 icon_offset + icon_size * stretch_offset / stretch_size
67}
68
69fn get_px_offset(
71 fixed_offset: f64,
72 fixed_size: f64,
73 stretch_offset: f64,
74 stretch_size: f64,
75) -> f64 {
76 fixed_offset - fixed_size * stretch_offset / stretch_size
77}
78
79struct Cut {
81 fixed: f64,
82 stretch: f64,
83}
84
85type Cuts = Vec<Cut>;
87
88fn stretch_zones_to_cuts(
90 stretch_zones: &ImageStretches,
91 fixed_size: f64,
92 stretch_size: f64,
93) -> Cuts {
94 let mut cuts = vec![Cut {
95 fixed: -(BORDER as f64),
96 stretch: 0.0,
97 }];
98
99 for zone in stretch_zones {
100 let c1 = zone.0;
101 let c2 = zone.1;
102 let last_stretch = cuts.last().unwrap().stretch;
103 cuts.push(Cut {
104 fixed: c1 - last_stretch,
105 stretch: last_stretch,
106 });
107 cuts.push(Cut {
108 fixed: c1 - last_stretch,
109 stretch: last_stretch + (c2 - c1),
110 });
111 }
112 cuts.push(Cut {
113 fixed: fixed_size + BORDER as f64,
114 stretch: stretch_size,
115 });
116 cuts
117}
118
119fn matrix_multiply<U>(m: &[f64; 4], p: Point2D<f64, U>) -> Point2D<f64, U> {
121 Point2D::<f64, U>::new(m[0] * p.x + m[1] * p.y, m[2] * p.x + m[3] * p.y)
122}
123
124pub fn get_icon_quads(
126 shaped_icon: &PositionedIcon,
127 icon_rotate: f64,
128 icon_type: SymbolContent,
129 has_icon_text_fit: bool,
130) -> SymbolQuads {
131 let mut quads = Vec::new();
132
133 let image = &shaped_icon.image;
134 let pixel_ratio = image.pixel_ratio;
135 let image_width: u16 = image.padded_rect.width() - 2 * BORDER;
136 let image_height: u16 = image.padded_rect.height() - 2 * BORDER;
137
138 let icon_width = shaped_icon.right - shaped_icon.left;
139 let icon_height = shaped_icon.bottom - shaped_icon.top;
140
141 let stretch_xfull: ImageStretches = vec![(0.0, image_width as f64)];
142 let stretch_yfull: ImageStretches = vec![(0.0, image_height as f64)];
143 let stretch_x: &ImageStretches = if !image.stretch_x.is_empty() {
144 &image.stretch_x
145 } else {
146 &stretch_xfull
147 };
148 let stretch_y: &ImageStretches = if !image.stretch_y.is_empty() {
149 &image.stretch_y
150 } else {
151 &stretch_yfull
152 };
153
154 let stretch_width = compute_stretch_sum(stretch_x);
155 let stretch_height = compute_stretch_sum(stretch_y);
156 let fixed_width = image_width as f64 - stretch_width;
157 let fixed_height = image_height as f64 - stretch_height;
158
159 let mut stretch_offset_x = 0.;
160 let mut stretch_content_width = stretch_width;
161 let mut stretch_offset_y = 0.;
162 let mut stretch_content_height = stretch_height;
163 let mut fixed_offset_x = 0.;
164 let mut fixed_content_width = fixed_width;
165 let mut fixed_offset_y = 0.;
166 let mut fixed_content_height = fixed_height;
167
168 if has_icon_text_fit {
169 if let Some(content) = &image.content {
170 stretch_offset_x = sum_within_range(stretch_x, 0., content.left);
171 stretch_offset_y = sum_within_range(stretch_y, 0., content.top);
172 stretch_content_width = sum_within_range(stretch_x, content.left, content.right);
173 stretch_content_height = sum_within_range(stretch_y, content.top, content.bottom);
174 fixed_offset_x = content.left - stretch_offset_x;
175 fixed_offset_y = content.top - stretch_offset_y;
176 fixed_content_width = content.right - content.left - stretch_content_width;
177 fixed_content_height = content.bottom - content.top - stretch_content_height;
178 }
179 }
180
181 let mut matrix: Option<[f64; 4]> = None;
182 if icon_rotate != 0.0 {
183 let angle = deg2radf(icon_rotate);
185 let angle_sin = angle.sin();
186 let angle_cos = angle.cos();
187 matrix = Some([angle_cos, -angle_sin, angle_sin, angle_cos]);
188 }
189
190 let mut make_box = |left: &Cut, top: &Cut, right: &Cut, bottom: &Cut| {
191 let left_em = get_em_offset(
192 left.stretch - stretch_offset_x,
193 stretch_content_width,
194 icon_width,
195 shaped_icon.left,
196 );
197 let left_px = get_px_offset(
198 left.fixed - fixed_offset_x,
199 fixed_content_width,
200 left.stretch,
201 stretch_width,
202 );
203
204 let top_em = get_em_offset(
205 top.stretch - stretch_offset_y,
206 stretch_content_height,
207 icon_height,
208 shaped_icon.top,
209 );
210 let top_px = get_px_offset(
211 top.fixed - fixed_offset_y,
212 fixed_content_height,
213 top.stretch,
214 stretch_height,
215 );
216
217 let right_em = get_em_offset(
218 right.stretch - stretch_offset_x,
219 stretch_content_width,
220 icon_width,
221 shaped_icon.left,
222 );
223 let right_px = get_px_offset(
224 right.fixed - fixed_offset_x,
225 fixed_content_width,
226 right.stretch,
227 stretch_width,
228 );
229
230 let bottom_em = get_em_offset(
231 bottom.stretch - stretch_offset_y,
232 stretch_content_height,
233 icon_height,
234 shaped_icon.top,
235 );
236 let bottom_px = get_px_offset(
237 bottom.fixed - fixed_offset_y,
238 fixed_content_height,
239 bottom.stretch,
240 stretch_height,
241 );
242
243 let mut tl = Point2D::<f64, TileSpace>::new(left_em, top_em);
244 let mut tr = Point2D::<f64, TileSpace>::new(right_em, top_em);
245 let mut br = Point2D::<f64, TileSpace>::new(right_em, bottom_em);
246 let mut bl = Point2D::<f64, TileSpace>::new(left_em, bottom_em);
247 let pixel_offset_tl =
248 Point2D::<f64, TileSpace>::new(left_px / pixel_ratio, top_px / pixel_ratio);
249 let pixel_offset_br =
250 Point2D::<f64, TileSpace>::new(right_px / pixel_ratio, bottom_px / pixel_ratio);
251
252 if let Some(matrix) = matrix {
253 tl = matrix_multiply(&matrix, tl);
254 tr = matrix_multiply(&matrix, tr);
255 bl = matrix_multiply(&matrix, bl);
256 br = matrix_multiply(&matrix, br);
257 }
258
259 let x1 = left.stretch + left.fixed;
260 let x2 = right.stretch + right.fixed;
261 let y1 = top.stretch + top.fixed;
262 let y2 = bottom.stretch + bottom.fixed;
263
264 let sub_rect: Rect<u16, TileSpace> = Rect::new(
266 Point2D::new(
267 (image.padded_rect.origin.x as f64 + BORDER as f64 + x1) as u16,
268 (image.padded_rect.origin.y as f64 + BORDER as f64 + y1) as u16,
269 ),
270 Size2D::new((x2 - x1) as u16, (y2 - y1) as u16),
271 );
272
273 let min_font_scale_x = fixed_content_width / pixel_ratio / icon_width;
274 let min_font_scale_y = fixed_content_height / pixel_ratio / icon_height;
275
276 quads.push(SymbolQuad {
278 tl,
279 tr,
280 bl,
281 br,
282 tex: sub_rect,
283 pixel_offset_tl,
284 pixel_offset_br,
285 glyph_offset: Point2D::new(0.0, 0.0),
286 writing_mode: WritingModeType::None,
287 is_sdf: icon_type == SymbolContent::IconSDF,
288 section_index: 0,
289 min_font_scale: Point2D::new(min_font_scale_x, min_font_scale_y),
290 });
291 };
292
293 if !has_icon_text_fit || (image.stretch_x.is_empty() && image.stretch_y.is_empty()) {
294 make_box(
295 &Cut {
296 fixed: 0.,
297 stretch: -1.,
298 },
299 &Cut {
300 fixed: 0.,
301 stretch: -1.,
302 },
303 &Cut {
304 fixed: 0.,
305 stretch: (image_width + 1) as f64,
306 },
307 &Cut {
308 fixed: 0.,
309 stretch: (image_height + 1) as f64,
310 },
311 );
312 } else {
313 let x_cuts = stretch_zones_to_cuts(stretch_x, fixed_width, stretch_width);
314 let y_cuts = stretch_zones_to_cuts(stretch_y, fixed_height, stretch_height);
315
316 for xi in 0..x_cuts.len() - 1 {
317 let x1 = &x_cuts[xi];
318 let x2 = &x_cuts[xi + 1];
319 for yi in 0..y_cuts.len() - 1 {
320 let y1 = &y_cuts[yi];
321 let y2 = &y_cuts[yi + 1];
322 make_box(x1, y1, x2, y2);
323 }
324 }
325 }
326
327 quads
328}
329
330pub fn get_glyph_quads(
332 shaped_text: &Shaping,
333 text_offset: [f64; 2],
334 layout: &SymbolLayoutProperties_Evaluated,
335 placement: SymbolPlacementType,
336 image_map: &ImageMap,
337 allow_vertical_placement: bool,
338) -> SymbolQuads {
339 let text_rotate: f64 = deg2radf(layout.get_eval::<TextRotate>());
340 let along_line: bool = layout.get::<TextRotationAlignment>() == AlignmentType::Map
341 && placement != SymbolPlacementType::Point;
342
343 let mut quads = Vec::new();
344
345 for line in &shaped_text.positioned_lines {
346 for positioned_glyph in &line.positioned_glyphs {
347 if positioned_glyph.rect.is_empty() {
348 continue;
349 }
350
351 let glyph_padding = 1.0;
353 let mut rect_buffer = 3.0 + glyph_padding;
354 let mut pixel_ratio = 1.0;
355 let mut line_offset = 0.0;
356 let rotate_vertical_glyph =
357 (along_line || allow_vertical_placement) && positioned_glyph.vertical;
358 let half_advance =
359 positioned_glyph.metrics.advance as f64 * positioned_glyph.scale / 2.0;
360 let rect = positioned_glyph.rect;
361 let mut is_sdf = true;
362
363 if allow_vertical_placement && shaped_text.verticalizable {
365 let scaled_glyph_offset = (positioned_glyph.scale - 1.) * ONE_EM;
366 let image_offset =
367 (ONE_EM - positioned_glyph.metrics.width as f64 * positioned_glyph.scale) / 2.0;
368 line_offset = line.line_offset / 2.0
369 - (if positioned_glyph.image_id.is_some() {
370 -image_offset
371 } else {
372 scaled_glyph_offset
373 });
374 }
375
376 if let Some(image_id) = &positioned_glyph.image_id {
377 let image = image_map.get(image_id);
378 if let Some(image) = image {
379 pixel_ratio = image.pixel_ratio;
380 rect_buffer = ImagePosition::PADDING as f64 / pixel_ratio;
381 is_sdf = image.sdf;
382 }
383 }
384
385 let glyph_offset = if along_line {
386 Point2D::new(positioned_glyph.x + half_advance, positioned_glyph.y)
387 } else {
388 Point2D::new(0.0, 0.0)
389 };
390
391 let mut built_in_offset = if along_line {
392 Vector2D::new(0.0, 0.0)
393 } else {
394 Vector2D::new(
395 positioned_glyph.x + half_advance + text_offset[0],
396 positioned_glyph.y + text_offset[1] - line_offset,
397 )
398 };
399
400 let mut verticalized_label_offset = Vector2D::<f64, TileSpace>::new(0.0, 0.0);
401 if rotate_vertical_glyph {
402 verticalized_label_offset = built_in_offset;
407 built_in_offset = Vector2D::new(0.0, 0.0);
408 }
409
410 let x1 = (positioned_glyph.metrics.left as f64 - rect_buffer) * positioned_glyph.scale
411 - half_advance
412 + built_in_offset.x;
413 let y1 = (-positioned_glyph.metrics.top as f64 - rect_buffer) * positioned_glyph.scale
414 + built_in_offset.y;
415 let x2 = x1 + rect.width() as f64 * positioned_glyph.scale / pixel_ratio;
416 let y2 = y1 + rect.height() as f64 * positioned_glyph.scale / pixel_ratio;
417
418 let mut tl: Point2D<f64, TileSpace> = Point2D::new(x1, y1);
419 let mut tr: Point2D<f64, TileSpace> = Point2D::new(x2, y1);
420 let mut bl: Point2D<f64, TileSpace> = Point2D::new(x1, y2);
421 let mut br: Point2D<f64, TileSpace> = Point2D::new(x2, y2);
422
423 if rotate_vertical_glyph {
424 let center = Point2D::new(-half_advance, half_advance - Shaping::Y_OFFSET as f64);
437 let vertical_rotation = -PI / 2.;
438
439 let x_half_widht_offsetcorrection = ONE_EM / 2. - half_advance;
443 let y_image_offset_correction = if positioned_glyph.image_id.is_some() {
444 x_half_widht_offsetcorrection
445 } else {
446 0.0
447 };
448
449 let x_offset_correction = Vector2D::<f64, TileSpace>::new(
450 5.0 - Shaping::Y_OFFSET as f64 - x_half_widht_offsetcorrection,
451 -y_image_offset_correction,
452 );
453
454 tl = center
455 + rotate(&(tl - center), vertical_rotation)
456 + x_offset_correction
457 + verticalized_label_offset;
458 tr = center
459 + rotate(&(tr - center), vertical_rotation)
460 + x_offset_correction
461 + verticalized_label_offset;
462 bl = center
463 + rotate(&(bl - center), vertical_rotation)
464 + x_offset_correction
465 + verticalized_label_offset;
466 br = center
467 + rotate(&(br - center), vertical_rotation)
468 + x_offset_correction
469 + verticalized_label_offset;
470 }
471
472 if text_rotate != 0.0 {
473 let angle_sin = text_rotate.sin();
476 let angle_cos = text_rotate.cos();
477 let matrix = [angle_cos, -angle_sin, angle_sin, angle_cos];
478
479 tl = matrix_multiply(&matrix, tl);
480 tr = matrix_multiply(&matrix, tr);
481 bl = matrix_multiply(&matrix, bl);
482 br = matrix_multiply(&matrix, br);
483 }
484
485 let pixel_offset_tl = Point2D::default();
486 let pixel_offset_br = Point2D::default();
487 let min_font_scale = Point2D::default();
488
489 quads.push(SymbolQuad {
490 tl,
491 tr,
492 bl,
493 br,
494 tex: rect,
495 pixel_offset_tl,
496 pixel_offset_br,
497 glyph_offset,
498 writing_mode: shaped_text.writing_mode,
499 is_sdf,
500 section_index: positioned_glyph.section_index,
501 min_font_scale,
502 });
503 }
504 }
505
506 quads
507}
508#[cfg(test)]
509mod tests {
510 use cgmath::ulps_eq;
511
512 use crate::{
513 euclid::{Point2D, Rect, Size2D},
514 legacy::{
515 geometry::anchor::Anchor,
516 geometry_tile_data::GeometryCoordinates,
517 glyph::{PositionedGlyph, PositionedLine, Shaping, WritingModeType},
518 image_atlas::ImagePosition,
519 layout::symbol_instance::SymbolContent,
520 quads::get_icon_quads,
521 shaping::PositionedIcon,
522 style_types::{IconTextFitType, SymbolAnchorType, SymbolLayoutProperties_Evaluated},
523 },
524 };
525
526 #[test]
527 pub fn get_icon_quads_normal() {
529 let layout = SymbolLayoutProperties_Evaluated;
530 let anchor = Anchor {
531 point: Point2D::new(2.0, 3.0),
532 angle: 0.0,
533 segment: Some(0),
534 };
535 let image: ImagePosition = ImagePosition {
536 pixel_ratio: 1.0,
537 padded_rect: Rect::new(Point2D::origin(), Size2D::new(15, 11)),
538 version: 0,
539 stretch_x: vec![],
540 stretch_y: vec![],
541 content: None,
542 };
543
544 let shaped_icon =
545 PositionedIcon::shape_icon(image.clone(), &[-6.5, -4.5], SymbolAnchorType::Center);
546
547 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
548
549 assert_eq!(quads.len(), 1);
550 let quad = &quads[0];
551 ulps_eq!(quad.tl.x, -14.);
552 ulps_eq!(quad.tl.y, -10.);
553 ulps_eq!(quad.tr.x, 1.);
554 ulps_eq!(quad.tr.y, -10.);
555 ulps_eq!(quad.bl.x, -14.);
556 ulps_eq!(quad.bl.y, 1.);
557 ulps_eq!(quad.br.x, 1.);
558 ulps_eq!(quad.br.y, 1.);
559 }
560
561 #[test]
562 pub fn get_icon_quads_style() {
564 let anchor = Anchor {
565 point: Point2D::new(0.0, 0.0),
566 angle: 0.0,
567 segment: Some(0),
568 };
569
570 let image: ImagePosition = ImagePosition {
571 pixel_ratio: 1.0,
572 padded_rect: Rect::new(Point2D::origin(), Size2D::new(20, 20)),
573 version: 0,
574 stretch_x: vec![],
575 stretch_y: vec![],
576 content: None,
577 };
578
579 let line = GeometryCoordinates::default();
580 let mut shaped_text: Shaping = Shaping {
581 top: -10.,
582 bottom: 30.0,
583 left: -60.,
584 right: 20.0,
585
586 positioned_lines: vec![],
587 writing_mode: WritingModeType::None,
588 verticalizable: false,
589 icons_in_text: false,
590 };
591
592 shaped_text.positioned_lines.push(PositionedLine::default());
595 shaped_text
596 .positioned_lines
597 .last_mut()
598 .unwrap()
599 .positioned_glyphs
600 .push(PositionedGlyph {
601 glyph: 32,
602 x: 0.0,
603 y: 0.0,
604 vertical: false,
605 font: 0,
606 scale: 0.0,
607 rect: Default::default(),
608 metrics: Default::default(),
609 image_id: None,
610 section_index: 0,
611 });
612
613 {
615 let shaped_icon =
616 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
617
618 ulps_eq!(-18.5, shaped_icon.top);
619 ulps_eq!(-0.5, shaped_icon.right);
620 ulps_eq!(-0.5, shaped_icon.bottom);
621 ulps_eq!(-18.5, shaped_icon.left);
622
623 let layout = SymbolLayoutProperties_Evaluated;
624 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
625
626 assert_eq!(quads.len(), 1);
627 let quad = &quads[0];
628
629 ulps_eq!(quad.tl.x, -19.5);
630 ulps_eq!(quad.tl.y, -19.5);
631 ulps_eq!(quad.tr.x, 0.5);
632 ulps_eq!(quad.tr.y, -19.5);
633 ulps_eq!(quad.bl.x, -19.5);
634 ulps_eq!(quad.bl.y, 0.5);
635 ulps_eq!(quad.br.x, 0.5);
636 ulps_eq!(quad.br.y, 0.5);
637 }
638
639 {
641 let mut shaped_icon =
642 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
643 shaped_icon.fit_icon_to_text(
644 &shaped_text,
645 IconTextFitType::Width,
646 &[0., 0., 0., 0.],
647 &[0., 0.],
648 24.0 / 24.0,
649 );
650 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
651
652 assert_eq!(quads.len(), 1);
653 let quad = &quads[0];
654
655 ulps_eq!(quad.tl.x, -64.4444427);
656 ulps_eq!(quad.tl.y, 0.);
657 ulps_eq!(quad.tr.x, 24.4444427);
658 ulps_eq!(quad.tr.y, 0.);
659 ulps_eq!(quad.bl.x, -64.4444427);
660 ulps_eq!(quad.bl.y, 20.);
661 ulps_eq!(quad.br.x, 24.4444427);
662 ulps_eq!(quad.br.y, 20.);
663 }
664
665 {
667 let mut shaped_icon =
668 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
669 shaped_icon.fit_icon_to_text(
670 &shaped_text,
671 IconTextFitType::Width,
672 &[0., 0., 0., 0.],
673 &[0., 0.],
674 12.0 / 24.0,
675 );
676 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
677
678 assert_eq!(quads.len(), 1);
679 let quad = &quads[0];
680
681 ulps_eq!(quad.tl.x, -32.2222214);
682 ulps_eq!(quad.tl.y, -5.);
683 ulps_eq!(quad.tr.x, 12.2222214);
684 ulps_eq!(quad.tr.y, -5.);
685 ulps_eq!(quad.bl.x, -32.2222214);
686 ulps_eq!(quad.bl.y, 15.);
687 ulps_eq!(quad.br.x, 12.2222214);
688 ulps_eq!(quad.br.y, 15.);
689 }
690
691 {
693 let mut shaped_icon =
694 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
695 shaped_icon.fit_icon_to_text(
696 &shaped_text,
697 IconTextFitType::Width,
698 &[5., 10., 5., 10.],
699 &[0., 0.],
700 12.0 / 24.0,
701 );
702 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
703
704 assert_eq!(quads.len(), 1);
705 let quad = &quads[0];
706
707 ulps_eq!(quad.tl.x, -43.3333321);
708 ulps_eq!(quad.tl.y, -5.);
709 ulps_eq!(quad.tr.x, 23.3333321);
710 ulps_eq!(quad.tr.y, -5.);
711 ulps_eq!(quad.bl.x, -43.3333321);
712 ulps_eq!(quad.bl.y, 15.);
713 ulps_eq!(quad.br.x, 23.3333321);
714 ulps_eq!(quad.br.y, 15.);
715 }
716
717 {
719 let mut shaped_icon =
720 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
721 shaped_icon.fit_icon_to_text(
722 &shaped_text,
723 IconTextFitType::Height,
724 &[0., 0., 0., 0.],
725 &[0., 0.],
726 24.0 / 24.0,
727 );
728 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
729
730 assert_eq!(quads.len(), 1);
731 let quad = &quads[0];
732
733 ulps_eq!(quad.tl.x, -30.);
734 ulps_eq!(quad.tl.y, -12.2222214);
735 ulps_eq!(quad.tr.x, -10.);
736 ulps_eq!(quad.tr.y, -12.2222214);
737 ulps_eq!(quad.bl.x, -30.);
738 ulps_eq!(quad.bl.y, 32.2222214);
739 ulps_eq!(quad.br.x, -10.);
740 ulps_eq!(quad.br.y, 32.2222214);
741 }
742
743 {
745 let layout = SymbolLayoutProperties_Evaluated;
746 let mut shaped_icon =
747 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
748 shaped_icon.fit_icon_to_text(
749 &shaped_text,
750 IconTextFitType::Height,
751 &[0., 0., 0., 0.],
752 &[0., 0.],
753 12.0 / 24.0,
754 );
755 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
756
757 assert_eq!(quads.len(), 1);
758 let quad = &quads[0];
759
760 ulps_eq!(quad.tl.x, -20.);
761 ulps_eq!(quad.tl.y, -6.11111069);
762 ulps_eq!(quad.tr.x, 0.);
763 ulps_eq!(quad.tr.y, -6.11111069);
764 ulps_eq!(quad.bl.x, -20.);
765 ulps_eq!(quad.bl.y, 16.1111107);
766 ulps_eq!(quad.br.x, 0.);
767 ulps_eq!(quad.br.y, 16.1111107);
768 }
769
770 {
772 let mut shaped_icon =
773 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
774 shaped_icon.fit_icon_to_text(
775 &shaped_text,
776 IconTextFitType::Height,
777 &[5., 10., 5., 20.],
778 &[0., 0.],
779 12.0 / 24.0,
780 );
781 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
782
783 assert_eq!(quads.len(), 1);
784 let quad = &quads[0];
785
786 ulps_eq!(quad.tl.x, -20.);
787 ulps_eq!(quad.tl.y, -11.666666);
788 ulps_eq!(quad.tr.x, 0.);
789 ulps_eq!(quad.tr.y, -11.666666);
790 ulps_eq!(quad.bl.x, -20.);
791 ulps_eq!(quad.bl.y, 21.666666);
792 ulps_eq!(quad.br.x, 0.);
793 ulps_eq!(quad.br.y, 21.666666);
794 }
795
796 {
798 let mut shaped_icon =
799 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
800 shaped_icon.fit_icon_to_text(
801 &shaped_text,
802 IconTextFitType::Both,
803 &[0., 0., 0., 0.],
804 &[0., 0.],
805 24.0 / 24.0,
806 );
807 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
808
809 assert_eq!(quads.len(), 1);
810 let quad = &quads[0];
811
812 ulps_eq!(quad.tl.x, -64.4444427);
813 ulps_eq!(quad.tl.y, -12.2222214);
814 ulps_eq!(quad.tr.x, 24.4444427);
815 ulps_eq!(quad.tr.y, -12.2222214);
816 ulps_eq!(quad.bl.x, -64.4444427);
817 ulps_eq!(quad.bl.y, 32.2222214);
818 ulps_eq!(quad.br.x, 24.4444427);
819 ulps_eq!(quad.br.y, 32.2222214);
820 }
821
822 {
824 let mut shaped_icon =
825 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
826 shaped_icon.fit_icon_to_text(
827 &shaped_text,
828 IconTextFitType::Both,
829 &[0., 0., 0., 0.],
830 &[0., 0.],
831 12.0 / 24.0,
832 );
833 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
834
835 assert_eq!(quads.len(), 1);
836 let quad = &quads[0];
837
838 ulps_eq!(quad.tl.x, -32.2222214);
839 ulps_eq!(quad.tl.y, -6.11111069);
840 ulps_eq!(quad.tr.x, 12.2222214);
841 ulps_eq!(quad.tr.y, -6.11111069);
842 ulps_eq!(quad.bl.x, -32.2222214);
843 ulps_eq!(quad.bl.y, 16.1111107);
844 ulps_eq!(quad.br.x, 12.2222214);
845 ulps_eq!(quad.br.y, 16.1111107);
846 }
847
848 {
850 let mut shaped_icon =
851 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
852 shaped_icon.fit_icon_to_text(
853 &shaped_text,
854 IconTextFitType::Both,
855 &[5., 10., 5., 10.],
856 &[0., 0.],
857 12.0 / 24.0,
858 );
859 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
860
861 assert_eq!(quads.len(), 1);
862 let quad = &quads[0];
863
864 ulps_eq!(quad.tl.x, -43.3333321);
865 ulps_eq!(quad.tl.y, -11.666666);
866 ulps_eq!(quad.tr.x, 23.3333321);
867 ulps_eq!(quad.tr.y, -11.666666);
868 ulps_eq!(quad.bl.x, -43.3333321);
869 ulps_eq!(quad.bl.y, 21.666666);
870 ulps_eq!(quad.br.x, 23.3333321);
871 ulps_eq!(quad.br.y, 21.666666);
872 }
873
874 {
876 let layout = SymbolLayoutProperties_Evaluated;
877 let mut shaped_icon =
879 PositionedIcon::shape_icon(image.clone(), &[-9.5, -9.5], SymbolAnchorType::Center);
880 shaped_icon.fit_icon_to_text(
881 &shaped_text,
882 IconTextFitType::Both,
883 &[0., 5., 10., 15.],
884 &[0., 0.],
885 12.0 / 24.0,
886 );
887 let quads = get_icon_quads(&shaped_icon, 0., SymbolContent::IconRGBA, false);
888
889 assert_eq!(quads.len(), 1);
890 let quad = &quads[0];
891
892 ulps_eq!(quad.tl.x, -48.3333321);
893 ulps_eq!(quad.tl.y, -6.66666603);
894 ulps_eq!(quad.tr.x, 18.3333321);
895 ulps_eq!(quad.tr.y, -6.66666603);
896 ulps_eq!(quad.bl.x, -48.3333321);
897 ulps_eq!(quad.bl.y, 26.666666);
898 ulps_eq!(quad.br.x, 18.3333321);
899 ulps_eq!(quad.br.y, 26.666666);
900 }
901 }
902}