-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
593 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
// Copyright 2021 the Parley Authors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! Context for layout. | ||
|
||
use super::context::*; | ||
use super::style::*; | ||
use super::FontContext; | ||
|
||
#[cfg(feature = "std")] | ||
use super::layout::Layout; | ||
|
||
use core::ops::RangeBounds; | ||
|
||
use crate::inline_box::InlineBox; | ||
|
||
/// Builder for constructing a text layout with ranged attributes. | ||
pub struct RangedBuilder<'a, B: Brush> { | ||
pub(crate) scale: f32, | ||
pub(crate) lcx: &'a mut LayoutContext<B>, | ||
pub(crate) fcx: &'a mut FontContext, | ||
} | ||
|
||
impl<'a, B: Brush> RangedBuilder<'a, B> { | ||
pub fn push_default(&mut self, property: &StyleProperty<B>) { | ||
let resolved = self | ||
.lcx | ||
.rcx | ||
.resolve_property(self.fcx, property, self.scale); | ||
self.lcx.ranged_style_builder.push_default(resolved); | ||
} | ||
|
||
pub fn push(&mut self, property: &StyleProperty<B>, range: impl RangeBounds<usize>) { | ||
let resolved = self | ||
.lcx | ||
.rcx | ||
.resolve_property(self.fcx, property, self.scale); | ||
self.lcx.ranged_style_builder.push(resolved, range); | ||
} | ||
|
||
pub fn push_inline_box(&mut self, inline_box: InlineBox) { | ||
self.lcx.inline_boxes.push(inline_box); | ||
} | ||
|
||
#[cfg(feature = "std")] | ||
pub fn build_into(&mut self, layout: &mut Layout<B>, text: impl AsRef<str>) { | ||
// Apply RangedStyleBuilder styles to LayoutContext | ||
self.lcx.ranged_style_builder.finish(&mut self.lcx.styles); | ||
|
||
// Call generic layout builder method | ||
build_into_layout(layout, self.scale, text.as_ref(), self.lcx, self.fcx); | ||
} | ||
|
||
#[cfg(feature = "std")] | ||
pub fn build(&mut self, text: impl AsRef<str>) -> Layout<B> { | ||
let mut layout = Layout::default(); | ||
self.build_into(&mut layout, text); | ||
layout | ||
} | ||
} | ||
|
||
/// Builder for constructing a text layout with a tree of attributes. | ||
pub struct TreeBuilder<'a, B: Brush> { | ||
pub(crate) scale: f32, | ||
pub(crate) lcx: &'a mut LayoutContext<B>, | ||
pub(crate) fcx: &'a mut FontContext, | ||
} | ||
|
||
impl<'a, B: Brush> TreeBuilder<'a, 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); | ||
} | ||
|
||
pub fn push_style_modification_span<'s, 'iter>( | ||
&mut self, | ||
properties: impl IntoIterator<Item = &'iter StyleProperty<'s, B>>, | ||
) where | ||
'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)), | ||
); | ||
} | ||
|
||
pub fn pop_style_span(&mut self) { | ||
self.lcx.tree_style_builder.pop_style_span(); | ||
} | ||
|
||
pub fn push_text(&mut self, text: &str) { | ||
self.lcx.tree_style_builder.push_text(text); | ||
} | ||
|
||
pub fn push_inline_box(&mut self, mut inline_box: InlineBox) { | ||
self.lcx.tree_style_builder.push_uncommitted_text(false); | ||
// TODO: arrange type better here to factor out the index | ||
inline_box.index = self.lcx.tree_style_builder.current_text_len(); | ||
self.lcx.inline_boxes.push(inline_box); | ||
} | ||
|
||
pub fn set_white_space_mode(&mut self, white_space_collapse: WhiteSpaceCollapse) { | ||
self.lcx | ||
.tree_style_builder | ||
.set_white_space_mode(white_space_collapse); | ||
} | ||
|
||
#[cfg(feature = "std")] | ||
pub fn build_into(&mut self, layout: &mut Layout<B>) -> String { | ||
// Apply TreeStyleBuilder styles to LayoutContext | ||
let text = self.lcx.tree_style_builder.finish(&mut self.lcx.styles); | ||
|
||
self.lcx.analyze_text(&text); | ||
|
||
// Call generic layout builder method | ||
build_into_layout(layout, self.scale, &text, self.lcx, self.fcx); | ||
|
||
text | ||
} | ||
|
||
#[cfg(feature = "std")] | ||
pub fn build(&mut self) -> (Layout<B>, String) { | ||
let mut layout = Layout::default(); | ||
let text = self.build_into(&mut layout); | ||
(layout, text) | ||
} | ||
} | ||
|
||
#[cfg(feature = "std")] | ||
fn build_into_layout<B: Brush>( | ||
layout: &mut Layout<B>, | ||
scale: f32, | ||
text: &str, | ||
lcx: &mut LayoutContext<B>, | ||
fcx: &mut FontContext, | ||
) { | ||
layout.data.clear(); | ||
layout.data.scale = scale; | ||
layout.data.has_bidi = !lcx.bidi.levels().is_empty(); | ||
layout.data.base_level = lcx.bidi.base_level(); | ||
layout.data.text_len = text.len(); | ||
|
||
// println!("BUILD INTO ({})", text.len()); | ||
// for span in &lcx.styles { | ||
// let stack = lcx.rcx.stack(span.style.font_stack); | ||
// println!( | ||
// "{:?} weight:{}, family: {:?}", | ||
// span.range, span.style.font_weight, stack | ||
// ); | ||
// } | ||
|
||
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); | ||
|
||
// dbg!(&lcx.inline_boxes); | ||
|
||
{ | ||
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(); | ||
} |
Oops, something went wrong.