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