@@ -12,7 +12,8 @@ use graphene_std::Color;
1212use graphene_std:: math:: quad:: Quad ;
1313use graphene_std:: subpath:: { self , Subpath } ;
1414use graphene_std:: table:: Table ;
15- use graphene_std:: text:: { TextAlign , TypesettingConfig , load_font, to_path} ;
15+ use graphene_std:: text:: TextContext ;
16+ use graphene_std:: text:: { Font , FontCache , TextAlign , TypesettingConfig } ;
1617use graphene_std:: vector:: click_target:: ClickTargetType ;
1718use graphene_std:: vector:: misc:: point_to_dvec2;
1819use graphene_std:: vector:: { PointId , SegmentId , Vector } ;
@@ -215,7 +216,7 @@ impl OverlayContext {
215216
216217 pub fn take_scene ( self ) -> Scene {
217218 let mut internal = self . internal . lock ( ) . expect ( "Failed to lock internal overlay context" ) ;
218- std:: mem:: take ( & mut * internal) . scene
219+ std:: mem:: take ( & mut internal. scene )
219220 }
220221
221222 fn internal ( & ' _ self ) -> MutexGuard < ' _ , OverlayContextInternal > {
@@ -411,26 +412,31 @@ pub(super) struct OverlayContextInternal {
411412 size : DVec2 ,
412413 device_pixel_ratio : f64 ,
413414 visibility_settings : OverlaysVisibilitySettings ,
415+ font_cache : FontCache ,
416+ thread_text : TextContext ,
414417}
415418
416419impl Default for OverlayContextInternal {
417420 fn default ( ) -> Self {
418- Self {
419- scene : Scene :: new ( ) ,
420- size : DVec2 :: ZERO ,
421- device_pixel_ratio : 1.0 ,
422- visibility_settings : OverlaysVisibilitySettings :: default ( ) ,
423- }
421+ Self :: new ( DVec2 :: new ( 100. , 100. ) , 1. , OverlaysVisibilitySettings :: default ( ) )
424422 }
425423}
426424
427425impl OverlayContextInternal {
428426 pub ( super ) fn new ( size : DVec2 , device_pixel_ratio : f64 , visibility_settings : OverlaysVisibilitySettings ) -> Self {
427+ let mut font_cache = FontCache :: default ( ) ;
428+ // Initialize with the hardcoded font used by overlay text
429+ const FONT_DATA : & [ u8 ] = include_bytes ! ( "source-sans-pro-regular.ttf" ) ;
430+ let font = Font :: new ( "Source Sans Pro" . to_string ( ) , "Regular" . to_string ( ) ) ;
431+ font_cache. insert ( font, String :: new ( ) , FONT_DATA . to_vec ( ) ) ;
432+
429433 Self {
430434 scene : Scene :: new ( ) ,
431435 size,
432436 device_pixel_ratio,
433437 visibility_settings,
438+ font_cache,
439+ thread_text : TextContext :: default ( ) ,
434440 }
435441 }
436442
@@ -1007,7 +1013,7 @@ impl OverlayContextInternal {
10071013 self . scene . fill ( peniko:: Fill :: NonZero , self . get_transform ( ) , & brush, None , & path) ;
10081014 }
10091015
1010- fn get_width ( & self , text : & str ) -> f64 {
1016+ fn get_width ( & mut self , text : & str ) -> f64 {
10111017 // Use the actual text-to-path system to get precise text width
10121018 const FONT_SIZE : f64 = 12.0 ;
10131019
@@ -1024,13 +1030,9 @@ impl OverlayContextInternal {
10241030 // Load Source Sans Pro font data
10251031 // TODO: Grab this from the node_modules folder (either with `include_bytes!` or ideally at runtime) instead of checking the font file into the repo.
10261032 // TODO: And maybe use the WOFF2 version (if it's supported) for its smaller, compressed file size.
1027- const FONT_DATA : & [ u8 ] = include_bytes ! ( "source-sans-pro-regular.ttf" ) ;
1028- let font_blob = Some ( load_font ( FONT_DATA ) ) ;
1029-
1030- // Convert text to paths and calculate actual bounds
1031- let text_table = to_path ( text, font_blob, typesetting, false ) ;
1032- let text_bounds = self . calculate_text_bounds ( & text_table) ;
1033- text_bounds. width ( )
1033+ let font = Font :: new ( "Source Sans Pro" . to_string ( ) , "Regular" . to_string ( ) ) ;
1034+ let bounds = self . thread_text . bounding_box ( text, & font, & self . font_cache , typesetting, false ) ;
1035+ bounds. x
10341036 }
10351037
10361038 fn text ( & mut self , text : & str , font_color : & str , background_color : Option < & str > , transform : DAffine2 , padding : f64 , pivot : [ Pivot ; 2 ] ) {
@@ -1051,15 +1053,17 @@ impl OverlayContextInternal {
10511053 // Load Source Sans Pro font data
10521054 // TODO: Grab this from the node_modules folder (either with `include_bytes!` or ideally at runtime) instead of checking the font file into the repo.
10531055 // TODO: And maybe use the WOFF2 version (if it's supported) for its smaller, compressed file size.
1054- const FONT_DATA : & [ u8 ] = include_bytes ! ( "source-sans-pro-regular.ttf" ) ;
1055- let font_blob = Some ( load_font ( FONT_DATA ) ) ;
1056+ let font = Font :: new ( "Source Sans Pro" . to_string ( ) , "Regular" . to_string ( ) ) ;
1057+
1058+ // Get text dimensions directly from layout
1059+ let text_size = self . thread_text . bounding_box ( text, & font, & self . font_cache , typesetting, false ) ;
1060+ let text_width = text_size. x ;
1061+ let text_height = text_size. y ;
1062+ // Create a rect from the size (assuming text starts at origin)
1063+ let text_bounds = kurbo:: Rect :: new ( 0.0 , 0.0 , text_width, text_height) ;
10561064
1057- // Convert text to vector paths using the existing text system
1058- let text_table = to_path ( text, font_blob, typesetting, false ) ;
1059- // Calculate text bounds from the generated paths
1060- let text_bounds = self . calculate_text_bounds ( & text_table) ;
1061- let text_width = text_bounds. width ( ) ;
1062- let text_height = text_bounds. height ( ) ;
1065+ // Convert text to vector paths for rendering
1066+ let text_table = self . thread_text . to_path ( text, & font, & self . font_cache , typesetting, false ) ;
10631067
10641068 // Calculate position based on pivot
10651069 let mut position = DVec2 :: ZERO ;
@@ -1094,56 +1098,6 @@ impl OverlayContextInternal {
10941098 self . render_text_paths ( & text_table, font_color, vello_transform) ;
10951099 }
10961100
1097- // Calculate bounds of text from vector table
1098- fn calculate_text_bounds ( & self , text_table : & Table < Vector > ) -> kurbo:: Rect {
1099- let mut min_x = f64:: INFINITY ;
1100- let mut min_y = f64:: INFINITY ;
1101- let mut max_x = f64:: NEG_INFINITY ;
1102- let mut max_y = f64:: NEG_INFINITY ;
1103-
1104- for row in text_table. iter ( ) {
1105- // Use the existing segment_bezier_iter to get all bezier curves
1106- for ( _, bezier, _, _) in row. element . segment_bezier_iter ( ) {
1107- let transformed_bezier = bezier. apply_transformation ( |point| row. transform . transform_point2 ( point) ) ;
1108-
1109- // Add start and end points to bounds
1110- let points = [ transformed_bezier. start , transformed_bezier. end ] ;
1111- for point in points {
1112- min_x = min_x. min ( point. x ) ;
1113- min_y = min_y. min ( point. y ) ;
1114- max_x = max_x. max ( point. x ) ;
1115- max_y = max_y. max ( point. y ) ;
1116- }
1117-
1118- // Add handle points if they exist
1119- match transformed_bezier. handles {
1120- subpath:: BezierHandles :: Quadratic { handle } => {
1121- min_x = min_x. min ( handle. x ) ;
1122- min_y = min_y. min ( handle. y ) ;
1123- max_x = max_x. max ( handle. x ) ;
1124- max_y = max_y. max ( handle. y ) ;
1125- }
1126- subpath:: BezierHandles :: Cubic { handle_start, handle_end } => {
1127- for handle in [ handle_start, handle_end] {
1128- min_x = min_x. min ( handle. x ) ;
1129- min_y = min_y. min ( handle. y ) ;
1130- max_x = max_x. max ( handle. x ) ;
1131- max_y = max_y. max ( handle. y ) ;
1132- }
1133- }
1134- _ => { }
1135- }
1136- }
1137- }
1138-
1139- if min_x. is_finite ( ) && min_y. is_finite ( ) && max_x. is_finite ( ) && max_y. is_finite ( ) {
1140- kurbo:: Rect :: new ( min_x, min_y, max_x, max_y)
1141- } else {
1142- // Fallback for empty text
1143- kurbo:: Rect :: new ( 0.0 , 0.0 , 0.0 , 12.0 )
1144- }
1145- }
1146-
11471101 // Render text paths to the vello scene using existing infrastructure
11481102 fn render_text_paths ( & mut self , text_table : & Table < Vector > , font_color : & str , base_transform : kurbo:: Affine ) {
11491103 let color = Self :: parse_color ( font_color) ;
0 commit comments