| 1 | // Copyright 2018 the Resvg Authors |
| 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
| 3 | |
| 4 | use std::sync::Arc; |
| 5 | |
| 6 | use strict_num::NonZeroPositiveF32; |
| 7 | pub use svgtypes::FontFamily; |
| 8 | |
| 9 | #[cfg (feature = "text" )] |
| 10 | use crate::layout::Span; |
| 11 | use crate::{Fill, Group, NonEmptyString, PaintOrder, Rect, Stroke, TextRendering, Transform}; |
| 12 | |
| 13 | /// A font stretch property. |
| 14 | #[allow (missing_docs)] |
| 15 | #[derive (Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] |
| 16 | pub enum FontStretch { |
| 17 | UltraCondensed, |
| 18 | ExtraCondensed, |
| 19 | Condensed, |
| 20 | SemiCondensed, |
| 21 | Normal, |
| 22 | SemiExpanded, |
| 23 | Expanded, |
| 24 | ExtraExpanded, |
| 25 | UltraExpanded, |
| 26 | } |
| 27 | |
| 28 | impl Default for FontStretch { |
| 29 | #[inline ] |
| 30 | fn default() -> Self { |
| 31 | Self::Normal |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | #[cfg (feature = "text" )] |
| 36 | impl From<fontdb::Stretch> for FontStretch { |
| 37 | fn from(stretch: fontdb::Stretch) -> Self { |
| 38 | match stretch { |
| 39 | fontdb::Stretch::UltraCondensed => FontStretch::UltraCondensed, |
| 40 | fontdb::Stretch::ExtraCondensed => FontStretch::ExtraCondensed, |
| 41 | fontdb::Stretch::Condensed => FontStretch::Condensed, |
| 42 | fontdb::Stretch::SemiCondensed => FontStretch::SemiCondensed, |
| 43 | fontdb::Stretch::Normal => FontStretch::Normal, |
| 44 | fontdb::Stretch::SemiExpanded => FontStretch::SemiExpanded, |
| 45 | fontdb::Stretch::Expanded => FontStretch::Expanded, |
| 46 | fontdb::Stretch::ExtraExpanded => FontStretch::ExtraExpanded, |
| 47 | fontdb::Stretch::UltraExpanded => FontStretch::UltraExpanded, |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | #[cfg (feature = "text" )] |
| 53 | impl From<FontStretch> for fontdb::Stretch { |
| 54 | fn from(stretch: FontStretch) -> Self { |
| 55 | match stretch { |
| 56 | FontStretch::UltraCondensed => fontdb::Stretch::UltraCondensed, |
| 57 | FontStretch::ExtraCondensed => fontdb::Stretch::ExtraCondensed, |
| 58 | FontStretch::Condensed => fontdb::Stretch::Condensed, |
| 59 | FontStretch::SemiCondensed => fontdb::Stretch::SemiCondensed, |
| 60 | FontStretch::Normal => fontdb::Stretch::Normal, |
| 61 | FontStretch::SemiExpanded => fontdb::Stretch::SemiExpanded, |
| 62 | FontStretch::Expanded => fontdb::Stretch::Expanded, |
| 63 | FontStretch::ExtraExpanded => fontdb::Stretch::ExtraExpanded, |
| 64 | FontStretch::UltraExpanded => fontdb::Stretch::UltraExpanded, |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | /// A font style property. |
| 70 | #[derive (Clone, Copy, PartialEq, Eq, Debug, Hash)] |
| 71 | pub enum FontStyle { |
| 72 | /// A face that is neither italic not obliqued. |
| 73 | Normal, |
| 74 | /// A form that is generally cursive in nature. |
| 75 | Italic, |
| 76 | /// A typically-sloped version of the regular face. |
| 77 | Oblique, |
| 78 | } |
| 79 | |
| 80 | impl Default for FontStyle { |
| 81 | #[inline ] |
| 82 | fn default() -> FontStyle { |
| 83 | Self::Normal |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | #[cfg (feature = "text" )] |
| 88 | impl From<fontdb::Style> for FontStyle { |
| 89 | fn from(style: fontdb::Style) -> Self { |
| 90 | match style { |
| 91 | fontdb::Style::Normal => FontStyle::Normal, |
| 92 | fontdb::Style::Italic => FontStyle::Italic, |
| 93 | fontdb::Style::Oblique => FontStyle::Oblique, |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | #[cfg (feature = "text" )] |
| 99 | impl From<FontStyle> for fontdb::Style { |
| 100 | fn from(style: FontStyle) -> Self { |
| 101 | match style { |
| 102 | FontStyle::Normal => fontdb::Style::Normal, |
| 103 | FontStyle::Italic => fontdb::Style::Italic, |
| 104 | FontStyle::Oblique => fontdb::Style::Oblique, |
| 105 | } |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | /// Text font properties. |
| 110 | #[derive (Clone, Eq, PartialEq, Hash, Debug)] |
| 111 | pub struct Font { |
| 112 | pub(crate) families: Vec<FontFamily>, |
| 113 | pub(crate) style: FontStyle, |
| 114 | pub(crate) stretch: FontStretch, |
| 115 | pub(crate) weight: u16, |
| 116 | } |
| 117 | |
| 118 | impl Font { |
| 119 | /// A list of family names. |
| 120 | /// |
| 121 | /// Never empty. Uses `usvg::Options::font_family` as fallback. |
| 122 | pub fn families(&self) -> &[FontFamily] { |
| 123 | &self.families |
| 124 | } |
| 125 | |
| 126 | /// A font style. |
| 127 | pub fn style(&self) -> FontStyle { |
| 128 | self.style |
| 129 | } |
| 130 | |
| 131 | /// A font stretch. |
| 132 | pub fn stretch(&self) -> FontStretch { |
| 133 | self.stretch |
| 134 | } |
| 135 | |
| 136 | /// A font width. |
| 137 | pub fn weight(&self) -> u16 { |
| 138 | self.weight |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | /// A dominant baseline property. |
| 143 | #[allow (missing_docs)] |
| 144 | #[derive (Clone, Copy, PartialEq, Debug)] |
| 145 | pub enum DominantBaseline { |
| 146 | Auto, |
| 147 | UseScript, |
| 148 | NoChange, |
| 149 | ResetSize, |
| 150 | Ideographic, |
| 151 | Alphabetic, |
| 152 | Hanging, |
| 153 | Mathematical, |
| 154 | Central, |
| 155 | Middle, |
| 156 | TextAfterEdge, |
| 157 | TextBeforeEdge, |
| 158 | } |
| 159 | |
| 160 | impl Default for DominantBaseline { |
| 161 | fn default() -> Self { |
| 162 | Self::Auto |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | /// An alignment baseline property. |
| 167 | #[allow (missing_docs)] |
| 168 | #[derive (Clone, Copy, PartialEq, Debug)] |
| 169 | pub enum AlignmentBaseline { |
| 170 | Auto, |
| 171 | Baseline, |
| 172 | BeforeEdge, |
| 173 | TextBeforeEdge, |
| 174 | Middle, |
| 175 | Central, |
| 176 | AfterEdge, |
| 177 | TextAfterEdge, |
| 178 | Ideographic, |
| 179 | Alphabetic, |
| 180 | Hanging, |
| 181 | Mathematical, |
| 182 | } |
| 183 | |
| 184 | impl Default for AlignmentBaseline { |
| 185 | fn default() -> Self { |
| 186 | Self::Auto |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | /// A baseline shift property. |
| 191 | #[allow (missing_docs)] |
| 192 | #[derive (Clone, Copy, PartialEq, Debug)] |
| 193 | pub enum BaselineShift { |
| 194 | Baseline, |
| 195 | Subscript, |
| 196 | Superscript, |
| 197 | Number(f32), |
| 198 | } |
| 199 | |
| 200 | impl Default for BaselineShift { |
| 201 | #[inline ] |
| 202 | fn default() -> BaselineShift { |
| 203 | BaselineShift::Baseline |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | /// A length adjust property. |
| 208 | #[allow (missing_docs)] |
| 209 | #[derive (Clone, Copy, PartialEq, Debug)] |
| 210 | pub enum LengthAdjust { |
| 211 | Spacing, |
| 212 | SpacingAndGlyphs, |
| 213 | } |
| 214 | |
| 215 | impl Default for LengthAdjust { |
| 216 | fn default() -> Self { |
| 217 | Self::Spacing |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | /// A text span decoration style. |
| 222 | /// |
| 223 | /// In SVG, text decoration and text it's applied to can have different styles. |
| 224 | /// So you can have black text and green underline. |
| 225 | /// |
| 226 | /// Also, in SVG you can specify text decoration stroking. |
| 227 | #[derive (Clone, Debug)] |
| 228 | pub struct TextDecorationStyle { |
| 229 | pub(crate) fill: Option<Fill>, |
| 230 | pub(crate) stroke: Option<Stroke>, |
| 231 | } |
| 232 | |
| 233 | impl TextDecorationStyle { |
| 234 | /// A fill style. |
| 235 | pub fn fill(&self) -> Option<&Fill> { |
| 236 | self.fill.as_ref() |
| 237 | } |
| 238 | |
| 239 | /// A stroke style. |
| 240 | pub fn stroke(&self) -> Option<&Stroke> { |
| 241 | self.stroke.as_ref() |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | /// A text span decoration. |
| 246 | #[derive (Clone, Debug)] |
| 247 | pub struct TextDecoration { |
| 248 | pub(crate) underline: Option<TextDecorationStyle>, |
| 249 | pub(crate) overline: Option<TextDecorationStyle>, |
| 250 | pub(crate) line_through: Option<TextDecorationStyle>, |
| 251 | } |
| 252 | |
| 253 | impl TextDecoration { |
| 254 | /// An optional underline and its style. |
| 255 | pub fn underline(&self) -> Option<&TextDecorationStyle> { |
| 256 | self.underline.as_ref() |
| 257 | } |
| 258 | |
| 259 | /// An optional overline and its style. |
| 260 | pub fn overline(&self) -> Option<&TextDecorationStyle> { |
| 261 | self.overline.as_ref() |
| 262 | } |
| 263 | |
| 264 | /// An optional line-through and its style. |
| 265 | pub fn line_through(&self) -> Option<&TextDecorationStyle> { |
| 266 | self.line_through.as_ref() |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | /// A text style span. |
| 271 | /// |
| 272 | /// Spans do not overlap inside a text chunk. |
| 273 | #[derive (Clone, Debug)] |
| 274 | pub struct TextSpan { |
| 275 | pub(crate) start: usize, |
| 276 | pub(crate) end: usize, |
| 277 | pub(crate) fill: Option<Fill>, |
| 278 | pub(crate) stroke: Option<Stroke>, |
| 279 | pub(crate) paint_order: PaintOrder, |
| 280 | pub(crate) font: Font, |
| 281 | pub(crate) font_size: NonZeroPositiveF32, |
| 282 | pub(crate) small_caps: bool, |
| 283 | pub(crate) apply_kerning: bool, |
| 284 | pub(crate) decoration: TextDecoration, |
| 285 | pub(crate) dominant_baseline: DominantBaseline, |
| 286 | pub(crate) alignment_baseline: AlignmentBaseline, |
| 287 | pub(crate) baseline_shift: Vec<BaselineShift>, |
| 288 | pub(crate) visible: bool, |
| 289 | pub(crate) letter_spacing: f32, |
| 290 | pub(crate) word_spacing: f32, |
| 291 | pub(crate) text_length: Option<f32>, |
| 292 | pub(crate) length_adjust: LengthAdjust, |
| 293 | } |
| 294 | |
| 295 | impl TextSpan { |
| 296 | /// A span start in bytes. |
| 297 | /// |
| 298 | /// Offset is relative to the parent text chunk and not the parent text element. |
| 299 | pub fn start(&self) -> usize { |
| 300 | self.start |
| 301 | } |
| 302 | |
| 303 | /// A span end in bytes. |
| 304 | /// |
| 305 | /// Offset is relative to the parent text chunk and not the parent text element. |
| 306 | pub fn end(&self) -> usize { |
| 307 | self.end |
| 308 | } |
| 309 | |
| 310 | /// A fill style. |
| 311 | pub fn fill(&self) -> Option<&Fill> { |
| 312 | self.fill.as_ref() |
| 313 | } |
| 314 | |
| 315 | /// A stroke style. |
| 316 | pub fn stroke(&self) -> Option<&Stroke> { |
| 317 | self.stroke.as_ref() |
| 318 | } |
| 319 | |
| 320 | /// A paint order style. |
| 321 | pub fn paint_order(&self) -> PaintOrder { |
| 322 | self.paint_order |
| 323 | } |
| 324 | |
| 325 | /// A font. |
| 326 | pub fn font(&self) -> &Font { |
| 327 | &self.font |
| 328 | } |
| 329 | |
| 330 | /// A font size. |
| 331 | pub fn font_size(&self) -> NonZeroPositiveF32 { |
| 332 | self.font_size |
| 333 | } |
| 334 | |
| 335 | /// Indicates that small caps should be used. |
| 336 | /// |
| 337 | /// Set by `font-variant="small-caps"` |
| 338 | pub fn small_caps(&self) -> bool { |
| 339 | self.small_caps |
| 340 | } |
| 341 | |
| 342 | /// Indicates that a kerning should be applied. |
| 343 | /// |
| 344 | /// Supports both `kerning` and `font-kerning` properties. |
| 345 | pub fn apply_kerning(&self) -> bool { |
| 346 | self.apply_kerning |
| 347 | } |
| 348 | |
| 349 | /// A span decorations. |
| 350 | pub fn decoration(&self) -> &TextDecoration { |
| 351 | &self.decoration |
| 352 | } |
| 353 | |
| 354 | /// A span dominant baseline. |
| 355 | pub fn dominant_baseline(&self) -> DominantBaseline { |
| 356 | self.dominant_baseline |
| 357 | } |
| 358 | |
| 359 | /// A span alignment baseline. |
| 360 | pub fn alignment_baseline(&self) -> AlignmentBaseline { |
| 361 | self.alignment_baseline |
| 362 | } |
| 363 | |
| 364 | /// A list of all baseline shift that should be applied to this span. |
| 365 | /// |
| 366 | /// Ordered from `text` element down to the actual `span` element. |
| 367 | pub fn baseline_shift(&self) -> &[BaselineShift] { |
| 368 | &self.baseline_shift |
| 369 | } |
| 370 | |
| 371 | /// A visibility property. |
| 372 | pub fn is_visible(&self) -> bool { |
| 373 | self.visible |
| 374 | } |
| 375 | |
| 376 | /// A letter spacing property. |
| 377 | pub fn letter_spacing(&self) -> f32 { |
| 378 | self.letter_spacing |
| 379 | } |
| 380 | |
| 381 | /// A word spacing property. |
| 382 | pub fn word_spacing(&self) -> f32 { |
| 383 | self.word_spacing |
| 384 | } |
| 385 | |
| 386 | /// A text length property. |
| 387 | pub fn text_length(&self) -> Option<f32> { |
| 388 | self.text_length |
| 389 | } |
| 390 | |
| 391 | /// A length adjust property. |
| 392 | pub fn length_adjust(&self) -> LengthAdjust { |
| 393 | self.length_adjust |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | /// A text chunk anchor property. |
| 398 | #[allow (missing_docs)] |
| 399 | #[derive (Clone, Copy, PartialEq, Debug)] |
| 400 | pub enum TextAnchor { |
| 401 | Start, |
| 402 | Middle, |
| 403 | End, |
| 404 | } |
| 405 | |
| 406 | impl Default for TextAnchor { |
| 407 | fn default() -> Self { |
| 408 | Self::Start |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | /// A path used by text-on-path. |
| 413 | #[derive (Debug)] |
| 414 | pub struct TextPath { |
| 415 | pub(crate) id: NonEmptyString, |
| 416 | pub(crate) start_offset: f32, |
| 417 | pub(crate) path: Arc<tiny_skia_path::Path>, |
| 418 | } |
| 419 | |
| 420 | impl TextPath { |
| 421 | /// Element's ID. |
| 422 | /// |
| 423 | /// Taken from the SVG itself. |
| 424 | pub fn id(&self) -> &str { |
| 425 | self.id.get() |
| 426 | } |
| 427 | |
| 428 | /// A text offset in SVG coordinates. |
| 429 | /// |
| 430 | /// Percentage values already resolved. |
| 431 | pub fn start_offset(&self) -> f32 { |
| 432 | self.start_offset |
| 433 | } |
| 434 | |
| 435 | /// A path. |
| 436 | pub fn path(&self) -> &tiny_skia_path::Path { |
| 437 | &self.path |
| 438 | } |
| 439 | } |
| 440 | |
| 441 | /// A text chunk flow property. |
| 442 | #[derive (Clone, Debug)] |
| 443 | pub enum TextFlow { |
| 444 | /// A linear layout. |
| 445 | /// |
| 446 | /// Includes left-to-right, right-to-left and top-to-bottom. |
| 447 | Linear, |
| 448 | /// A text-on-path layout. |
| 449 | Path(Arc<TextPath>), |
| 450 | } |
| 451 | |
| 452 | /// A text chunk. |
| 453 | /// |
| 454 | /// Text alignment and BIDI reordering can only be done inside a text chunk. |
| 455 | #[derive (Clone, Debug)] |
| 456 | pub struct TextChunk { |
| 457 | pub(crate) x: Option<f32>, |
| 458 | pub(crate) y: Option<f32>, |
| 459 | pub(crate) anchor: TextAnchor, |
| 460 | pub(crate) spans: Vec<TextSpan>, |
| 461 | pub(crate) text_flow: TextFlow, |
| 462 | pub(crate) text: String, |
| 463 | } |
| 464 | |
| 465 | impl TextChunk { |
| 466 | /// An absolute X axis offset. |
| 467 | pub fn x(&self) -> Option<f32> { |
| 468 | self.x |
| 469 | } |
| 470 | |
| 471 | /// An absolute Y axis offset. |
| 472 | pub fn y(&self) -> Option<f32> { |
| 473 | self.y |
| 474 | } |
| 475 | |
| 476 | /// A text anchor. |
| 477 | pub fn anchor(&self) -> TextAnchor { |
| 478 | self.anchor |
| 479 | } |
| 480 | |
| 481 | /// A list of text chunk style spans. |
| 482 | pub fn spans(&self) -> &[TextSpan] { |
| 483 | &self.spans |
| 484 | } |
| 485 | |
| 486 | /// A text chunk flow. |
| 487 | pub fn text_flow(&self) -> TextFlow { |
| 488 | self.text_flow.clone() |
| 489 | } |
| 490 | |
| 491 | /// A text chunk actual text. |
| 492 | pub fn text(&self) -> &str { |
| 493 | &self.text |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | /// A writing mode. |
| 498 | #[allow (missing_docs)] |
| 499 | #[derive (Clone, Copy, PartialEq, Debug)] |
| 500 | pub enum WritingMode { |
| 501 | LeftToRight, |
| 502 | TopToBottom, |
| 503 | } |
| 504 | |
| 505 | /// A text element. |
| 506 | /// |
| 507 | /// `text` element in SVG. |
| 508 | #[derive (Clone, Debug)] |
| 509 | pub struct Text { |
| 510 | pub(crate) id: String, |
| 511 | pub(crate) rendering_mode: TextRendering, |
| 512 | pub(crate) dx: Vec<f32>, |
| 513 | pub(crate) dy: Vec<f32>, |
| 514 | pub(crate) rotate: Vec<f32>, |
| 515 | pub(crate) writing_mode: WritingMode, |
| 516 | pub(crate) chunks: Vec<TextChunk>, |
| 517 | pub(crate) abs_transform: Transform, |
| 518 | pub(crate) bounding_box: Rect, |
| 519 | pub(crate) abs_bounding_box: Rect, |
| 520 | pub(crate) stroke_bounding_box: Rect, |
| 521 | pub(crate) abs_stroke_bounding_box: Rect, |
| 522 | pub(crate) flattened: Box<Group>, |
| 523 | #[cfg (feature = "text" )] |
| 524 | pub(crate) layouted: Vec<Span>, |
| 525 | } |
| 526 | |
| 527 | impl Text { |
| 528 | /// Element's ID. |
| 529 | /// |
| 530 | /// Taken from the SVG itself. |
| 531 | /// Isn't automatically generated. |
| 532 | /// Can be empty. |
| 533 | pub fn id(&self) -> &str { |
| 534 | &self.id |
| 535 | } |
| 536 | |
| 537 | /// Rendering mode. |
| 538 | /// |
| 539 | /// `text-rendering` in SVG. |
| 540 | pub fn rendering_mode(&self) -> TextRendering { |
| 541 | self.rendering_mode |
| 542 | } |
| 543 | |
| 544 | /// A relative X axis offsets. |
| 545 | /// |
| 546 | /// One offset for each Unicode codepoint. Aka `char` in Rust. |
| 547 | pub fn dx(&self) -> &[f32] { |
| 548 | &self.dx |
| 549 | } |
| 550 | |
| 551 | /// A relative Y axis offsets. |
| 552 | /// |
| 553 | /// One offset for each Unicode codepoint. Aka `char` in Rust. |
| 554 | pub fn dy(&self) -> &[f32] { |
| 555 | &self.dy |
| 556 | } |
| 557 | |
| 558 | /// A list of rotation angles. |
| 559 | /// |
| 560 | /// One angle for each Unicode codepoint. Aka `char` in Rust. |
| 561 | pub fn rotate(&self) -> &[f32] { |
| 562 | &self.rotate |
| 563 | } |
| 564 | |
| 565 | /// A writing mode. |
| 566 | pub fn writing_mode(&self) -> WritingMode { |
| 567 | self.writing_mode |
| 568 | } |
| 569 | |
| 570 | /// A list of text chunks. |
| 571 | pub fn chunks(&self) -> &[TextChunk] { |
| 572 | &self.chunks |
| 573 | } |
| 574 | |
| 575 | /// Element's absolute transform. |
| 576 | /// |
| 577 | /// Contains all ancestors transforms including elements's transform. |
| 578 | /// |
| 579 | /// Note that this is not the relative transform present in SVG. |
| 580 | /// The SVG one would be set only on groups. |
| 581 | pub fn abs_transform(&self) -> Transform { |
| 582 | self.abs_transform |
| 583 | } |
| 584 | |
| 585 | /// Element's text bounding box. |
| 586 | /// |
| 587 | /// Text bounding box is special in SVG and doesn't represent |
| 588 | /// tight bounds of the element's content. |
| 589 | /// You can find more about it |
| 590 | /// [here](https://razrfalcon.github.io/notes-on-svg-parsing/text/bbox.html). |
| 591 | /// |
| 592 | /// `objectBoundingBox` in SVG terms. Meaning it doesn't affected by parent transforms. |
| 593 | /// |
| 594 | /// Returns `None` when the `text` build feature was disabled. |
| 595 | /// This is because we have to perform a text layout before calculating a bounding box. |
| 596 | pub fn bounding_box(&self) -> Rect { |
| 597 | self.bounding_box |
| 598 | } |
| 599 | |
| 600 | /// Element's text bounding box in canvas coordinates. |
| 601 | /// |
| 602 | /// `userSpaceOnUse` in SVG terms. |
| 603 | pub fn abs_bounding_box(&self) -> Rect { |
| 604 | self.abs_bounding_box |
| 605 | } |
| 606 | |
| 607 | /// Element's object bounding box including stroke. |
| 608 | /// |
| 609 | /// Similar to `bounding_box`, but includes stroke. |
| 610 | /// |
| 611 | /// Will have the same value as `bounding_box` when path has no stroke. |
| 612 | pub fn stroke_bounding_box(&self) -> Rect { |
| 613 | self.stroke_bounding_box |
| 614 | } |
| 615 | |
| 616 | /// Element's bounding box including stroke in canvas coordinates. |
| 617 | pub fn abs_stroke_bounding_box(&self) -> Rect { |
| 618 | self.abs_stroke_bounding_box |
| 619 | } |
| 620 | |
| 621 | /// Text converted into paths, ready to render. |
| 622 | /// |
| 623 | /// Note that this is only a |
| 624 | /// "best-effort" attempt: The text will be converted into group/paths/image |
| 625 | /// primitives, so that they can be rendered with the existing infrastructure. |
| 626 | /// This process is in general lossless and should lead to correct output, with |
| 627 | /// two notable exceptions: |
| 628 | /// 1. For glyphs based on the `SVG` table, only glyphs that are pure SVG 1.1/2.0 |
| 629 | /// are supported. Glyphs that make use of features in the OpenType specification |
| 630 | /// that are not part of the original SVG specification are not supported. |
| 631 | /// 2. For glyphs based on the `COLR` table, there are a certain number of features |
| 632 | /// that are not (correctly) supported, such as conical |
| 633 | /// gradients, certain gradient transforms and some blend modes. But this shouldn't |
| 634 | /// cause any issues in 95% of the cases, as most of those are edge cases. |
| 635 | /// If the two above are not acceptable, then you will need to implement your own |
| 636 | /// glyph rendering logic based on the layouted glyphs (see the `layouted` method). |
| 637 | pub fn flattened(&self) -> &Group { |
| 638 | &self.flattened |
| 639 | } |
| 640 | |
| 641 | /// The positioned glyphs and decoration spans of the text. |
| 642 | /// |
| 643 | /// This should only be used if you need more low-level access |
| 644 | /// to the glyphs that make up the text. If you just need the |
| 645 | /// outlines of the text, you should use `flattened` instead. |
| 646 | #[cfg (feature = "text" )] |
| 647 | pub fn layouted(&self) -> &[Span] { |
| 648 | &self.layouted |
| 649 | } |
| 650 | |
| 651 | pub(crate) fn subroots(&self, f: &mut dyn FnMut(&Group)) { |
| 652 | f(&self.flattened); |
| 653 | } |
| 654 | } |
| 655 | |