mirror of
https://github.com/penpot/penpot.git
synced 2025-12-23 22:48:40 -05:00
WIP
This commit is contained in:
@@ -379,6 +379,23 @@
|
||||
(->> (rx/from added)
|
||||
(rx/map process-wasm-object)))))))
|
||||
|
||||
(when render-wasm?
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? :wasm/position-data))
|
||||
(rx/map deref)
|
||||
(rx/filter
|
||||
(fn [{:keys [position-data]}]
|
||||
(some? position-data)))
|
||||
(rx/map
|
||||
(fn [{:keys [id position-data]}]
|
||||
(prn "???" id position-data)
|
||||
(dwsh/update-shapes
|
||||
[id]
|
||||
(fn [shape]
|
||||
(.log js/console (clj->js shape))
|
||||
(assoc shape :position-data position-data))
|
||||
{:ignore-wasm? true})))))
|
||||
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
|
||||
@@ -50,7 +50,8 @@
|
||||
([ids update-fn] (update-shapes ids update-fn nil))
|
||||
([ids update-fn
|
||||
{:keys [reg-objects? save-undo? stack-undo? attrs ignore-tree page-id
|
||||
ignore-touched undo-group with-objects? changed-sub-attr]
|
||||
ignore-touched undo-group with-objects? changed-sub-attr
|
||||
ignore-wasm?]
|
||||
:or {reg-objects? false
|
||||
save-undo? true
|
||||
stack-undo? false
|
||||
@@ -89,6 +90,7 @@
|
||||
:ignore-tree ignore-tree
|
||||
:ignore-touched ignore-touched
|
||||
:with-objects? with-objects?})
|
||||
(assoc :ignore-wasm? ignore-wasm?)
|
||||
(cond-> undo-group
|
||||
(pcb/set-undo-group undo-group)))
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
(ns app.main.ui.workspace.viewport.debug
|
||||
(:require
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
@@ -275,3 +276,29 @@
|
||||
:y2 (:y end-p)
|
||||
:style {:stroke "red"
|
||||
:stroke-width (/ 1 zoom)}}]))]))))
|
||||
|
||||
(mf/defc debug-text-position-data
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [objects (unchecked-get props "objects")
|
||||
zoom (unchecked-get props "zoom")
|
||||
selected-shapes (unchecked-get props "selected-shapes")
|
||||
|
||||
selected-text
|
||||
(when (and (= (count selected-shapes) 1) (= :text (-> selected-shapes first :type)))
|
||||
(first selected-shapes))
|
||||
|
||||
position-data
|
||||
(when selected-text
|
||||
(wasm.api/calculate-position-data selected-text))]
|
||||
|
||||
(for [{:keys [x y width height]} position-data]
|
||||
[:rect {:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:fill "none"
|
||||
:strokeWidth 1
|
||||
:stroke "red"}]
|
||||
|
||||
)))
|
||||
|
||||
@@ -635,6 +635,10 @@
|
||||
:hover-top-frame-id @hover-top-frame-id
|
||||
:zoom zoom}])
|
||||
|
||||
[:& wvd/debug-text-position-data {:selected-shapes selected-shapes
|
||||
:objects base-objects
|
||||
:zoom zoom}]
|
||||
|
||||
(when show-selection-handlers?
|
||||
[:g.selection-handlers {:clipPath "url(#clip-handlers)"}
|
||||
(when-not text-editing?
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
(ns app.render-wasm.api
|
||||
"A WASM based render API"
|
||||
(:require
|
||||
[potok.v2.core :as ptk]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.ui.shapes.text]
|
||||
["react-dom/server" :as rds]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
@@ -127,10 +130,18 @@
|
||||
(render ts)))))
|
||||
|
||||
(declare get-text-dimensions)
|
||||
(declare calculate-position-data)
|
||||
|
||||
(defn update-text-rect!
|
||||
[id]
|
||||
(when wasm/context-initialized?
|
||||
(let [objects (dsh/lookup-page-objects @st/state)
|
||||
shape (get objects id)
|
||||
position-data (calculate-position-data shape)]
|
||||
(.log js/console (:name shape) (clj->js position-data))
|
||||
(st/emit!
|
||||
(ptk/data-event :wasm/position-data {:id id :position-data position-data})))
|
||||
|
||||
(mw/emit!
|
||||
{:cmd :index/update-text-rect
|
||||
:page-id (:current-page-id @st/state)
|
||||
@@ -988,10 +999,7 @@
|
||||
(run!
|
||||
(fn [id]
|
||||
(f/update-text-layout id)
|
||||
(mw/emit! {:cmd :index/update-text-rect
|
||||
:page-id (:current-page-id @st/state)
|
||||
:shape-id id
|
||||
:dimensions (get-text-dimensions id)})))))
|
||||
(update-text-rect! id)))))
|
||||
|
||||
(defn process-pending
|
||||
([shapes thumbnails full on-complete]
|
||||
@@ -1347,6 +1355,58 @@
|
||||
(h/call wasm/internal-module "_end_temp_objects")
|
||||
content)))
|
||||
|
||||
(def POSITION-DATA-U8-SIZE 36)
|
||||
(def POSITION-DATA-U32-SIZE (/ POSITION-DATA-U8-SIZE 4))
|
||||
|
||||
(defn calculate-position-data
|
||||
[shape]
|
||||
(use-shape (:id shape))
|
||||
(let [heapf32 (mem/get-heap-f32)
|
||||
heapu32 (mem/get-heap-u32)
|
||||
offset (-> (h/call wasm/internal-module "_calc_position_data")
|
||||
(mem/->offset-32))
|
||||
length (aget heapu32 offset)
|
||||
|
||||
max-offset (+ offset 1 (* length POSITION-DATA-U32-SIZE))
|
||||
|
||||
result
|
||||
(loop [result (transient [])
|
||||
offset (inc offset)]
|
||||
(if (< offset max-offset)
|
||||
(let [entry (dr/read-position-data-entry heapu32 heapf32 offset)]
|
||||
(recur (conj! result entry)
|
||||
(+ offset POSITION-DATA-U32-SIZE)))
|
||||
(persistent! result)))
|
||||
|
||||
result
|
||||
(->> result
|
||||
(mapv
|
||||
(fn [{:keys [paragraph span start-pos end-pos direction x y width height]}]
|
||||
(let [content (:content shape)
|
||||
element (-> content :children
|
||||
(get 0) :children ;; paragraph-set
|
||||
(get paragraph) :children ;; paragraph
|
||||
(get span))
|
||||
text (subs (:text element) start-pos end-pos)]
|
||||
|
||||
{:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:direction direction
|
||||
:font-family (get element :font-family)
|
||||
:font-size (get element :font-size)
|
||||
:font-weight (get element :font-weight)
|
||||
:text-transform (get element :text-transform)
|
||||
:text-decoration (get element :text-decoration)
|
||||
:letter-spacing (get element :letter-spacing)
|
||||
:font-style (get element :font-style)
|
||||
:fills (get element :fills)
|
||||
:text text}))))]
|
||||
(mem/free)
|
||||
|
||||
result))
|
||||
|
||||
(defn init-wasm-module
|
||||
[module]
|
||||
(let [default-fn (unchecked-get module "default")
|
||||
|
||||
@@ -45,4 +45,23 @@
|
||||
:center (gpt/point cx cy)
|
||||
:transform (gmt/matrix a b c d e f)}))
|
||||
|
||||
|
||||
(defn read-position-data-entry
|
||||
[heapu32 heapf32 offset]
|
||||
(let [paragraph (aget heapu32 (+ offset 0))
|
||||
span (aget heapu32 (+ offset 1))
|
||||
start-pos (aget heapu32 (+ offset 2))
|
||||
end-pos (aget heapu32 (+ offset 3))
|
||||
x (aget heapf32 (+ offset 4))
|
||||
y (aget heapf32 (+ offset 5))
|
||||
width (aget heapf32 (+ offset 6))
|
||||
height (aget heapf32 (+ offset 7))
|
||||
direction (aget heapu32 (+ offset 8))]
|
||||
{:paragraph paragraph
|
||||
:span span
|
||||
:start-pos start-pos
|
||||
:end-pos end-pos
|
||||
:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:direction direction}))
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
(ns debug
|
||||
(:require
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.repair :as cfr]
|
||||
@@ -456,3 +457,10 @@
|
||||
(defn ^:export network-averages
|
||||
[]
|
||||
(.log js/console (clj->js @http/network-averages)))
|
||||
|
||||
(defn ^:export tmp
|
||||
[]
|
||||
(let [objects (dsh/lookup-page-objects @st/state)
|
||||
shape (->> (get-selected @st/state) (first) (get objects))]
|
||||
(wasm.api/calculate-position-data shape))
|
||||
)
|
||||
|
||||
@@ -847,6 +847,8 @@ impl RenderState {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// text::render_position_data(self, fills_surface_id, &shape, &text_content);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
shapes::{
|
||||
merge_fills, set_paint_fill, ParagraphBuilderGroup, Stroke, StrokeKind, TextContent,
|
||||
VerticalAlign,
|
||||
calc_position_data
|
||||
},
|
||||
utils::{get_fallback_fonts, get_font_collection},
|
||||
};
|
||||
@@ -504,6 +505,29 @@ pub fn render_as_path(
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn render_position_data(
|
||||
render_state: &mut RenderState,
|
||||
surface_id: SurfaceId,
|
||||
shape: &Shape,
|
||||
text_content: &TextContent
|
||||
) {
|
||||
let position_data = calc_position_data(shape, text_content);
|
||||
|
||||
let mut paint = skia::Paint::default();
|
||||
paint.set_style(skia::PaintStyle::Stroke);
|
||||
paint.set_color(skia::Color::from_argb(255, 255, 0, 0));
|
||||
paint.set_stroke_width(2.);
|
||||
|
||||
for pd in position_data {
|
||||
let rect = Rect::from_xywh(pd.x, pd.y, pd.width, pd.height);
|
||||
render_state.surfaces
|
||||
.canvas(surface_id)
|
||||
.draw_rect(rect, &paint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// How to use it?
|
||||
// Type::Text(text_content) => {
|
||||
// self.surfaces
|
||||
|
||||
@@ -204,6 +204,49 @@ fn intersects(paragraph: &skia_safe::textlayout::Paragraph, x: f32, y: f32) -> b
|
||||
rects.iter().any(|r| r.rect.contains(&Point::new(x, y)))
|
||||
}
|
||||
|
||||
|
||||
/// Performs a text auto layout without width limits.
|
||||
/// This should be the same as text_auto_layout.
|
||||
pub fn build_paragraphs_from_paragraph_builders(
|
||||
paragraph_builders: &mut [ParagraphBuilderGroup],
|
||||
width: f32,
|
||||
) -> Vec<Vec<skia::textlayout::Paragraph>> {
|
||||
let paragraphs = paragraph_builders
|
||||
.iter_mut()
|
||||
.map(|builders| {
|
||||
builders
|
||||
.iter_mut()
|
||||
.map(|builder| {
|
||||
let mut paragraph = builder.build();
|
||||
// For auto-width, always layout with infinite width first to get intrinsic width
|
||||
paragraph.layout(width);
|
||||
paragraph
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
paragraphs
|
||||
}
|
||||
|
||||
/// Calculate the normalized line height from paragraph builders
|
||||
pub fn calculate_normalized_line_height(
|
||||
paragraph_builders: &mut [ParagraphBuilderGroup],
|
||||
width: f32,
|
||||
) -> f32 {
|
||||
let mut normalized_line_height = 0.0;
|
||||
for paragraph_builder_group in paragraph_builders.iter_mut() {
|
||||
for paragraph_builder in paragraph_builder_group.iter_mut() {
|
||||
let mut paragraph = paragraph_builder.build();
|
||||
paragraph.layout(width);
|
||||
let baseline = paragraph.ideographic_baseline();
|
||||
if baseline > normalized_line_height {
|
||||
normalized_line_height = baseline;
|
||||
}
|
||||
}
|
||||
}
|
||||
normalized_line_height
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TextContent {
|
||||
pub paragraphs: Vec<Paragraph>,
|
||||
@@ -440,59 +483,15 @@ impl TextContent {
|
||||
paragraph_group
|
||||
}
|
||||
|
||||
/// Performs a text auto layout without width limits.
|
||||
/// This should be the same as text_auto_layout.
|
||||
fn build_paragraphs_from_paragraph_builders(
|
||||
&self,
|
||||
paragraph_builders: &mut [ParagraphBuilderGroup],
|
||||
width: f32,
|
||||
) -> Vec<Vec<skia::textlayout::Paragraph>> {
|
||||
let paragraphs = paragraph_builders
|
||||
.iter_mut()
|
||||
.map(|builders| {
|
||||
builders
|
||||
.iter_mut()
|
||||
.map(|builder| {
|
||||
let mut paragraph = builder.build();
|
||||
// For auto-width, always layout with infinite width first to get intrinsic width
|
||||
paragraph.layout(width);
|
||||
paragraph
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
paragraphs
|
||||
}
|
||||
|
||||
/// Calculate the normalized line height from paragraph builders
|
||||
fn calculate_normalized_line_height(
|
||||
&self,
|
||||
paragraph_builders: &mut [ParagraphBuilderGroup],
|
||||
width: f32,
|
||||
) -> f32 {
|
||||
let mut normalized_line_height = 0.0;
|
||||
for paragraph_builder_group in paragraph_builders.iter_mut() {
|
||||
for paragraph_builder in paragraph_builder_group.iter_mut() {
|
||||
let mut paragraph = paragraph_builder.build();
|
||||
paragraph.layout(width);
|
||||
let baseline = paragraph.ideographic_baseline();
|
||||
if baseline > normalized_line_height {
|
||||
normalized_line_height = baseline;
|
||||
}
|
||||
}
|
||||
}
|
||||
normalized_line_height
|
||||
}
|
||||
|
||||
/// Performs an Auto Width text layout.
|
||||
fn text_layout_auto_width(&self) -> TextContentLayoutResult {
|
||||
let mut paragraph_builders = self.paragraph_builder_group_from_text(None);
|
||||
|
||||
let normalized_line_height =
|
||||
self.calculate_normalized_line_height(&mut paragraph_builders, f32::MAX);
|
||||
calculate_normalized_line_height(&mut paragraph_builders, f32::MAX);
|
||||
|
||||
let paragraphs =
|
||||
self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, f32::MAX);
|
||||
build_paragraphs_from_paragraph_builders(&mut paragraph_builders, f32::MAX);
|
||||
|
||||
let (width, height) =
|
||||
paragraphs
|
||||
@@ -521,10 +520,10 @@ impl TextContent {
|
||||
let mut paragraph_builders = self.paragraph_builder_group_from_text(None);
|
||||
|
||||
let normalized_line_height =
|
||||
self.calculate_normalized_line_height(&mut paragraph_builders, width);
|
||||
calculate_normalized_line_height(&mut paragraph_builders, width);
|
||||
|
||||
let paragraphs =
|
||||
self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
|
||||
build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
|
||||
let height = paragraphs
|
||||
.iter()
|
||||
.flatten()
|
||||
@@ -546,10 +545,10 @@ impl TextContent {
|
||||
let mut paragraph_builders = self.paragraph_builder_group_from_text(None);
|
||||
|
||||
let normalized_line_height =
|
||||
self.calculate_normalized_line_height(&mut paragraph_builders, width);
|
||||
calculate_normalized_line_height(&mut paragraph_builders, width);
|
||||
|
||||
let paragraphs =
|
||||
self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
|
||||
build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
|
||||
let paragraph_height = paragraphs
|
||||
.iter()
|
||||
.flatten()
|
||||
@@ -577,7 +576,7 @@ impl TextContent {
|
||||
pub fn get_height(&self, width: f32) -> f32 {
|
||||
let mut paragraph_builders = self.paragraph_builder_group_from_text(None);
|
||||
let paragraphs =
|
||||
self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
|
||||
build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
|
||||
let paragraph_height = paragraphs
|
||||
.iter()
|
||||
.flatten()
|
||||
@@ -734,7 +733,7 @@ impl TextContent {
|
||||
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);
|
||||
build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
|
||||
|
||||
paragraphs
|
||||
.iter()
|
||||
@@ -1045,3 +1044,121 @@ impl TextSpan {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct PositionData {
|
||||
pub paragraph: u32, // 4
|
||||
pub span: u32, // 4
|
||||
pub start_pos: u32, // 4
|
||||
pub end_pos: u32, // 4
|
||||
pub x: f32, // 4
|
||||
pub y: f32, // 4
|
||||
pub width: f32, // 4
|
||||
pub height: f32, // 4
|
||||
pub direction: u32 // 4, u32 to align with 32 bytes
|
||||
}
|
||||
|
||||
fn direction_to_int(direction: TextDirection) -> u32 {
|
||||
match direction {
|
||||
TextDirection::RTL => 0,
|
||||
TextDirection::LTR => 1
|
||||
}
|
||||
}
|
||||
|
||||
//fn get_unicode_substring(full_text: &str, start: usize, end: usize) -> String {
|
||||
// let chars: Vec<char> = full_text.chars().collect();
|
||||
// chars[start..end].iter().collect()
|
||||
//}
|
||||
|
||||
pub fn calc_position_data(
|
||||
shape: &Shape,
|
||||
text_content: &TextContent
|
||||
) -> Vec<PositionData> {
|
||||
let mut result: Vec<PositionData> = Vec::default();
|
||||
let mut text_content = text_content.clone();
|
||||
text_content.update_layout(shape.selrect);
|
||||
let rect = text_content.content_rect(&shape.selrect, shape.vertical_align);
|
||||
|
||||
let x = rect.x();
|
||||
let mut y = rect.y();
|
||||
|
||||
let fonts = get_font_collection();
|
||||
let fallback_fonts = get_fallback_fonts();
|
||||
|
||||
for (paragraph_index, paragraph) in text_content.paragraphs().iter().enumerate() {
|
||||
let mut paragraph_text = String::default();
|
||||
let paragraph_style = paragraph.paragraph_to_style();
|
||||
let mut builder = ParagraphBuilder::new(¶graph_style, fonts);
|
||||
|
||||
let mut span_ranges: Vec<(usize, usize, usize)> = vec![];
|
||||
let mut cur = 0;
|
||||
|
||||
for (span_index, span) in paragraph.children().iter().enumerate() {
|
||||
let text_style = span.to_style(
|
||||
&text_content.bounds(),
|
||||
fallback_fonts,
|
||||
false,
|
||||
paragraph.line_height(),
|
||||
);
|
||||
let text: String = span.apply_text_transform();
|
||||
builder.push_style(&text_style);
|
||||
builder.add_text(&text);
|
||||
|
||||
span_ranges.push((cur, cur + text.len(), span_index));
|
||||
cur += text.len();
|
||||
|
||||
paragraph_text += &text;
|
||||
}
|
||||
|
||||
let mut p = builder.build();
|
||||
p.layout(shape.selrect.width());
|
||||
|
||||
for (start, end, span_index) in span_ranges {
|
||||
let rects = p.get_rects_for_range(
|
||||
start .. end,
|
||||
RectHeightStyle::Tight,
|
||||
RectWidthStyle::Tight,
|
||||
);
|
||||
|
||||
for textbox in rects {
|
||||
let direction = textbox.direct;
|
||||
let mut rect = textbox.rect;
|
||||
let cy = rect.top + rect.height() / 2.0;
|
||||
|
||||
let start_pos = p
|
||||
.get_glyph_position_at_coordinate((rect.left + 0.1, cy))
|
||||
.position as usize;
|
||||
|
||||
let end_pos = p
|
||||
.get_glyph_position_at_coordinate((rect.right - 0.1, cy))
|
||||
.position as usize;
|
||||
|
||||
// start_pos and end_pos are relative to the paragraph but we
|
||||
// want it relative to the span
|
||||
|
||||
let start_pos = start_pos - start;
|
||||
let end_pos = end_pos - start;
|
||||
|
||||
rect.offset((x, y));
|
||||
|
||||
result.push(PositionData {
|
||||
paragraph: paragraph_index as u32,
|
||||
span: span_index as u32,
|
||||
start_pos: start_pos as u32,
|
||||
end_pos: end_pos as u32,
|
||||
x: rect.x(),
|
||||
y: rect.y(),
|
||||
width: rect.width(),
|
||||
height: rect.height(),
|
||||
direction: direction_to_int(direction)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
y += p.height();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ use macros::ToJs;
|
||||
|
||||
use super::{fills::RawFillData, fonts::RawFontStyle};
|
||||
use crate::math::{Matrix, Point};
|
||||
use crate::mem;
|
||||
use crate::mem::{self, SerializableResult};
|
||||
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, with_state_mut, with_state_mut_current_shape, STATE,
|
||||
with_current_shape, 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>();
|
||||
@@ -411,3 +411,37 @@ pub extern "C" fn get_caret_position_at(x: f32, y: f32) -> i32 {
|
||||
});
|
||||
-1
|
||||
}
|
||||
|
||||
const RAW_POSITION_DATA_SIZE: usize = size_of::<shapes::PositionData>();
|
||||
|
||||
impl SerializableResult for shapes::PositionData {
|
||||
type BytesType = [u8; RAW_POSITION_DATA_SIZE];
|
||||
|
||||
fn from_bytes(bytes: Self::BytesType) -> Self {
|
||||
unsafe { std::mem::transmute(bytes) }
|
||||
}
|
||||
fn as_bytes(&self) -> Self::BytesType {
|
||||
let ptr = self as *const shapes::PositionData as *const u8;
|
||||
let bytes: &[u8] = unsafe { std::slice::from_raw_parts(ptr, RAW_POSITION_DATA_SIZE) };
|
||||
let mut result = [0; RAW_POSITION_DATA_SIZE];
|
||||
result.copy_from_slice(bytes);
|
||||
result
|
||||
}
|
||||
|
||||
// The generic trait doesn't know the size of the array. This is why the
|
||||
// clone needs to be here even if it could be generic.
|
||||
fn clone_to_slice(&self, slice: &mut [u8]) {
|
||||
slice.clone_from_slice(&self.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn calc_position_data() -> *mut u8 {
|
||||
let mut result = Vec::<shapes::PositionData>::default();
|
||||
with_current_shape!(state, |shape: &Shape| {
|
||||
if let Type::Text(text_content) = &shape.shape_type {
|
||||
result = shapes::calc_position_data(shape, &text_content);
|
||||
}
|
||||
});
|
||||
mem::write_vec(result)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user