@@ -12,7 +12,8 @@ use graphene_std::Color;
12
12
use graphene_std:: math:: quad:: Quad ;
13
13
use graphene_std:: subpath:: { self , Subpath } ;
14
14
use 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 } ;
16
17
use graphene_std:: vector:: click_target:: ClickTargetType ;
17
18
use graphene_std:: vector:: misc:: point_to_dvec2;
18
19
use graphene_std:: vector:: { PointId , SegmentId , Vector } ;
@@ -215,7 +216,7 @@ impl OverlayContext {
215
216
216
217
pub fn take_scene ( self ) -> Scene {
217
218
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 )
219
220
}
220
221
221
222
fn internal ( & ' _ self ) -> MutexGuard < ' _ , OverlayContextInternal > {
@@ -411,26 +412,31 @@ pub(super) struct OverlayContextInternal {
411
412
size : DVec2 ,
412
413
device_pixel_ratio : f64 ,
413
414
visibility_settings : OverlaysVisibilitySettings ,
415
+ font_cache : FontCache ,
416
+ thread_text : TextContext ,
414
417
}
415
418
416
419
impl Default for OverlayContextInternal {
417
420
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 ( ) )
424
422
}
425
423
}
426
424
427
425
impl OverlayContextInternal {
428
426
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
+
429
433
Self {
430
434
scene : Scene :: new ( ) ,
431
435
size,
432
436
device_pixel_ratio,
433
437
visibility_settings,
438
+ font_cache,
439
+ thread_text : TextContext :: default ( ) ,
434
440
}
435
441
}
436
442
@@ -1007,7 +1013,7 @@ impl OverlayContextInternal {
1007
1013
self . scene . fill ( peniko:: Fill :: NonZero , self . get_transform ( ) , & brush, None , & path) ;
1008
1014
}
1009
1015
1010
- fn get_width ( & self , text : & str ) -> f64 {
1016
+ fn get_width ( & mut self , text : & str ) -> f64 {
1011
1017
// Use the actual text-to-path system to get precise text width
1012
1018
const FONT_SIZE : f64 = 12.0 ;
1013
1019
@@ -1024,13 +1030,9 @@ impl OverlayContextInternal {
1024
1030
// Load Source Sans Pro font data
1025
1031
// 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.
1026
1032
// 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
1034
1036
}
1035
1037
1036
1038
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 {
1051
1053
// Load Source Sans Pro font data
1052
1054
// 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.
1053
1055
// 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) ;
1056
1064
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 ) ;
1063
1067
1064
1068
// Calculate position based on pivot
1065
1069
let mut position = DVec2 :: ZERO ;
@@ -1094,56 +1098,6 @@ impl OverlayContextInternal {
1094
1098
self . render_text_paths ( & text_table, font_color, vello_transform) ;
1095
1099
}
1096
1100
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
-
1147
1101
// Render text paths to the vello scene using existing infrastructure
1148
1102
fn render_text_paths ( & mut self , text_table : & Table < Vector > , font_color : & str , base_transform : kurbo:: Affine ) {
1149
1103
let color = Self :: parse_color ( font_color) ;
0 commit comments