mirror of
https://github.com/penpot/penpot.git
synced 2025-12-12 06:24:17 +01:00
🔧 Rename textleafs and inlines to keep coherence between render and editor
This commit is contained in:
@@ -33,8 +33,8 @@ pub fn stroke_paragraph_builder_group_from_text(
|
||||
let mut stroke_paragraphs_map: std::collections::HashMap<usize, ParagraphBuilder> =
|
||||
std::collections::HashMap::new();
|
||||
|
||||
for leaf in paragraph.children().iter() {
|
||||
let text_paint: skia_safe::Handle<_> = merge_fills(leaf.fills(), *bounds);
|
||||
for span in paragraph.children().iter() {
|
||||
let text_paint: skia_safe::Handle<_> = merge_fills(span.fills(), *bounds);
|
||||
let stroke_paints = get_text_stroke_paints(
|
||||
stroke,
|
||||
bounds,
|
||||
@@ -43,7 +43,7 @@ pub fn stroke_paragraph_builder_group_from_text(
|
||||
remove_stroke_alpha,
|
||||
);
|
||||
|
||||
let text: String = leaf.apply_text_transform();
|
||||
let text: String = span.apply_text_transform();
|
||||
|
||||
for (paint_idx, stroke_paint) in stroke_paints.iter().enumerate() {
|
||||
let builder = stroke_paragraphs_map.entry(paint_idx).or_insert_with(|| {
|
||||
@@ -51,9 +51,9 @@ pub fn stroke_paragraph_builder_group_from_text(
|
||||
ParagraphBuilder::new(¶graph_style, fonts)
|
||||
});
|
||||
let stroke_paint = stroke_paint.clone();
|
||||
let remove_alpha = use_shadow.unwrap_or(false) && !leaf.is_transparent();
|
||||
let remove_alpha = use_shadow.unwrap_or(false) && !span.is_transparent();
|
||||
let stroke_style =
|
||||
leaf.to_stroke_style(&stroke_paint, fallback_fonts, remove_alpha);
|
||||
span.to_stroke_style(&stroke_paint, fallback_fonts, remove_alpha);
|
||||
builder.push_style(&stroke_style);
|
||||
builder.add_text(&text);
|
||||
}
|
||||
@@ -342,7 +342,7 @@ fn render_text_decoration(
|
||||
let (max_underline_thickness, underline_y, max_strike_thickness, strike_y) =
|
||||
calculate_decoration_metrics(&style_metrics, line_baseline);
|
||||
|
||||
// Draw decorations per segment (text leaf)
|
||||
// Draw decorations per segment (text span)
|
||||
for (i, (style_start, style_metric)) in style_metrics.iter().enumerate() {
|
||||
let text_style = &style_metric.text_style;
|
||||
let style_end = style_metrics
|
||||
|
||||
@@ -98,7 +98,7 @@ impl TextContentSize {
|
||||
pub struct TextPositionWithAffinity {
|
||||
pub position_with_affinity: PositionWithAffinity,
|
||||
pub paragraph: i32,
|
||||
pub leaf: i32,
|
||||
pub span: i32,
|
||||
pub offset: i32,
|
||||
}
|
||||
|
||||
@@ -106,13 +106,13 @@ impl TextPositionWithAffinity {
|
||||
pub fn new(
|
||||
position_with_affinity: PositionWithAffinity,
|
||||
paragraph: i32,
|
||||
leaf: i32,
|
||||
span: i32,
|
||||
offset: i32,
|
||||
) -> Self {
|
||||
Self {
|
||||
position_with_affinity,
|
||||
paragraph,
|
||||
leaf,
|
||||
span,
|
||||
offset,
|
||||
}
|
||||
}
|
||||
@@ -289,7 +289,7 @@ impl TextContent {
|
||||
let layout_paragraphs = self.layout.paragraphs.iter().flatten();
|
||||
|
||||
let mut paragraph_index: i32 = -1;
|
||||
let mut leaf_index: i32 = -1;
|
||||
let mut span_index: i32 = -1;
|
||||
for layout_paragraph in layout_paragraphs {
|
||||
paragraph_index += 1;
|
||||
let start_y = offset_y;
|
||||
@@ -303,17 +303,17 @@ impl TextContent {
|
||||
if let Some(paragraph) = self.paragraphs().get(paragraph_index as usize) {
|
||||
// Computed position keeps the current position in terms
|
||||
// of number of characters of text. This is used to know
|
||||
// in which leaf we are.
|
||||
// in which span we are.
|
||||
let mut computed_position = 0;
|
||||
let mut leaf_offset = 0;
|
||||
for leaf in paragraph.children() {
|
||||
leaf_index += 1;
|
||||
let length = leaf.text.len();
|
||||
let mut span_offset = 0;
|
||||
for span in paragraph.children() {
|
||||
span_index += 1;
|
||||
let length = span.text.len();
|
||||
let start_position = computed_position;
|
||||
let end_position = computed_position + length;
|
||||
let current_position = position_with_affinity.position as usize;
|
||||
if start_position <= current_position && end_position >= current_position {
|
||||
leaf_offset = position_with_affinity.position - start_position as i32;
|
||||
span_offset = position_with_affinity.position - start_position as i32;
|
||||
break;
|
||||
}
|
||||
computed_position += length;
|
||||
@@ -321,8 +321,8 @@ impl TextContent {
|
||||
return Some(TextPositionWithAffinity::new(
|
||||
position_with_affinity,
|
||||
paragraph_index,
|
||||
leaf_index,
|
||||
leaf_offset,
|
||||
span_index,
|
||||
span_offset,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -344,10 +344,10 @@ impl TextContent {
|
||||
for paragraph in self.paragraphs() {
|
||||
let paragraph_style = paragraph.paragraph_to_style();
|
||||
let mut builder = ParagraphBuilder::new(¶graph_style, fonts);
|
||||
for leaf in paragraph.children() {
|
||||
let remove_alpha = use_shadow.unwrap_or(false) && !leaf.is_transparent();
|
||||
let text_style = leaf.to_style(&self.bounds(), fallback_fonts, remove_alpha);
|
||||
let text = leaf.apply_text_transform();
|
||||
for span in paragraph.children() {
|
||||
let remove_alpha = use_shadow.unwrap_or(false) && !span.is_transparent();
|
||||
let text_style = span.to_style(&self.bounds(), fallback_fonts, remove_alpha);
|
||||
let text = span.apply_text_transform();
|
||||
builder.push_style(&text_style);
|
||||
builder.add_text(&text);
|
||||
}
|
||||
@@ -519,7 +519,7 @@ pub struct Paragraph {
|
||||
letter_spacing: f32,
|
||||
typography_ref_file: Uuid,
|
||||
typography_ref_id: Uuid,
|
||||
children: Vec<TextLeaf>,
|
||||
children: Vec<TextSpan>,
|
||||
}
|
||||
|
||||
impl Default for Paragraph {
|
||||
@@ -549,7 +549,7 @@ impl Paragraph {
|
||||
letter_spacing: f32,
|
||||
typography_ref_file: Uuid,
|
||||
typography_ref_id: Uuid,
|
||||
children: Vec<TextLeaf>,
|
||||
children: Vec<TextSpan>,
|
||||
) -> Self {
|
||||
Self {
|
||||
text_align,
|
||||
@@ -565,17 +565,17 @@ impl Paragraph {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn set_children(&mut self, children: Vec<TextLeaf>) {
|
||||
fn set_children(&mut self, children: Vec<TextSpan>) {
|
||||
self.children = children;
|
||||
}
|
||||
|
||||
pub fn children(&self) -> &[TextLeaf] {
|
||||
pub fn children(&self) -> &[TextSpan] {
|
||||
&self.children
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn add_leaf(&mut self, leaf: TextLeaf) {
|
||||
self.children.push(leaf);
|
||||
fn add_span(&mut self, span: TextSpan) {
|
||||
self.children.push(span);
|
||||
}
|
||||
|
||||
// FIXME: move serialization to wasm module
|
||||
@@ -622,7 +622,7 @@ impl Paragraph {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TextLeaf {
|
||||
pub struct TextSpan {
|
||||
text: String,
|
||||
font_family: FontFamily,
|
||||
font_size: f32,
|
||||
@@ -635,7 +635,7 @@ pub struct TextLeaf {
|
||||
fills: Vec<shapes::Fill>,
|
||||
}
|
||||
|
||||
impl TextLeaf {
|
||||
impl TextSpan {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
text: String,
|
||||
|
||||
@@ -37,7 +37,7 @@ impl TextPaths {
|
||||
let start = line_metrics.start_index;
|
||||
let end = line_metrics.end_index;
|
||||
|
||||
// 3. Get styles present in line for each text leaf
|
||||
// 3. Get styles present in line for each text span
|
||||
let style_metrics = line_metrics.get_style_metrics(start..end);
|
||||
|
||||
let mut offset_x = 0.0;
|
||||
@@ -56,23 +56,23 @@ impl TextPaths {
|
||||
.map(|(i, _)| i)
|
||||
.unwrap_or(text.len());
|
||||
|
||||
let leaf_text = &text[start_byte..end_byte];
|
||||
let span_text = &text[start_byte..end_byte];
|
||||
|
||||
let font = skia_paragraph.get_font_at(*start_index);
|
||||
|
||||
let blob_offset_x = self.bounds.x() + line_metrics.left as f32 + offset_x;
|
||||
let blob_offset_y = line_offset_y;
|
||||
|
||||
// 4. Get the path for each text leaf
|
||||
// 4. Get the path for each text span
|
||||
if let Some((text_path, paint)) = self.generate_text_path(
|
||||
leaf_text,
|
||||
span_text,
|
||||
&font,
|
||||
blob_offset_x,
|
||||
blob_offset_y,
|
||||
style_metric,
|
||||
antialias,
|
||||
) {
|
||||
let text_width = font.measure_text(leaf_text, None).0;
|
||||
let text_width = font.measure_text(span_text, None).0;
|
||||
offset_x += text_width;
|
||||
paths.push((text_path, paint));
|
||||
}
|
||||
@@ -87,7 +87,7 @@ impl TextPaths {
|
||||
|
||||
fn generate_text_path(
|
||||
&self,
|
||||
leaf_text: &str,
|
||||
span_text: &str,
|
||||
font: &skia::Font,
|
||||
blob_offset_x: f32,
|
||||
blob_offset_y: f32,
|
||||
@@ -99,10 +99,10 @@ impl TextPaths {
|
||||
// This is used to avoid rendering empty paths, but we can
|
||||
// revisit this logic later
|
||||
if let Some((text_blob_path, text_blob_bounds)) =
|
||||
Self::get_text_blob_path(leaf_text, font, blob_offset_x, blob_offset_y)
|
||||
Self::get_text_blob_path(span_text, font, blob_offset_x, blob_offset_y)
|
||||
{
|
||||
let mut text_path = text_blob_path.clone();
|
||||
let text_width = font.measure_text(leaf_text, None).0;
|
||||
let text_width = font.measure_text(span_text, None).0;
|
||||
|
||||
let decoration = style_metric.text_style.decoration();
|
||||
let font_metrics = style_metric.font_metrics;
|
||||
@@ -165,13 +165,13 @@ impl TextPaths {
|
||||
}
|
||||
|
||||
fn get_text_blob_path(
|
||||
leaf_text: &str,
|
||||
span_text: &str,
|
||||
font: &skia::Font,
|
||||
blob_offset_x: f32,
|
||||
blob_offset_y: f32,
|
||||
) -> Option<(skia::Path, skia::Rect)> {
|
||||
with_state_mut!(state, {
|
||||
let utf16_text = leaf_text.encode_utf16().collect::<Vec<u16>>();
|
||||
let utf16_text = span_text.encode_utf16().collect::<Vec<u16>>();
|
||||
let text = unsafe { skia_safe::as_utf16_unchecked(&utf16_text) };
|
||||
let emoji_font = state.render_state.fonts().get_emoji_font(font.size());
|
||||
let use_font = emoji_font.as_ref().unwrap_or(font);
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
use crate::shapes::TextPositionWithAffinity;
|
||||
|
||||
/// TODO: Now this is just a tuple with 2 i32 working
|
||||
/// as indices (paragraph and leaf).
|
||||
/// as indices (paragraph and span).
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub struct TextNodePosition {
|
||||
pub paragraph: i32,
|
||||
pub leaf: i32,
|
||||
pub span: i32,
|
||||
}
|
||||
|
||||
impl TextNodePosition {
|
||||
pub fn new(paragraph: i32, leaf: i32) -> Self {
|
||||
Self { paragraph, leaf }
|
||||
pub fn new(paragraph: i32, span: i32) -> Self {
|
||||
Self { paragraph, span }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn is_invalid(&self) -> bool {
|
||||
self.paragraph < 0 || self.leaf < 0
|
||||
self.paragraph < 0 || self.span < 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ impl TextEditorState {
|
||||
self.selection.set(
|
||||
Some(TextNodePosition::new(
|
||||
text_position_with_affinity.paragraph,
|
||||
text_position_with_affinity.leaf,
|
||||
text_position_with_affinity.span,
|
||||
)),
|
||||
text_position_with_affinity.offset,
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::shapes::{
|
||||
use crate::utils::{uuid_from_u32, uuid_from_u32_quartet};
|
||||
use crate::{with_current_shape_mut, with_state_mut, with_state_mut_current_shape, STATE};
|
||||
|
||||
const RAW_LEAF_DATA_SIZE: usize = std::mem::size_of::<RawTextLeaf>();
|
||||
const RAW_SPAN_DATA_SIZE: usize = std::mem::size_of::<RawTextSpan>();
|
||||
const RAW_PARAGRAPH_DATA_SIZE: usize = std::mem::size_of::<RawParagraphData>();
|
||||
|
||||
const MAX_TEXT_FILLS: usize = 8;
|
||||
@@ -94,7 +94,7 @@ impl From<RawTextTransform> for Option<TextTransform> {
|
||||
#[repr(align(4))]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RawParagraphData {
|
||||
leaf_count: u32,
|
||||
span_count: u32,
|
||||
text_align: RawTextAlign,
|
||||
text_direction: RawTextDirection,
|
||||
text_decoration: RawTextDecoration,
|
||||
@@ -124,7 +124,7 @@ impl TryFrom<&[u8]> for RawParagraphData {
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct RawTextLeaf {
|
||||
pub struct RawTextSpan {
|
||||
font_style: RawFontStyle,
|
||||
text_decoration: RawTextDecoration,
|
||||
text_transform: RawTextTransform,
|
||||
@@ -140,25 +140,25 @@ pub struct RawTextLeaf {
|
||||
fills: [RawFillData; MAX_TEXT_FILLS],
|
||||
}
|
||||
|
||||
impl From<[u8; RAW_LEAF_DATA_SIZE]> for RawTextLeaf {
|
||||
fn from(bytes: [u8; RAW_LEAF_DATA_SIZE]) -> Self {
|
||||
impl From<[u8; RAW_SPAN_DATA_SIZE]> for RawTextSpan {
|
||||
fn from(bytes: [u8; RAW_SPAN_DATA_SIZE]) -> Self {
|
||||
unsafe { std::mem::transmute(bytes) }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for RawTextLeaf {
|
||||
impl TryFrom<&[u8]> for RawTextSpan {
|
||||
type Error = String;
|
||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let data: [u8; RAW_LEAF_DATA_SIZE] = bytes
|
||||
.get(0..RAW_LEAF_DATA_SIZE)
|
||||
let data: [u8; RAW_SPAN_DATA_SIZE] = bytes
|
||||
.get(0..RAW_SPAN_DATA_SIZE)
|
||||
.and_then(|slice| slice.try_into().ok())
|
||||
.ok_or("Invalid text leaf data".to_string())?;
|
||||
Ok(RawTextLeaf::from(data))
|
||||
.ok_or("Invalid text span data".to_string())?;
|
||||
Ok(RawTextSpan::from(data))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawTextLeaf> for shapes::TextLeaf {
|
||||
fn from(value: RawTextLeaf) -> Self {
|
||||
impl From<RawTextSpan> for shapes::TextSpan {
|
||||
fn from(value: RawTextSpan) -> Self {
|
||||
let text = String::default();
|
||||
|
||||
let font_family = shapes::FontFamily::new(
|
||||
@@ -193,7 +193,7 @@ impl From<RawTextLeaf> for shapes::TextLeaf {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RawParagraph {
|
||||
attrs: RawParagraphData,
|
||||
leaves: Vec<RawTextLeaf>,
|
||||
leaves: Vec<RawTextSpan>,
|
||||
text_buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -204,12 +204,12 @@ impl TryFrom<&Vec<u8>> for RawParagraph {
|
||||
fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
|
||||
let attrs = RawParagraphData::try_from(&bytes[..RAW_PARAGRAPH_DATA_SIZE])?;
|
||||
let mut offset = RAW_PARAGRAPH_DATA_SIZE;
|
||||
let mut raw_text_leaves: Vec<RawTextLeaf> = Vec::new();
|
||||
let mut raw_text_leaves: Vec<RawTextSpan> = Vec::new();
|
||||
|
||||
for _ in 0..attrs.leaf_count {
|
||||
let text_leaf = RawTextLeaf::try_from(&bytes[offset..(offset + RAW_LEAF_DATA_SIZE)])?;
|
||||
offset += RAW_LEAF_DATA_SIZE;
|
||||
raw_text_leaves.push(text_leaf);
|
||||
for _ in 0..attrs.span_count {
|
||||
let text_span = RawTextSpan::try_from(&bytes[offset..(offset + RAW_SPAN_DATA_SIZE)])?;
|
||||
offset += RAW_SPAN_DATA_SIZE;
|
||||
raw_text_leaves.push(text_span);
|
||||
}
|
||||
|
||||
let text_buffer = &bytes[offset..];
|
||||
@@ -230,16 +230,16 @@ impl From<RawParagraph> for shapes::Paragraph {
|
||||
let mut leaves = vec![];
|
||||
|
||||
let mut offset = 0;
|
||||
for raw_leaf in value.leaves.into_iter() {
|
||||
let delta = raw_leaf.text_length as usize;
|
||||
for raw_span in value.leaves.into_iter() {
|
||||
let delta = raw_span.text_length as usize;
|
||||
let text_buffer = &value.text_buffer[offset..offset + delta];
|
||||
|
||||
let mut leaf = shapes::TextLeaf::from(raw_leaf);
|
||||
let mut span = shapes::TextSpan::from(raw_span);
|
||||
if !text_buffer.is_empty() {
|
||||
leaf.set_text(String::from_utf8_lossy(text_buffer).to_string());
|
||||
span.set_text(String::from_utf8_lossy(text_buffer).to_string());
|
||||
}
|
||||
|
||||
leaves.push(leaf);
|
||||
leaves.push(span);
|
||||
offset += delta;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user