@@ -21,6 +21,7 @@ pub struct GraphOperationMessageContext<'a> {
2121 pub network_interface : & ' a mut NodeNetworkInterface ,
2222 pub collapsed : & ' a mut CollapsedLayers ,
2323 pub node_graph : & ' a mut NodeGraphMessageHandler ,
24+ pub fonts : & ' a FontsMessageHandler ,
2425}
2526
2627#[ derive( Debug , Clone , PartialEq , Default , serde:: Serialize , serde:: Deserialize , ExtractField ) ]
@@ -423,7 +424,27 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
423424 insert_index,
424425 center,
425426 } => {
426- let tree = match usvg:: Tree :: from_str ( & svg, & usvg:: Options :: default ( ) ) {
427+ let mut options = usvg:: Options :: default ( ) ;
428+ options. font_family = graphene_std:: consts:: DEFAULT_FONT_FAMILY . to_string ( ) ;
429+ let mut fontdb = usvg:: fontdb:: Database :: new ( ) ;
430+ fontdb. load_system_fonts ( ) ;
431+ fontdb. load_font_data ( graphene_std:: text:: FALLBACK_FONT_RESOURCE . to_vec ( ) ) ;
432+ for data in context. fonts . font_data ( ) . values ( ) {
433+ fontdb. load_font_data ( data. to_vec ( ) ) ;
434+ }
435+ let fallback_family = fontdb
436+ . faces ( )
437+ . next ( )
438+ . and_then ( |face| face. families . first ( ) . map ( |( name, _) | name. clone ( ) ) )
439+ . unwrap_or_else ( || "Source Sans Pro" . to_string ( ) ) ;
440+ fontdb. set_sans_serif_family ( & fallback_family) ;
441+ fontdb. set_serif_family ( & fallback_family) ;
442+ fontdb. set_monospace_family ( & fallback_family) ;
443+ fontdb. set_cursive_family ( & fallback_family) ;
444+ fontdb. set_fantasy_family ( & fallback_family) ;
445+ options. fontdb = std:: sync:: Arc :: new ( fontdb) ;
446+
447+ let tree = match usvg:: Tree :: from_str ( & svg, & options) {
427448 Ok ( t) => t,
428449 Err ( e) => {
429450 responses. add ( DialogMessage :: DisplayDialogError {
@@ -621,8 +642,9 @@ fn import_usvg_node(
621642 }
622643 usvg:: Node :: Text ( text) => {
623644 let font = Font :: new ( graphene_std:: consts:: DEFAULT_FONT_FAMILY . to_string ( ) , graphene_std:: consts:: DEFAULT_FONT_STYLE . to_string ( ) ) ;
624- modify_inputs. insert_text ( text. chunks ( ) . iter ( ) . map ( |chunk| chunk. text ( ) ) . collect ( ) , font, TypesettingConfig :: default ( ) , layer) ;
645+ modify_inputs. insert_text ( text. chunks ( ) . iter ( ) . map ( |chunk| chunk. text ( ) ) . collect ( ) , font, usvg_text_typesetting ( text ) , layer) ;
625646 modify_inputs. fill_set ( Fill :: Solid ( Color :: BLACK ) ) ;
647+ apply_usvg_text_transform ( modify_inputs, text) ;
626648 }
627649 }
628650}
@@ -673,13 +695,45 @@ fn import_usvg_node_inner(
673695 }
674696 usvg:: Node :: Text ( text) => {
675697 let font = Font :: new ( graphene_std:: consts:: DEFAULT_FONT_FAMILY . to_string ( ) , graphene_std:: consts:: DEFAULT_FONT_STYLE . to_string ( ) ) ;
676- modify_inputs. insert_text ( text. chunks ( ) . iter ( ) . map ( |chunk| chunk. text ( ) ) . collect ( ) , font, TypesettingConfig :: default ( ) , layer) ;
698+ modify_inputs. insert_text ( text. chunks ( ) . iter ( ) . map ( |chunk| chunk. text ( ) ) . collect ( ) , font, usvg_text_typesetting ( text ) , layer) ;
677699 modify_inputs. fill_set ( Fill :: Solid ( Color :: BLACK ) ) ;
700+ apply_usvg_text_transform ( modify_inputs, text) ;
678701 0
679702 }
680703 }
681704}
682705
706+ fn usvg_text_typesetting ( text : & usvg:: Text ) -> TypesettingConfig {
707+ let mut typesetting = TypesettingConfig :: default ( ) ;
708+
709+ for span in text. chunks ( ) . iter ( ) . flat_map ( |chunk| chunk. spans ( ) ) {
710+ let decoration = span. decoration ( ) ;
711+ typesetting. underline |= decoration. underline ( ) . is_some ( ) ;
712+ typesetting. overline |= decoration. overline ( ) . is_some ( ) ;
713+ typesetting. strikethrough |= decoration. line_through ( ) . is_some ( ) ;
714+ }
715+
716+ if let Some ( first_span) = text. chunks ( ) . first ( ) . and_then ( |chunk| chunk. spans ( ) . first ( ) ) {
717+ typesetting. font_size = first_span. font_size ( ) . get ( ) as f64 ;
718+ }
719+
720+ typesetting
721+ }
722+
723+ fn apply_usvg_text_transform ( modify_inputs : & mut ModifyInputsContext , text : & usvg:: Text ) {
724+ let elem_transform = usvg_transform ( text. abs_transform ( ) ) ;
725+ let chunk_offset = text. chunks ( ) . first ( ) . map ( |c| DVec2 :: new ( c. x ( ) . unwrap_or ( 0. ) as f64 , c. y ( ) . unwrap_or ( 0. ) as f64 ) ) . unwrap_or_default ( ) ;
726+ let text_transform = elem_transform * DAffine2 :: from_translation ( chunk_offset) ;
727+
728+ if text_transform. abs_diff_eq ( DAffine2 :: IDENTITY , 1e-6 ) {
729+ return ;
730+ }
731+ // `insert_text` always creates a Transform node; update it in-place.
732+ if let Some ( transform_node_id) = modify_inputs. existing_proto_node_id ( graphene_std:: transform_nodes:: transform:: IDENTIFIER , false ) {
733+ transform_utils:: update_transform ( modify_inputs. network_interface , & transform_node_id, text_transform) ;
734+ }
735+ }
736+
683737/// Helper to apply path data (vector geometry, fill, stroke, transform) to a layer.
684738fn import_usvg_path ( modify_inputs : & mut ModifyInputsContext , node : & usvg:: Node , path : & usvg:: Path , layer : LayerNodeIdentifier , graphite_gradient_stops : & HashMap < String , GradientStops > ) {
685739 let subpaths = convert_usvg_path ( path) ;
0 commit comments