use std::sync::Arc;
use strict_num::NonZeroPositiveF32;
pub use svgtypes::FontFamily;
#[cfg(feature = "text")]
use crate::layout::Span;
use crate::{Fill, Group, NonEmptyString, PaintOrder, Rect, Stroke, TextRendering, 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
}
}
#[cfg(feature = "text")]
impl From<fontdb::Stretch> for FontStretch {
fn from(stretch: fontdb::Stretch) -> Self {
match stretch {
fontdb::Stretch::UltraCondensed => FontStretch::UltraCondensed,
fontdb::Stretch::ExtraCondensed => FontStretch::ExtraCondensed,
fontdb::Stretch::Condensed => FontStretch::Condensed,
fontdb::Stretch::SemiCondensed => FontStretch::SemiCondensed,
fontdb::Stretch::Normal => FontStretch::Normal,
fontdb::Stretch::SemiExpanded => FontStretch::SemiExpanded,
fontdb::Stretch::Expanded => FontStretch::Expanded,
fontdb::Stretch::ExtraExpanded => FontStretch::ExtraExpanded,
fontdb::Stretch::UltraExpanded => FontStretch::UltraExpanded,
}
}
}
#[cfg(feature = "text")]
impl From<FontStretch> for fontdb::Stretch {
fn from(stretch: FontStretch) -> Self {
match stretch {
FontStretch::UltraCondensed => fontdb::Stretch::UltraCondensed,
FontStretch::ExtraCondensed => fontdb::Stretch::ExtraCondensed,
FontStretch::Condensed => fontdb::Stretch::Condensed,
FontStretch::SemiCondensed => fontdb::Stretch::SemiCondensed,
FontStretch::Normal => fontdb::Stretch::Normal,
FontStretch::SemiExpanded => fontdb::Stretch::SemiExpanded,
FontStretch::Expanded => fontdb::Stretch::Expanded,
FontStretch::ExtraExpanded => fontdb::Stretch::ExtraExpanded,
FontStretch::UltraExpanded => fontdb::Stretch::UltraExpanded,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct FontVariation {
pub tag: [u8; 4],
pub value: f32,
}
impl FontVariation {
pub fn new(tag: [u8; 4], value: f32) -> Self {
Self { tag, value }
}
}
impl PartialEq for FontVariation {
fn eq(&self, other: &Self) -> bool {
self.tag == other.tag && self.value.to_bits() == other.value.to_bits()
}
}
impl Eq for FontVariation {}
impl std::hash::Hash for FontVariation {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.tag.hash(state);
self.value.to_bits().hash(state);
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum FontStyle {
Normal,
Italic,
Oblique,
}
impl Default for FontStyle {
#[inline]
fn default() -> FontStyle {
Self::Normal
}
}
#[cfg(feature = "text")]
impl From<fontdb::Style> for FontStyle {
fn from(style: fontdb::Style) -> Self {
match style {
fontdb::Style::Normal => FontStyle::Normal,
fontdb::Style::Italic => FontStyle::Italic,
fontdb::Style::Oblique => FontStyle::Oblique,
}
}
}
#[cfg(feature = "text")]
impl From<FontStyle> for fontdb::Style {
fn from(style: FontStyle) -> Self {
match style {
FontStyle::Normal => fontdb::Style::Normal,
FontStyle::Italic => fontdb::Style::Italic,
FontStyle::Oblique => fontdb::Style::Oblique,
}
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct Font {
pub(crate) families: Vec<FontFamily>,
pub(crate) style: FontStyle,
pub(crate) stretch: FontStretch,
pub(crate) weight: u16,
pub(crate) variations: Vec<FontVariation>,
}
impl Font {
pub fn families(&self) -> &[FontFamily] {
&self.families
}
pub fn style(&self) -> FontStyle {
self.style
}
pub fn stretch(&self) -> FontStretch {
self.stretch
}
pub fn weight(&self) -> u16 {
self.weight
}
pub fn variations(&self) -> &[FontVariation] {
&self.variations
}
}
#[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, Copy, PartialEq, Debug)]
pub enum FontOpticalSizing {
Auto,
None,
}
impl Default for FontOpticalSizing {
fn default() -> Self {
Self::Auto
}
}
#[derive(Clone, Debug)]
pub struct TextDecorationStyle {
pub(crate) fill: Option<Fill>,
pub(crate) stroke: Option<Stroke>,
}
impl TextDecorationStyle {
pub fn fill(&self) -> Option<&Fill> {
self.fill.as_ref()
}
pub fn stroke(&self) -> Option<&Stroke> {
self.stroke.as_ref()
}
}
#[derive(Clone, Debug)]
pub struct TextDecoration {
pub(crate) underline: Option<TextDecorationStyle>,
pub(crate) overline: Option<TextDecorationStyle>,
pub(crate) line_through: Option<TextDecorationStyle>,
}
impl TextDecoration {
pub fn underline(&self) -> Option<&TextDecorationStyle> {
self.underline.as_ref()
}
pub fn overline(&self) -> Option<&TextDecorationStyle> {
self.overline.as_ref()
}
pub fn line_through(&self) -> Option<&TextDecorationStyle> {
self.line_through.as_ref()
}
}
#[derive(Clone, Debug)]
pub struct TextSpan {
pub(crate) start: usize,
pub(crate) end: usize,
pub(crate) fill: Option<Fill>,
pub(crate) stroke: Option<Stroke>,
pub(crate) paint_order: PaintOrder,
pub(crate) font: Font,
pub(crate) font_size: NonZeroPositiveF32,
pub(crate) small_caps: bool,
pub(crate) apply_kerning: bool,
pub(crate) font_optical_sizing: FontOpticalSizing,
pub(crate) decoration: TextDecoration,
pub(crate) dominant_baseline: DominantBaseline,
pub(crate) alignment_baseline: AlignmentBaseline,
pub(crate) baseline_shift: Vec<BaselineShift>,
pub(crate) visible: bool,
pub(crate) letter_spacing: f32,
pub(crate) word_spacing: f32,
pub(crate) text_length: Option<f32>,
pub(crate) length_adjust: LengthAdjust,
}
impl TextSpan {
pub fn start(&self) -> usize {
self.start
}
pub fn end(&self) -> usize {
self.end
}
pub fn fill(&self) -> Option<&Fill> {
self.fill.as_ref()
}
pub fn stroke(&self) -> Option<&Stroke> {
self.stroke.as_ref()
}
pub fn paint_order(&self) -> PaintOrder {
self.paint_order
}
pub fn font(&self) -> &Font {
&self.font
}
pub fn font_size(&self) -> NonZeroPositiveF32 {
self.font_size
}
pub fn small_caps(&self) -> bool {
self.small_caps
}
pub fn apply_kerning(&self) -> bool {
self.apply_kerning
}
pub fn font_optical_sizing(&self) -> FontOpticalSizing {
self.font_optical_sizing
}
pub fn decoration(&self) -> &TextDecoration {
&self.decoration
}
pub fn dominant_baseline(&self) -> DominantBaseline {
self.dominant_baseline
}
pub fn alignment_baseline(&self) -> AlignmentBaseline {
self.alignment_baseline
}
pub fn baseline_shift(&self) -> &[BaselineShift] {
&self.baseline_shift
}
pub fn is_visible(&self) -> bool {
self.visible
}
pub fn letter_spacing(&self) -> f32 {
self.letter_spacing
}
pub fn word_spacing(&self) -> f32 {
self.word_spacing
}
pub fn text_length(&self) -> Option<f32> {
self.text_length
}
pub fn length_adjust(&self) -> LengthAdjust {
self.length_adjust
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum TextAnchor {
Start,
Middle,
End,
}
impl Default for TextAnchor {
fn default() -> Self {
Self::Start
}
}
#[derive(Debug)]
pub struct TextPath {
pub(crate) id: NonEmptyString,
pub(crate) start_offset: f32,
pub(crate) path: Arc<tiny_skia_path::Path>,
}
impl TextPath {
pub fn id(&self) -> &str {
self.id.get()
}
pub fn start_offset(&self) -> f32 {
self.start_offset
}
pub fn path(&self) -> &tiny_skia_path::Path {
&self.path
}
}
#[derive(Clone, Debug)]
pub enum TextFlow {
Linear,
Path(Arc<TextPath>),
}
#[derive(Clone, Debug)]
pub struct TextChunk {
pub(crate) x: Option<f32>,
pub(crate) y: Option<f32>,
pub(crate) anchor: TextAnchor,
pub(crate) spans: Vec<TextSpan>,
pub(crate) text_flow: TextFlow,
pub(crate) text: String,
}
impl TextChunk {
pub fn x(&self) -> Option<f32> {
self.x
}
pub fn y(&self) -> Option<f32> {
self.y
}
pub fn anchor(&self) -> TextAnchor {
self.anchor
}
pub fn spans(&self) -> &[TextSpan] {
&self.spans
}
pub fn text_flow(&self) -> TextFlow {
self.text_flow.clone()
}
pub fn text(&self) -> &str {
&self.text
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum WritingMode {
LeftToRight,
TopToBottom,
}
#[derive(Clone, Debug)]
pub struct Text {
pub(crate) id: String,
pub(crate) rendering_mode: TextRendering,
pub(crate) dx: Vec<f32>,
pub(crate) dy: Vec<f32>,
pub(crate) rotate: Vec<f32>,
pub(crate) writing_mode: WritingMode,
pub(crate) chunks: Vec<TextChunk>,
pub(crate) abs_transform: Transform,
pub(crate) bounding_box: Rect,
pub(crate) abs_bounding_box: Rect,
pub(crate) stroke_bounding_box: Rect,
pub(crate) abs_stroke_bounding_box: Rect,
pub(crate) flattened: Box<Group>,
#[cfg(feature = "text")]
pub(crate) layouted: Vec<Span>,
}
impl Text {
pub fn id(&self) -> &str {
&self.id
}
pub fn rendering_mode(&self) -> TextRendering {
self.rendering_mode
}
pub fn dx(&self) -> &[f32] {
&self.dx
}
pub fn dy(&self) -> &[f32] {
&self.dy
}
pub fn rotate(&self) -> &[f32] {
&self.rotate
}
pub fn writing_mode(&self) -> WritingMode {
self.writing_mode
}
pub fn chunks(&self) -> &[TextChunk] {
&self.chunks
}
pub fn abs_transform(&self) -> Transform {
self.abs_transform
}
pub fn bounding_box(&self) -> Rect {
self.bounding_box
}
pub fn abs_bounding_box(&self) -> Rect {
self.abs_bounding_box
}
pub fn stroke_bounding_box(&self) -> Rect {
self.stroke_bounding_box
}
pub fn abs_stroke_bounding_box(&self) -> Rect {
self.abs_stroke_bounding_box
}
pub fn flattened(&self) -> &Group {
&self.flattened
}
#[cfg(feature = "text")]
pub fn layouted(&self) -> &[Span] {
&self.layouted
}
pub(crate) fn subroots(&self, f: &mut dyn FnMut(&Group)) {
f(&self.flattened);
}
}