mirror of
https://github.com/penpot/penpot.git
synced 2026-09-03 18:49:45 +00:00
♻️ Clean unnecessary methods (#11472)
* ♻️ Remove duplicated/unused set-children code * ♻️ Remove unused methods
This commit is contained in:
parent
b9ddfc1596
commit
03e6f119e5
@ -17,7 +17,6 @@
|
||||
[app.common.math :as mth]
|
||||
[app.common.render-wasm.helpers :as h]
|
||||
[app.common.render-wasm.mem :as mem]
|
||||
[app.common.render-wasm.mem.heap32 :as mem.h32]
|
||||
[app.common.render-wasm.serializers :as sr]
|
||||
[app.common.render-wasm.serializers.color :as sr-clr]
|
||||
[app.common.render-wasm.wasm :as wasm]
|
||||
@ -27,22 +26,6 @@
|
||||
|
||||
(def ^:const MAX_BUFFER_CHUNK_SIZE (* 256 1024))
|
||||
|
||||
(def ^:const UUID-U8-SIZE 16)
|
||||
|
||||
(defn set-shape-children
|
||||
"Uploads the child id list via the dynamic `_set_children` path (handles any
|
||||
count). The browser also has fixed-arity fast paths for the incremental edit
|
||||
path; this dynamic one is the shared/batch version."
|
||||
[children]
|
||||
(let [children (into [] (filter uuid?) children)]
|
||||
(if (empty? children)
|
||||
(h/call wasm/internal-module "_set_children_0")
|
||||
(let [heap (mem/get-heap-u32)
|
||||
size (mem/get-alloc-size children UUID-U8-SIZE)
|
||||
offset (mem/alloc->offset-32 size)]
|
||||
(reduce (fn [o id] (mem.h32/write-uuid o heap id)) offset children)
|
||||
(h/call wasm/internal-module "_set_children")))))
|
||||
|
||||
(defn set-shape-bool-type
|
||||
[bool-type]
|
||||
(h/call wasm/internal-module "_set_shape_bool_type" (sr/translate-bool-type bool-type)))
|
||||
|
||||
@ -844,61 +844,8 @@
|
||||
[children]
|
||||
(perf/begin-measure "set-shape-children")
|
||||
(let [children (into [] (filter uuid?) children)]
|
||||
(case (count children)
|
||||
0
|
||||
(if (empty? children)
|
||||
(h/call wasm/internal-module "_set_children_0")
|
||||
|
||||
1
|
||||
(let [[c1] children
|
||||
c1 (uuid/get-u32 c1)]
|
||||
(h/call wasm/internal-module "_set_children_1"
|
||||
(aget c1 0) (aget c1 1) (aget c1 2) (aget c1 3)))
|
||||
|
||||
2
|
||||
(let [[c1 c2] children
|
||||
c1 (uuid/get-u32 c1)
|
||||
c2 (uuid/get-u32 c2)]
|
||||
(h/call wasm/internal-module "_set_children_2"
|
||||
(aget c1 0) (aget c1 1) (aget c1 2) (aget c1 3)
|
||||
(aget c2 0) (aget c2 1) (aget c2 2) (aget c2 3)))
|
||||
|
||||
3
|
||||
(let [[c1 c2 c3] children
|
||||
c1 (uuid/get-u32 c1)
|
||||
c2 (uuid/get-u32 c2)
|
||||
c3 (uuid/get-u32 c3)]
|
||||
(h/call wasm/internal-module "_set_children_3"
|
||||
(aget c1 0) (aget c1 1) (aget c1 2) (aget c1 3)
|
||||
(aget c2 0) (aget c2 1) (aget c2 2) (aget c2 3)
|
||||
(aget c3 0) (aget c3 1) (aget c3 2) (aget c3 3)))
|
||||
|
||||
4
|
||||
(let [[c1 c2 c3 c4] children
|
||||
c1 (uuid/get-u32 c1)
|
||||
c2 (uuid/get-u32 c2)
|
||||
c3 (uuid/get-u32 c3)
|
||||
c4 (uuid/get-u32 c4)]
|
||||
(h/call wasm/internal-module "_set_children_4"
|
||||
(aget c1 0) (aget c1 1) (aget c1 2) (aget c1 3)
|
||||
(aget c2 0) (aget c2 1) (aget c2 2) (aget c2 3)
|
||||
(aget c3 0) (aget c3 1) (aget c3 2) (aget c3 3)
|
||||
(aget c4 0) (aget c4 1) (aget c4 2) (aget c4 3)))
|
||||
|
||||
5
|
||||
(let [[c1 c2 c3 c4 c5] children
|
||||
c1 (uuid/get-u32 c1)
|
||||
c2 (uuid/get-u32 c2)
|
||||
c3 (uuid/get-u32 c3)
|
||||
c4 (uuid/get-u32 c4)
|
||||
c5 (uuid/get-u32 c5)]
|
||||
(h/call wasm/internal-module "_set_children_5"
|
||||
(aget c1 0) (aget c1 1) (aget c1 2) (aget c1 3)
|
||||
(aget c2 0) (aget c2 1) (aget c2 2) (aget c2 3)
|
||||
(aget c3 0) (aget c3 1) (aget c3 2) (aget c3 3)
|
||||
(aget c4 0) (aget c4 1) (aget c4 2) (aget c4 3)
|
||||
(aget c5 0) (aget c5 1) (aget c5 2) (aget c5 3)))
|
||||
|
||||
;; Dynamic call for children > 5
|
||||
(let [heap (mem/get-heap-u32)
|
||||
size (mem/get-alloc-size children UUID-U8-SIZE)
|
||||
offset (mem/alloc->offset-32 size)]
|
||||
|
||||
@ -51,47 +51,6 @@ pub extern "C" fn set_render_options(debug: u32, dpr: f32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_viewport_interest_area_threshold(
|
||||
viewport_interest_area_threshold: i32,
|
||||
) -> Result<()> {
|
||||
let render_state = get_render_state();
|
||||
render_state.set_viewport_interest_area_threshold(viewport_interest_area_threshold)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_max_blocking_time_ms(max_blocking_time_ms: i32) -> Result<()> {
|
||||
let render_state = get_render_state();
|
||||
render_state.set_max_blocking_time_ms(max_blocking_time_ms);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_node_batch_threshold(node_batch_threshold: i32) -> Result<()> {
|
||||
let render_state = get_render_state();
|
||||
render_state.set_node_batch_threshold(node_batch_threshold);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_blur_downscale_threshold(blur_downscale_threshold: f32) -> Result<()> {
|
||||
let render_state = get_render_state();
|
||||
render_state.set_blur_downscale_threshold(blur_downscale_threshold);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_antialias_threshold(threshold: f32) -> Result<()> {
|
||||
get_render_state().set_antialias_threshold(threshold);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_canvas_background(raw_color: u32) -> Result<()> {
|
||||
@ -469,16 +428,6 @@ pub extern "C" fn has_shape(a: u32, b: u32, c: u32, d: u32) -> Result<bool> {
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn touch_shape(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
|
||||
with_state!(state, {
|
||||
let shape_id = uuid_from_u32_quartet(a, b, c, d);
|
||||
state.touch_shape(shape_id);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_parent(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
|
||||
@ -541,16 +490,6 @@ pub extern "C" fn set_shape_transform(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn add_shape_child(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
shape.add_child(id);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_children_set(entries: Vec<Uuid>) -> Result<()> {
|
||||
with_state!(state, {
|
||||
state.set_current_shape_children(entries)?;
|
||||
@ -566,124 +505,6 @@ pub extern "C" fn set_children_0() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_children_1(a1: u32, b1: u32, c1: u32, d1: u32) -> Result<()> {
|
||||
let entries = vec![uuid_from_u32_quartet(a1, b1, c1, d1)];
|
||||
set_children_set(entries)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_children_2(
|
||||
a1: u32,
|
||||
b1: u32,
|
||||
c1: u32,
|
||||
d1: u32,
|
||||
a2: u32,
|
||||
b2: u32,
|
||||
c2: u32,
|
||||
d2: u32,
|
||||
) -> Result<()> {
|
||||
let entries = vec![
|
||||
uuid_from_u32_quartet(a1, b1, c1, d1),
|
||||
uuid_from_u32_quartet(a2, b2, c2, d2),
|
||||
];
|
||||
set_children_set(entries)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_children_3(
|
||||
a1: u32,
|
||||
b1: u32,
|
||||
c1: u32,
|
||||
d1: u32,
|
||||
a2: u32,
|
||||
b2: u32,
|
||||
c2: u32,
|
||||
d2: u32,
|
||||
a3: u32,
|
||||
b3: u32,
|
||||
c3: u32,
|
||||
d3: u32,
|
||||
) -> Result<()> {
|
||||
let entries = vec![
|
||||
uuid_from_u32_quartet(a1, b1, c1, d1),
|
||||
uuid_from_u32_quartet(a2, b2, c2, d2),
|
||||
uuid_from_u32_quartet(a3, b3, c3, d3),
|
||||
];
|
||||
set_children_set(entries)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_children_4(
|
||||
a1: u32,
|
||||
b1: u32,
|
||||
c1: u32,
|
||||
d1: u32,
|
||||
a2: u32,
|
||||
b2: u32,
|
||||
c2: u32,
|
||||
d2: u32,
|
||||
a3: u32,
|
||||
b3: u32,
|
||||
c3: u32,
|
||||
d3: u32,
|
||||
a4: u32,
|
||||
b4: u32,
|
||||
c4: u32,
|
||||
d4: u32,
|
||||
) -> Result<()> {
|
||||
let entries = vec![
|
||||
uuid_from_u32_quartet(a1, b1, c1, d1),
|
||||
uuid_from_u32_quartet(a2, b2, c2, d2),
|
||||
uuid_from_u32_quartet(a3, b3, c3, d3),
|
||||
uuid_from_u32_quartet(a4, b4, c4, d4),
|
||||
];
|
||||
set_children_set(entries)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_children_5(
|
||||
a1: u32,
|
||||
b1: u32,
|
||||
c1: u32,
|
||||
d1: u32,
|
||||
a2: u32,
|
||||
b2: u32,
|
||||
c2: u32,
|
||||
d2: u32,
|
||||
a3: u32,
|
||||
b3: u32,
|
||||
c3: u32,
|
||||
d3: u32,
|
||||
a4: u32,
|
||||
b4: u32,
|
||||
c4: u32,
|
||||
d4: u32,
|
||||
a5: u32,
|
||||
b5: u32,
|
||||
c5: u32,
|
||||
d5: u32,
|
||||
) -> Result<()> {
|
||||
let entries = vec![
|
||||
uuid_from_u32_quartet(a1, b1, c1, d1),
|
||||
uuid_from_u32_quartet(a2, b2, c2, d2),
|
||||
uuid_from_u32_quartet(a3, b3, c3, d3),
|
||||
uuid_from_u32_quartet(a4, b4, c4, d4),
|
||||
uuid_from_u32_quartet(a5, b5, c5, d5),
|
||||
];
|
||||
set_children_set(entries)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_children() -> Result<()> {
|
||||
|
||||
@ -911,37 +911,6 @@ impl RenderState {
|
||||
.ensure_tile_atlas_layout(self.tile_viewbox.interest_rect.len().max(1) as usize);
|
||||
}
|
||||
|
||||
pub fn set_antialias_threshold(&mut self, value: f32) {
|
||||
self.options.set_antialias_threshold(value);
|
||||
}
|
||||
|
||||
pub fn set_viewport_interest_area_threshold(&mut self, value: i32) -> Result<()> {
|
||||
// Only when this function returns true (it means the value
|
||||
// was changed properly) the tile_viewbox.set_interest is called.
|
||||
if self.options.set_viewport_interest_area_threshold(value) {
|
||||
// The TileViewbox stores its own copy of `interest` (set at
|
||||
// construction). Without propagating, options change wouldn't
|
||||
// affect pending_tiles generation.
|
||||
self.tile_viewbox
|
||||
.set_interest(self.options.dpr_viewport_interest_area_threshold);
|
||||
self.tile_viewbox.update(&self.viewbox);
|
||||
self.ensure_tile_atlas_layout();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_node_batch_threshold(&mut self, value: i32) {
|
||||
self.options.set_node_batch_threshold(value);
|
||||
}
|
||||
|
||||
pub fn set_max_blocking_time_ms(&mut self, value: i32) {
|
||||
self.options.set_max_blocking_time_ms(value);
|
||||
}
|
||||
|
||||
pub fn set_blur_downscale_threshold(&mut self, value: f32) {
|
||||
self.options.set_blur_downscale_threshold(value);
|
||||
}
|
||||
|
||||
pub fn set_background_color(&mut self, color: skia::Color) {
|
||||
self.background_color = color;
|
||||
}
|
||||
|
||||
@ -121,45 +121,4 @@ impl RenderOptions {
|
||||
pub fn show_wasm_info(&self) -> bool {
|
||||
self.flags & SHOW_WASM_INFO == SHOW_WASM_INFO
|
||||
}
|
||||
|
||||
pub fn set_antialias_threshold(&mut self, value: f32) -> bool {
|
||||
if value.is_finite() && value > 0.0 {
|
||||
self.antialias_threshold = value;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn set_blur_downscale_threshold(&mut self, value: f32) -> bool {
|
||||
if value.is_finite() && value > 0.0 {
|
||||
self.blur_downscale_threshold = value;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn set_viewport_interest_area_threshold(&mut self, value: i32) -> bool {
|
||||
if value >= 0 && self.viewport_interest_area_threshold != value {
|
||||
self.viewport_interest_area_threshold = value;
|
||||
self.update_dpr_viewport_interest_area_threshold();
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn set_node_batch_threshold(&mut self, value: i32) -> bool {
|
||||
if value > 0 {
|
||||
self.node_batch_threshold = value;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn set_max_blocking_time_ms(&mut self, value: i32) -> bool {
|
||||
if value > 0 {
|
||||
self.max_blocking_time_ms = value;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@ -652,6 +652,7 @@ impl Shape {
|
||||
self.background_blur.filter(|blur| !blur.hidden)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn add_child(&mut self, id: Uuid) {
|
||||
self.children.push(id);
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use macros::{wasm_error, ToJs};
|
||||
|
||||
use crate::globals::{get_render_state, get_text_editor_state};
|
||||
use crate::math::{Matrix, Point, Rect};
|
||||
use crate::math::{Matrix, Point};
|
||||
use crate::mem;
|
||||
use crate::render::text_editor as text_editor_render;
|
||||
use crate::render::SurfaceId;
|
||||
use crate::shapes::{Shape, TextAlign, TextContent, TextPositionWithAffinity, Type, VerticalAlign};
|
||||
use crate::state::{State, TextEditorEvent, TextSelection};
|
||||
use crate::shapes::{TextAlign, TextPositionWithAffinity, Type, VerticalAlign};
|
||||
use crate::state::{State, TextEditorEvent};
|
||||
use crate::utils::uuid_from_u32_quartet;
|
||||
use crate::utils::uuid_to_u32_quartet;
|
||||
use crate::uuid::Uuid;
|
||||
@ -643,40 +643,6 @@ pub extern "C" fn text_editor_move_cursor(
|
||||
// RENDERING & EXPORT
|
||||
// ============================================================================
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn text_editor_get_cursor_rect() -> *mut u8 {
|
||||
with_state!(state, {
|
||||
if !get_text_editor_state().has_focus || !get_text_editor_state().cursor_visible {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let Some(shape_id) = get_text_editor_state().active_shape_id else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let Some(shape) = state.shapes.get(&shape_id) else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let Type::Text(text_content) = &shape.shape_type else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let cursor = &get_text_editor_state().selection.focus;
|
||||
|
||||
if let Some(rect) = get_cursor_rect(text_content, cursor, shape) {
|
||||
let mut bytes = vec![0u8; 16];
|
||||
bytes[0..4].copy_from_slice(&rect.left().to_le_bytes());
|
||||
bytes[4..8].copy_from_slice(&rect.top().to_le_bytes());
|
||||
bytes[8..12].copy_from_slice(&rect.width().to_le_bytes());
|
||||
bytes[12..16].copy_from_slice(&rect.height().to_le_bytes());
|
||||
return mem::write_bytes(bytes);
|
||||
}
|
||||
|
||||
std::ptr::null_mut()
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn text_editor_get_current_styles() -> *mut u8 {
|
||||
with_state!(state, {
|
||||
@ -838,47 +804,6 @@ pub extern "C" fn text_editor_get_current_styles() -> *mut u8 {
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn text_editor_get_selection_rects() -> *mut u8 {
|
||||
with_state!(state, {
|
||||
if !get_text_editor_state().has_focus {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
if get_text_editor_state().selection.is_collapsed() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let Some(shape_id) = get_text_editor_state().active_shape_id else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let Some(shape) = state.shapes.get(&shape_id) else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let Type::Text(text_content) = &shape.shape_type else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let selection = &get_text_editor_state().selection;
|
||||
let rects = get_selection_rects(text_content, selection, shape);
|
||||
if rects.is_empty() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let mut bytes = Vec::with_capacity(4 + rects.len() * 16);
|
||||
bytes.extend_from_slice(&(rects.len() as u32).to_le_bytes());
|
||||
for rect in rects {
|
||||
bytes.extend_from_slice(&rect.left().to_le_bytes());
|
||||
bytes.extend_from_slice(&rect.top().to_le_bytes());
|
||||
bytes.extend_from_slice(&rect.width().to_le_bytes());
|
||||
bytes.extend_from_slice(&rect.height().to_le_bytes());
|
||||
}
|
||||
mem::write_bytes(bytes)
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn text_editor_update_blink(timestamp_ms: f32) {
|
||||
get_text_editor_state().update_blink(timestamp_ms);
|
||||
@ -1124,139 +1049,3 @@ pub extern "C" fn text_editor_get_selection(buffer_ptr: *mut u32) -> bool {
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// HELPERS: Cursor & Selection
|
||||
// ============================================================================
|
||||
|
||||
fn get_cursor_rect(
|
||||
text_content: &TextContent,
|
||||
cursor: &TextPositionWithAffinity,
|
||||
shape: &Shape,
|
||||
) -> Option<Rect> {
|
||||
let paragraphs = text_content.paragraphs();
|
||||
if cursor.paragraph >= paragraphs.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let layout_paragraphs: Vec<_> = text_content.layout.paragraphs.iter().flatten().collect();
|
||||
|
||||
let total_height: f32 = layout_paragraphs.iter().map(|p| p.height()).sum();
|
||||
let valign_offset = match shape.vertical_align() {
|
||||
VerticalAlign::Center => (shape.selrect().height() - total_height) / 2.0,
|
||||
VerticalAlign::Bottom => shape.selrect().height() - total_height,
|
||||
_ => 0.0,
|
||||
};
|
||||
|
||||
let mut y_offset = valign_offset;
|
||||
for (idx, laid_out_para) in layout_paragraphs.iter().enumerate() {
|
||||
if idx == cursor.paragraph {
|
||||
let utf16_pos = paragraphs[cursor.paragraph].char_offset_to_utf16(cursor.offset);
|
||||
|
||||
use skia_safe::textlayout::{RectHeightStyle, RectWidthStyle};
|
||||
let rects = laid_out_para.get_rects_for_range(
|
||||
utf16_pos..utf16_pos,
|
||||
RectHeightStyle::Tight,
|
||||
RectWidthStyle::Tight,
|
||||
);
|
||||
|
||||
let (x, height) = if !rects.is_empty() {
|
||||
(rects[0].rect.left(), rects[0].rect.height())
|
||||
} else {
|
||||
let pos = laid_out_para.get_glyph_position_at_coordinate((0.0, 0.0));
|
||||
let height = laid_out_para.height();
|
||||
(pos.position as f32, height)
|
||||
};
|
||||
|
||||
let selrect = shape.selrect();
|
||||
let base_x = selrect.x();
|
||||
let base_y = selrect.y() + y_offset;
|
||||
|
||||
return Some(Rect::from_xywh(base_x + x, base_y, 1.0, height));
|
||||
}
|
||||
y_offset += laid_out_para.height();
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Get selection rectangles for a given selection.
|
||||
fn get_selection_rects(
|
||||
text_content: &TextContent,
|
||||
selection: &TextSelection,
|
||||
shape: &Shape,
|
||||
) -> Vec<Rect> {
|
||||
let mut rects = Vec::new();
|
||||
|
||||
let start = selection.start();
|
||||
let end = selection.end();
|
||||
|
||||
let paragraphs = text_content.paragraphs();
|
||||
let layout_paragraphs: Vec<_> = text_content.layout.paragraphs.iter().flatten().collect();
|
||||
|
||||
let selrect = shape.selrect();
|
||||
|
||||
let total_height: f32 = layout_paragraphs.iter().map(|p| p.height()).sum();
|
||||
let valign_offset = match shape.vertical_align() {
|
||||
VerticalAlign::Center => (selrect.height() - total_height) / 2.0,
|
||||
VerticalAlign::Bottom => selrect.height() - total_height,
|
||||
_ => 0.0,
|
||||
};
|
||||
|
||||
let mut y_offset = valign_offset;
|
||||
|
||||
for (para_idx, laid_out_para) in layout_paragraphs.iter().enumerate() {
|
||||
let para_height = laid_out_para.height();
|
||||
|
||||
if para_idx < start.paragraph || para_idx > end.paragraph {
|
||||
y_offset += para_height;
|
||||
continue;
|
||||
}
|
||||
|
||||
if para_idx >= paragraphs.len() {
|
||||
y_offset += para_height;
|
||||
continue;
|
||||
}
|
||||
|
||||
let para = ¶graphs[para_idx];
|
||||
let para_char_count: usize = para
|
||||
.children()
|
||||
.iter()
|
||||
.map(|span| span.text.chars().count())
|
||||
.sum();
|
||||
let range_start = if para_idx == start.paragraph {
|
||||
start.offset
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let range_end = if para_idx == end.paragraph {
|
||||
end.offset
|
||||
} else {
|
||||
para_char_count
|
||||
};
|
||||
|
||||
if range_start < range_end {
|
||||
use skia_safe::textlayout::{RectHeightStyle, RectWidthStyle};
|
||||
let text_boxes = laid_out_para.get_rects_for_range(
|
||||
para.char_offset_to_utf16(range_start)..para.char_offset_to_utf16(range_end),
|
||||
RectHeightStyle::Tight,
|
||||
RectWidthStyle::Tight,
|
||||
);
|
||||
|
||||
for text_box in text_boxes {
|
||||
let r = text_box.rect;
|
||||
rects.push(Rect::from_xywh(
|
||||
selrect.x() + r.left(),
|
||||
selrect.y() + y_offset + r.top(),
|
||||
r.width(),
|
||||
r.height(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
y_offset += para_height;
|
||||
}
|
||||
|
||||
rects
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user