Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 14 additions & 74 deletions parley/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use super::style::{Brush, StyleProperty, TextStyle, WhiteSpaceCollapse};
use super::layout::Layout;

use alloc::string::String;
use alloc::vec::Vec;
use core::ops::RangeBounds;

use crate::inline_box::InlineBox;
Expand All @@ -28,7 +29,6 @@ impl<B: Brush> RangedBuilder<'_, B> {
pub fn push_default<'a>(&mut self, property: impl Into<StyleProperty<'a, B>>) {
let resolved = self
.lcx
.rcx
.resolve_property(self.fcx, &property.into(), self.scale);
self.lcx.ranged_style_builder.push_default(resolved);
}
Expand All @@ -40,7 +40,6 @@ impl<B: Brush> RangedBuilder<'_, B> {
) {
let resolved = self
.lcx
.rcx
.resolve_property(self.fcx, &property.into(), self.scale);
self.lcx.ranged_style_builder.push(resolved, range);
}
Expand All @@ -54,14 +53,8 @@ impl<B: Brush> RangedBuilder<'_, B> {
self.lcx.ranged_style_builder.finish(&mut self.lcx.styles);

// Call generic layout builder method
build_into_layout(
layout,
self.scale,
self.quantize,
text.as_ref(),
self.lcx,
self.fcx,
);
self.lcx
.build_into_layout(layout, self.scale, self.quantize, text.as_ref(), self.fcx);
}

pub fn build(self, text: impl AsRef<str>) -> Layout<B> {
Expand All @@ -84,7 +77,6 @@ impl<B: Brush> TreeBuilder<'_, B> {
pub fn push_style_span(&mut self, style: TextStyle<'_, B>) {
let resolved = self
.lcx
.rcx
.resolve_entire_style_set(self.fcx, &style, self.scale);
self.lcx.tree_style_builder.push_style_span(resolved);
}
Expand All @@ -96,11 +88,15 @@ impl<B: Brush> TreeBuilder<'_, B> {
's: 'iter,
B: 'iter,
{
self.lcx.tree_style_builder.push_style_modification_span(
properties
.into_iter()
.map(|p| self.lcx.rcx.resolve_property(self.fcx, p, self.scale)),
);
// FIXME: eliminate allocation if/when the "style builders" are extracted
// from the LayoutContext
let resolved_properties: Vec<_> = properties
.into_iter()
.map(|p| self.lcx.resolve_property(self.fcx, p, self.scale))
.collect();
self.lcx
.tree_style_builder
.push_style_modification_span(resolved_properties.into_iter());
}

pub fn pop_style_span(&mut self) {
Expand Down Expand Up @@ -134,7 +130,8 @@ impl<B: Brush> TreeBuilder<'_, B> {
let text = self.lcx.tree_style_builder.finish(&mut self.lcx.styles);

// Call generic layout builder method
build_into_layout(layout, self.scale, self.quantize, &text, self.lcx, self.fcx);
self.lcx
.build_into_layout(layout, self.scale, self.quantize, &text, self.fcx);

text
}
Expand All @@ -146,60 +143,3 @@ impl<B: Brush> TreeBuilder<'_, B> {
(layout, text)
}
}

fn build_into_layout<B: Brush>(
layout: &mut Layout<B>,
scale: f32,
quantize: bool,
text: &str,
lcx: &mut LayoutContext<B>,
fcx: &mut FontContext,
) {
lcx.analyze_text(text);

layout.data.clear();
layout.data.scale = scale;
layout.data.quantize = quantize;
layout.data.has_bidi = !lcx.bidi.levels().is_empty();
layout.data.base_level = lcx.bidi.base_level();
layout.data.text_len = text.len();

let mut char_index = 0;
for (i, style) in lcx.styles.iter().enumerate() {
for _ in text[style.range.clone()].chars() {
lcx.info[char_index].1 = i as u16;
char_index += 1;
}
}

// Copy the visual styles into the layout
layout
.data
.styles
.extend(lcx.styles.iter().map(|s| s.style.as_layout_style()));

// Sort the inline boxes as subsequent code assumes that they are in text index order.
// Note: It's important that this is a stable sort to allow users to control the order of contiguous inline boxes
lcx.inline_boxes.sort_by_key(|b| b.index);

{
let query = fcx.collection.query(&mut fcx.source_cache);
super::shape::shape_text(
&lcx.rcx,
query,
&lcx.styles,
&lcx.inline_boxes,
&lcx.info,
lcx.bidi.levels(),
&mut lcx.scx,
text,
layout,
);
}

// Move inline boxes into the layout
layout.data.inline_boxes.clear();
core::mem::swap(&mut layout.data.inline_boxes, &mut lcx.inline_boxes);

layout.data.finish();
}
94 changes: 90 additions & 4 deletions parley/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,28 @@ use super::style::{Brush, TextStyle};
use swash::shape::ShapeContext;
use swash::text::cluster::CharInfo;

use crate::Layout;
use crate::StyleProperty;
use crate::builder::TreeBuilder;
use crate::inline_box::InlineBox;
use crate::resolve::ResolvedProperty;

/// Shared scratch space used when constructing text layouts.
///
/// This type is designed to be a global resource with only one per-application (or per-thread).
pub struct LayoutContext<B: Brush = [u8; 4]> {
pub(crate) bidi: bidi::BidiResolver,
pub(crate) rcx: ResolveContext,
pub(crate) styles: Vec<RangedStyle<B>>,
pub(crate) inline_boxes: Vec<InlineBox>,

// Reusable style builders (to amortise allocations)
pub(crate) ranged_style_builder: RangedStyleBuilder<B>,
pub(crate) tree_style_builder: TreeStyleBuilder<B>,

pub(crate) info: Vec<(CharInfo, u16)>,
pub(crate) scx: ShapeContext,
// Internal contexts
bidi: bidi::BidiResolver,
rcx: ResolveContext,
scx: ShapeContext,
info: Vec<(CharInfo, u16)>,
}

impl<B: Brush> LayoutContext<B> {
Expand Down Expand Up @@ -179,6 +183,88 @@ impl<B: Brush> LayoutContext<B> {
}
}

pub(crate) fn resolve_property(
&mut self,
fcx: &mut FontContext,
property: &StyleProperty<'_, B>,
scale: f32,
) -> ResolvedProperty<B> {
self.rcx.resolve_property(fcx, property, scale)
}

pub(crate) fn resolve_entire_style_set(
&mut self,
fcx: &mut FontContext,
raw_style: &TextStyle<'_, B>,
scale: f32,
) -> ResolvedStyle<B> {
self.rcx.resolve_entire_style_set(fcx, raw_style, scale)
}

pub(crate) fn shape_into_layout(
&mut self,
fcx: &mut FontContext,
text: &str,
layout: &mut Layout<B>,
) {
let query = fcx.collection.query(&mut fcx.source_cache);
super::shape::shape_text(
&self.rcx,
query,
&self.styles,
&self.inline_boxes,
&self.info,
self.bidi.levels(),
&mut self.scx,
text,
layout,
);
}

pub(crate) fn build_into_layout(
&mut self,
layout: &mut Layout<B>,
scale: f32,
quantize: bool,
text: &str,
fcx: &mut FontContext,
) {
self.analyze_text(text);

layout.data.clear();
layout.data.scale = scale;
layout.data.quantize = quantize;
layout.data.has_bidi = !self.bidi.levels().is_empty();
layout.data.base_level = self.bidi.base_level();
layout.data.text_len = text.len();

let mut char_index = 0;
for (i, style) in self.styles.iter().enumerate() {
for _ in text[style.range.clone()].chars() {
self.info[char_index].1 = i as u16;
char_index += 1;
}
}

// Copy the visual styles into the layout
layout
.data
.styles
.extend(self.styles.iter().map(|s| s.style.as_layout_style()));

// Sort the inline boxes as subsequent code assumes that they are in text index order.
// Note: It's important that this is a stable sort to allow users to control the order of contiguous inline boxes
self.inline_boxes.sort_by_key(|b| b.index);

self.shape_into_layout(fcx, text, layout);

// Move inline boxes into the layout
layout.data.inline_boxes.clear();
core::mem::swap(&mut layout.data.inline_boxes, &mut self.inline_boxes);

layout.data.finish();
}

fn begin(&mut self) {
self.rcx.clear();
self.styles.clear();
Expand Down