initial support for custom brushes
This commit is contained in:
parent
bb16bccf28
commit
7596ee8b03
|
@ -2,6 +2,7 @@ use super::context::LayoutState;
|
|||
use super::font::system::{Font, SystemFontCollection};
|
||||
use super::font::{FontCollection, FontFamilyHandle, GenericFontFamily};
|
||||
use super::itemize::*;
|
||||
use super::Color;
|
||||
use super::Layout;
|
||||
use fount::FamilyId;
|
||||
use piet::kurbo::{Point, Rect, Size};
|
||||
|
@ -174,7 +175,10 @@ impl piet::TextLayoutBuilder for PietTextLayoutBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_attr(attr: &TextAttribute, fonts: &mut SystemFontCollection) -> AttributeKind<FamilyId> {
|
||||
fn convert_attr(
|
||||
attr: &TextAttribute,
|
||||
fonts: &mut SystemFontCollection,
|
||||
) -> AttributeKind<FamilyId, ()> {
|
||||
use piet::FontStyle;
|
||||
use swash::{Style, Weight};
|
||||
match attr {
|
||||
|
@ -201,7 +205,7 @@ fn convert_attr(attr: &TextAttribute, fonts: &mut SystemFontCollection) -> Attri
|
|||
}),
|
||||
TextAttribute::TextColor(color) => {
|
||||
let (r, g, b, a) = color.as_rgba8();
|
||||
AttributeKind::Color([r, g, b, a])
|
||||
AttributeKind::Color(Color::Solid([r, g, b, a]))
|
||||
}
|
||||
TextAttribute::Underline(yes) => AttributeKind::Underline(*yes),
|
||||
TextAttribute::Strikethrough(yes) => AttributeKind::Strikethrough(*yes),
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
use super::font::{FontCollection, FontFamily, FontFamilyHandle, GenericFontFamily};
|
||||
use super::itemize::{AttributeKind, ItemData, RangedAttribute, SpanData};
|
||||
use super::{Alignment, Attribute};
|
||||
use super::{Alignment, Attribute, Brush};
|
||||
use super::{Glyph, Layout, Run};
|
||||
use core::ops::{Bound, Range, RangeBounds};
|
||||
use fount::Library;
|
||||
use swash::shape::ShapeContext;
|
||||
|
||||
pub struct LayoutContext<C: FontCollection> {
|
||||
state: LayoutState<C>,
|
||||
pub struct LayoutContext<C: FontCollection, B: Brush> {
|
||||
state: LayoutState<C, B>,
|
||||
}
|
||||
|
||||
impl<C: FontCollection> LayoutContext<C> {
|
||||
impl<C: FontCollection, B: Brush> LayoutContext<C, B> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: LayoutState::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_layout<'a>(&'a mut self, fonts: &'a mut C, text: &'a str) -> LayoutBuilder<'a, C> {
|
||||
pub fn new_layout<'a>(&'a mut self, fonts: &'a mut C, text: &'a str) -> LayoutBuilder<'a, C, B> {
|
||||
fonts.begin_session();
|
||||
LayoutBuilder {
|
||||
state: &mut self.state,
|
||||
|
@ -27,19 +27,19 @@ impl<C: FontCollection> LayoutContext<C> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct LayoutBuilder<'a, C: FontCollection> {
|
||||
state: &'a mut LayoutState<C>,
|
||||
pub struct LayoutBuilder<'a, C: FontCollection, B: Brush> {
|
||||
state: &'a mut LayoutState<C, B>,
|
||||
fonts: &'a mut C,
|
||||
text: &'a str,
|
||||
}
|
||||
|
||||
impl<'a, C: FontCollection> LayoutBuilder<'a, C> {}
|
||||
impl<'a, C: FontCollection, B: Brush> LayoutBuilder<'a, C, B> {}
|
||||
|
||||
pub struct LayoutState<C: FontCollection> {
|
||||
pub struct LayoutState<C: FontCollection, B: Brush = ()> {
|
||||
pub shape_context: ShapeContext,
|
||||
pub defaults: SpanData<C::Family>,
|
||||
pub attributes: Vec<RangedAttribute<C::Family>>,
|
||||
pub spans: Vec<SpanData<C::Family>>,
|
||||
pub defaults: SpanData<C::Family, B>,
|
||||
pub attributes: Vec<RangedAttribute<C::Family, B>>,
|
||||
pub spans: Vec<SpanData<C::Family, B>>,
|
||||
pub items: Vec<ItemData>,
|
||||
pub glyphs: Vec<Glyph>,
|
||||
pub runs: Vec<Run<C::Font>>,
|
||||
|
@ -47,7 +47,7 @@ pub struct LayoutState<C: FontCollection> {
|
|||
pub alignment: Alignment,
|
||||
}
|
||||
|
||||
impl<C: FontCollection> LayoutState<C> {
|
||||
impl<C: FontCollection, B: Brush> LayoutState<C, B> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
shape_context: ShapeContext::new(),
|
||||
|
@ -73,7 +73,7 @@ impl<C: FontCollection> LayoutState<C> {
|
|||
self.alignment = Alignment::Start;
|
||||
}
|
||||
|
||||
pub fn default_attribute(&mut self, attribute: AttributeKind<C::Family>) {
|
||||
pub fn default_attribute(&mut self, attribute: AttributeKind<C::Family, B>) {
|
||||
self.defaults.apply(&attribute);
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ impl<C: FontCollection> LayoutState<C> {
|
|||
&mut self,
|
||||
text_len: usize,
|
||||
range: impl RangeBounds<usize>,
|
||||
attribute: AttributeKind<C::Family>,
|
||||
attribute: AttributeKind<C::Family, B>,
|
||||
) {
|
||||
let range = resolve_range(range, text_len);
|
||||
if !range.is_empty() {
|
||||
|
@ -116,7 +116,7 @@ impl<C: FontCollection> LayoutState<C> {
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_attr<C: FontCollection>(attr: &Attribute, fonts: &mut C) -> AttributeKind<C::Family> {
|
||||
fn convert_attr<C: FontCollection, B: Brush>(attr: &Attribute<B>, fonts: &mut C) -> AttributeKind<C::Family, B> {
|
||||
match attr {
|
||||
Attribute::FontFamily(family) => AttributeKind::Family(match family {
|
||||
FontFamily::Named(name) => fonts
|
||||
|
@ -129,7 +129,7 @@ fn convert_attr<C: FontCollection>(attr: &Attribute, fonts: &mut C) -> Attribute
|
|||
Attribute::FontWeight(weight) => AttributeKind::Weight(*weight),
|
||||
Attribute::FontStyle(style) => AttributeKind::Style(*style),
|
||||
Attribute::FontStretch(stretch) => AttributeKind::Stretch(*stretch),
|
||||
Attribute::Color(color) => AttributeKind::Color(*color),
|
||||
Attribute::Color(color) => AttributeKind::Color(color.clone()),
|
||||
Attribute::Underline(yes) => AttributeKind::Underline(*yes),
|
||||
Attribute::Strikethrough(yes) => AttributeKind::Strikethrough(*yes),
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ pub use swash::{Stretch as FontStretch, Style as FontStyle, Weight as FontWeight
|
|||
|
||||
pub mod system;
|
||||
|
||||
pub trait FontInstance: Clone + PartialEq {
|
||||
pub trait FontHandle: Clone + PartialEq {
|
||||
fn as_font_ref(&self) -> FontRef;
|
||||
|
||||
fn synthesis(&self) -> Option<Synthesis> {
|
||||
|
@ -20,7 +20,7 @@ pub trait FontInstance: Clone + PartialEq {
|
|||
|
||||
pub trait FontCollection {
|
||||
type Family: Clone + PartialEq + Debug;
|
||||
type Font: FontInstance;
|
||||
type Font: FontHandle;
|
||||
|
||||
/// Begins a layout sesion with this collection.
|
||||
fn begin_session(&mut self);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
mod collection;
|
||||
mod font;
|
||||
|
||||
use super::FontInstance;
|
||||
use super::FontHandle;
|
||||
pub use collection::SystemFontCollection;
|
||||
pub use font::Font;
|
||||
use swash::{FontRef, Synthesis};
|
||||
|
||||
impl FontInstance for Font {
|
||||
impl FontHandle for Font {
|
||||
fn as_font_ref(&self) -> FontRef {
|
||||
self.as_ref()
|
||||
}
|
||||
|
|
|
@ -3,15 +3,16 @@ use core::fmt::Debug;
|
|||
use fount::{FamilyId, GenericFamily, Locale};
|
||||
use swash::text::Script;
|
||||
use swash::{Attributes, Stretch, Style, Weight};
|
||||
use super::{Brush, Color};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SpanData<F: Clone + PartialEq + Debug> {
|
||||
pub struct SpanData<F: Clone + PartialEq + Debug, B: Brush> {
|
||||
pub family: FontFamilyHandle<F>,
|
||||
pub size: f64,
|
||||
pub stretch: Stretch,
|
||||
pub style: Style,
|
||||
pub weight: Weight,
|
||||
pub color: [u8; 4],
|
||||
pub color: Color<B>,
|
||||
pub underline: bool,
|
||||
pub strikethrough: bool,
|
||||
pub start: usize,
|
||||
|
@ -19,11 +20,11 @@ pub struct SpanData<F: Clone + PartialEq + Debug> {
|
|||
pub count: usize,
|
||||
}
|
||||
|
||||
impl<F: Clone + PartialEq + Debug> SpanData<F> {
|
||||
pub fn apply(&mut self, attr: &AttributeKind<F>) -> bool {
|
||||
impl<F: Clone + PartialEq + Debug, B: Brush> SpanData<F, B> {
|
||||
pub fn apply(&mut self, attr: &AttributeKind<F, B>) -> bool {
|
||||
match attr {
|
||||
AttributeKind::Family(family) => self.family = family.clone(),
|
||||
AttributeKind::Color(color) => self.color = *color,
|
||||
AttributeKind::Color(color) => self.color = color.clone(),
|
||||
AttributeKind::Size(size) => self.size = *size,
|
||||
AttributeKind::Stretch(stretch) => self.stretch = *stretch,
|
||||
AttributeKind::Style(style) => self.style = *style,
|
||||
|
@ -34,7 +35,7 @@ impl<F: Clone + PartialEq + Debug> SpanData<F> {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn check(&self, attr: &AttributeKind<F>) -> bool {
|
||||
pub fn check(&self, attr: &AttributeKind<F, B>) -> bool {
|
||||
match attr {
|
||||
AttributeKind::Family(family) => self.family == *family,
|
||||
AttributeKind::Size(size) => self.size == *size,
|
||||
|
@ -63,7 +64,7 @@ impl<F: Clone + PartialEq + Debug> SpanData<F> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<F: Clone + PartialEq + Debug> Default for SpanData<F> {
|
||||
impl<F: Clone + PartialEq + Debug, B: Brush> Default for SpanData<F, B> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
family: FontFamilyHandle::Default,
|
||||
|
@ -71,7 +72,7 @@ impl<F: Clone + PartialEq + Debug> Default for SpanData<F> {
|
|||
stretch: Stretch::NORMAL,
|
||||
style: Style::Normal,
|
||||
weight: Weight::NORMAL,
|
||||
color: [0, 0, 0, 255],
|
||||
color: Color::Solid([0, 0, 0, 255]),
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
start: 0,
|
||||
|
@ -93,28 +94,28 @@ pub struct ItemData {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum AttributeKind<F: Clone + PartialEq + Debug> {
|
||||
pub enum AttributeKind<F: Clone + PartialEq + Debug, B: Brush> {
|
||||
Family(FontFamilyHandle<F>),
|
||||
Style(Style),
|
||||
Weight(Weight),
|
||||
Stretch(Stretch),
|
||||
Size(f64),
|
||||
Color([u8; 4]),
|
||||
Color(Color<B>),
|
||||
Underline(bool),
|
||||
Strikethrough(bool),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RangedAttribute<F: Clone + PartialEq + Debug> {
|
||||
pub attr: AttributeKind<F>,
|
||||
pub struct RangedAttribute<F: Clone + PartialEq + Debug, B: Brush> {
|
||||
pub attr: AttributeKind<F, B>,
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
pub fn normalize_spans<F: Clone + PartialEq + Debug>(
|
||||
attrs: &[RangedAttribute<F>],
|
||||
defaults: &SpanData<F>,
|
||||
spans: &mut Vec<SpanData<F>>,
|
||||
pub fn normalize_spans<F: Clone + PartialEq + Debug, B: Brush>(
|
||||
attrs: &[RangedAttribute<F, B>],
|
||||
defaults: &SpanData<F, B>,
|
||||
spans: &mut Vec<SpanData<F, B>>,
|
||||
) {
|
||||
spans.push(defaults.clone());
|
||||
for attr in attrs {
|
||||
|
@ -182,9 +183,9 @@ pub fn normalize_spans<F: Clone + PartialEq + Debug>(
|
|||
spans.truncate(spans.len() - merged_count);
|
||||
}
|
||||
|
||||
pub fn itemize<F: Clone + PartialEq + Debug>(
|
||||
pub fn itemize<F: Clone + PartialEq + Debug, B: Brush>(
|
||||
text: &str,
|
||||
spans: &mut [SpanData<F>],
|
||||
spans: &mut [SpanData<F, B>],
|
||||
items: &mut Vec<ItemData>,
|
||||
) {
|
||||
use swash::text::Codepoint as _;
|
||||
|
@ -255,9 +256,9 @@ struct SpanSplitRange {
|
|||
last: Option<usize>,
|
||||
}
|
||||
|
||||
fn span_split_range<F: Clone + PartialEq + Debug>(
|
||||
attr: &RangedAttribute<F>,
|
||||
spans: &[SpanData<F>],
|
||||
fn span_split_range<F: Clone + PartialEq + Debug, B: Brush>(
|
||||
attr: &RangedAttribute<F, B>,
|
||||
spans: &[SpanData<F, B>],
|
||||
) -> SpanSplitRange {
|
||||
let mut range = SpanSplitRange::default();
|
||||
let start_span_index = match spans.binary_search_by(|span| span.start.cmp(&attr.start)) {
|
||||
|
|
24
src/lib.rs
24
src/lib.rs
|
@ -19,26 +19,26 @@ pub use swash;
|
|||
use core::ops::Range;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Layout<F: FontInstance> {
|
||||
pub struct Layout<F: FontHandle> {
|
||||
pub glyphs: Vec<Glyph>,
|
||||
pub runs: Vec<Run<F>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Run<F: FontInstance> {
|
||||
pub struct Run<F: FontHandle> {
|
||||
pub font: F,
|
||||
pub text_range: Range<usize>,
|
||||
pub glyph_range: Range<usize>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum Attribute<'a> {
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Attribute<'a, B: Brush = ()> {
|
||||
FontFamily(FontFamily<'a>),
|
||||
FontSize(f32),
|
||||
FontStretch(FontStretch),
|
||||
FontStyle(FontStyle),
|
||||
FontWeight(FontWeight),
|
||||
Color([u8; 4]),
|
||||
Color(Color<B>),
|
||||
Underline(bool),
|
||||
Strikethrough(bool),
|
||||
}
|
||||
|
@ -74,3 +74,17 @@ pub enum Alignment {
|
|||
Center,
|
||||
Justified,
|
||||
}
|
||||
|
||||
/// Rendering style for glyphs and text decorations.
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Color<B: Brush = ()> {
|
||||
/// 32-bit color in RGBA order.
|
||||
Solid([u8; 4]),
|
||||
/// Custom brush.
|
||||
Brush(B)
|
||||
}
|
||||
|
||||
/// Trait for types that represent custom rendering styles.
|
||||
pub trait Brush: Clone + PartialEq + core::fmt::Debug {}
|
||||
|
||||
impl Brush for () {}
|
||||
|
|
24
src/shape.rs
24
src/shape.rs
|
@ -1,16 +1,16 @@
|
|||
use super::font::*;
|
||||
use super::itemize::*;
|
||||
use super::{Glyph, Layout, Run};
|
||||
use super::{Glyph, Layout, Run, Brush};
|
||||
use fount::Locale;
|
||||
use swash::shape::{self, ShapeContext};
|
||||
use swash::text::cluster::CharCluster;
|
||||
use swash::text::Script;
|
||||
use swash::{Attributes, FontRef, Synthesis};
|
||||
|
||||
pub fn shape<C: FontCollection>(
|
||||
pub fn shape<C: FontCollection, B: Brush>(
|
||||
shape_context: &mut ShapeContext,
|
||||
font_selector: &mut FontSelector<C>,
|
||||
spans: &[SpanData<C::Family>],
|
||||
font_selector: &mut FontSelector<C, B>,
|
||||
spans: &[SpanData<C::Family, B>],
|
||||
items: &[ItemData],
|
||||
text: &str,
|
||||
glyphs: &mut Vec<Glyph>,
|
||||
|
@ -73,9 +73,9 @@ pub fn shape<C: FontCollection>(
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FontSelector<'a, C: FontCollection> {
|
||||
pub struct FontSelector<'a, C: FontCollection, B: Brush> {
|
||||
fonts: &'a mut C,
|
||||
spans: &'a [SpanData<C::Family>],
|
||||
spans: &'a [SpanData<C::Family, B>],
|
||||
span_index: u32,
|
||||
script: Script,
|
||||
locale: Option<Locale>,
|
||||
|
@ -83,8 +83,8 @@ pub struct FontSelector<'a, C: FontCollection> {
|
|||
attrs: Attributes,
|
||||
}
|
||||
|
||||
impl<'a, C: FontCollection> FontSelector<'a, C> {
|
||||
pub fn new(fonts: &'a mut C, spans: &'a [SpanData<C::Family>], first_item: &ItemData) -> Self {
|
||||
impl<'a, C: FontCollection, B: Brush> FontSelector<'a, C, B> {
|
||||
pub fn new(fonts: &'a mut C, spans: &'a [SpanData<C::Family, B>], first_item: &ItemData) -> Self {
|
||||
let first_span = &spans[0];
|
||||
let attrs = first_span.attributes();
|
||||
Self {
|
||||
|
@ -99,7 +99,7 @@ impl<'a, C: FontCollection> FontSelector<'a, C> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, C: FontCollection> shape::partition::Selector for FontSelector<'a, C> {
|
||||
impl<'a, C: FontCollection, B: Brush> shape::partition::Selector for FontSelector<'a, C, B> {
|
||||
type SelectedFont = SelectedFont<C::Font>;
|
||||
|
||||
fn select_font(&mut self, cluster: &mut CharCluster) -> Option<Self::SelectedFont> {
|
||||
|
@ -136,17 +136,17 @@ impl<'a, C: FontCollection> shape::partition::Selector for FontSelector<'a, C> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SelectedFont<F: FontInstance> {
|
||||
pub struct SelectedFont<F: FontHandle> {
|
||||
pub font: F,
|
||||
}
|
||||
|
||||
impl<F: FontInstance> PartialEq for SelectedFont<F> {
|
||||
impl<F: FontHandle> PartialEq for SelectedFont<F> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.font == other.font
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FontInstance> shape::partition::SelectedFont for SelectedFont<F> {
|
||||
impl<F: FontHandle> shape::partition::SelectedFont for SelectedFont<F> {
|
||||
fn font(&self) -> FontRef {
|
||||
self.font.as_font_ref()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue