1use alloc::{
15 string::{String, ToString},
16 vec::Vec,
17};
18use core::fmt;
19
20use azul_css::{
21 props::{
22 basic::{
23 ColorF, ColorU, OptionColorU, OptionLayoutSize, PixelValue, SvgCubicCurve, SvgPoint,
24 SvgQuadraticCurve, SvgRect, SvgVector,
25 },
26 style::{StyleTransform, StyleTransformOrigin, StyleTransformVec},
27 },
28 AzString, OptionString, StringVec, U32Vec,
29};
30
31use crate::{
32 geom::PhysicalSizeU32,
33 gl::{
34 GlContextPtr, GlShader, IndexBufferFormat, Texture, Uniform, UniformType, VertexAttribute,
35 VertexAttributeType, VertexBuffer, VertexLayout, VertexLayoutDescription,
36 },
37 transform::{ComputedTransform3D, RotationMode},
38 xml::XmlError,
39};
40
41const DEFAULT_MITER_LIMIT: f32 = 4.0;
43const DEFAULT_LINE_WIDTH: f32 = 1.0;
45const DEFAULT_TOLERANCE: f32 = 0.1;
47
48#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
50#[repr(C)]
51pub struct SvgSize {
52 pub width: f32,
54 pub height: f32,
56}
57
58#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
60#[repr(C)]
61pub struct SvgLine {
62 pub start: SvgPoint,
64 pub end: SvgPoint,
66}
67
68impl SvgLine {
69 #[inline]
71 pub const fn new(start: SvgPoint, end: SvgPoint) -> Self {
72 Self { start, end }
73 }
74
75 pub fn inwards_normal(&self) -> Option<SvgPoint> {
80 let dx = self.end.x - self.start.x;
81 let dy = self.end.y - self.start.y;
82 let edge_length = (dx * dx + dy * dy).sqrt();
83 let x = -dy / edge_length;
84 let y = dx / edge_length;
85
86 if x.is_finite() && y.is_finite() {
87 Some(SvgPoint { x, y })
88 } else {
89 None
90 }
91 }
92
93 pub fn outwards_normal(&self) -> Option<SvgPoint> {
95 let inwards = self.inwards_normal()?;
96 Some(SvgPoint {
97 x: -inwards.x,
98 y: -inwards.y,
99 })
100 }
101
102 pub fn reverse(&mut self) {
104 let temp = self.start;
105 self.start = self.end;
106 self.end = temp;
107 }
108 pub fn get_start(&self) -> SvgPoint {
110 self.start
111 }
112 pub fn get_end(&self) -> SvgPoint {
114 self.end
115 }
116
117 pub fn get_t_at_offset(&self, offset: f64) -> f64 {
119 offset / self.get_length()
120 }
121
122 pub fn get_tangent_vector_at_t(&self) -> SvgVector {
126 let dx = self.end.x - self.start.x;
127 let dy = self.end.y - self.start.y;
128 SvgVector {
129 x: dx as f64,
130 y: dy as f64,
131 }
132 .normalize()
133 }
134
135 pub fn get_x_at_t(&self, t: f64) -> f64 {
137 self.start.x as f64 + (self.end.x as f64 - self.start.x as f64) * t
138 }
139
140 pub fn get_y_at_t(&self, t: f64) -> f64 {
142 self.start.y as f64 + (self.end.y as f64 - self.start.y as f64) * t
143 }
144
145 pub fn get_length(&self) -> f64 {
147 let dx = self.end.x - self.start.x;
148 let dy = self.end.y - self.start.y;
149 libm::hypotf(dx, dy) as f64
150 }
151
152 pub fn get_bounds(&self) -> SvgRect {
154 let min_x = self.start.x.min(self.end.x);
155 let max_x = self.start.x.max(self.end.x);
156
157 let min_y = self.start.y.min(self.end.y);
158 let max_y = self.start.y.max(self.end.y);
159
160 let width = (max_x - min_x).abs();
161 let height = (max_y - min_y).abs();
162
163 SvgRect {
164 width,
165 height,
166 x: min_x,
167 y: min_y,
168 radius_top_left: 0.0,
169 radius_top_right: 0.0,
170 radius_bottom_left: 0.0,
171 radius_bottom_right: 0.0,
172 }
173 }
174}
175
176#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
177#[repr(C, u8)]
178pub enum SvgPathElement {
179 Line(SvgLine),
180 QuadraticCurve(SvgQuadraticCurve),
181 CubicCurve(SvgCubicCurve),
182}
183
184impl_option!(
185 SvgPathElement,
186 OptionSvgPathElement,
187 [Debug, Copy, Clone, PartialEq, PartialOrd]
188);
189
190impl SvgPathElement {
191 #[inline]
193 pub const fn line(l: SvgLine) -> Self {
194 SvgPathElement::Line(l)
195 }
196
197 #[inline]
199 pub const fn quadratic_curve(qc: SvgQuadraticCurve) -> Self {
200 SvgPathElement::QuadraticCurve(qc)
201 }
202
203 #[inline]
205 pub const fn cubic_curve(cc: SvgCubicCurve) -> Self {
206 SvgPathElement::CubicCurve(cc)
207 }
208
209 pub fn set_last(&mut self, point: SvgPoint) {
211 match self {
212 SvgPathElement::Line(l) => l.end = point,
213 SvgPathElement::QuadraticCurve(qc) => qc.end = point,
214 SvgPathElement::CubicCurve(cc) => cc.end = point,
215 }
216 }
217
218 pub fn set_first(&mut self, point: SvgPoint) {
220 match self {
221 SvgPathElement::Line(l) => l.start = point,
222 SvgPathElement::QuadraticCurve(qc) => qc.start = point,
223 SvgPathElement::CubicCurve(cc) => cc.start = point,
224 }
225 }
226
227 pub fn reverse(&mut self) {
229 match self {
230 SvgPathElement::Line(l) => l.reverse(),
231 SvgPathElement::QuadraticCurve(qc) => qc.reverse(),
232 SvgPathElement::CubicCurve(cc) => cc.reverse(),
233 }
234 }
235 pub fn get_start(&self) -> SvgPoint {
237 match self {
238 SvgPathElement::Line(l) => l.get_start(),
239 SvgPathElement::QuadraticCurve(qc) => qc.get_start(),
240 SvgPathElement::CubicCurve(cc) => cc.get_start(),
241 }
242 }
243 pub fn get_end(&self) -> SvgPoint {
245 match self {
246 SvgPathElement::Line(l) => l.get_end(),
247 SvgPathElement::QuadraticCurve(qc) => qc.get_end(),
248 SvgPathElement::CubicCurve(cc) => cc.get_end(),
249 }
250 }
251 pub fn get_bounds(&self) -> SvgRect {
253 match self {
254 SvgPathElement::Line(l) => l.get_bounds(),
255 SvgPathElement::QuadraticCurve(qc) => qc.get_bounds(),
256 SvgPathElement::CubicCurve(cc) => cc.get_bounds(),
257 }
258 }
259 pub fn get_length(&self) -> f64 {
261 match self {
262 SvgPathElement::Line(l) => l.get_length(),
263 SvgPathElement::QuadraticCurve(qc) => qc.get_length(),
264 SvgPathElement::CubicCurve(cc) => cc.get_length(),
265 }
266 }
267 pub fn get_t_at_offset(&self, offset: f64) -> f64 {
269 match self {
270 SvgPathElement::Line(l) => l.get_t_at_offset(offset),
271 SvgPathElement::QuadraticCurve(qc) => qc.get_t_at_offset(offset),
272 SvgPathElement::CubicCurve(cc) => cc.get_t_at_offset(offset),
273 }
274 }
275 pub fn get_tangent_vector_at_t(&self, t: f64) -> SvgVector {
277 match self {
278 SvgPathElement::Line(l) => l.get_tangent_vector_at_t(),
279 SvgPathElement::QuadraticCurve(qc) => qc.get_tangent_vector_at_t(t),
280 SvgPathElement::CubicCurve(cc) => cc.get_tangent_vector_at_t(t),
281 }
282 }
283 pub fn get_x_at_t(&self, t: f64) -> f64 {
285 match self {
286 SvgPathElement::Line(l) => l.get_x_at_t(t),
287 SvgPathElement::QuadraticCurve(qc) => qc.get_x_at_t(t),
288 SvgPathElement::CubicCurve(cc) => cc.get_x_at_t(t),
289 }
290 }
291 pub fn get_y_at_t(&self, t: f64) -> f64 {
293 match self {
294 SvgPathElement::Line(l) => l.get_y_at_t(t),
295 SvgPathElement::QuadraticCurve(qc) => qc.get_y_at_t(t),
296 SvgPathElement::CubicCurve(cc) => cc.get_y_at_t(t),
297 }
298 }
299}
300
301impl_vec!(SvgPathElement, SvgPathElementVec, SvgPathElementVecDestructor, SvgPathElementVecDestructorType, SvgPathElementVecSlice, OptionSvgPathElement);
302impl_vec_debug!(SvgPathElement, SvgPathElementVec);
303impl_vec_clone!(
304 SvgPathElement,
305 SvgPathElementVec,
306 SvgPathElementVecDestructor
307);
308impl_vec_partialeq!(SvgPathElement, SvgPathElementVec);
309impl_vec_partialord!(SvgPathElement, SvgPathElementVec);
310
311#[derive(Debug, Clone, PartialEq, PartialOrd)]
312#[repr(C)]
313pub struct SvgPath {
314 pub items: SvgPathElementVec,
315}
316
317impl_option!(
318 SvgPath,
319 OptionSvgPath,
320 copy = false,
321 [Debug, Clone, PartialEq, PartialOrd]
322);
323
324impl SvgPath {
325 #[inline]
327 pub const fn create(items: SvgPathElementVec) -> Self {
328 Self { items }
329 }
330
331 pub fn get_start(&self) -> Option<SvgPoint> {
333 self.items.as_ref().first().map(|s| s.get_start())
334 }
335
336 pub fn get_end(&self) -> Option<SvgPoint> {
338 self.items.as_ref().last().map(|s| s.get_end())
339 }
340
341 pub fn close(&mut self) {
343 let first = match self.items.as_ref().first() {
344 Some(s) => s,
345 None => return,
346 };
347 let last = match self.items.as_ref().last() {
348 Some(s) => s,
349 None => return,
350 };
351 if first.get_start() != last.get_end() {
352 let mut elements = self.items.as_slice().to_vec();
353 elements.push(SvgPathElement::Line(SvgLine {
354 start: last.get_end(),
355 end: first.get_start(),
356 }));
357 self.items = elements.into();
358 }
359 }
360
361 pub fn is_closed(&self) -> bool {
363 let first = self.items.as_ref().first();
364 let last = self.items.as_ref().last();
365 match (first, last) {
366 (Some(f), Some(l)) => (f.get_start() == l.get_end()),
367 _ => false,
368 }
369 }
370
371 pub fn reverse(&mut self) {
373 let mut vec = SvgPathElementVec::from_const_slice(&[]);
375 core::mem::swap(&mut vec, &mut self.items);
376 let mut vec = vec.into_library_owned_vec();
377
378 vec.reverse();
380
381 for item in vec.iter_mut() {
384 item.reverse();
385 }
386
387 let mut vec = SvgPathElementVec::from_vec(vec);
389 core::mem::swap(&mut vec, &mut self.items);
390 }
391
392 pub fn join_with(&mut self, mut path: Self) -> Option<()> {
394 let self_last_point = self.items.as_ref().last()?.get_end();
395 let other_start_point = path.items.as_ref().first()?.get_start();
396 let interpolated_join_point = SvgPoint {
397 x: (self_last_point.x + other_start_point.x) / 2.0,
398 y: (self_last_point.y + other_start_point.y) / 2.0,
399 };
400
401 let mut vec = SvgPathElementVec::from_const_slice(&[]);
403 core::mem::swap(&mut vec, &mut self.items);
404 let mut vec = vec.into_library_owned_vec();
405
406 let mut other = SvgPathElementVec::from_const_slice(&[]);
407 core::mem::swap(&mut other, &mut path.items);
408 let mut other = other.into_library_owned_vec();
409
410 let vec_len = vec.len() - 1;
411 vec.get_mut(vec_len)?.set_last(interpolated_join_point);
412 other.get_mut(0)?.set_first(interpolated_join_point);
413 vec.append(&mut other);
414
415 let mut vec = SvgPathElementVec::from_vec(vec);
417 core::mem::swap(&mut vec, &mut self.items);
418
419 Some(())
420 }
421 pub fn get_bounds(&self) -> SvgRect {
423 let mut first_bounds = match self.items.as_ref().get(0) {
424 Some(s) => s.get_bounds(),
425 None => return SvgRect::default(),
426 };
427
428 for mp in self.items.as_ref().iter().skip(1) {
429 let mp_bounds = mp.get_bounds();
430 first_bounds.union_with(&mp_bounds);
431 }
432
433 first_bounds
434 }
435}
436
437#[derive(Debug, Clone, PartialEq, PartialOrd)]
438#[repr(C)]
439pub struct SvgMultiPolygon {
440 pub rings: SvgPathVec,
442}
443
444impl_option!(
445 SvgMultiPolygon,
446 OptionSvgMultiPolygon,
447 copy = false,
448 [Debug, Clone, PartialEq, PartialOrd]
449);
450
451impl SvgMultiPolygon {
452 #[inline]
455 pub const fn create(rings: SvgPathVec) -> Self {
456 Self { rings }
457 }
458
459 pub fn get_bounds(&self) -> SvgRect {
461 let mut first_bounds = match self
462 .rings
463 .get(0)
464 .and_then(|b| b.items.get(0).map(|i| i.get_bounds()))
465 {
466 Some(s) => s,
467 None => return SvgRect::default(),
469 };
470
471 for ring in self.rings.iter() {
472 for item in ring.items.iter() {
473 first_bounds.union_with(&item.get_bounds());
474 }
475 }
476
477 first_bounds
478 }
479}
480
481impl_vec!(SvgPath, SvgPathVec, SvgPathVecDestructor, SvgPathVecDestructorType, SvgPathVecSlice, OptionSvgPath);
482impl_vec_debug!(SvgPath, SvgPathVec);
483impl_vec_clone!(SvgPath, SvgPathVec, SvgPathVecDestructor);
484impl_vec_partialeq!(SvgPath, SvgPathVec);
485impl_vec_partialord!(SvgPath, SvgPathVec);
486
487impl_vec!(SvgMultiPolygon, SvgMultiPolygonVec, SvgMultiPolygonVecDestructor, SvgMultiPolygonVecDestructorType, SvgMultiPolygonVecSlice, OptionSvgMultiPolygon);
488impl_vec_debug!(SvgMultiPolygon, SvgMultiPolygonVec);
489impl_vec_clone!(
490 SvgMultiPolygon,
491 SvgMultiPolygonVec,
492 SvgMultiPolygonVecDestructor
493);
494impl_vec_partialeq!(SvgMultiPolygon, SvgMultiPolygonVec);
495impl_vec_partialord!(SvgMultiPolygon, SvgMultiPolygonVec);
496
497#[derive(Debug, Clone, PartialOrd, PartialEq)]
499#[repr(C, u8)]
500pub enum SvgNode {
501 MultiPolygonCollection(SvgMultiPolygonVec),
503 MultiPolygon(SvgMultiPolygon),
504 MultiShape(SvgSimpleNodeVec),
505 Path(SvgPath),
506 Circle(SvgCircle),
507 Rect(SvgRect),
508}
509
510#[derive(Debug, Clone, PartialOrd, PartialEq)]
512#[repr(C, u8)]
513pub enum SvgSimpleNode {
514 Path(SvgPath),
515 Circle(SvgCircle),
516 Rect(SvgRect),
517 CircleHole(SvgCircle),
518 RectHole(SvgRect),
519}
520
521impl_option!(
522 SvgSimpleNode,
523 OptionSvgSimpleNode,
524 copy = false,
525 [Debug, Clone, PartialOrd, PartialEq]
526);
527
528impl_vec!(SvgSimpleNode, SvgSimpleNodeVec, SvgSimpleNodeVecDestructor, SvgSimpleNodeVecDestructorType, SvgSimpleNodeVecSlice, OptionSvgSimpleNode);
529impl_vec_debug!(SvgSimpleNode, SvgSimpleNodeVec);
530impl_vec_clone!(SvgSimpleNode, SvgSimpleNodeVec, SvgSimpleNodeVecDestructor);
531impl_vec_partialeq!(SvgSimpleNode, SvgSimpleNodeVec);
532impl_vec_partialord!(SvgSimpleNode, SvgSimpleNodeVec);
533
534impl SvgSimpleNode {
535 pub fn get_bounds(&self) -> SvgRect {
537 match self {
538 SvgSimpleNode::Path(a) => a.get_bounds(),
539 SvgSimpleNode::Circle(a) => a.get_bounds(),
540 SvgSimpleNode::Rect(a) => a.clone(),
541 SvgSimpleNode::CircleHole(a) => a.get_bounds(),
542 SvgSimpleNode::RectHole(a) => a.clone(),
543 }
544 }
545 pub fn is_closed(&self) -> bool {
547 match self {
548 SvgSimpleNode::Path(a) => a.is_closed(),
549 SvgSimpleNode::Circle(_) => true,
550 SvgSimpleNode::Rect(_) => true,
551 SvgSimpleNode::CircleHole(_) => true,
552 SvgSimpleNode::RectHole(_) => true,
553 }
554 }
555}
556
557impl SvgNode {
558 pub fn get_bounds(&self) -> SvgRect {
560 match self {
561 SvgNode::MultiPolygonCollection(a) => {
562 let mut first_mp_bounds = match a.get(0) {
563 Some(s) => s.get_bounds(),
564 None => return SvgRect::default(),
565 };
566 for mp in a.iter().skip(1) {
567 let mp_bounds = mp.get_bounds();
568 first_mp_bounds.union_with(&mp_bounds);
569 }
570
571 first_mp_bounds
572 }
573 SvgNode::MultiPolygon(a) => a.get_bounds(),
574 SvgNode::MultiShape(a) => {
575 let mut first_mp_bounds = match a.get(0) {
576 Some(s) => s.get_bounds(),
577 None => return SvgRect::default(),
578 };
579 for mp in a.iter().skip(1) {
580 let mp_bounds = mp.get_bounds();
581 first_mp_bounds.union_with(&mp_bounds);
582 }
583
584 first_mp_bounds
585 }
586 SvgNode::Path(a) => a.get_bounds(),
587 SvgNode::Circle(a) => a.get_bounds(),
588 SvgNode::Rect(a) => a.clone(),
589 }
590 }
591 pub fn is_closed(&self) -> bool {
593 match self {
594 SvgNode::MultiPolygonCollection(a) => {
595 for mp in a.iter() {
596 for p in mp.rings.as_ref().iter() {
597 if !p.is_closed() {
598 return false;
599 }
600 }
601 }
602
603 true
604 }
605 SvgNode::MultiPolygon(a) => {
606 for p in a.rings.as_ref().iter() {
607 if !p.is_closed() {
608 return false;
609 }
610 }
611
612 true
613 }
614 SvgNode::MultiShape(a) => {
615 for p in a.as_ref().iter() {
616 if !p.is_closed() {
617 return false;
618 }
619 }
620
621 true
622 }
623 SvgNode::Path(a) => a.is_closed(),
624 SvgNode::Circle(_) => true,
625 SvgNode::Rect(_) => true,
626 }
627 }
628}
629
630#[derive(Debug, Clone, PartialOrd, PartialEq)]
632#[repr(C)]
633pub struct SvgStyledNode {
634 pub geometry: SvgNode,
635 pub style: SvgStyle,
636}
637
638#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
640#[repr(C)]
641pub struct SvgVertex {
642 pub x: f32,
643 pub y: f32,
644}
645
646impl_option!(
647 SvgVertex,
648 OptionSvgVertex,
649 [Debug, Copy, Clone, PartialOrd, PartialEq]
650);
651
652impl VertexLayoutDescription for SvgVertex {
653 fn get_description() -> VertexLayout {
654 VertexLayout {
655 fields: vec![VertexAttribute {
656 va_name: String::from("vAttrXY").into(),
657 layout_location: None.into(),
658 attribute_type: VertexAttributeType::Float,
659 item_count: 2,
660 }]
661 .into(),
662 }
663 }
664}
665
666#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
668#[repr(C)]
669pub struct SvgColoredVertex {
670 pub x: f32,
671 pub y: f32,
672 pub z: f32,
673 pub r: f32,
674 pub g: f32,
675 pub b: f32,
676 pub a: f32,
677}
678
679impl_option!(
680 SvgColoredVertex,
681 OptionSvgColoredVertex,
682 [Debug, Copy, Clone, PartialOrd, PartialEq]
683);
684
685impl VertexLayoutDescription for SvgColoredVertex {
686 fn get_description() -> VertexLayout {
687 VertexLayout {
688 fields: vec![
689 VertexAttribute {
690 va_name: String::from("vAttrXY").into(),
691 layout_location: None.into(),
692 attribute_type: VertexAttributeType::Float,
693 item_count: 3,
694 },
695 VertexAttribute {
696 va_name: String::from("vColor").into(),
697 layout_location: None.into(),
698 attribute_type: VertexAttributeType::Float,
699 item_count: 4,
700 },
701 ]
702 .into(),
703 }
704 }
705}
706
707#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
709#[repr(C)]
710pub struct SvgCircle {
711 pub center_x: f32,
712 pub center_y: f32,
713 pub radius: f32,
714}
715
716impl SvgCircle {
717 pub fn contains_point(&self, x: f32, y: f32) -> bool {
719 let x_diff = libm::fabsf(x - self.center_x);
720 let y_diff = libm::fabsf(y - self.center_y);
721 (x_diff * x_diff) + (y_diff * y_diff) < (self.radius * self.radius)
722 }
723 pub fn get_bounds(&self) -> SvgRect {
725 SvgRect {
726 width: self.radius * 2.0,
727 height: self.radius * 2.0,
728 x: self.center_x - self.radius,
729 y: self.center_y - self.radius,
730 radius_top_left: 0.0,
731 radius_top_right: 0.0,
732 radius_bottom_left: 0.0,
733 radius_bottom_right: 0.0,
734 }
735 }
736}
737
738#[derive(Debug, Clone, PartialEq, PartialOrd)]
739#[repr(C)]
740pub struct TessellatedSvgNode {
741 pub vertices: SvgVertexVec,
742 pub indices: U32Vec,
743}
744
745impl_option!(
746 TessellatedSvgNode,
747 OptionTessellatedSvgNode,
748 copy = false,
749 [Debug, Clone, PartialEq, PartialOrd]
750);
751
752impl Default for TessellatedSvgNode {
753 fn default() -> Self {
754 Self {
755 vertices: Vec::new().into(),
756 indices: Vec::new().into(),
757 }
758 }
759}
760
761impl_vec!(TessellatedSvgNode, TessellatedSvgNodeVec, TessellatedSvgNodeVecDestructor, TessellatedSvgNodeVecDestructorType, TessellatedSvgNodeVecSlice, OptionTessellatedSvgNode);
762impl_vec_debug!(TessellatedSvgNode, TessellatedSvgNodeVec);
763impl_vec_partialord!(TessellatedSvgNode, TessellatedSvgNodeVec);
764impl_vec_clone!(
765 TessellatedSvgNode,
766 TessellatedSvgNodeVec,
767 TessellatedSvgNodeVecDestructor
768);
769impl_vec_partialeq!(TessellatedSvgNode, TessellatedSvgNodeVec);
770
771impl TessellatedSvgNode {
772 pub fn empty() -> Self {
773 Self::default()
774 }
775}
776
777impl TessellatedSvgNodeVec {
778 pub fn get_ref(&self) -> TessellatedSvgNodeVecRef {
779 let slice = self.as_ref();
780 TessellatedSvgNodeVecRef {
781 ptr: slice.as_ptr(),
782 len: slice.len(),
783 }
784 }
785}
786
787impl fmt::Debug for TessellatedSvgNodeVecRef {
788 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
789 self.as_slice().fmt(f)
790 }
791}
792
793#[repr(C)]
795pub struct TessellatedSvgNodeVecRef {
796 pub ptr: *const TessellatedSvgNode,
797 pub len: usize,
798}
799
800impl Clone for TessellatedSvgNodeVecRef {
801 fn clone(&self) -> Self {
802 Self {
803 ptr: self.ptr,
804 len: self.len,
805 }
806 }
807}
808
809impl TessellatedSvgNodeVecRef {
810 pub fn as_slice<'a>(&'a self) -> &'a [TessellatedSvgNode] {
811 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
812 }
813}
814
815#[derive(Debug, Clone, PartialEq, PartialOrd)]
816#[repr(C)]
817pub struct TessellatedColoredSvgNode {
818 pub vertices: SvgColoredVertexVec,
819 pub indices: U32Vec,
820}
821
822impl_option!(
823 TessellatedColoredSvgNode,
824 OptionTessellatedColoredSvgNode,
825 copy = false,
826 [Debug, Clone, PartialEq, PartialOrd]
827);
828
829impl Default for TessellatedColoredSvgNode {
830 fn default() -> Self {
831 Self {
832 vertices: Vec::new().into(),
833 indices: Vec::new().into(),
834 }
835 }
836}
837
838impl_vec!(TessellatedColoredSvgNode, TessellatedColoredSvgNodeVec, TessellatedColoredSvgNodeVecDestructor, TessellatedColoredSvgNodeVecDestructorType, TessellatedColoredSvgNodeVecSlice, OptionTessellatedColoredSvgNode);
839impl_vec_debug!(TessellatedColoredSvgNode, TessellatedColoredSvgNodeVec);
840impl_vec_partialord!(TessellatedColoredSvgNode, TessellatedColoredSvgNodeVec);
841impl_vec_clone!(
842 TessellatedColoredSvgNode,
843 TessellatedColoredSvgNodeVec,
844 TessellatedColoredSvgNodeVecDestructor
845);
846impl_vec_partialeq!(TessellatedColoredSvgNode, TessellatedColoredSvgNodeVec);
847
848impl TessellatedColoredSvgNode {
849 pub fn empty() -> Self {
850 Self::default()
851 }
852}
853
854impl TessellatedColoredSvgNodeVec {
855 pub fn get_ref(&self) -> TessellatedColoredSvgNodeVecRef {
856 let slice = self.as_ref();
857 TessellatedColoredSvgNodeVecRef {
858 ptr: slice.as_ptr(),
859 len: slice.len(),
860 }
861 }
862}
863
864impl fmt::Debug for TessellatedColoredSvgNodeVecRef {
865 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
866 self.as_slice().fmt(f)
867 }
868}
869
870#[repr(C)]
872pub struct TessellatedColoredSvgNodeVecRef {
873 pub ptr: *const TessellatedColoredSvgNode,
874 pub len: usize,
875}
876
877impl Clone for TessellatedColoredSvgNodeVecRef {
878 fn clone(&self) -> Self {
879 Self {
880 ptr: self.ptr,
881 len: self.len,
882 }
883 }
884}
885
886impl TessellatedColoredSvgNodeVecRef {
887 pub fn as_slice<'a>(&'a self) -> &'a [TessellatedColoredSvgNode] {
888 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
889 }
890}
891
892impl_vec!(SvgVertex, SvgVertexVec, SvgVertexVecDestructor, SvgVertexVecDestructorType, SvgVertexVecSlice, OptionSvgVertex);
893impl_vec_debug!(SvgVertex, SvgVertexVec);
894impl_vec_partialord!(SvgVertex, SvgVertexVec);
895impl_vec_clone!(SvgVertex, SvgVertexVec, SvgVertexVecDestructor);
896impl_vec_partialeq!(SvgVertex, SvgVertexVec);
897
898impl_vec!(SvgColoredVertex, SvgColoredVertexVec, SvgColoredVertexVecDestructor, SvgColoredVertexVecDestructorType, SvgColoredVertexVecSlice, OptionSvgColoredVertex);
899impl_vec_debug!(SvgColoredVertex, SvgColoredVertexVec);
900impl_vec_partialord!(SvgColoredVertex, SvgColoredVertexVec);
901impl_vec_clone!(
902 SvgColoredVertex,
903 SvgColoredVertexVec,
904 SvgColoredVertexVecDestructor
905);
906impl_vec_partialeq!(SvgColoredVertex, SvgColoredVertexVec);
907
908fn compute_svg_transform_uniforms(
913 target_size: PhysicalSizeU32,
914 transforms: &[StyleTransform],
915) -> (Uniform, Uniform) {
916 let transform_origin = StyleTransformOrigin {
917 x: PixelValue::px(target_size.width as f32 / 2.0),
918 y: PixelValue::px(target_size.height as f32 / 2.0),
919 };
920
921 let computed_transform = ComputedTransform3D::from_style_transform_vec(
922 transforms,
923 &transform_origin,
924 target_size.width as f32,
925 target_size.height as f32,
926 RotationMode::ForWebRender,
927 );
928
929 let m = computed_transform.get_column_major().m;
932 let matrix: [f32; 16] = core::array::from_fn(|i| m[i / 4][i % 4]);
933
934 let bbox_uniform = Uniform {
935 uniform_name: "vBboxSize".into(),
936 uniform_type: UniformType::FloatVec2([
937 target_size.width as f32,
938 target_size.height as f32,
939 ]),
940 };
941
942 let transform_uniform = Uniform {
943 uniform_name: "vTransformMatrix".into(),
944 uniform_type: UniformType::Matrix4 {
945 transpose: false,
946 matrix,
947 },
948 };
949
950 (bbox_uniform, transform_uniform)
951}
952
953#[derive(Debug, Clone, PartialEq, PartialOrd)]
954#[repr(C)]
955pub struct TessellatedGPUSvgNode {
956 pub vertex_index_buffer: VertexBuffer,
957}
958
959impl TessellatedGPUSvgNode {
960 pub fn new(node: &TessellatedSvgNode, gl: GlContextPtr) -> Self {
962 let svg_shader_id = gl.ptr.svg_shader;
963 Self {
964 vertex_index_buffer: VertexBuffer::new(
965 gl,
966 svg_shader_id,
967 node.vertices.as_ref(),
968 node.indices.as_ref(),
969 IndexBufferFormat::Triangles,
970 ),
971 }
972 }
973
974 pub fn draw(
976 &self,
977 texture: &mut Texture,
978 target_size: PhysicalSizeU32,
979 color: ColorU,
980 transforms: StyleTransformVec,
981 ) -> bool {
982 let (bbox_uniform, transform_uniform) =
983 compute_svg_transform_uniforms(target_size, transforms.as_ref());
984
985 let color: ColorF = color.into();
986
987 let uniforms = [
988 bbox_uniform,
989 Uniform {
990 uniform_name: "fDrawColor".into(),
991 uniform_type: UniformType::FloatVec4([color.r, color.g, color.b, color.a]),
992 },
993 transform_uniform,
994 ];
995
996 GlShader::draw(
997 texture.gl_context.ptr.svg_shader,
998 texture,
999 &[(&self.vertex_index_buffer, &uniforms[..])],
1000 );
1001
1002 true
1003 }
1004}
1005
1006#[derive(Debug, Clone, PartialEq, PartialOrd)]
1007#[repr(C)]
1008pub struct TessellatedColoredGPUSvgNode {
1009 pub vertex_index_buffer: VertexBuffer,
1010}
1011
1012impl TessellatedColoredGPUSvgNode {
1013 pub fn new(node: &TessellatedColoredSvgNode, gl: GlContextPtr) -> Self {
1015 let svg_shader_id = gl.ptr.svg_multicolor_shader;
1016 Self {
1017 vertex_index_buffer: VertexBuffer::new(
1018 gl,
1019 svg_shader_id,
1020 node.vertices.as_ref(),
1021 node.indices.as_ref(),
1022 IndexBufferFormat::Triangles,
1023 ),
1024 }
1025 }
1026
1027 pub fn draw(
1029 &self,
1030 texture: &mut Texture,
1031 target_size: PhysicalSizeU32,
1032 transforms: StyleTransformVec,
1033 ) -> bool {
1034 let (bbox_uniform, transform_uniform) =
1035 compute_svg_transform_uniforms(target_size, transforms.as_ref());
1036
1037 let uniforms = [bbox_uniform, transform_uniform];
1038
1039 GlShader::draw(
1040 texture.gl_context.ptr.svg_multicolor_shader,
1041 texture,
1042 &[(&self.vertex_index_buffer, &uniforms[..])],
1043 );
1044
1045 true
1046 }
1047}
1048
1049#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1050#[repr(C, u8)]
1051pub enum SvgStyle {
1052 Fill(SvgFillStyle),
1053 Stroke(SvgStrokeStyle),
1054}
1055
1056impl SvgStyle {
1057 pub fn get_antialias(&self) -> bool {
1058 match self {
1059 SvgStyle::Fill(f) => f.anti_alias,
1060 SvgStyle::Stroke(s) => s.anti_alias,
1061 }
1062 }
1063 pub fn get_high_quality_aa(&self) -> bool {
1064 match self {
1065 SvgStyle::Fill(f) => f.high_quality_aa,
1066 SvgStyle::Stroke(s) => s.high_quality_aa,
1067 }
1068 }
1069 pub fn get_transform(&self) -> SvgTransform {
1070 match self {
1071 SvgStyle::Fill(f) => f.transform,
1072 SvgStyle::Stroke(s) => s.transform,
1073 }
1074 }
1075}
1076#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1078#[repr(C)]
1079pub enum SvgFillRule {
1080 Winding,
1081 EvenOdd,
1082}
1083
1084impl Default for SvgFillRule {
1085 fn default() -> Self {
1086 SvgFillRule::Winding
1087 }
1088}
1089
1090#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
1091#[repr(C)]
1092pub struct SvgTransform {
1093 pub sx: f32,
1094 pub kx: f32,
1095 pub ky: f32,
1096 pub sy: f32,
1097 pub tx: f32,
1098 pub ty: f32,
1099}
1100
1101#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1102#[repr(C)]
1103pub struct SvgFillStyle {
1104 pub line_join: SvgLineJoin,
1108 pub miter_limit: f32,
1113 pub tolerance: f32,
1118 pub fill_rule: SvgFillRule,
1120 pub transform: SvgTransform,
1123 pub anti_alias: bool,
1125 pub high_quality_aa: bool,
1127}
1128
1129impl Default for SvgFillStyle {
1130 fn default() -> Self {
1131 Self {
1132 line_join: SvgLineJoin::Miter,
1133 miter_limit: DEFAULT_MITER_LIMIT,
1134 tolerance: DEFAULT_TOLERANCE,
1135 fill_rule: SvgFillRule::default(),
1136 transform: SvgTransform::default(),
1137 anti_alias: true,
1138 high_quality_aa: false,
1139 }
1140 }
1141}
1142
1143#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1144#[repr(C)]
1145pub struct SvgStrokeStyle {
1146 pub dash_pattern: OptionSvgDashPattern,
1148 pub transform: SvgTransform,
1151 pub start_cap: SvgLineCap,
1155 pub end_cap: SvgLineCap,
1159 pub line_join: SvgLineJoin,
1163 pub line_width: f32,
1167 pub miter_limit: f32,
1172 pub tolerance: f32,
1177 pub apply_line_width: bool,
1185 pub anti_alias: bool,
1187 pub high_quality_aa: bool,
1189}
1190
1191impl Default for SvgStrokeStyle {
1192 fn default() -> Self {
1193 Self {
1194 dash_pattern: OptionSvgDashPattern::None,
1195 transform: SvgTransform::default(),
1196 start_cap: SvgLineCap::default(),
1197 end_cap: SvgLineCap::default(),
1198 line_join: SvgLineJoin::default(),
1199 line_width: DEFAULT_LINE_WIDTH,
1200 miter_limit: DEFAULT_MITER_LIMIT,
1201 tolerance: DEFAULT_TOLERANCE,
1202 apply_line_width: true,
1203 anti_alias: true,
1204 high_quality_aa: false,
1205 }
1206 }
1207}
1208
1209#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1210#[repr(C)]
1211pub struct SvgDashPattern {
1212 pub offset: f32,
1213 pub length_1: f32,
1214 pub gap_1: f32,
1215 pub length_2: f32,
1216 pub gap_2: f32,
1217 pub length_3: f32,
1218 pub gap_3: f32,
1219}
1220
1221impl_option!(
1222 SvgDashPattern,
1223 OptionSvgDashPattern,
1224 [Debug, Copy, Clone, PartialEq, PartialOrd]
1225);
1226
1227#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
1229#[repr(C)]
1230pub enum SvgLineCap {
1231 Butt,
1232 Square,
1233 Round,
1234}
1235
1236impl Default for SvgLineCap {
1237 fn default() -> Self {
1238 SvgLineCap::Butt
1239 }
1240}
1241
1242#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
1244#[repr(C)]
1245pub enum SvgLineJoin {
1246 Miter,
1247 MiterClip,
1248 Round,
1249 Bevel,
1250}
1251
1252impl Default for SvgLineJoin {
1253 fn default() -> Self {
1254 SvgLineJoin::Miter
1255 }
1256}
1257
1258pub use core::ffi::c_void;
1259
1260#[derive(Debug, Clone)]
1261#[repr(C)]
1262pub struct SvgXmlNode {
1263 pub node: *const c_void, pub run_destructor: bool,
1265}
1266
1267#[derive(Debug, Clone)]
1268#[repr(C)]
1269pub struct Svg {
1270 pub tree: *const c_void, pub run_destructor: bool,
1272}
1273
1274#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1276#[repr(C)]
1277pub enum ShapeRendering {
1278 OptimizeSpeed,
1279 CrispEdges,
1280 GeometricPrecision,
1281}
1282
1283#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1285#[repr(C)]
1286pub enum ImageRendering {
1287 OptimizeQuality,
1288 OptimizeSpeed,
1289}
1290
1291#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1293#[repr(C)]
1294pub enum TextRendering {
1295 OptimizeSpeed,
1296 OptimizeLegibility,
1297 GeometricPrecision,
1298}
1299
1300#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1302#[repr(C)]
1303pub enum FontDatabase {
1304 Empty,
1305 System,
1306}
1307
1308#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)]
1309#[repr(C)]
1310pub struct SvgRenderOptions {
1311 pub target_size: OptionLayoutSize,
1312 pub background_color: OptionColorU,
1313 pub fit: SvgFitTo,
1314 pub transform: SvgRenderTransform,
1315}
1316
1317#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)]
1318#[repr(C)]
1319pub struct SvgRenderTransform {
1320 pub sx: f32,
1321 pub kx: f32,
1322 pub ky: f32,
1323 pub sy: f32,
1324 pub tx: f32,
1325 pub ty: f32,
1326}
1327
1328#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1329#[repr(C, u8)]
1330pub enum SvgFitTo {
1331 Original,
1332 Width(u32),
1333 Height(u32),
1334 Zoom(f32),
1335}
1336
1337impl Default for SvgFitTo {
1338 fn default() -> Self {
1339 SvgFitTo::Original
1340 }
1341}
1342
1343#[derive(Debug, Clone, PartialEq, PartialOrd)]
1344#[repr(C)]
1345pub struct SvgParseOptions {
1346 pub relative_image_path: OptionString,
1348 pub default_font_family: AzString,
1351 pub languages: StringVec,
1354 pub dpi: f32,
1356 pub font_size: f32,
1359 pub shape_rendering: ShapeRendering,
1362 pub text_rendering: TextRendering,
1365 pub image_rendering: ImageRendering,
1368 pub fontdb: FontDatabase,
1370 pub keep_named_groups: bool,
1373}
1374
1375impl Default for SvgParseOptions {
1376 fn default() -> Self {
1377 let lang_vec: Vec<AzString> = vec![String::from("en").into()];
1378 SvgParseOptions {
1379 relative_image_path: OptionString::None,
1380 default_font_family: "Times New Roman".to_string().into(),
1381 languages: lang_vec.into(),
1382 dpi: 96.0,
1383 font_size: 12.0,
1384 shape_rendering: ShapeRendering::GeometricPrecision,
1385 text_rendering: TextRendering::OptimizeLegibility,
1386 image_rendering: ImageRendering::OptimizeQuality,
1387 fontdb: FontDatabase::System,
1388 keep_named_groups: false,
1389 }
1390 }
1391}
1392
1393#[derive(Debug, Clone, PartialEq, PartialOrd)]
1394#[repr(C)]
1395pub struct SvgXmlOptions {
1396 pub use_single_quote: bool,
1397 pub indent: Indent,
1398 pub attributes_indent: Indent,
1399}
1400
1401impl Default for SvgXmlOptions {
1402 fn default() -> Self {
1403 SvgXmlOptions {
1404 use_single_quote: false,
1405 indent: Indent::Spaces(2),
1406 attributes_indent: Indent::Spaces(2),
1407 }
1408 }
1409}
1410
1411#[derive(Debug, PartialEq, PartialOrd, Clone)]
1412#[repr(C, u8)]
1413pub enum SvgParseError {
1414 NoParserAvailable,
1415 ElementsLimitReached,
1416 NotAnUtf8Str,
1417 MalformedGZip,
1418 InvalidSize,
1419 ParsingFailed(XmlError),
1420}
1421
1422impl fmt::Display for SvgParseError {
1423 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1424 use self::SvgParseError::*;
1425 match self {
1426 NoParserAvailable => write!(
1427 f,
1428 "Library was compiled without SVG support (no parser available)"
1429 ),
1430 ElementsLimitReached => write!(f, "Error parsing SVG: Elements limit reached"),
1431 NotAnUtf8Str => write!(f, "Error parsing SVG: Not an UTF-8 String"),
1432 MalformedGZip => write!(
1433 f,
1434 "Error parsing SVG: SVG is compressed with a malformed GZIP compression"
1435 ),
1436 InvalidSize => write!(f, "Error parsing SVG: Invalid size"),
1437 ParsingFailed(e) => write!(f, "Error parsing SVG: Parsing SVG as XML failed: {}", e),
1438 }
1439 }
1440}
1441
1442impl_result!(
1443 SvgXmlNode,
1444 SvgParseError,
1445 ResultSvgXmlNodeSvgParseError,
1446 copy = false,
1447 [Debug, Clone]
1448);
1449impl_result!(
1450 Svg,
1451 SvgParseError,
1452 ResultSvgSvgParseError,
1453 copy = false,
1454 [Debug, Clone]
1455);
1456
1457#[derive(Debug, Clone, PartialEq, PartialOrd)]
1459#[repr(C, u8)]
1460pub enum Indent {
1461 None,
1462 Spaces(u8),
1463 Tabs,
1464}