diff --git a/src/paint/builder.rs b/src/paint/builder.rs
index 6bfebcb6a..0fccaaa1d 100644
--- a/src/paint/builder.rs
+++ b/src/paint/builder.rs
@@ -57,55 +57,39 @@ impl LayerBuilder {
}
let own_ops = match &node.node_type {
- RenderNodeType::PageBackground(background) => Some(vec![PaintOp::PageBackground {
- bbox: node.bbox,
- background: background.clone(),
- }]),
+ RenderNodeType::PageBackground(background) => Some(vec![PaintOp::page_background(
+ node.bbox,
+ background.clone(),
+ )]),
RenderNodeType::TextRun(run) => {
Some(text_run_ops(node.bbox, run.clone(), self.output_options))
}
- RenderNodeType::FootnoteMarker(marker) => Some(vec![PaintOp::FootnoteMarker {
- bbox: node.bbox,
- marker: marker.clone(),
- }]),
- RenderNodeType::Line(line) => Some(vec![PaintOp::Line {
- bbox: node.bbox,
- line: line.clone(),
- }]),
- RenderNodeType::Rectangle(rect) => Some(vec![PaintOp::Rectangle {
- bbox: node.bbox,
- rect: rect.clone(),
- }]),
- RenderNodeType::Ellipse(ellipse) => Some(vec![PaintOp::Ellipse {
- bbox: node.bbox,
- ellipse: ellipse.clone(),
- }]),
- RenderNodeType::Path(path) => Some(vec![PaintOp::Path {
- bbox: node.bbox,
- path: path.clone(),
- }]),
- RenderNodeType::Image(image) => Some(vec![PaintOp::Image {
- bbox: node.bbox,
- image: image.clone(),
- resolved: crate::renderer::image_resolver::resolve_image_payload(image)
- .map(Box::new),
- }]),
- RenderNodeType::Equation(equation) => Some(vec![PaintOp::Equation {
- bbox: node.bbox,
- equation: equation.clone(),
- }]),
- RenderNodeType::FormObject(form) => Some(vec![PaintOp::FormObject {
- bbox: node.bbox,
- form: form.clone(),
- }]),
- RenderNodeType::Placeholder(placeholder) => Some(vec![PaintOp::Placeholder {
- bbox: node.bbox,
- placeholder: placeholder.clone(),
- }]),
- RenderNodeType::RawSvg(raw) => Some(vec![PaintOp::RawSvg {
- bbox: node.bbox,
- raw: raw.clone(),
- }]),
+ RenderNodeType::FootnoteMarker(marker) => {
+ Some(vec![PaintOp::footnote_marker(node.bbox, marker.clone())])
+ }
+ RenderNodeType::Line(line) => Some(vec![PaintOp::line(node.bbox, line.clone())]),
+ RenderNodeType::Rectangle(rect) => {
+ Some(vec![PaintOp::rectangle(node.bbox, rect.clone())])
+ }
+ RenderNodeType::Ellipse(ellipse) => {
+ Some(vec![PaintOp::ellipse(node.bbox, ellipse.clone())])
+ }
+ RenderNodeType::Path(path) => Some(vec![PaintOp::path(node.bbox, path.clone())]),
+ RenderNodeType::Image(image) => Some(vec![PaintOp::image(
+ node.bbox,
+ image.clone(),
+ crate::renderer::image_resolver::resolve_image_payload(image),
+ )]),
+ RenderNodeType::Equation(equation) => {
+ Some(vec![PaintOp::equation(node.bbox, equation.clone())])
+ }
+ RenderNodeType::FormObject(form) => {
+ Some(vec![PaintOp::form_object(node.bbox, form.clone())])
+ }
+ RenderNodeType::Placeholder(placeholder) => {
+ Some(vec![PaintOp::placeholder(node.bbox, placeholder.clone())])
+ }
+ RenderNodeType::RawSvg(raw) => Some(vec![PaintOp::raw_svg(node.bbox, raw.clone())]),
_ => None,
};
@@ -251,48 +235,36 @@ fn text_run_ops(
+ has_strikethrough as usize
+ has_emphasis_dot as usize,
);
- ops.push(PaintOp::TextRun {
- bbox,
- run: run.clone(),
- });
+ ops.push(PaintOp::text_run(bbox, run.clone()));
if has_char_overlap {
- ops.push(PaintOp::CharOverlap {
- bbox,
- run: run.clone(),
- });
+ ops.push(PaintOp::char_overlap(bbox, run.clone()));
}
if has_control_mark {
- ops.push(PaintOp::TextControlMark {
- bbox,
- run: run.clone(),
- });
+ ops.push(PaintOp::text_control_mark(bbox, run.clone()));
}
if has_tab_leader {
- ops.push(PaintOp::TabLeader {
- bbox,
- run: run.clone(),
- });
+ ops.push(PaintOp::tab_leader(bbox, run.clone()));
}
if has_underline {
- ops.push(PaintOp::TextDecoration {
+ ops.push(PaintOp::text_decoration(
bbox,
- run: run.clone(),
- kind: TextDecorationKind::Underline,
- });
+ run.clone(),
+ TextDecorationKind::Underline,
+ ));
}
if has_strikethrough {
- ops.push(PaintOp::TextDecoration {
+ ops.push(PaintOp::text_decoration(
bbox,
- run: run.clone(),
- kind: TextDecorationKind::Strikethrough,
- });
+ run.clone(),
+ TextDecorationKind::Strikethrough,
+ ));
}
if has_emphasis_dot {
- ops.push(PaintOp::TextDecoration {
+ ops.push(PaintOp::text_decoration(
bbox,
run,
- kind: TextDecorationKind::EmphasisDot,
- });
+ TextDecorationKind::EmphasisDot,
+ ));
}
ops
}
diff --git a/src/paint/json.rs b/src/paint/json.rs
index a02761952..10dc2201f 100644
--- a/src/paint/json.rs
+++ b/src/paint/json.rs
@@ -2582,9 +2582,9 @@ mod tests {
#[test]
fn serializes_text_and_shape_ops_for_browser_replay() {
- let text = PaintOp::TextRun {
- bbox: BoundingBox::new(10.0, 20.0, 80.0, 18.0),
- run: TextRunNode {
+ let text = PaintOp::text_run(
+ BoundingBox::new(10.0, 20.0, 80.0, 18.0),
+ TextRunNode {
text: "가A".to_string(),
style: TextStyle {
font_family: "Noto Sans KR".to_string(),
@@ -2615,10 +2615,10 @@ mod tests {
baseline: 13.0,
field_marker: FieldMarkerType::FieldBegin,
},
- };
- let rect = PaintOp::Rectangle {
- bbox: BoundingBox::new(8.0, 18.0, 84.0, 22.0),
- rect: crate::renderer::render_tree::RectangleNode::new(
+ );
+ let rect = PaintOp::rectangle(
+ BoundingBox::new(8.0, 18.0, 84.0, 22.0),
+ crate::renderer::render_tree::RectangleNode::new(
4.0,
ShapeStyle {
fill_color: Some(0x00F0F1F2),
@@ -2628,7 +2628,7 @@ mod tests {
},
None,
),
- };
+ );
let tree = PageLayerTree::new(
120.0,
@@ -2725,9 +2725,9 @@ mod tests {
let display_text = "(인)(Signature)";
let source_positions = compute_char_positions(text, &style);
let display_positions = compute_char_positions(display_text, &style);
- let text_run = PaintOp::TextRun {
- bbox: BoundingBox::new(10.0, 20.0, 80.0, 18.0),
- run: TextRunNode {
+ let text_run = PaintOp::text_run(
+ BoundingBox::new(10.0, 20.0, 80.0, 18.0),
+ TextRunNode {
text: text.to_string(),
style: style.clone(),
char_shape_id: None,
@@ -2745,7 +2745,7 @@ mod tests {
baseline: 13.0,
field_marker: FieldMarkerType::None,
},
- };
+ );
let tree = PageLayerTree::new(
120.0,
80.0,
@@ -2783,9 +2783,9 @@ mod tests {
#[test]
fn serializes_empty_display_positions_for_hidden_pua_filler() {
- let text_run = PaintOp::TextRun {
- bbox: BoundingBox::new(10.0, 20.0, 80.0, 18.0),
- run: TextRunNode {
+ let text_run = PaintOp::text_run(
+ BoundingBox::new(10.0, 20.0, 80.0, 18.0),
+ TextRunNode {
text: "\u{F081C}".to_string(),
style: TextStyle {
font_family: "Noto Sans KR".to_string(),
@@ -2807,7 +2807,7 @@ mod tests {
baseline: 13.0,
field_marker: FieldMarkerType::None,
},
- };
+ );
let tree = PageLayerTree::new(
120.0,
80.0,
@@ -2868,32 +2868,12 @@ mod tests {
BoundingBox::new(0.0, 0.0, 120.0, 80.0),
None,
vec![
- PaintOp::TextRun {
- bbox,
- run: run.clone(),
- },
- PaintOp::CharOverlap {
- bbox,
- run: run.clone(),
- },
- PaintOp::TextControlMark {
- bbox,
- run: run.clone(),
- },
- PaintOp::TabLeader {
- bbox,
- run: run.clone(),
- },
- PaintOp::TextDecoration {
- bbox,
- run: run.clone(),
- kind: TextDecorationKind::Underline,
- },
- PaintOp::TextDecoration {
- bbox,
- run,
- kind: TextDecorationKind::EmphasisDot,
- },
+ PaintOp::text_run(bbox, run.clone()),
+ PaintOp::char_overlap(bbox, run.clone()),
+ PaintOp::text_control_mark(bbox, run.clone()),
+ PaintOp::tab_leader(bbox, run.clone()),
+ PaintOp::text_decoration(bbox, run.clone(), TextDecorationKind::Underline),
+ PaintOp::text_decoration(bbox, run, TextDecorationKind::EmphasisDot),
],
),
);
@@ -2940,9 +2920,9 @@ mod tests {
shaping_engine: ShapingEngineId("test".to_string()),
fallback_policy: FontFallbackPolicyId("none".to_string()),
};
- let text_run = PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
- run: TextRunNode {
+ let text_run = PaintOp::text_run(
+ BoundingBox::new(0.0, 0.0, 20.0, 20.0),
+ TextRunNode {
text: "A".to_string(),
style: TextStyle {
font_family: "Test".to_string(),
@@ -2965,7 +2945,7 @@ mod tests {
baseline: 12.0,
field_marker: FieldMarkerType::None,
},
- };
+ );
let glyph_run = PaintOp::GlyphRun {
bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
run: Box::new(LayerGlyphRunPaint {
@@ -3119,9 +3099,9 @@ mod tests {
utf16_range: TextSourceRange::new(0, 1),
stable_source_key: None,
};
- let text_run = PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
- run: TextRunNode {
+ let text_run = PaintOp::text_run(
+ BoundingBox::new(0.0, 0.0, 20.0, 20.0),
+ TextRunNode {
text: "A".to_string(),
style: TextStyle {
font_family: "Test".to_string(),
@@ -3144,7 +3124,7 @@ mod tests {
baseline: 12.0,
field_marker: FieldMarkerType::None,
},
- };
+ );
let outline = PaintOp::GlyphOutline {
bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
outline: Box::new(LayerGlyphOutlinePaint {
@@ -3605,18 +3585,11 @@ mod tests {
BoundingBox::new(0.0, 0.0, 120.0, 80.0),
None,
vec![
- PaintOp::Path {
- bbox: BoundingBox::new(1.0, 2.0, 30.0, 20.0),
- path,
- },
- PaintOp::Image {
- bbox: BoundingBox::new(3.0, 4.0, 30.0, 20.0),
- image,
- resolved: None,
- },
- PaintOp::Equation {
- bbox: BoundingBox::new(5.0, 6.0, 30.0, 20.0),
- equation: EquationNode {
+ PaintOp::path(BoundingBox::new(1.0, 2.0, 30.0, 20.0), path),
+ PaintOp::image(BoundingBox::new(3.0, 4.0, 30.0, 20.0), image, None),
+ PaintOp::equation(
+ BoundingBox::new(5.0, 6.0, 30.0, 20.0),
+ EquationNode {
svg_content: "x".to_string(),
layout_box: LayoutBox {
x: 0.0,
@@ -3636,21 +3609,21 @@ mod tests {
cell_para_index: None,
note_ref: None,
},
- },
- PaintOp::Placeholder {
- bbox: BoundingBox::new(7.0, 8.0, 30.0, 20.0),
- placeholder: PlaceholderNode {
+ ),
+ PaintOp::placeholder(
+ BoundingBox::new(7.0, 8.0, 30.0, 20.0),
+ PlaceholderNode {
fill_color: 0x00F0F0F0,
stroke_color: 0x00000000,
label: "OLE".to_string(),
},
- },
- PaintOp::RawSvg {
- bbox: BoundingBox::new(9.0, 10.0, 30.0, 20.0),
- raw: RawSvgNode {
+ ),
+ PaintOp::raw_svg(
+ BoundingBox::new(9.0, 10.0, 30.0, 20.0),
+ RawSvgNode {
svg: "".to_string(),
},
- },
+ ),
],
),
);
diff --git a/src/paint/paint_op.rs b/src/paint/paint_op.rs
index 33788af42..91c62b800 100644
--- a/src/paint/paint_op.rs
+++ b/src/paint/paint_op.rs
@@ -49,11 +49,11 @@ pub struct ResolvedImagePayload {
pub enum PaintOp {
PageBackground {
bbox: BoundingBox,
- background: PageBackgroundNode,
+ background: Box,
},
TextRun {
bbox: BoundingBox,
- run: TextRunNode,
+ run: Box,
},
GlyphRun {
bbox: BoundingBox,
@@ -69,68 +69,200 @@ pub enum PaintOp {
/// 새 backend는 이 op를 선택하고 TextRun mirror를 건너뛸 수 있다.
CharOverlap {
bbox: BoundingBox,
- run: TextRunNode,
+ run: Box,
},
/// 문단 끝/줄 바꿈/필드 마커처럼 source text와 visual projection이 다른 표식.
TextControlMark {
bbox: BoundingBox,
- run: TextRunNode,
+ run: Box,
},
/// 탭 리더 visual geometry.
TabLeader {
bbox: BoundingBox,
- run: TextRunNode,
+ run: Box,
},
/// 밑줄/취소선/강조점 visual geometry.
TextDecoration {
bbox: BoundingBox,
- run: TextRunNode,
+ run: Box,
kind: TextDecorationKind,
},
FootnoteMarker {
bbox: BoundingBox,
- marker: FootnoteMarkerNode,
+ marker: Box,
},
Line {
bbox: BoundingBox,
- line: LineNode,
+ line: Box,
},
Rectangle {
bbox: BoundingBox,
- rect: RectangleNode,
+ rect: Box,
},
Ellipse {
bbox: BoundingBox,
- ellipse: EllipseNode,
+ ellipse: Box,
},
Path {
bbox: BoundingBox,
- path: PathNode,
+ path: Box,
},
Image {
bbox: BoundingBox,
- image: ImageNode,
+ image: Box,
resolved: Option>,
},
Equation {
bbox: BoundingBox,
- equation: EquationNode,
+ equation: Box,
},
FormObject {
bbox: BoundingBox,
- form: FormObjectNode,
+ form: Box,
},
Placeholder {
bbox: BoundingBox,
- placeholder: PlaceholderNode,
+ placeholder: Box,
},
RawSvg {
bbox: BoundingBox,
- raw: RawSvgNode,
+ raw: Box,
},
}
impl PaintOp {
+ pub fn page_background(bbox: BoundingBox, background: PageBackgroundNode) -> Self {
+ Self::PageBackground {
+ bbox,
+ background: Box::new(background),
+ }
+ }
+
+ pub fn text_run(bbox: BoundingBox, run: TextRunNode) -> Self {
+ Self::TextRun {
+ bbox,
+ run: Box::new(run),
+ }
+ }
+
+ pub fn glyph_run(bbox: BoundingBox, run: LayerGlyphRunPaint) -> Self {
+ Self::GlyphRun {
+ bbox,
+ run: Box::new(run),
+ }
+ }
+
+ pub fn glyph_outline(bbox: BoundingBox, outline: LayerGlyphOutlinePaint) -> Self {
+ Self::GlyphOutline {
+ bbox,
+ outline: Box::new(outline),
+ }
+ }
+
+ pub fn char_overlap(bbox: BoundingBox, run: TextRunNode) -> Self {
+ Self::CharOverlap {
+ bbox,
+ run: Box::new(run),
+ }
+ }
+
+ pub fn text_control_mark(bbox: BoundingBox, run: TextRunNode) -> Self {
+ Self::TextControlMark {
+ bbox,
+ run: Box::new(run),
+ }
+ }
+
+ pub fn tab_leader(bbox: BoundingBox, run: TextRunNode) -> Self {
+ Self::TabLeader {
+ bbox,
+ run: Box::new(run),
+ }
+ }
+
+ pub fn text_decoration(bbox: BoundingBox, run: TextRunNode, kind: TextDecorationKind) -> Self {
+ Self::TextDecoration {
+ bbox,
+ run: Box::new(run),
+ kind,
+ }
+ }
+
+ pub fn footnote_marker(bbox: BoundingBox, marker: FootnoteMarkerNode) -> Self {
+ Self::FootnoteMarker {
+ bbox,
+ marker: Box::new(marker),
+ }
+ }
+
+ pub fn line(bbox: BoundingBox, line: LineNode) -> Self {
+ Self::Line {
+ bbox,
+ line: Box::new(line),
+ }
+ }
+
+ pub fn rectangle(bbox: BoundingBox, rect: RectangleNode) -> Self {
+ Self::Rectangle {
+ bbox,
+ rect: Box::new(rect),
+ }
+ }
+
+ pub fn ellipse(bbox: BoundingBox, ellipse: EllipseNode) -> Self {
+ Self::Ellipse {
+ bbox,
+ ellipse: Box::new(ellipse),
+ }
+ }
+
+ pub fn path(bbox: BoundingBox, path: PathNode) -> Self {
+ Self::Path {
+ bbox,
+ path: Box::new(path),
+ }
+ }
+
+ pub fn image(
+ bbox: BoundingBox,
+ image: ImageNode,
+ resolved: Option,
+ ) -> Self {
+ Self::Image {
+ bbox,
+ image: Box::new(image),
+ resolved: resolved.map(Box::new),
+ }
+ }
+
+ pub fn equation(bbox: BoundingBox, equation: EquationNode) -> Self {
+ Self::Equation {
+ bbox,
+ equation: Box::new(equation),
+ }
+ }
+
+ pub fn form_object(bbox: BoundingBox, form: FormObjectNode) -> Self {
+ Self::FormObject {
+ bbox,
+ form: Box::new(form),
+ }
+ }
+
+ pub fn placeholder(bbox: BoundingBox, placeholder: PlaceholderNode) -> Self {
+ Self::Placeholder {
+ bbox,
+ placeholder: Box::new(placeholder),
+ }
+ }
+
+ pub fn raw_svg(bbox: BoundingBox, raw: RawSvgNode) -> Self {
+ Self::RawSvg {
+ bbox,
+ raw: Box::new(raw),
+ }
+ }
+
pub fn bounds(&self) -> BoundingBox {
match self {
PaintOp::PageBackground { bbox, .. }
diff --git a/src/paint/replay_order.rs b/src/paint/replay_order.rs
index 9cb83358d..249461571 100644
--- a/src/paint/replay_order.rs
+++ b/src/paint/replay_order.rs
@@ -105,11 +105,7 @@ mod tests {
fn image_with_wrap(wrap: Option) -> PaintOp {
let mut image = ImageNode::new(1, Some(vec![1, 2, 3]));
image.text_wrap = wrap;
- PaintOp::Image {
- bbox: bbox(),
- image,
- resolved: None,
- }
+ PaintOp::image(bbox(), image, None)
}
#[test]
@@ -122,16 +118,16 @@ mod tests {
#[test]
fn page_background_replays_on_background_plane() {
- let op = PaintOp::PageBackground {
- bbox: bbox(),
- background: PageBackgroundNode {
+ let op = PaintOp::page_background(
+ bbox(),
+ PageBackgroundNode {
background_color: None,
border_color: None,
border_width: 0.0,
gradient: None,
image: None,
},
- };
+ );
assert_eq!(paint_op_replay_plane(&op), PaintReplayPlane::Background);
}
@@ -154,10 +150,8 @@ mod tests {
fn non_layered_ops_replay_on_flow_plane() {
let plain_image = image_with_wrap(None);
let top_and_bottom_image = image_with_wrap(Some(TextWrap::TopAndBottom));
- let vector = PaintOp::Rectangle {
- bbox: bbox(),
- rect: RectangleNode::new(0.0, ShapeStyle::default(), None),
- };
+ let vector =
+ PaintOp::rectangle(bbox(), RectangleNode::new(0.0, ShapeStyle::default(), None));
assert_eq!(paint_op_replay_plane(&plain_image), PaintReplayPlane::Flow);
assert_eq!(
@@ -169,10 +163,8 @@ mod tests {
#[test]
fn render_layer_metadata_overrides_non_image_paint_ops() {
- let vector = PaintOp::Rectangle {
- bbox: bbox(),
- rect: RectangleNode::new(0.0, ShapeStyle::default(), None),
- };
+ let vector =
+ PaintOp::rectangle(bbox(), RectangleNode::new(0.0, ShapeStyle::default(), None));
let behind_layer = RenderLayerInfo::new(Some(TextWrap::BehindText), 1, 1);
let front_layer = RenderLayerInfo::new(Some(TextWrap::InFrontOfText), 2, 2);
@@ -216,10 +208,10 @@ mod tests {
let child = LayerNode::leaf(
bbox(),
None,
- vec![PaintOp::Rectangle {
- bbox: bbox(),
- rect: RectangleNode::new(0.0, ShapeStyle::default(), None),
- }],
+ vec![PaintOp::rectangle(
+ bbox(),
+ RectangleNode::new(0.0, ShapeStyle::default(), None),
+ )],
);
let group = LayerNode::group(
bbox(),
diff --git a/src/paint/text_shape.rs b/src/paint/text_shape.rs
index c837c4201..5c23aa88c 100644
--- a/src/paint/text_shape.rs
+++ b/src/paint/text_shape.rs
@@ -513,10 +513,10 @@ mod tests {
let root = LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 100.0, 100.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
- run: text_run("A"),
- }],
+ vec![PaintOp::text_run(
+ BoundingBox::new(0.0, 0.0, 20.0, 20.0),
+ text_run("A"),
+ )],
);
let lowerer = TextShapeLowerer::diagnostics_only(&PortableResolver);
let report = lowerer.analyze_root(&root);
@@ -539,10 +539,10 @@ mod tests {
let mut root = LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 100.0, 100.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
- run: text_run("A"),
- }],
+ vec![PaintOp::text_run(
+ BoundingBox::new(0.0, 0.0, 20.0, 20.0),
+ text_run("A"),
+ )],
);
let lowerer = TextShapeLowerer::new(&PortableResolver);
let report = lowerer.lower_root(&mut root);
@@ -574,10 +574,10 @@ mod tests {
let mut root = LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 100.0, 100.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
- run: text_run("A"),
- }],
+ vec![PaintOp::text_run(
+ BoundingBox::new(0.0, 0.0, 20.0, 20.0),
+ text_run("A"),
+ )],
);
let lowerer = TextShapeLowerer::new(&EmittingResolver);
let report = lowerer.lower_root(&mut root);
@@ -603,10 +603,10 @@ mod tests {
let mut root = LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 100.0, 100.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
- run: text_run("A"),
- }],
+ vec![PaintOp::text_run(
+ BoundingBox::new(0.0, 0.0, 20.0, 20.0),
+ text_run("A"),
+ )],
);
let lowerer = TextShapeLowerer::new(&EmittingResolver);
let first_report = lowerer.lower_root(&mut root);
@@ -632,10 +632,10 @@ mod tests {
let mut root = LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 100.0, 100.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
+ vec![PaintOp::text_run(
+ BoundingBox::new(0.0, 0.0, 20.0, 20.0),
run,
- }],
+ )],
);
let lowerer = TextShapeLowerer::new(&EmittingResolver);
let report = lowerer.lower_root(&mut root);
diff --git a/src/paint/text_v2.rs b/src/paint/text_v2.rs
index 08e9c102d..c6883dc0f 100644
--- a/src/paint/text_v2.rs
+++ b/src/paint/text_v2.rs
@@ -830,10 +830,7 @@ mod tests {
}
fn text_op(text: &str) -> PaintOp {
- PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
- run: text_run(text),
- }
+ PaintOp::text_run(BoundingBox::new(0.0, 0.0, 20.0, 20.0), text_run(text))
}
fn add_portable_font_resources(resources: &mut ResourceArena) {
@@ -1458,10 +1455,10 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 100.0, 100.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
+ vec![PaintOp::text_run(
+ BoundingBox::new(0.0, 0.0, 20.0, 20.0),
run,
- }],
+ )],
),
);
let diagnostics = TextV2Diagnostics::from_layer_tree(&tree);
@@ -1486,10 +1483,7 @@ mod tests {
BoundingBox::new(0.0, 0.0, 100.0, 100.0),
None,
vec![
- PaintOp::TextRun {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
- run,
- },
+ PaintOp::text_run(BoundingBox::new(0.0, 0.0, 20.0, 20.0), run),
glyph_op_for_text("A\tB", None, 0),
],
),
diff --git a/src/paint/text_variants.rs b/src/paint/text_variants.rs
index 722adac6e..a5e78464e 100644
--- a/src/paint/text_variants.rs
+++ b/src/paint/text_variants.rs
@@ -325,9 +325,9 @@ mod tests {
}
fn text_op() -> PaintOp {
- PaintOp::TextRun {
- bbox: bbox(),
- run: TextRunNode {
+ PaintOp::text_run(
+ bbox(),
+ TextRunNode {
text: "A".to_string(),
style: TextStyle::default(),
char_shape_id: None,
@@ -345,7 +345,7 @@ mod tests {
baseline: 10.0,
field_marker: FieldMarkerType::None,
},
- }
+ )
}
fn glyph_op(variant: PaintVariantMeta) -> PaintOp {
diff --git a/src/renderer/canvaskit_policy.rs b/src/renderer/canvaskit_policy.rs
index 6980d7b0a..3a9fa6dd7 100644
--- a/src/renderer/canvaskit_policy.rs
+++ b/src/renderer/canvaskit_policy.rs
@@ -825,11 +825,11 @@ mod tests {
#[test]
fn default_mode_reports_simple_image_as_direct() {
- let tree = tree_with_ops(vec![PaintOp::Image {
- bbox: bbox(),
- image: ImageNode::new(1, Some(vec![1, 2, 3])),
- resolved: None,
- }]);
+ let tree = tree_with_ops(vec![PaintOp::image(
+ bbox(),
+ ImageNode::new(1, Some(vec![1, 2, 3])),
+ None,
+ )]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -847,11 +847,11 @@ mod tests {
#[test]
fn compat_mode_reports_simple_image_as_direct() {
- let tree = tree_with_ops(vec![PaintOp::Image {
- bbox: bbox(),
- image: ImageNode::new(1, Some(vec![1, 2, 3])),
- resolved: None,
- }]);
+ let tree = tree_with_ops(vec![PaintOp::image(
+ bbox(),
+ ImageNode::new(1, Some(vec![1, 2, 3])),
+ None,
+ )]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Compat);
@@ -876,11 +876,7 @@ mod tests {
image.crop = Some((10, 20, 90, 80));
image.transform.rotation = 15.0;
- let tree = tree_with_ops(vec![PaintOp::Image {
- bbox: bbox(),
- image,
- resolved: None,
- }]);
+ let tree = tree_with_ops(vec![PaintOp::image(bbox(), image, None)]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -898,11 +894,7 @@ mod tests {
image.brightness = 10;
image.contrast = -20;
- let tree = tree_with_ops(vec![PaintOp::Image {
- bbox: bbox(),
- image,
- resolved: None,
- }]);
+ let tree = tree_with_ops(vec![PaintOp::image(bbox(), image, None)]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -920,16 +912,16 @@ mod tests {
image.brightness = 70;
image.contrast = -50;
- let tree = tree_with_ops(vec![PaintOp::Image {
- bbox: bbox(),
+ let tree = tree_with_ops(vec![PaintOp::image(
+ bbox(),
image,
- resolved: Some(Box::new(ResolvedImagePayload {
+ Some(ResolvedImagePayload {
data: vec![4, 5, 6],
mime: "image/png",
kind: ResolvedImageKind::BakedWatermark,
suppress_effects: true,
- })),
- }]);
+ }),
+ )]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -948,24 +940,10 @@ mod tests {
front.text_wrap = Some(TextWrap::InFrontOfText);
let tree = tree_with_ops(vec![
- PaintOp::PageBackground {
- bbox: bbox(),
- background: page_background(None, None),
- },
- PaintOp::Image {
- bbox: bbox(),
- image: behind,
- resolved: None,
- },
- PaintOp::TextRun {
- bbox: bbox(),
- run: text_run("A"),
- },
- PaintOp::Image {
- bbox: bbox(),
- image: front,
- resolved: None,
- },
+ PaintOp::page_background(bbox(), page_background(None, None)),
+ PaintOp::image(bbox(), behind, None),
+ PaintOp::text_run(bbox(), text_run("A")),
+ PaintOp::image(bbox(), front, None),
]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -989,20 +967,14 @@ mod tests {
let layered_rect = LayerNode::leaf(
bbox(),
None,
- vec![PaintOp::Rectangle {
- bbox: bbox(),
- rect: RectangleNode::new(0.0, ShapeStyle::default(), None),
- }],
+ vec![PaintOp::rectangle(
+ bbox(),
+ RectangleNode::new(0.0, ShapeStyle::default(), None),
+ )],
)
.with_layer(Some(RenderLayerInfo::new(Some(TextWrap::BehindText), 1, 1)));
- let flow_text = LayerNode::leaf(
- bbox(),
- None,
- vec![PaintOp::TextRun {
- bbox: bbox(),
- run: text_run("A"),
- }],
- );
+ let flow_text =
+ LayerNode::leaf(bbox(), None, vec![PaintOp::text_run(bbox(), text_run("A"))]);
let tree = PageLayerTree::new(
100.0,
100.0,
@@ -1034,11 +1006,7 @@ mod tests {
let mut image = ImageNode::new(1, Some(vec![1, 2, 3]));
image.external_path = Some("linked-image.png".to_string());
- let tree = tree_with_ops(vec![PaintOp::Image {
- bbox: bbox(),
- image,
- resolved: None,
- }]);
+ let tree = tree_with_ops(vec![PaintOp::image(bbox(), image, None)]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -1054,11 +1022,7 @@ mod tests {
let mut image = ImageNode::new(1, None);
image.external_path = Some("linked-image.png".to_string());
- let tree = tree_with_ops(vec![PaintOp::Image {
- bbox: bbox(),
- image,
- resolved: None,
- }]);
+ let tree = tree_with_ops(vec![PaintOp::image(bbox(), image, None)]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -1093,14 +1057,8 @@ mod tests {
})),
);
let tree = tree_with_ops(vec![
- PaintOp::PageBackground {
- bbox: bbox(),
- background: image_background,
- },
- PaintOp::PageBackground {
- bbox: bbox(),
- background: gradient_background,
- },
+ PaintOp::page_background(bbox(), image_background),
+ PaintOp::page_background(bbox(), gradient_background),
]);
let default_plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -1131,14 +1089,8 @@ mod tests {
let mut vertical = text_run("A");
vertical.is_vertical = true;
let tree = tree_with_ops(vec![
- PaintOp::TextRun {
- bbox: bbox(),
- run: text_run("A"),
- },
- PaintOp::TextRun {
- bbox: bbox(),
- run: vertical,
- },
+ PaintOp::text_run(bbox(), text_run("A")),
+ PaintOp::text_run(bbox(), vertical),
]);
let default_plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -1158,10 +1110,7 @@ mod tests {
#[test]
fn text_run_op_type_matches_layer_tree_schema_name() {
- let tree = tree_with_ops(vec![PaintOp::TextRun {
- bbox: bbox(),
- run: text_run("A"),
- }]);
+ let tree = tree_with_ops(vec![PaintOp::text_run(bbox(), text_run("A"))]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
@@ -1170,9 +1119,9 @@ mod tests {
#[test]
fn footnote_marker_is_reported_as_text_special_visual() {
- let tree = tree_with_ops(vec![PaintOp::FootnoteMarker {
- bbox: bbox(),
- marker: FootnoteMarkerNode {
+ let tree = tree_with_ops(vec![PaintOp::footnote_marker(
+ bbox(),
+ FootnoteMarkerNode {
number: 1,
text: "1)".to_string(),
base_font_size: 12.0,
@@ -1182,7 +1131,7 @@ mod tests {
para_index: 0,
control_index: 0,
},
- }]);
+ )]);
let default_plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
assert_eq!(
@@ -1220,10 +1169,7 @@ mod tests {
#[test]
fn replay_plan_serializes_mode_and_summary() {
- let tree = tree_with_ops(vec![PaintOp::TextRun {
- bbox: bbox(),
- run: text_run("A"),
- }]);
+ let tree = tree_with_ops(vec![PaintOp::text_run(bbox(), text_run("A"))]);
let plan = analyze_canvaskit_replay_plan(&tree, CanvasKitReplayMode::Default);
let json = serde_json::to_string(&plan).expect("serialize CanvasKit replay plan");
diff --git a/src/renderer/layer_renderer.rs b/src/renderer/layer_renderer.rs
index 836dfa728..00d7248d4 100644
--- a/src/renderer/layer_renderer.rs
+++ b/src/renderer/layer_renderer.rs
@@ -784,9 +784,9 @@ mod tests {
}
fn text_op() -> PaintOp {
- PaintOp::TextRun {
- bbox: bbox(),
- run: TextRunNode {
+ PaintOp::text_run(
+ bbox(),
+ TextRunNode {
text: "A".to_string(),
style: TextStyle {
font_family: "Test".to_string(),
@@ -809,7 +809,7 @@ mod tests {
baseline: 12.0,
field_marker: FieldMarkerType::None,
},
- }
+ )
}
fn variant(kind: TextVariantKind, id: &str) -> PaintVariantMeta {
diff --git a/src/renderer/skia/equation_conv.rs b/src/renderer/skia/equation_conv.rs
index 18ff62200..468e7f329 100644
--- a/src/renderer/skia/equation_conv.rs
+++ b/src/renderer/skia/equation_conv.rs
@@ -1,6 +1,8 @@
use skia_safe::{font, paint, Canvas, Color, Font, FontMgr, FontStyle, Paint, PathBuilder};
-use super::font_lookup::{match_system_family_style, SystemFontFamilies};
+use super::font_lookup::{
+ legacy_typeface_for_style, match_system_family_style, SystemFontFamilies,
+};
use crate::renderer::equation::ast::MatrixStyle;
use crate::renderer::equation::layout::{
@@ -699,7 +701,7 @@ fn draw_text(
.map(str::trim)
.filter(|family| !family.is_empty())
.find_map(|family| match_system_family_style(font_mgr, system_families, family, font_style))
- .or_else(|| font_mgr.legacy_make_typeface(None::<&str>, font_style));
+ .or_else(|| legacy_typeface_for_style(font_mgr, font_style));
let mut font = if let Some(typeface) = typeface {
Font::new(typeface, font_size as f32)
} else {
diff --git a/src/renderer/skia/font_lookup.rs b/src/renderer/skia/font_lookup.rs
index 15c89c18f..fca21c536 100644
--- a/src/renderer/skia/font_lookup.rs
+++ b/src/renderer/skia/font_lookup.rs
@@ -1,9 +1,40 @@
-use std::collections::HashSet;
+use std::cell::RefCell;
+use std::collections::{HashMap, HashSet};
use skia_safe::{FontMgr, FontStyle, Typeface};
pub(super) type SystemFontFamilies = HashSet;
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+struct FontStyleCacheKey {
+ weight: i32,
+ width: i32,
+ slant: i32,
+}
+
+impl FontStyleCacheKey {
+ fn new(style: FontStyle) -> Self {
+ Self {
+ weight: *style.weight(),
+ width: *style.width(),
+ slant: style.slant() as i32,
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+struct FontLookupKey {
+ family: String,
+ style: FontStyleCacheKey,
+}
+
+thread_local! {
+ static SYSTEM_TYPEFACE_CACHE: RefCell>> =
+ RefCell::new(HashMap::new());
+ static LEGACY_TYPEFACE_CACHE: RefCell>> =
+ RefCell::new(HashMap::new());
+}
+
pub(super) fn collect_system_families(font_mgr: &FontMgr) -> SystemFontFamilies {
font_mgr.family_names().collect()
}
@@ -18,11 +49,36 @@ pub(super) fn match_system_family_style(
family: &str,
style: FontStyle,
) -> Option {
- if has_system_family(system_families, family) {
- font_mgr.match_family_style(family, style)
- } else {
- None
+ if !has_system_family(system_families, family) {
+ return None;
}
+
+ let key = FontLookupKey {
+ family: family.to_string(),
+ style: FontStyleCacheKey::new(style),
+ };
+ SYSTEM_TYPEFACE_CACHE.with(|cache| {
+ if let Some(cached) = { cache.borrow().get(&key).cloned() } {
+ return cached;
+ }
+
+ let matched = font_mgr.match_family_style(family, style);
+ cache.borrow_mut().insert(key, matched.clone());
+ matched
+ })
+}
+
+pub(super) fn legacy_typeface_for_style(font_mgr: &FontMgr, style: FontStyle) -> Option {
+ let key = FontStyleCacheKey::new(style);
+ LEGACY_TYPEFACE_CACHE.with(|cache| {
+ if let Some(cached) = { cache.borrow().get(&key).cloned() } {
+ return cached;
+ }
+
+ let matched = font_mgr.legacy_make_typeface(None::<&str>, style);
+ cache.borrow_mut().insert(key, matched.clone());
+ matched
+ })
}
#[cfg(test)]
diff --git a/src/renderer/skia/image_conv.rs b/src/renderer/skia/image_conv.rs
index b4dba6bfe..0212c2aee 100644
--- a/src/renderer/skia/image_conv.rs
+++ b/src/renderer/skia/image_conv.rs
@@ -3,6 +3,7 @@ use skia_safe::{
canvas::SrcRectConstraint, color_filters, image::RequiredProperties, Color, Data, FilterMode,
IRect, Image, Matrix, MipmapMode, Paint, Rect, SamplingOptions, TileMode,
};
+use std::sync::{Arc, OnceLock};
use crate::model::image::ImageEffect;
use crate::model::style::ImageFillMode;
@@ -361,10 +362,21 @@ fn svg_parse_options() -> usvg::Options<'static> {
resolve_data: usvg::ImageHrefResolver::default_data_resolver(),
resolve_string: Box::new(|_, _| None),
};
- let fontdb = options.fontdb_mut();
- fontdb.load_system_fonts();
- fontdb.set_sans_serif_family("Noto Sans CJK KR");
- fontdb.set_serif_family("Noto Serif CJK KR");
- fontdb.set_monospace_family("D2Coding");
+ options.fontdb = svg_fontdb();
options
}
+
+fn svg_fontdb() -> Arc {
+ static SVG_FONTDB: OnceLock> = OnceLock::new();
+
+ SVG_FONTDB
+ .get_or_init(|| {
+ let mut fontdb = usvg::fontdb::Database::new();
+ fontdb.load_system_fonts();
+ fontdb.set_sans_serif_family("Noto Sans CJK KR");
+ fontdb.set_serif_family("Noto Serif CJK KR");
+ fontdb.set_monospace_family("D2Coding");
+ Arc::new(fontdb)
+ })
+ .clone()
+}
diff --git a/src/renderer/skia/renderer.rs b/src/renderer/skia/renderer.rs
index 0d6095b3a..71badc5e9 100644
--- a/src/renderer/skia/renderer.rs
+++ b/src/renderer/skia/renderer.rs
@@ -1,6 +1,6 @@
use skia_safe::{
- paint, surfaces, Canvas, Color, EncodedImageFormat, Font, FontMgr, FontStyle, Paint,
- PathBuilder, PathEffect, RRect, Rect, Typeface,
+ paint, png_encoder, surfaces, Canvas, Color, Font, FontMgr, FontStyle, Paint, PathBuilder,
+ PathEffect, RRect, Rect, Typeface,
};
use std::borrow::Cow;
use std::collections::{BTreeSet, HashMap, HashSet};
@@ -23,7 +23,10 @@ use crate::renderer::render_tree::RenderLayerInfo;
use crate::renderer::{svg_arc_to_beziers, LineStyle, PathCommand, ShapeStyle, StrokeDash};
use super::equation_conv::render_equation;
-use super::font_lookup::{collect_system_families, match_system_family_style, SystemFontFamilies};
+use super::font_lookup::{
+ collect_system_families, legacy_typeface_for_style, match_system_family_style,
+ SystemFontFamilies,
+};
use super::image_conv::{draw_image_bytes, draw_svg_fragment, ImageSampling};
use super::text_replay::SkiaTextReplay;
@@ -401,6 +404,7 @@ impl SkiaLayerRenderer {
if options.scale != 1.0 {
canvas.scale((options.scale as f32, options.scale as f32));
}
+
let mut next_text_source_id = 0_u32;
for replay_plane in PaintReplayPlane::ORDERED {
if !layer_node_has_replay_plane(&tree.root, replay_plane) {
@@ -418,9 +422,16 @@ impl SkiaLayerRenderer {
}
let image = surface.image_snapshot();
- let data = image
- .encode(None, EncodedImageFormat::PNG, None)
- .ok_or_else(|| HwpError::RenderError("Skia PNG 인코딩 실패".to_string()))?;
+ let mut png_options = png_encoder::Options::default();
+ // PNG is lossless at every zlib level. Level 1 avoids spending most of
+ // native export time on compression while preserving decoded pixels.
+ png_options.z_lib_level = 1;
+ let data = png_encoder::encode_image(
+ None::<&mut skia_safe::gpu::DirectContext>,
+ &image,
+ &png_options,
+ )
+ .ok_or_else(|| HwpError::RenderError("Skia PNG 인코딩 실패".to_string()))?;
Ok(RasterRenderOutput {
bytes: data.as_bytes().to_vec(),
format: RasterOutputFormat::Png,
@@ -1137,7 +1148,7 @@ impl SkiaLayerRenderer {
return Font::new(tf, size);
}
}
- if let Some(tf) = self.font_mgr.legacy_make_typeface(None::<&str>, style) {
+ if let Some(tf) = legacy_typeface_for_style(&self.font_mgr, style) {
return Font::new(tf, size);
}
let mut f = Font::default();
@@ -1836,18 +1847,18 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, page_width, page_height),
None,
- vec![PaintOp::Rectangle {
+ vec![PaintOp::rectangle(
bbox,
- rect: RectangleNode::new(0.0, style, None),
- }],
+ RectangleNode::new(0.0, style, None),
+ )],
),
)
}
fn solid_rect_op(bbox: BoundingBox, fill_color: ColorRef) -> PaintOp {
- PaintOp::Rectangle {
+ PaintOp::rectangle(
bbox,
- rect: RectangleNode::new(
+ RectangleNode::new(
0.0,
ShapeStyle {
fill_color: Some(fill_color),
@@ -1855,17 +1866,13 @@ mod tests {
},
None,
),
- }
+ )
}
fn solid_image_op(bbox: BoundingBox, color: [u8; 4], wrap: TextWrap) -> PaintOp {
let mut image = ImageNode::new(1, Some(solid_png(color)));
image.text_wrap = Some(wrap);
- PaintOp::Image {
- bbox,
- image,
- resolved: None,
- }
+ PaintOp::image(bbox, image, None)
}
#[test]
@@ -1964,10 +1971,10 @@ mod tests {
let child = LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 20.0, 20.0),
None,
- vec![PaintOp::Rectangle {
- bbox: BoundingBox::new(0.0, 0.0, 20.0, 20.0),
- rect: RectangleNode::new(0.0, style, None),
- }],
+ vec![PaintOp::rectangle(
+ BoundingBox::new(0.0, 0.0, 20.0, 20.0),
+ RectangleNode::new(0.0, style, None),
+ )],
);
let clipped = PageLayerTree::new(
20.0,
@@ -2114,16 +2121,16 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 8.0, 8.0),
None,
- vec![PaintOp::PageBackground {
- bbox: BoundingBox::new(0.0, 0.0, 8.0, 8.0),
- background: PageBackgroundNode {
+ vec![PaintOp::page_background(
+ BoundingBox::new(0.0, 0.0, 8.0, 8.0),
+ PageBackgroundNode {
background_color: Some(0x0000ff00),
border_color: Some(0x00ff0000),
border_width: 2.0,
gradient: None,
image: None,
},
- }],
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2148,9 +2155,9 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 8.0, 8.0),
None,
- vec![PaintOp::PageBackground {
- bbox: BoundingBox::new(0.0, 0.0, 8.0, 8.0),
- background: PageBackgroundNode {
+ vec![PaintOp::page_background(
+ BoundingBox::new(0.0, 0.0, 8.0, 8.0),
+ PageBackgroundNode {
background_color: None,
border_color: None,
border_width: 0.0,
@@ -2163,7 +2170,7 @@ mod tests {
effect: crate::model::image::ImageEffect::RealPic,
}),
},
- }],
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2251,26 +2258,11 @@ mod tests {
BoundingBox::new(0.0, 0.0, 40.0, 40.0),
None,
vec![
- PaintOp::Rectangle {
- bbox: BoundingBox::new(2.0, 2.0, 10.0, 8.0),
- rect: gradient_rect,
- },
- PaintOp::Rectangle {
- bbox: BoundingBox::new(16.0, 2.0, 10.0, 8.0),
- rect: pattern_rect,
- },
- PaintOp::Ellipse {
- bbox: BoundingBox::new(2.0, 12.0, 10.0, 10.0),
- ellipse,
- },
- PaintOp::Path {
- bbox: BoundingBox::new(2.0, 24.0, 10.0, 10.0),
- path,
- },
- PaintOp::Line {
- bbox: BoundingBox::new(18.0, 28.0, 16.0, 4.0),
- line,
- },
+ PaintOp::rectangle(BoundingBox::new(2.0, 2.0, 10.0, 8.0), gradient_rect),
+ PaintOp::rectangle(BoundingBox::new(16.0, 2.0, 10.0, 8.0), pattern_rect),
+ PaintOp::ellipse(BoundingBox::new(2.0, 12.0, 10.0, 10.0), ellipse),
+ PaintOp::path(BoundingBox::new(2.0, 24.0, 10.0, 10.0), path),
+ PaintOp::line(BoundingBox::new(18.0, 28.0, 16.0, 4.0), line),
],
),
);
@@ -2311,10 +2303,7 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 24.0, 18.0),
None,
- vec![PaintOp::Path {
- bbox: BoundingBox::new(4.0, 4.0, 16.0, 12.0),
- path,
- }],
+ vec![PaintOp::path(BoundingBox::new(4.0, 4.0, 16.0, 12.0), path)],
),
);
let output = SkiaLayerRenderer::new()
@@ -2334,16 +2323,16 @@ mod tests {
BoundingBox::new(0.0, 0.0, 20.0, 10.0),
None,
vec![
- PaintOp::Image {
- bbox: BoundingBox::new(0.0, 0.0, 8.0, 8.0),
- image: ImageNode::new(1, Some(solid_png([0, 0, 255, 255]))),
- resolved: None,
- },
- PaintOp::Image {
- bbox: BoundingBox::new(10.0, 0.0, 8.0, 8.0),
- image: ImageNode::new(2, Some(vec![1, 2, 3, 4])),
- resolved: None,
- },
+ PaintOp::image(
+ BoundingBox::new(0.0, 0.0, 8.0, 8.0),
+ ImageNode::new(1, Some(solid_png([0, 0, 255, 255]))),
+ None,
+ ),
+ PaintOp::image(
+ BoundingBox::new(10.0, 0.0, 8.0, 8.0),
+ ImageNode::new(2, Some(vec![1, 2, 3, 4])),
+ None,
+ ),
],
),
);
@@ -2462,11 +2451,11 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 8.0, 8.0),
None,
- vec![PaintOp::Image {
- bbox: BoundingBox::new(0.0, 0.0, 8.0, 8.0),
- image: node,
- resolved: None,
- }],
+ vec![PaintOp::image(
+ BoundingBox::new(0.0, 0.0, 8.0, 8.0),
+ node,
+ None,
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2493,11 +2482,11 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 16.0, 4.0),
None,
- vec![PaintOp::Image {
- bbox: BoundingBox::new(0.0, 0.0, 16.0, 4.0),
- image: node,
- resolved: None,
- }],
+ vec![PaintOp::image(
+ BoundingBox::new(0.0, 0.0, 16.0, 4.0),
+ node,
+ None,
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2525,11 +2514,11 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 8.0, 8.0),
None,
- vec![PaintOp::Image {
- bbox: BoundingBox::new(0.0, 0.0, 8.0, 8.0),
- image: node,
- resolved: None,
- }],
+ vec![PaintOp::image(
+ BoundingBox::new(0.0, 0.0, 8.0, 8.0),
+ node,
+ None,
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2552,11 +2541,11 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 8.0, 8.0),
None,
- vec![PaintOp::Image {
- bbox: BoundingBox::new(f64::NAN, 0.0, 8.0, 8.0),
- image: ImageNode::new(1, Some(solid_png([255, 0, 0, 255]))),
- resolved: None,
- }],
+ vec![PaintOp::image(
+ BoundingBox::new(f64::NAN, 0.0, 8.0, 8.0),
+ ImageNode::new(1, Some(solid_png([255, 0, 0, 255]))),
+ None,
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2608,14 +2597,8 @@ mod tests {
BoundingBox::new(0.0, 0.0, 64.0, 32.0),
None,
vec![
- PaintOp::TextRun {
- bbox: BoundingBox::new(4.0, 4.0, 24.0, 24.0),
- run,
- },
- PaintOp::FootnoteMarker {
- bbox: BoundingBox::new(32.0, 4.0, 24.0, 24.0),
- marker,
- },
+ PaintOp::text_run(BoundingBox::new(4.0, 4.0, 24.0, 24.0), run),
+ PaintOp::footnote_marker(BoundingBox::new(32.0, 4.0, 24.0, 24.0), marker),
],
),
);
@@ -2660,10 +2643,10 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 40.0, 40.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(8.0, 8.0, 24.0, 24.0),
+ vec![PaintOp::text_run(
+ BoundingBox::new(8.0, 8.0, 24.0, 24.0),
run,
- }],
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2709,10 +2692,10 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 88.0, 36.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(4.0, 4.0, 80.0, 28.0),
+ vec![PaintOp::text_run(
+ BoundingBox::new(4.0, 4.0, 80.0, 28.0),
run,
- }],
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2753,10 +2736,10 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 72.0, 36.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(4.0, 4.0, 60.0, 28.0),
+ vec![PaintOp::text_run(
+ BoundingBox::new(4.0, 4.0, 60.0, 28.0),
run,
- }],
+ )],
),
)
.with_output_options(LayerOutputOptions {
@@ -2805,10 +2788,10 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 48.0, 40.0),
None,
- vec![PaintOp::TextRun {
- bbox: BoundingBox::new(8.0, 8.0, 32.0, 28.0),
+ vec![PaintOp::text_run(
+ BoundingBox::new(8.0, 8.0, 32.0, 28.0),
run,
- }],
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2845,10 +2828,10 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 64.0, 48.0),
None,
- vec![PaintOp::Equation {
- bbox: BoundingBox::new(6.0, 6.0, 44.0, 32.0),
+ vec![PaintOp::equation(
+ BoundingBox::new(6.0, 6.0, 44.0, 32.0),
equation,
- }],
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2892,10 +2875,10 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 64.0, 48.0),
None,
- vec![PaintOp::Equation {
- bbox: BoundingBox::new(6.0, 6.0, 44.0, 32.0),
+ vec![PaintOp::equation(
+ BoundingBox::new(6.0, 6.0, 44.0, 32.0),
equation,
- }],
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -2936,24 +2919,21 @@ mod tests {
BoundingBox::new(0.0, 0.0, 48.0, 16.0),
None,
vec![
- PaintOp::Placeholder {
- bbox: BoundingBox::new(0.0, 0.0, 14.0, 14.0),
- placeholder: PlaceholderNode {
+ PaintOp::placeholder(
+ BoundingBox::new(0.0, 0.0, 14.0, 14.0),
+ PlaceholderNode {
fill_color: 0,
stroke_color: 0,
label: "ph".to_string(),
},
- },
- PaintOp::RawSvg {
- bbox: BoundingBox::new(16.0, 0.0, 14.0, 14.0),
- raw: RawSvgNode {
+ ),
+ PaintOp::raw_svg(
+ BoundingBox::new(16.0, 0.0, 14.0, 14.0),
+ RawSvgNode {
svg: ""
.to_string(),
},
- }],
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -3011,15 +2991,15 @@ mod tests {
LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 32.0, 24.0),
None,
- vec![PaintOp::RawSvg {
- bbox: BoundingBox::new(4.0, 4.0, 20.0, 16.0),
- raw: RawSvgNode {
+ vec![PaintOp::raw_svg(
+ BoundingBox::new(4.0, 4.0, 20.0, 16.0),
+ RawSvgNode {
svg: format!(
"",
external_href
),
},
- }],
+ )],
),
);
let output = SkiaLayerRenderer::new()
@@ -3040,9 +3020,9 @@ mod tests {
let red = LayerNode::leaf(
BoundingBox::new(0.0, 0.0, 12.0, 12.0),
None,
- vec![PaintOp::Rectangle {
- bbox: BoundingBox::new(0.0, 0.0, 12.0, 12.0),
- rect: RectangleNode::new(
+ vec![PaintOp::rectangle(
+ BoundingBox::new(0.0, 0.0, 12.0, 12.0),
+ RectangleNode::new(
0.0,
ShapeStyle {
fill_color: Some(0x000000ff),
@@ -3050,14 +3030,14 @@ mod tests {
},
None,
),
- }],
+ )],
);
let blue = LayerNode::leaf(
BoundingBox::new(3.0, 3.0, 6.0, 6.0),
None,
- vec![PaintOp::Rectangle {
- bbox: BoundingBox::new(3.0, 3.0, 6.0, 6.0),
- rect: RectangleNode::new(
+ vec![PaintOp::rectangle(
+ BoundingBox::new(3.0, 3.0, 6.0, 6.0),
+ RectangleNode::new(
0.0,
ShapeStyle {
fill_color: Some(0x00ff0000),
@@ -3065,7 +3045,7 @@ mod tests {
},
None,
),
- }],
+ )],
);
let tree = PageLayerTree::new(
12.0,
diff --git a/src/renderer/skia/text_replay.rs b/src/renderer/skia/text_replay.rs
index bd4d28ee6..6eac33a90 100644
--- a/src/renderer/skia/text_replay.rs
+++ b/src/renderer/skia/text_replay.rs
@@ -13,7 +13,9 @@ use crate::renderer::layout::{compute_char_positions, split_into_clusters};
use crate::renderer::render_tree::BoundingBox;
use crate::renderer::{clamp_tab_leader_end_x, TextStyle};
-use super::font_lookup::{match_system_family_style, SystemFontFamilies};
+use super::font_lookup::{
+ legacy_typeface_for_style, match_system_family_style, SystemFontFamilies,
+};
use super::renderer::colorref_to_skia;
pub(super) struct SkiaTextReplay<'a> {
@@ -115,7 +117,7 @@ impl SkiaTextReplay<'_> {
push(&mut chain, &mut seen, tf);
}
}
- if let Some(tf) = self.font_mgr.legacy_make_typeface(None::<&str>, font_style) {
+ if let Some(tf) = legacy_typeface_for_style(self.font_mgr, font_style) {
push(&mut chain, &mut seen, tf);
}
chain
@@ -693,10 +695,7 @@ impl SkiaTextReplay<'_> {
"DejaVu Sans",
FontStyle::normal(),
)
- .or_else(|| {
- self.font_mgr
- .legacy_make_typeface(None::<&str>, FontStyle::normal())
- })
+ .or_else(|| legacy_typeface_for_style(self.font_mgr, FontStyle::normal()))
.map(|tf| Font::new(tf, size))
.unwrap_or_else(|| {
let mut font = Font::default();
diff --git a/src/renderer/svg_layer.rs b/src/renderer/svg_layer.rs
index 375c1090a..415e8e3a7 100644
--- a/src/renderer/svg_layer.rs
+++ b/src/renderer/svg_layer.rs
@@ -124,37 +124,37 @@ impl SvgLayerRenderer {
let node = match op {
PaintOp::PageBackground { bbox, background } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::PageBackground(background.clone()),
+ RenderNodeType::PageBackground(background.as_ref().clone()),
*bbox,
),
PaintOp::TextRun { bbox, run } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::TextRun(run.clone()),
+ RenderNodeType::TextRun(run.as_ref().clone()),
*bbox,
),
PaintOp::FootnoteMarker { bbox, marker } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::FootnoteMarker(marker.clone()),
+ RenderNodeType::FootnoteMarker(marker.as_ref().clone()),
*bbox,
),
PaintOp::Line { bbox, line } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::Line(line.clone()),
+ RenderNodeType::Line(line.as_ref().clone()),
*bbox,
),
PaintOp::Rectangle { bbox, rect } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::Rectangle(rect.clone()),
+ RenderNodeType::Rectangle(rect.as_ref().clone()),
*bbox,
),
PaintOp::Ellipse { bbox, ellipse } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::Ellipse(ellipse.clone()),
+ RenderNodeType::Ellipse(ellipse.as_ref().clone()),
*bbox,
),
PaintOp::Path { bbox, path } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::Path(path.clone()),
+ RenderNodeType::Path(path.as_ref().clone()),
*bbox,
),
PaintOp::Image {
@@ -173,22 +173,22 @@ impl SvgLayerRenderer {
),
PaintOp::Equation { bbox, equation } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::Equation(equation.clone()),
+ RenderNodeType::Equation(equation.as_ref().clone()),
*bbox,
),
PaintOp::FormObject { bbox, form } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::FormObject(form.clone()),
+ RenderNodeType::FormObject(form.as_ref().clone()),
*bbox,
),
PaintOp::Placeholder { bbox, placeholder } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::Placeholder(placeholder.clone()),
+ RenderNodeType::Placeholder(placeholder.as_ref().clone()),
*bbox,
),
PaintOp::RawSvg { bbox, raw } => RenderNode::new(
self.take_node_id(source_node_id),
- RenderNodeType::RawSvg(raw.clone()),
+ RenderNodeType::RawSvg(raw.as_ref().clone()),
*bbox,
),
PaintOp::GlyphRun { .. }