mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
🐛 Fix problem with selection and text shapes for new render
This commit is contained in:
@@ -6,13 +6,16 @@ use crate::{
|
||||
|
||||
use core::f32;
|
||||
use macros::ToJs;
|
||||
use skia_safe::textlayout::{RectHeightStyle, RectWidthStyle};
|
||||
use skia_safe::{
|
||||
self as skia,
|
||||
paint::{self, Paint},
|
||||
textlayout::ParagraphBuilder,
|
||||
textlayout::ParagraphStyle,
|
||||
textlayout::PositionWithAffinity,
|
||||
Contains,
|
||||
};
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::FontFamily;
|
||||
@@ -182,6 +185,24 @@ impl TextContentLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the current x,y (in paragraph relative coordinates) is inside
|
||||
* the paragraph
|
||||
*/
|
||||
fn intersects(paragraph: &skia_safe::textlayout::Paragraph, x: f32, y: f32) -> bool {
|
||||
if y < 0.0 || y > paragraph.height() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let pos = paragraph.get_glyph_position_at_coordinate((x, y));
|
||||
let idx = pos.position as usize;
|
||||
|
||||
let rects =
|
||||
paragraph.get_rects_for_range(0..idx + 1, RectHeightStyle::Tight, RectWidthStyle::Tight);
|
||||
|
||||
rects.iter().any(|r| r.rect.contains(&Point::new(x, y)))
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TextContent {
|
||||
pub paragraphs: Vec<Paragraph>,
|
||||
@@ -304,6 +325,32 @@ impl TextContent {
|
||||
bounds
|
||||
}
|
||||
|
||||
pub fn content_rect(&self, selrect: &Rect, valign: VerticalAlign) -> Rect {
|
||||
let x = selrect.x();
|
||||
let mut y = selrect.y();
|
||||
|
||||
let width = if self.grow_type() == GrowType::AutoWidth {
|
||||
self.size.width
|
||||
} else {
|
||||
selrect.width()
|
||||
};
|
||||
|
||||
let height = if self.size.width.round() != width.round() {
|
||||
self.get_height(width)
|
||||
} else {
|
||||
self.size.height
|
||||
};
|
||||
|
||||
let offset_y = match valign {
|
||||
VerticalAlign::Center => (selrect.height() - height) / 2.0,
|
||||
VerticalAlign::Bottom => selrect.height() - height,
|
||||
_ => 0.0,
|
||||
};
|
||||
y += offset_y;
|
||||
|
||||
Rect::from_xywh(x, y, width, height)
|
||||
}
|
||||
|
||||
pub fn transform(&mut self, transform: &Matrix) {
|
||||
let left = self.bounds.left();
|
||||
let right = self.bounds.right();
|
||||
@@ -645,6 +692,42 @@ impl TextContent {
|
||||
|
||||
(fallback_width, fallback_height)
|
||||
}
|
||||
|
||||
pub fn intersect_position(&self, shape: &Shape, x_pos: f32, y_pos: f32) -> bool {
|
||||
let rect = self.content_rect(&shape.selrect, shape.vertical_align);
|
||||
let mut matrix = Matrix::new_identity();
|
||||
let center = shape.center();
|
||||
let Some(inv_transform) = &shape.transform.invert() else {
|
||||
return false;
|
||||
};
|
||||
matrix.pre_translate(center);
|
||||
matrix.pre_concat(inv_transform);
|
||||
matrix.pre_translate(-center);
|
||||
|
||||
let result = matrix.map_point((x_pos, y_pos));
|
||||
|
||||
// Change coords to content space
|
||||
let x_pos = result.x - rect.x();
|
||||
let y_pos = result.y - rect.y();
|
||||
|
||||
let width = self.width();
|
||||
let mut paragraph_builders = self.paragraph_builder_group_from_text(None);
|
||||
let paragraphs =
|
||||
self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
|
||||
|
||||
paragraphs
|
||||
.iter()
|
||||
.flatten()
|
||||
.scan(
|
||||
(0 as f32, None::<skia::textlayout::Paragraph>),
|
||||
|(height, _), p| {
|
||||
let prev_height = *height;
|
||||
*height += p.height();
|
||||
Some((prev_height, p))
|
||||
},
|
||||
)
|
||||
.any(|(height, p)| intersects(p, x_pos, y_pos - height))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TextContent {
|
||||
|
||||
@@ -7,7 +7,9 @@ use crate::shapes::{
|
||||
self, GrowType, Shape, TextAlign, TextDecoration, TextDirection, TextTransform, Type,
|
||||
};
|
||||
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};
|
||||
use crate::{
|
||||
with_current_shape_mut, with_state, with_state_mut, with_state_mut_current_shape, STATE,
|
||||
};
|
||||
|
||||
const RAW_SPAN_DATA_SIZE: usize = std::mem::size_of::<RawTextSpan>();
|
||||
const RAW_PARAGRAPH_DATA_SIZE: usize = std::mem::size_of::<RawParagraphData>();
|
||||
@@ -312,14 +314,23 @@ pub extern "C" fn set_shape_grow_type(grow_type: u8) {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_text_dimensions() -> *mut u8 {
|
||||
let mut ptr = std::ptr::null_mut();
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
if let Type::Text(content) = &mut shape.shape_type {
|
||||
let text_content_size = content.update_layout(shape.selrect);
|
||||
|
||||
let mut bytes = vec![0; 12];
|
||||
// Sacar de aqui x, y, width, height
|
||||
let rect = content.content_rect(&shape.selrect, shape.vertical_align);
|
||||
|
||||
let mut bytes = vec![0; 20];
|
||||
bytes[0..4].clone_from_slice(&text_content_size.width.to_le_bytes());
|
||||
bytes[4..8].clone_from_slice(&text_content_size.height.to_le_bytes());
|
||||
bytes[8..12].clone_from_slice(&text_content_size.max_width.to_le_bytes());
|
||||
|
||||
// veamos
|
||||
bytes[12..16].clone_from_slice(&rect.x().to_le_bytes());
|
||||
bytes[16..20].clone_from_slice(&rect.y().to_le_bytes());
|
||||
|
||||
ptr = mem::write_bytes(bytes)
|
||||
}
|
||||
});
|
||||
@@ -329,6 +340,27 @@ pub extern "C" fn get_text_dimensions() -> *mut u8 {
|
||||
ptr
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn intersect_position(
|
||||
a: u32,
|
||||
b: u32,
|
||||
c: u32,
|
||||
d: u32,
|
||||
x_pos: f32,
|
||||
y_pos: f32,
|
||||
) -> bool {
|
||||
with_state!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
let Some(shape) = state.shapes.get(&id) else {
|
||||
return false;
|
||||
};
|
||||
if let Type::Text(content) = &shape.shape_type {
|
||||
return content.intersect_position(shape, x_pos, y_pos);
|
||||
}
|
||||
});
|
||||
false
|
||||
}
|
||||
|
||||
fn update_text_layout(shape: &mut Shape) {
|
||||
if let Type::Text(text_content) = &mut shape.shape_type {
|
||||
text_content.update_layout(shape.selrect);
|
||||
|
||||
Reference in New Issue
Block a user