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::{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 pub fn inwards_normal(&self) -> Option<SvgPoint> {
74 let dx = self.end.x - self.start.x;
75 let dy = self.end.y - self.start.y;
76 let edge_length = (dx * dx + dy * dy).sqrt();
77 let x = -dy / edge_length;
78 let y = dx / edge_length;
79
80 if x.is_finite() && y.is_finite() {
81 Some(SvgPoint { x, y })
82 } else {
83 None
84 }
85 }
86
87 pub fn outwards_normal(&self) -> Option<SvgPoint> {
88 let inwards = self.inwards_normal()?;
89 Some(SvgPoint {
90 x: -inwards.x,
91 y: -inwards.y,
92 })
93 }
94
95 pub fn reverse(&mut self) {
96 let temp = self.start;
97 self.start = self.end;
98 self.end = temp;
99 }
100 pub fn get_start(&self) -> SvgPoint {
101 self.start
102 }
103 pub fn get_end(&self) -> SvgPoint {
104 self.end
105 }
106
107 pub fn get_t_at_offset(&self, offset: f64) -> f64 {
108 offset / self.get_length()
109 }
110
111 pub fn get_tangent_vector_at_t(&self) -> SvgVector {
115 let dx = self.end.x - self.start.x;
116 let dy = self.end.y - self.start.y;
117 SvgVector {
118 x: dx as f64,
119 y: dy as f64,
120 }
121 .normalize()
122 }
123
124 pub fn get_x_at_t(&self, t: f64) -> f64 {
125 self.start.x as f64 + (self.end.x as f64 - self.start.x as f64) * t
126 }
127
128 pub fn get_y_at_t(&self, t: f64) -> f64 {
129 self.start.y as f64 + (self.end.y as f64 - self.start.y as f64) * t
130 }
131
132 pub fn get_length(&self) -> f64 {
133 let dx = self.end.x - self.start.x;
134 let dy = self.end.y - self.start.y;
135 libm::hypotf(dx, dy) as f64
136 }
137
138 pub fn get_bounds(&self) -> SvgRect {
139 let min_x = self.start.x.min(self.end.x);
140 let max_x = self.start.x.max(self.end.x);
141
142 let min_y = self.start.y.min(self.end.y);
143 let max_y = self.start.y.max(self.end.y);
144
145 let width = (max_x - min_x).abs();
146 let height = (max_y - min_y).abs();
147
148 SvgRect {
149 width,
150 height,
151 x: min_x,
152 y: min_y,
153 ..SvgRect::default()
154 }
155 }
156}
157
158#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
159#[repr(C, u8)]
160pub enum SvgPathElement {
161 Line(SvgLine),
162 QuadraticCurve(SvgQuadraticCurve),
163 CubicCurve(SvgCubicCurve),
164}
165
166impl SvgPathElement {
167 pub fn set_last(&mut self, point: SvgPoint) {
168 match self {
169 SvgPathElement::Line(l) => l.end = point,
170 SvgPathElement::QuadraticCurve(qc) => qc.end = point,
171 SvgPathElement::CubicCurve(cc) => cc.end = point,
172 }
173 }
174
175 pub fn set_first(&mut self, point: SvgPoint) {
176 match self {
177 SvgPathElement::Line(l) => l.start = point,
178 SvgPathElement::QuadraticCurve(qc) => qc.start = point,
179 SvgPathElement::CubicCurve(cc) => cc.start = point,
180 }
181 }
182
183 pub fn reverse(&mut self) {
184 match self {
185 SvgPathElement::Line(l) => l.reverse(),
186 SvgPathElement::QuadraticCurve(qc) => qc.reverse(),
187 SvgPathElement::CubicCurve(cc) => cc.reverse(),
188 }
189 }
190 pub fn get_start(&self) -> SvgPoint {
191 match self {
192 SvgPathElement::Line(l) => l.get_start(),
193 SvgPathElement::QuadraticCurve(qc) => qc.get_start(),
194 SvgPathElement::CubicCurve(cc) => cc.get_start(),
195 }
196 }
197 pub fn get_end(&self) -> SvgPoint {
198 match self {
199 SvgPathElement::Line(l) => l.get_end(),
200 SvgPathElement::QuadraticCurve(qc) => qc.get_end(),
201 SvgPathElement::CubicCurve(cc) => cc.get_end(),
202 }
203 }
204 pub fn get_bounds(&self) -> SvgRect {
205 match self {
206 SvgPathElement::Line(l) => l.get_bounds(),
207 SvgPathElement::QuadraticCurve(qc) => qc.get_bounds(),
208 SvgPathElement::CubicCurve(cc) => cc.get_bounds(),
209 }
210 }
211 pub fn get_length(&self) -> f64 {
212 match self {
213 SvgPathElement::Line(l) => l.get_length(),
214 SvgPathElement::QuadraticCurve(qc) => qc.get_length(),
215 SvgPathElement::CubicCurve(cc) => cc.get_length(),
216 }
217 }
218 pub fn get_t_at_offset(&self, offset: f64) -> f64 {
219 match self {
220 SvgPathElement::Line(l) => l.get_t_at_offset(offset),
221 SvgPathElement::QuadraticCurve(qc) => qc.get_t_at_offset(offset),
222 SvgPathElement::CubicCurve(cc) => cc.get_t_at_offset(offset),
223 }
224 }
225 pub fn get_tangent_vector_at_t(&self, t: f64) -> SvgVector {
226 match self {
227 SvgPathElement::Line(l) => l.get_tangent_vector_at_t(),
228 SvgPathElement::QuadraticCurve(qc) => qc.get_tangent_vector_at_t(t),
229 SvgPathElement::CubicCurve(cc) => cc.get_tangent_vector_at_t(t),
230 }
231 }
232 pub fn get_x_at_t(&self, t: f64) -> f64 {
233 match self {
234 SvgPathElement::Line(l) => l.get_x_at_t(t),
235 SvgPathElement::QuadraticCurve(qc) => qc.get_x_at_t(t),
236 SvgPathElement::CubicCurve(cc) => cc.get_x_at_t(t),
237 }
238 }
239 pub fn get_y_at_t(&self, t: f64) -> f64 {
240 match self {
241 SvgPathElement::Line(l) => l.get_y_at_t(t),
242 SvgPathElement::QuadraticCurve(qc) => qc.get_y_at_t(t),
243 SvgPathElement::CubicCurve(cc) => cc.get_y_at_t(t),
244 }
245 }
246}
247
248impl_vec!(
249 SvgPathElement,
250 SvgPathElementVec,
251 SvgPathElementVecDestructor,
252 SvgPathElementVecDestructorType
253);
254impl_vec_debug!(SvgPathElement, SvgPathElementVec);
255impl_vec_clone!(
256 SvgPathElement,
257 SvgPathElementVec,
258 SvgPathElementVecDestructor
259);
260impl_vec_partialeq!(SvgPathElement, SvgPathElementVec);
261impl_vec_partialord!(SvgPathElement, SvgPathElementVec);
262
263#[derive(Debug, Clone, PartialEq, PartialOrd)]
264#[repr(C)]
265pub struct SvgPath {
266 pub items: SvgPathElementVec,
267}
268
269impl SvgPath {
270 pub fn get_start(&self) -> Option<SvgPoint> {
271 self.items.as_ref().first().map(|s| s.get_start())
272 }
273
274 pub fn get_end(&self) -> Option<SvgPoint> {
275 self.items.as_ref().last().map(|s| s.get_end())
276 }
277
278 pub fn close(&mut self) {
279 let first = match self.items.as_ref().first() {
280 Some(s) => s,
281 None => return,
282 };
283 let last = match self.items.as_ref().last() {
284 Some(s) => s,
285 None => return,
286 };
287 if first.get_start() != last.get_end() {
288 let mut elements = self.items.as_slice().to_vec();
289 elements.push(SvgPathElement::Line(SvgLine {
290 start: last.get_end(),
291 end: first.get_start(),
292 }));
293 self.items = elements.into();
294 }
295 }
296
297 pub fn is_closed(&self) -> bool {
298 let first = self.items.as_ref().first();
299 let last = self.items.as_ref().last();
300 match (first, last) {
301 (Some(f), Some(l)) => (f.get_start() == l.get_end()),
302 _ => false,
303 }
304 }
305
306 pub fn reverse(&mut self) {
308 let mut vec = SvgPathElementVec::from_const_slice(&[]);
310 core::mem::swap(&mut vec, &mut self.items);
311 let mut vec = vec.into_library_owned_vec();
312
313 vec.reverse();
315
316 for item in vec.iter_mut() {
319 item.reverse();
320 }
321
322 let mut vec = SvgPathElementVec::from_vec(vec);
324 core::mem::swap(&mut vec, &mut self.items);
325 }
326
327 pub fn join_with(&mut self, mut path: Self) -> Option<()> {
328 let self_last_point = self.items.as_ref().last()?.get_end();
329 let other_start_point = path.items.as_ref().first()?.get_start();
330 let interpolated_join_point = SvgPoint {
331 x: (self_last_point.x + other_start_point.x) / 2.0,
332 y: (self_last_point.y + other_start_point.y) / 2.0,
333 };
334
335 let mut vec = SvgPathElementVec::from_const_slice(&[]);
337 core::mem::swap(&mut vec, &mut self.items);
338 let mut vec = vec.into_library_owned_vec();
339
340 let mut other = SvgPathElementVec::from_const_slice(&[]);
341 core::mem::swap(&mut other, &mut path.items);
342 let mut other = other.into_library_owned_vec();
343
344 let vec_len = vec.len() - 1;
345 vec.get_mut(vec_len)?.set_last(interpolated_join_point);
346 other.get_mut(0)?.set_first(interpolated_join_point);
347 vec.append(&mut other);
348
349 let mut vec = SvgPathElementVec::from_vec(vec);
351 core::mem::swap(&mut vec, &mut self.items);
352
353 Some(())
354 }
355 pub fn get_bounds(&self) -> SvgRect {
356 let mut first_bounds = match self.items.as_ref().get(0) {
357 Some(s) => s.get_bounds(),
358 None => return SvgRect::default(),
359 };
360
361 for mp in self.items.as_ref().iter().skip(1) {
362 let mp_bounds = mp.get_bounds();
363 first_bounds.union_with(&mp_bounds);
364 }
365
366 first_bounds
367 }
368}
369
370#[derive(Debug, Clone, PartialEq, PartialOrd)]
371#[repr(C)]
372pub struct SvgMultiPolygon {
373 pub rings: SvgPathVec,
375}
376
377impl SvgMultiPolygon {
378 pub fn get_bounds(&self) -> SvgRect {
379 let mut first_bounds = match self
380 .rings
381 .get(0)
382 .and_then(|b| b.items.get(0).map(|i| i.get_bounds()))
383 {
384 Some(s) => s,
385 None => return SvgRect::default(), };
387
388 for ring in self.rings.iter() {
389 for item in ring.items.iter() {
390 first_bounds.union_with(&item.get_bounds());
391 }
392 }
393
394 first_bounds
395 }
396}
397
398impl_vec!(
399 SvgPath,
400 SvgPathVec,
401 SvgPathVecDestructor,
402 SvgPathVecDestructorType
403);
404impl_vec_debug!(SvgPath, SvgPathVec);
405impl_vec_clone!(SvgPath, SvgPathVec, SvgPathVecDestructor);
406impl_vec_partialeq!(SvgPath, SvgPathVec);
407impl_vec_partialord!(SvgPath, SvgPathVec);
408
409impl_vec!(
410 SvgMultiPolygon,
411 SvgMultiPolygonVec,
412 SvgMultiPolygonVecDestructor,
413 SvgMultiPolygonVecDestructorType
414);
415impl_vec_debug!(SvgMultiPolygon, SvgMultiPolygonVec);
416impl_vec_clone!(
417 SvgMultiPolygon,
418 SvgMultiPolygonVec,
419 SvgMultiPolygonVecDestructor
420);
421impl_vec_partialeq!(SvgMultiPolygon, SvgMultiPolygonVec);
422impl_vec_partialord!(SvgMultiPolygon, SvgMultiPolygonVec);
423
424#[derive(Debug, Clone, PartialOrd, PartialEq)]
426#[repr(C, u8)]
427pub enum SvgNode {
428 MultiPolygonCollection(SvgMultiPolygonVec),
430 MultiPolygon(SvgMultiPolygon),
431 MultiShape(SvgSimpleNodeVec),
432 Path(SvgPath),
433 Circle(SvgCircle),
434 Rect(SvgRect),
435}
436
437#[derive(Debug, Clone, PartialOrd, PartialEq)]
439#[repr(C, u8)]
440pub enum SvgSimpleNode {
441 Path(SvgPath),
442 Circle(SvgCircle),
443 Rect(SvgRect),
444 CircleHole(SvgCircle),
445 RectHole(SvgRect),
446}
447
448impl_vec!(
449 SvgSimpleNode,
450 SvgSimpleNodeVec,
451 SvgSimpleNodeVecDestructor,
452 SvgSimpleNodeVecDestructorType
453);
454impl_vec_debug!(SvgSimpleNode, SvgSimpleNodeVec);
455impl_vec_clone!(SvgSimpleNode, SvgSimpleNodeVec, SvgSimpleNodeVecDestructor);
456impl_vec_partialeq!(SvgSimpleNode, SvgSimpleNodeVec);
457impl_vec_partialord!(SvgSimpleNode, SvgSimpleNodeVec);
458
459impl SvgSimpleNode {
460 pub fn get_bounds(&self) -> SvgRect {
461 match self {
462 SvgSimpleNode::Path(a) => a.get_bounds(),
463 SvgSimpleNode::Circle(a) => a.get_bounds(),
464 SvgSimpleNode::Rect(a) => a.clone(),
465 SvgSimpleNode::CircleHole(a) => a.get_bounds(),
466 SvgSimpleNode::RectHole(a) => a.clone(),
467 }
468 }
469 pub fn is_closed(&self) -> bool {
470 match self {
471 SvgSimpleNode::Path(a) => a.is_closed(),
472 SvgSimpleNode::Circle(a) => true,
473 SvgSimpleNode::Rect(a) => true,
474 SvgSimpleNode::CircleHole(a) => true,
475 SvgSimpleNode::RectHole(a) => true,
476 }
477 }
478}
479
480impl SvgNode {
481 pub fn get_bounds(&self) -> SvgRect {
482 match self {
483 SvgNode::MultiPolygonCollection(a) => {
484 let mut first_mp_bounds = match a.get(0) {
485 Some(s) => s.get_bounds(),
486 None => return SvgRect::default(),
487 };
488 for mp in a.iter().skip(1) {
489 let mp_bounds = mp.get_bounds();
490 first_mp_bounds.union_with(&mp_bounds);
491 }
492
493 first_mp_bounds
494 }
495 SvgNode::MultiPolygon(a) => a.get_bounds(),
496 SvgNode::MultiShape(a) => {
497 let mut first_mp_bounds = match a.get(0) {
498 Some(s) => s.get_bounds(),
499 None => return SvgRect::default(),
500 };
501 for mp in a.iter().skip(1) {
502 let mp_bounds = mp.get_bounds();
503 first_mp_bounds.union_with(&mp_bounds);
504 }
505
506 first_mp_bounds
507 }
508 SvgNode::Path(a) => a.get_bounds(),
509 SvgNode::Circle(a) => a.get_bounds(),
510 SvgNode::Rect(a) => a.clone(),
511 }
512 }
513 pub fn is_closed(&self) -> bool {
514 match self {
515 SvgNode::MultiPolygonCollection(a) => {
516 for mp in a.iter() {
517 for p in mp.rings.as_ref().iter() {
518 if !p.is_closed() {
519 return false;
520 }
521 }
522 }
523
524 true
525 }
526 SvgNode::MultiPolygon(a) => {
527 for p in a.rings.as_ref().iter() {
528 if !p.is_closed() {
529 return false;
530 }
531 }
532
533 true
534 }
535 SvgNode::MultiShape(a) => {
536 for p in a.as_ref().iter() {
537 if !p.is_closed() {
538 return false;
539 }
540 }
541
542 true
543 }
544 SvgNode::Path(a) => a.is_closed(),
545 SvgNode::Circle(a) => true,
546 SvgNode::Rect(a) => true,
547 }
548 }
549}
550
551#[derive(Debug, Clone, PartialOrd, PartialEq)]
552#[repr(C)]
553pub struct SvgStyledNode {
554 pub geometry: SvgNode,
555 pub style: SvgStyle,
556}
557
558#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
559#[repr(C)]
560pub struct SvgVertex {
561 pub x: f32,
562 pub y: f32,
563}
564
565impl VertexLayoutDescription for SvgVertex {
566 fn get_description() -> VertexLayout {
567 VertexLayout {
568 fields: vec![VertexAttribute {
569 va_name: String::from("vAttrXY").into(),
570 layout_location: None.into(),
571 attribute_type: VertexAttributeType::Float,
572 item_count: 2,
573 }]
574 .into(),
575 }
576 }
577}
578
579#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
580#[repr(C)]
581pub struct SvgColoredVertex {
582 pub x: f32,
583 pub y: f32,
584 pub z: f32,
585 pub r: f32,
586 pub g: f32,
587 pub b: f32,
588 pub a: f32,
589}
590
591impl VertexLayoutDescription for SvgColoredVertex {
592 fn get_description() -> VertexLayout {
593 VertexLayout {
594 fields: vec![
595 VertexAttribute {
596 va_name: String::from("vAttrXY").into(),
597 layout_location: None.into(),
598 attribute_type: VertexAttributeType::Float,
599 item_count: 3,
600 },
601 VertexAttribute {
602 va_name: String::from("vColor").into(),
603 layout_location: None.into(),
604 attribute_type: VertexAttributeType::Float,
605 item_count: 4,
606 },
607 ]
608 .into(),
609 }
610 }
611}
612
613#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
614#[repr(C)]
615pub struct SvgCircle {
616 pub center_x: f32,
617 pub center_y: f32,
618 pub radius: f32,
619}
620
621impl SvgCircle {
622 pub fn contains_point(&self, x: f32, y: f32) -> bool {
623 let x_diff = libm::fabsf(x - self.center_x);
624 let y_diff = libm::fabsf(y - self.center_y);
625 (x_diff * x_diff) + (y_diff * y_diff) < (self.radius * self.radius)
626 }
627 pub fn get_bounds(&self) -> SvgRect {
628 SvgRect {
629 width: self.radius * 2.0,
630 height: self.radius * 2.0,
631 x: self.center_x - self.radius,
632 y: self.center_y - self.radius,
633 radius_top_left: 0.0,
634 radius_top_right: 0.0,
635 radius_bottom_left: 0.0,
636 radius_bottom_right: 0.0,
637 }
638 }
639}
640
641#[derive(Debug, Clone, PartialEq, PartialOrd)]
642#[repr(C)]
643pub struct TessellatedSvgNode {
644 pub vertices: SvgVertexVec,
645 pub indices: U32Vec,
646}
647
648impl Default for TessellatedSvgNode {
649 fn default() -> Self {
650 Self {
651 vertices: Vec::new().into(),
652 indices: Vec::new().into(),
653 }
654 }
655}
656
657impl_vec!(
658 TessellatedSvgNode,
659 TessellatedSvgNodeVec,
660 TessellatedSvgNodeVecDestructor,
661 TessellatedSvgNodeVecDestructorType
662);
663impl_vec_debug!(TessellatedSvgNode, TessellatedSvgNodeVec);
664impl_vec_partialord!(TessellatedSvgNode, TessellatedSvgNodeVec);
665impl_vec_clone!(
666 TessellatedSvgNode,
667 TessellatedSvgNodeVec,
668 TessellatedSvgNodeVecDestructor
669);
670impl_vec_partialeq!(TessellatedSvgNode, TessellatedSvgNodeVec);
671
672impl TessellatedSvgNode {
673 pub fn empty() -> Self {
674 Self::default()
675 }
676}
677
678impl TessellatedSvgNodeVec {
679 pub fn get_ref(&self) -> TessellatedSvgNodeVecRef {
680 let slice = self.as_ref();
681 TessellatedSvgNodeVecRef {
682 ptr: slice.as_ptr(),
683 len: slice.len(),
684 }
685 }
686}
687
688impl fmt::Debug for TessellatedSvgNodeVecRef {
689 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
690 self.as_slice().fmt(f)
691 }
692}
693
694#[repr(C)]
696pub struct TessellatedSvgNodeVecRef {
697 pub ptr: *const TessellatedSvgNode,
698 pub len: usize,
699}
700
701impl Clone for TessellatedSvgNodeVecRef {
702 fn clone(&self) -> Self {
703 Self {
704 ptr: self.ptr,
705 len: self.len,
706 }
707 }
708}
709
710impl TessellatedSvgNodeVecRef {
711 pub fn as_slice<'a>(&'a self) -> &'a [TessellatedSvgNode] {
712 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
713 }
714}
715
716#[derive(Debug, Clone, PartialEq, PartialOrd)]
717#[repr(C)]
718pub struct TessellatedColoredSvgNode {
719 pub vertices: SvgColoredVertexVec,
720 pub indices: U32Vec,
721}
722
723impl Default for TessellatedColoredSvgNode {
724 fn default() -> Self {
725 Self {
726 vertices: Vec::new().into(),
727 indices: Vec::new().into(),
728 }
729 }
730}
731
732impl_vec!(
733 TessellatedColoredSvgNode,
734 TessellatedColoredSvgNodeVec,
735 TessellatedColoredSvgNodeVecDestructor,
736 TessellatedColoredSvgNodeVecDestructorType
737);
738impl_vec_debug!(TessellatedColoredSvgNode, TessellatedColoredSvgNodeVec);
739impl_vec_partialord!(TessellatedColoredSvgNode, TessellatedColoredSvgNodeVec);
740impl_vec_clone!(
741 TessellatedColoredSvgNode,
742 TessellatedColoredSvgNodeVec,
743 TessellatedColoredSvgNodeVecDestructor
744);
745impl_vec_partialeq!(TessellatedColoredSvgNode, TessellatedColoredSvgNodeVec);
746
747impl TessellatedColoredSvgNode {
748 pub fn empty() -> Self {
749 Self::default()
750 }
751}
752
753impl TessellatedColoredSvgNodeVec {
754 pub fn get_ref(&self) -> TessellatedColoredSvgNodeVecRef {
755 let slice = self.as_ref();
756 TessellatedColoredSvgNodeVecRef {
757 ptr: slice.as_ptr(),
758 len: slice.len(),
759 }
760 }
761}
762
763impl fmt::Debug for TessellatedColoredSvgNodeVecRef {
764 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
765 self.as_slice().fmt(f)
766 }
767}
768
769#[repr(C)]
771pub struct TessellatedColoredSvgNodeVecRef {
772 pub ptr: *const TessellatedColoredSvgNode,
773 pub len: usize,
774}
775
776impl Clone for TessellatedColoredSvgNodeVecRef {
777 fn clone(&self) -> Self {
778 Self {
779 ptr: self.ptr,
780 len: self.len,
781 }
782 }
783}
784
785impl TessellatedColoredSvgNodeVecRef {
786 pub fn as_slice<'a>(&'a self) -> &'a [TessellatedColoredSvgNode] {
787 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
788 }
789}
790
791impl_vec!(
792 SvgVertex,
793 SvgVertexVec,
794 SvgVertexVecDestructor,
795 SvgVertexVecDestructorType
796);
797impl_vec_debug!(SvgVertex, SvgVertexVec);
798impl_vec_partialord!(SvgVertex, SvgVertexVec);
799impl_vec_clone!(SvgVertex, SvgVertexVec, SvgVertexVecDestructor);
800impl_vec_partialeq!(SvgVertex, SvgVertexVec);
801
802impl_vec!(
803 SvgColoredVertex,
804 SvgColoredVertexVec,
805 SvgColoredVertexVecDestructor,
806 SvgColoredVertexVecDestructorType
807);
808impl_vec_debug!(SvgColoredVertex, SvgColoredVertexVec);
809impl_vec_partialord!(SvgColoredVertex, SvgColoredVertexVec);
810impl_vec_clone!(
811 SvgColoredVertex,
812 SvgColoredVertexVec,
813 SvgColoredVertexVecDestructor
814);
815impl_vec_partialeq!(SvgColoredVertex, SvgColoredVertexVec);
816
817#[derive(Debug, Clone, PartialEq, PartialOrd)]
818#[repr(C)]
819pub struct TessellatedGPUSvgNode {
820 pub vertex_index_buffer: VertexBuffer,
821}
822
823impl TessellatedGPUSvgNode {
824 pub fn new(node: &TessellatedSvgNode, gl: GlContextPtr) -> Self {
826 let svg_shader_id = gl.ptr.svg_shader;
827 Self {
828 vertex_index_buffer: VertexBuffer::new(
829 gl,
830 svg_shader_id,
831 node.vertices.as_ref(),
832 node.indices.as_ref(),
833 IndexBufferFormat::Triangles,
834 ),
835 }
836 }
837
838 pub fn draw(
840 &self,
841 texture: &mut Texture,
842 target_size: PhysicalSizeU32,
843 color: ColorU,
844 transforms: StyleTransformVec,
845 ) -> bool {
846 let transform_origin = StyleTransformOrigin {
847 x: PixelValue::px(target_size.width as f32 / 2.0),
848 y: PixelValue::px(target_size.height as f32 / 2.0),
849 };
850
851 let computed_transform = ComputedTransform3D::from_style_transform_vec(
852 transforms.as_ref(),
853 &transform_origin,
854 target_size.width as f32,
855 target_size.height as f32,
856 RotationMode::ForWebRender,
857 );
858
859 let column_major = computed_transform.get_column_major();
862
863 let color: ColorF = color.into();
864
865 let uniforms = [
867 Uniform {
868 uniform_name: "vBboxSize".into(),
869 uniform_type: UniformType::FloatVec2([
870 target_size.width as f32,
871 target_size.height as f32,
872 ]),
873 },
874 Uniform {
875 uniform_name: "fDrawColor".into(),
876 uniform_type: UniformType::FloatVec4([color.r, color.g, color.b, color.a]),
877 },
878 Uniform {
879 uniform_name: "vTransformMatrix".into(),
880 uniform_type: UniformType::Matrix4 {
881 transpose: false,
882 matrix: unsafe { core::mem::transmute(column_major.m) },
883 },
884 },
885 ];
886
887 GlShader::draw(
888 texture.gl_context.ptr.svg_shader,
889 texture,
890 &[(&self.vertex_index_buffer, &uniforms[..])],
891 );
892
893 true
894 }
895}
896
897#[derive(Debug, Clone, PartialEq, PartialOrd)]
898#[repr(C)]
899pub struct TessellatedColoredGPUSvgNode {
900 pub vertex_index_buffer: VertexBuffer,
901}
902
903impl TessellatedColoredGPUSvgNode {
904 pub fn new(node: &TessellatedColoredSvgNode, gl: GlContextPtr) -> Self {
906 let svg_shader_id = gl.ptr.svg_multicolor_shader;
907 Self {
908 vertex_index_buffer: VertexBuffer::new(
909 gl,
910 svg_shader_id,
911 node.vertices.as_ref(),
912 node.indices.as_ref(),
913 IndexBufferFormat::Triangles,
914 ),
915 }
916 }
917
918 pub fn draw(
920 &self,
921 texture: &mut Texture,
922 target_size: PhysicalSizeU32,
923 transforms: StyleTransformVec,
924 ) -> bool {
925 use azul_css::props::basic::PixelValue;
926
927 use crate::gl::{GlShader, Uniform, UniformType};
928
929 let transform_origin = StyleTransformOrigin {
930 x: PixelValue::px(target_size.width as f32 / 2.0),
931 y: PixelValue::px(target_size.height as f32 / 2.0),
932 };
933
934 let computed_transform = ComputedTransform3D::from_style_transform_vec(
935 transforms.as_ref(),
936 &transform_origin,
937 target_size.width as f32,
938 target_size.height as f32,
939 RotationMode::ForWebRender,
940 );
941
942 let column_major = computed_transform.get_column_major();
945
946 let uniforms = [
948 Uniform {
949 uniform_name: "vBboxSize".into(),
950 uniform_type: UniformType::FloatVec2([
951 target_size.width as f32,
952 target_size.height as f32,
953 ]),
954 },
955 Uniform {
956 uniform_name: "vTransformMatrix".into(),
957 uniform_type: UniformType::Matrix4 {
958 transpose: false,
959 matrix: unsafe { core::mem::transmute(column_major.m) },
960 },
961 },
962 ];
963
964 GlShader::draw(
965 texture.gl_context.ptr.svg_multicolor_shader,
966 texture,
967 &[(&self.vertex_index_buffer, &uniforms[..])],
968 );
969
970 true
971 }
972}
973
974#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
975#[repr(C, u8)]
976pub enum SvgStyle {
977 Fill(SvgFillStyle),
978 Stroke(SvgStrokeStyle),
979}
980
981impl SvgStyle {
982 pub fn get_antialias(&self) -> bool {
983 match self {
984 SvgStyle::Fill(f) => f.anti_alias,
985 SvgStyle::Stroke(s) => s.anti_alias,
986 }
987 }
988 pub fn get_high_quality_aa(&self) -> bool {
989 match self {
990 SvgStyle::Fill(f) => f.high_quality_aa,
991 SvgStyle::Stroke(s) => s.high_quality_aa,
992 }
993 }
994 pub fn get_transform(&self) -> SvgTransform {
995 match self {
996 SvgStyle::Fill(f) => f.transform,
997 SvgStyle::Stroke(s) => s.transform,
998 }
999 }
1000}
1001#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1002#[repr(C)]
1003pub enum SvgFillRule {
1004 Winding,
1005 EvenOdd,
1006}
1007
1008impl Default for SvgFillRule {
1009 fn default() -> Self {
1010 SvgFillRule::Winding
1011 }
1012}
1013
1014#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
1015#[repr(C)]
1016pub struct SvgTransform {
1017 pub sx: f32,
1018 pub kx: f32,
1019 pub ky: f32,
1020 pub sy: f32,
1021 pub tx: f32,
1022 pub ty: f32,
1023}
1024
1025#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1026#[repr(C)]
1027pub struct SvgFillStyle {
1028 pub line_join: SvgLineJoin,
1032 pub miter_limit: f32,
1037 pub tolerance: f32,
1042 pub fill_rule: SvgFillRule,
1044 pub transform: SvgTransform,
1047 pub anti_alias: bool,
1049 pub high_quality_aa: bool,
1051}
1052
1053impl Default for SvgFillStyle {
1054 fn default() -> Self {
1055 Self {
1056 line_join: SvgLineJoin::Miter,
1057 miter_limit: DEFAULT_MITER_LIMIT,
1058 tolerance: DEFAULT_TOLERANCE,
1059 fill_rule: SvgFillRule::default(),
1060 transform: SvgTransform::default(),
1061 anti_alias: true,
1062 high_quality_aa: false,
1063 }
1064 }
1065}
1066
1067#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1068#[repr(C)]
1069pub struct SvgStrokeStyle {
1070 pub start_cap: SvgLineCap,
1074 pub end_cap: SvgLineCap,
1078 pub line_join: SvgLineJoin,
1082 pub dash_pattern: OptionSvgDashPattern,
1084 pub line_width: f32,
1088 pub miter_limit: f32,
1093 pub tolerance: f32,
1098 pub apply_line_width: bool,
1106 pub transform: SvgTransform,
1109 pub anti_alias: bool,
1111 pub high_quality_aa: bool,
1113}
1114
1115impl Default for SvgStrokeStyle {
1116 fn default() -> Self {
1117 Self {
1118 start_cap: SvgLineCap::default(),
1119 end_cap: SvgLineCap::default(),
1120 line_join: SvgLineJoin::default(),
1121 dash_pattern: OptionSvgDashPattern::None,
1122 line_width: DEFAULT_LINE_WIDTH,
1123 miter_limit: DEFAULT_MITER_LIMIT,
1124 tolerance: DEFAULT_TOLERANCE,
1125 apply_line_width: true,
1126 anti_alias: true,
1127 high_quality_aa: false,
1128 transform: SvgTransform::default(),
1129 }
1130 }
1131}
1132
1133#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1134#[repr(C)]
1135pub struct SvgDashPattern {
1136 pub offset: f32,
1137 pub length_1: f32,
1138 pub gap_1: f32,
1139 pub length_2: f32,
1140 pub gap_2: f32,
1141 pub length_3: f32,
1142 pub gap_3: f32,
1143}
1144
1145impl_option!(
1146 SvgDashPattern,
1147 OptionSvgDashPattern,
1148 [Debug, Copy, Clone, PartialEq, PartialOrd]
1149);
1150
1151#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
1152#[repr(C)]
1153pub enum SvgLineCap {
1154 Butt,
1155 Square,
1156 Round,
1157}
1158
1159impl Default for SvgLineCap {
1160 fn default() -> Self {
1161 SvgLineCap::Butt
1162 }
1163}
1164
1165#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
1166#[repr(C)]
1167pub enum SvgLineJoin {
1168 Miter,
1169 MiterClip,
1170 Round,
1171 Bevel,
1172}
1173
1174impl Default for SvgLineJoin {
1175 fn default() -> Self {
1176 SvgLineJoin::Miter
1177 }
1178}
1179
1180#[allow(non_camel_case_types)]
1181pub enum c_void {}
1182
1183pub type GlyphId = u16;
1184
1185#[derive(Debug, Clone)]
1186#[repr(C)]
1187pub struct SvgXmlNode {
1188 pub node: *const c_void, pub run_destructor: bool,
1190}
1191
1192#[derive(Debug, Clone)]
1193#[repr(C)]
1194pub struct Svg {
1195 pub tree: *const c_void, pub run_destructor: bool,
1197}
1198
1199#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1200#[repr(C)]
1201pub enum ShapeRendering {
1202 OptimizeSpeed,
1203 CrispEdges,
1204 GeometricPrecision,
1205}
1206
1207#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1208#[repr(C)]
1209pub enum ImageRendering {
1210 OptimizeQuality,
1211 OptimizeSpeed,
1212}
1213
1214#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1215#[repr(C)]
1216pub enum TextRendering {
1217 OptimizeSpeed,
1218 OptimizeLegibility,
1219 GeometricPrecision,
1220}
1221
1222#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1223#[repr(C)]
1224pub enum FontDatabase {
1225 Empty,
1226 System,
1227}
1228
1229#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)]
1230#[repr(C)]
1231pub struct SvgRenderOptions {
1232 pub target_size: OptionLayoutSize,
1233 pub background_color: OptionColorU,
1234 pub fit: SvgFitTo,
1235 pub transform: SvgRenderTransform,
1236}
1237
1238#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)]
1239#[repr(C)]
1240pub struct SvgRenderTransform {
1241 pub sx: f32,
1242 pub kx: f32,
1243 pub ky: f32,
1244 pub sy: f32,
1245 pub tx: f32,
1246 pub ty: f32,
1247}
1248
1249#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1250#[repr(C, u8)]
1251pub enum SvgFitTo {
1252 Original,
1253 Width(u32),
1254 Height(u32),
1255 Zoom(f32),
1256}
1257
1258impl Default for SvgFitTo {
1259 fn default() -> Self {
1260 SvgFitTo::Original
1261 }
1262}
1263
1264#[derive(Debug, Clone, PartialEq, PartialOrd)]
1265#[repr(C)]
1266pub struct SvgParseOptions {
1267 pub relative_image_path: OptionString,
1269 pub dpi: f32,
1271 pub default_font_family: AzString,
1274 pub font_size: f32,
1277 pub languages: StringVec,
1280 pub shape_rendering: ShapeRendering,
1283 pub text_rendering: TextRendering,
1286 pub image_rendering: ImageRendering,
1289 pub keep_named_groups: bool,
1292 pub fontdb: FontDatabase,
1294}
1295
1296impl Default for SvgParseOptions {
1297 fn default() -> Self {
1298 let lang_vec: Vec<AzString> = vec![String::from("en").into()];
1299 SvgParseOptions {
1300 relative_image_path: OptionString::None,
1301 dpi: 96.0,
1302 default_font_family: "Times New Roman".to_string().into(),
1303 font_size: 12.0,
1304 languages: lang_vec.into(),
1305 shape_rendering: ShapeRendering::GeometricPrecision,
1306 text_rendering: TextRendering::OptimizeLegibility,
1307 image_rendering: ImageRendering::OptimizeQuality,
1308 keep_named_groups: false,
1309 fontdb: FontDatabase::System,
1310 }
1311 }
1312}
1313
1314#[derive(Debug, Clone, PartialEq, PartialOrd)]
1315#[repr(C)]
1316pub struct SvgXmlOptions {
1317 pub use_single_quote: bool,
1318 pub indent: Indent,
1319 pub attributes_indent: Indent,
1320}
1321
1322impl Default for SvgXmlOptions {
1323 fn default() -> Self {
1324 SvgXmlOptions {
1325 use_single_quote: false,
1326 indent: Indent::Spaces(2),
1327 attributes_indent: Indent::Spaces(2),
1328 }
1329 }
1330}
1331
1332#[derive(Debug, PartialEq, PartialOrd, Clone)]
1333#[repr(C, u8)]
1334pub enum SvgParseError {
1335 NoParserAvailable,
1336 ElementsLimitReached,
1337 NotAnUtf8Str,
1338 MalformedGZip,
1339 InvalidSize,
1340 ParsingFailed(XmlError),
1341}
1342
1343impl fmt::Display for SvgParseError {
1344 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1345 use self::SvgParseError::*;
1346 match self {
1347 NoParserAvailable => write!(
1348 f,
1349 "Library was compiled without SVG support (no parser available)"
1350 ),
1351 InvalidFileSuffix => write!(f, "Error parsing SVG: Invalid file suffix"),
1352 FileOpenFailed => write!(f, "Error parsing SVG: Failed to open file"),
1353 NotAnUtf8Str => write!(f, "Error parsing SVG: Not an UTF-8 String"),
1354 MalformedGZip => write!(
1355 f,
1356 "Error parsing SVG: SVG is compressed with a malformed GZIP compression"
1357 ),
1358 InvalidSize => write!(f, "Error parsing SVG: Invalid size"),
1359 ParsingFailed(e) => write!(f, "Error parsing SVG: Parsing SVG as XML failed: {}", e),
1360 }
1361 }
1362}
1363
1364impl_result!(
1365 SvgXmlNode,
1366 SvgParseError,
1367 ResultSvgXmlNodeSvgParseError,
1368 copy = false,
1369 [Debug, Clone]
1370);
1371impl_result!(
1372 Svg,
1373 SvgParseError,
1374 ResultSvgSvgParseError,
1375 copy = false,
1376 [Debug, Clone]
1377);
1378
1379#[derive(Debug, Clone, PartialEq, PartialOrd)]
1380#[repr(C, u8)]
1381pub enum Indent {
1382 None,
1383 Spaces(u8),
1384 Tabs,
1385}