use std::rc::Rc;
use strict_num::NonZeroPositiveF32;
use crate::{Fill, Group, Paint, PaintOrder, Stroke, TextRendering, Visibility};
use tiny_skia_path::{NonZeroRect, Transform};
#[allow(missing_docs)]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum FontStretch {
UltraCondensed,
ExtraCondensed,
Condensed,
SemiCondensed,
Normal,
SemiExpanded,
Expanded,
ExtraExpanded,
UltraExpanded,
}
impl Default for FontStretch {
#[inline]
fn default() -> Self {
Self::Normal
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum FontStyle {
Normal,
Italic,
Oblique,
}
impl Default for FontStyle {
#[inline]
fn default() -> FontStyle {
Self::Normal
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct Font {
pub families: Vec<String>,
pub style: FontStyle,
pub stretch: FontStretch,
pub weight: u16,
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum DominantBaseline {
Auto,
UseScript,
NoChange,
ResetSize,
Ideographic,
Alphabetic,
Hanging,
Mathematical,
Central,
Middle,
TextAfterEdge,
TextBeforeEdge,
}
impl Default for DominantBaseline {
fn default() -> Self {
Self::Auto
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum AlignmentBaseline {
Auto,
Baseline,
BeforeEdge,
TextBeforeEdge,
Middle,
Central,
AfterEdge,
TextAfterEdge,
Ideographic,
Alphabetic,
Hanging,
Mathematical,
}
impl Default for AlignmentBaseline {
fn default() -> Self {
Self::Auto
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum BaselineShift {
Baseline,
Subscript,
Superscript,
Number(f32),
}
impl Default for BaselineShift {
#[inline]
fn default() -> BaselineShift {
BaselineShift::Baseline
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum LengthAdjust {
Spacing,
SpacingAndGlyphs,
}
impl Default for LengthAdjust {
fn default() -> Self {
Self::Spacing
}
}
#[derive(Clone, Debug)]
pub struct TextDecorationStyle {
pub fill: Option<Fill>,
pub stroke: Option<Stroke>,
}
#[derive(Clone, Debug)]
pub struct TextDecoration {
pub underline: Option<TextDecorationStyle>,
pub overline: Option<TextDecorationStyle>,
pub line_through: Option<TextDecorationStyle>,
}
#[derive(Clone, Debug)]
pub struct TextSpan {
pub start: usize,
pub end: usize,
pub fill: Option<Fill>,
pub stroke: Option<Stroke>,
pub paint_order: PaintOrder,
pub font: Font,
pub font_size: NonZeroPositiveF32,
pub small_caps: bool,
pub apply_kerning: bool,
pub decoration: TextDecoration,
pub dominant_baseline: DominantBaseline,
pub alignment_baseline: AlignmentBaseline,
pub baseline_shift: Vec<BaselineShift>,
pub visibility: Visibility,
pub letter_spacing: f32,
pub word_spacing: f32,
pub text_length: Option<f32>,
pub length_adjust: LengthAdjust,
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum TextAnchor {
Start,
Middle,
End,
}
impl Default for TextAnchor {
fn default() -> Self {
Self::Start
}
}
#[derive(Clone, Debug)]
pub struct TextPath {
pub id: String,
pub start_offset: f32,
pub path: Rc<tiny_skia_path::Path>,
}
#[derive(Clone, Debug)]
pub enum TextFlow {
Linear,
Path(Rc<TextPath>),
}
#[derive(Clone, Debug)]
pub struct TextChunk {
pub x: Option<f32>,
pub y: Option<f32>,
pub anchor: TextAnchor,
pub spans: Vec<TextSpan>,
pub text_flow: TextFlow,
pub text: String,
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum WritingMode {
LeftToRight,
TopToBottom,
}
#[derive(Clone, Debug)]
pub struct Text {
pub id: String,
pub rendering_mode: TextRendering,
pub dx: Vec<f32>,
pub dy: Vec<f32>,
pub rotate: Vec<f32>,
pub writing_mode: WritingMode,
pub chunks: Vec<TextChunk>,
pub abs_transform: Transform,
pub bounding_box: Option<NonZeroRect>,
pub stroke_bounding_box: Option<NonZeroRect>,
pub flattened: Option<Box<Group>>,
}
impl Text {
pub(crate) fn subroots(&self, f: &mut dyn FnMut(&Group)) {
if let Some(ref flattened) = self.flattened {
f(flattened);
return;
}
let mut push_patt = |paint: Option<&Paint>| {
if let Some(Paint::Pattern(ref patt)) = paint {
f(&patt.borrow().root);
}
};
for chunk in &self.chunks {
for span in &chunk.spans {
push_patt(span.fill.as_ref().map(|f| &f.paint));
push_patt(span.stroke.as_ref().map(|f| &f.paint));
if let Some(ref underline) = span.decoration.underline {
push_patt(underline.fill.as_ref().map(|f| &f.paint));
push_patt(underline.stroke.as_ref().map(|f| &f.paint));
}
if let Some(ref overline) = span.decoration.overline {
push_patt(overline.fill.as_ref().map(|f| &f.paint));
push_patt(overline.stroke.as_ref().map(|f| &f.paint));
}
if let Some(ref line_through) = span.decoration.line_through {
push_patt(line_through.fill.as_ref().map(|f| &f.paint));
push_patt(line_through.stroke.as_ref().map(|f| &f.paint));
}
}
}
}
pub(crate) fn subroots_mut(&mut self, f: &mut dyn FnMut(&mut Group)) {
if let Some(ref mut flattened) = self.flattened {
f(flattened);
return;
}
let mut push_patt = |paint: Option<&Paint>| {
if let Some(Paint::Pattern(ref patt)) = paint {
f(&mut patt.borrow_mut().root);
}
};
for chunk in &self.chunks {
for span in &chunk.spans {
push_patt(span.fill.as_ref().map(|f| &f.paint));
push_patt(span.stroke.as_ref().map(|f| &f.paint));
if let Some(ref underline) = span.decoration.underline {
push_patt(underline.fill.as_ref().map(|f| &f.paint));
push_patt(underline.stroke.as_ref().map(|f| &f.paint));
}
if let Some(ref overline) = span.decoration.overline {
push_patt(overline.fill.as_ref().map(|f| &f.paint));
push_patt(overline.stroke.as_ref().map(|f| &f.paint));
}
if let Some(ref line_through) = span.decoration.line_through {
push_patt(line_through.fill.as_ref().map(|f| &f.paint));
push_patt(line_through.stroke.as_ref().map(|f| &f.paint));
}
}
}
}
}