Current section
Files
Jump to
Current section
Files
native/skia_native/src/generated_text.rs
// Generated by mix skia.codegen. Do not edit by hand.
fn draw_text_blob<'a>(canvas: &skia_safe::Canvas, command: Term<'a>) -> NifResult<()> {
let args = decode_args(command)?;
let opts = decode_opts(command)?;
let decoded_opts = generated_opts::decode_text_blob_opts(&opts)?;
draw_text_blob_impl(canvas, args, decoded_opts, &opts)
}
fn draw_text_blob_impl<'a>(
canvas: &skia_safe::Canvas,
args: Vec<Term<'a>>,
opts: generated_opts::TextBlobOpts<'a>,
raw_opts: &[(Atom, Term<'a>)],
) -> NifResult<()> {
let blob = text_blob_from_term(*args.first().ok_or(rustler::Error::BadArg)?)?;
let mut paint = match opts.fill {
Some(term) => decode_paint(term)?,
None => fill_paint(Color::BLACK),
};
apply_paint_effects(&mut paint, raw_opts)?;
canvas.draw_text_blob(blob, (opts.x, opts.y), &paint);
Ok(())
}
fn draw_text<'a>(canvas: &skia_safe::Canvas, command: Term<'a>) -> NifResult<()> {
let args = decode_args(command)?;
let opts = decode_opts(command)?;
let decoded_opts = generated_opts::decode_text_opts(&opts)?;
draw_text_impl(canvas, args, decoded_opts, &opts)
}
fn draw_text_impl<'a>(
canvas: &skia_safe::Canvas,
args: Vec<Term<'a>>,
opts: generated_opts::TextOpts<'a>,
_raw_opts: &[(Atom, Term<'a>)],
) -> NifResult<()> {
let text = args.first().ok_or(rustler::Error::BadArg)?.decode::<String>()?;
let size = opts.size.unwrap_or(16.0);
let mut font = match opts.font {
Some(term) => font_from_term(term, size)?,
None => Font::default(),
};
font.set_size(size);
let paint = match opts.fill {
Some(term) => fill_paint(decode_color(term)?),
None => fill_paint(Color::BLACK),
};
match opts.width {
Some(width) => {
draw_paragraph_text(
canvas,
&text,
opts.x,
opts.y,
width,
size,
&paint,
&opts,
)?;
}
None => {
canvas.draw_str(text, (opts.x, opts.y), &font, &paint);
}
};
Ok(())
}
fn draw_paragraph_text<'a>(
canvas: &skia_safe::Canvas,
text: &str,
x: f32,
y: f32,
width: f32,
size: f32,
paint: &Paint,
opts: &generated_opts::TextOpts<'a>,
) -> NifResult<()> {
let mut text_style = TextStyle::new();
text_style.set_font_size(size);
text_style.set_color(paint.color());
if let Some(term) = opts.font {
let font = font_from_term(term, size)?;
text_style.set_font_families(&vec![font.typeface().family_name()]);
text_style.set_typeface(font.typeface());
}
if let Some(family) = &opts.font_family {
text_style.set_font_families(&vec![family]);
}
if let Some(line_height) = opts.line_height {
text_style.set_height(line_height / size);
text_style.set_height_override(true);
}
if let Some(letter_spacing) = opts.letter_spacing {
text_style.set_letter_spacing(letter_spacing);
}
if let Some(decoration) = opts.decoration {
text_style.set_decoration_type(decode_text_decoration(decoration)?);
}
if let Some(style) = opts.decoration_style {
text_style.set_decoration_style(decode_text_decoration_style(style)?);
}
if let Some(mode) = opts.decoration_mode {
text_style.set_decoration_mode(decode_text_decoration_mode(mode)?);
}
if let Some(color) = opts.decoration_color {
text_style.set_decoration_color(decode_color(color)?);
}
let mut paragraph_style = ParagraphStyle::new();
paragraph_style.set_text_style(&text_style);
if let Some(align) = opts.align {
paragraph_style.set_text_align(decode_text_align(align)?);
}
if let Some(direction) = opts.direction {
paragraph_style.set_text_direction(decode_text_direction(direction)?);
}
if let Some(max_lines) = opts.max_lines {
paragraph_style.set_max_lines(max_lines);
}
if let Some(ellipsis) = &opts.ellipsis {
paragraph_style.set_ellipsis(ellipsis);
}
let mut font_collection = FontCollection::new();
let mut provider = TypefaceFontProvider::new();
if let Some(term) = opts.font {
let font = font_from_term(term, size)?;
provider.register_typeface(font.typeface(), None);
}
let spans = match opts.spans {
Some(spans_term) => {
Some(spans_term.decode::<Vec<(String, Vec<(Atom, Term<'a>)>)>>()?)
}
None => None,
};
if let Some(values) = &spans {
register_span_typefaces(&mut provider, values, size)?;
}
font_collection.set_asset_font_manager(Some(FontMgr::from(provider)));
font_collection.set_default_font_manager(FontMgr::default(), None);
let mut paragraph_builder = ParagraphBuilder::new(¶graph_style, font_collection);
match spans {
Some(values) => {
for (span_text, style_opts) in values {
let span_style = text_style_from_opts(&text_style, &style_opts)?;
paragraph_builder.push_style(&span_style);
paragraph_builder.add_text(span_text);
paragraph_builder.pop();
}
}
None => {
paragraph_builder.push_style(&text_style);
paragraph_builder.add_text(text);
paragraph_builder.pop();
}
};
let mut paragraph = paragraph_builder.build();
paragraph.layout(width);
let paint_y = match opts.height {
Some(height) => {
match opts.vertical_align {
Some(align) => paragraph_paint_y(y, height, paragraph.height(), align)?,
None => y,
}
}
None => y,
};
match opts.height {
Some(height) => {
canvas.save();
canvas
.clip_rect(
Rect::from_xywh(x, y, width, height),
ClipOp::Intersect,
true,
);
paragraph.paint(canvas, Point::new(x, paint_y));
canvas.restore();
}
None => {
paragraph.paint(canvas, Point::new(x, paint_y));
}
};
Ok(())
}
fn register_span_typefaces<'a>(
provider: &mut TypefaceFontProvider,
spans: &[(String, Vec<(Atom, Term<'a>)>)],
size: f32,
) -> NifResult<()> {
for (_span_text, style_opts) in spans {
if let Some(term) = opt_term(style_opts, atoms::font()) {
let font = font_from_term(term, size)?;
provider.register_typeface(font.typeface(), None);
}
}
Ok(())
}
fn text_style_from_opts<'a>(
base: &TextStyle,
opts: &[(Atom, Term<'a>)],
) -> NifResult<TextStyle> {
let mut style = base.clone();
if let Some(size) = opt_f32_option(opts, atoms::size())? {
style.set_font_size(size);
}
if let Some(fill) = opt_term(opts, atoms::fill()) {
style.set_color(decode_color(fill)?);
}
if let Some(term) = opt_term(opts, atoms::font()) {
let font = font_from_term(term, base.font_size())?;
style.set_font_families(&vec![font.typeface().family_name()]);
style.set_typeface(font.typeface());
}
if let Some(term) = opt_term(opts, atoms::font_family()) {
let family = term.decode::<String>()?;
style.set_font_families(&vec![family]);
}
if let Some(line_height) = opt_f32_option(opts, atoms::line_height())? {
let font_size = opt_f32_option(opts, atoms::size())?.unwrap_or(base.font_size());
style.set_height(line_height / font_size);
style.set_height_override(true);
}
if let Some(letter_spacing) = opt_f32_option(opts, atoms::letter_spacing())? {
style.set_letter_spacing(letter_spacing);
}
if let Some(term) = opt_term(opts, atoms::decoration()) {
let decoration = term.decode::<Atom>()?;
style.set_decoration_type(decode_text_decoration(decoration)?);
}
if let Some(term) = opt_term(opts, atoms::decoration_style()) {
let decoration_style = term.decode::<Atom>()?;
style.set_decoration_style(decode_text_decoration_style(decoration_style)?);
}
if let Some(term) = opt_term(opts, atoms::decoration_mode()) {
let decoration_mode = term.decode::<Atom>()?;
style.set_decoration_mode(decode_text_decoration_mode(decoration_mode)?);
}
if let Some(color) = opt_term(opts, atoms::decoration_color()) {
style.set_decoration_color(decode_color(color)?);
}
Ok(style)
}
fn paragraph_paint_y(
y: f32,
height: f32,
content_height: f32,
align: Atom,
) -> NifResult<f32> {
let remaining = (height - content_height).max(0.0);
match align {
value if value == atoms::top() => Ok(y),
value if value == atoms::center() => Ok(y + remaining / 2.0),
value if value == atoms::bottom() => Ok(y + remaining),
_ => Err(rustler::Error::BadArg),
}
}
fn decode_text_align(value: Atom) -> NifResult<TextAlign> {
match value {
value if value == atoms::center() => Ok(TextAlign::Center),
value if value == atoms::right() => Ok(TextAlign::Right),
value if value == atoms::justify() => Ok(TextAlign::Justify),
value if value == atoms::left() => Ok(TextAlign::Left),
_ => Err(rustler::Error::BadArg),
}
}
fn decode_text_decoration(value: Atom) -> NifResult<TextDecoration> {
match value {
atom if atom == atoms::none() => Ok(TextDecoration::NO_DECORATION),
atom if atom == atoms::underline() => Ok(TextDecoration::UNDERLINE),
atom if atom == atoms::line_through() => Ok(TextDecoration::LINE_THROUGH),
_ => Err(rustler::Error::BadArg),
}
}
fn decode_text_decoration_style(value: Atom) -> NifResult<TextDecorationStyle> {
match value {
value if value == atoms::solid() => Ok(TextDecorationStyle::Solid),
value if value == atoms::double() => Ok(TextDecorationStyle::Double),
value if value == atoms::dotted() => Ok(TextDecorationStyle::Dotted),
value if value == atoms::dashed() => Ok(TextDecorationStyle::Dashed),
value if value == atoms::wavy() => Ok(TextDecorationStyle::Wavy),
_ => Err(rustler::Error::BadArg),
}
}
fn decode_text_decoration_mode(value: Atom) -> NifResult<DecorationMode> {
match value {
value if value == atoms::gaps() => Ok(DecorationMode::default()),
value if value == atoms::through() => Ok(DecorationMode::Through),
_ => Err(rustler::Error::BadArg),
}
}
fn decode_text_direction(value: Atom) -> NifResult<TextDirection> {
match value {
value if value == atoms::rtl() => Ok(TextDirection::RTL),
value if value == atoms::ltr() => Ok(TextDirection::LTR),
_ => Err(rustler::Error::BadArg),
}
}