@@ -114,6 +114,25 @@ mod tests {
114
114
} ,
115
115
}
116
116
}
117
+
118
+ fn noto_color_emoji ( ) -> Self {
119
+ Self {
120
+ name : "Noto Color Emoji" ,
121
+ face : FaceMetrics {
122
+ cell_width : 20.0 , // Emoji are typically double-width
123
+ ascent : 14.0 ,
124
+ descent : 3.5 ,
125
+ line_gap : 1.0 ,
126
+ underline_position : Some ( -2.0 ) ,
127
+ underline_thickness : Some ( 1.2 ) ,
128
+ strikethrough_position : Some ( 7.0 ) ,
129
+ strikethrough_thickness : Some ( 1.2 ) ,
130
+ cap_height : Some ( 10.5 ) ,
131
+ ex_height : Some ( 7.0 ) ,
132
+ ic_width : None ,
133
+ } ,
134
+ }
135
+ }
117
136
}
118
137
119
138
#[ test]
@@ -866,4 +885,130 @@ mod tests {
866
885
"Mixed content must not affect total height calculations"
867
886
) ;
868
887
}
888
+
889
+ /// Test edge cases for font metrics calculations
890
+ #[ test]
891
+ fn test_edge_cases ( ) {
892
+ // Test extremely small font size
893
+ let tiny_font = FaceMetrics {
894
+ cell_width : 0.1 ,
895
+ ascent : 0.1 ,
896
+ descent : 0.05 ,
897
+ line_gap : 0.01 ,
898
+ underline_position : Some ( -0.01 ) ,
899
+ underline_thickness : Some ( 0.01 ) ,
900
+ strikethrough_position : Some ( 0.05 ) ,
901
+ strikethrough_thickness : Some ( 0.01 ) ,
902
+ cap_height : Some ( 0.08 ) ,
903
+ ex_height : Some ( 0.05 ) ,
904
+ ic_width : None ,
905
+ } ;
906
+
907
+ let tiny_metrics = Metrics :: calc ( tiny_font) ;
908
+ assert ! (
909
+ tiny_metrics. cell_width >= 1 ,
910
+ "Cell width must be at least 1 pixel"
911
+ ) ;
912
+ assert ! (
913
+ tiny_metrics. cell_height >= 1 ,
914
+ "Cell height must be at least 1 pixel"
915
+ ) ;
916
+ assert ! (
917
+ tiny_metrics. underline_thickness >= 1 ,
918
+ "Line thickness must be at least 1 pixel"
919
+ ) ;
920
+
921
+ // Test extremely large font size
922
+ let huge_font = FaceMetrics {
923
+ cell_width : 1000.0 ,
924
+ ascent : 1200.0 ,
925
+ descent : 300.0 ,
926
+ line_gap : 100.0 ,
927
+ underline_position : Some ( -100.0 ) ,
928
+ underline_thickness : Some ( 100.0 ) ,
929
+ strikethrough_position : Some ( 600.0 ) ,
930
+ strikethrough_thickness : Some ( 100.0 ) ,
931
+ cap_height : Some ( 900.0 ) ,
932
+ ex_height : Some ( 600.0 ) ,
933
+ ic_width : None ,
934
+ } ;
935
+
936
+ let huge_metrics = Metrics :: calc ( huge_font) ;
937
+ assert_eq ! (
938
+ huge_metrics. cell_width, 1000 ,
939
+ "Large font metrics should be preserved"
940
+ ) ;
941
+ assert_eq ! (
942
+ huge_metrics. cell_height, 1700 ,
943
+ "Large font height calculation"
944
+ ) ;
945
+
946
+ // Test font with missing optional metrics
947
+ let minimal_font = FaceMetrics {
948
+ cell_width : 10.0 ,
949
+ ascent : 12.0 ,
950
+ descent : 3.0 ,
951
+ line_gap : 1.0 ,
952
+ underline_position : None ,
953
+ underline_thickness : None ,
954
+ strikethrough_position : None ,
955
+ strikethrough_thickness : None ,
956
+ cap_height : None ,
957
+ ex_height : None ,
958
+ ic_width : None ,
959
+ } ;
960
+
961
+ let minimal_metrics = Metrics :: calc ( minimal_font) ;
962
+ assert ! (
963
+ minimal_metrics. underline_thickness >= 1 ,
964
+ "Default underline thickness"
965
+ ) ;
966
+ assert ! (
967
+ minimal_metrics. strikethrough_thickness >= 1 ,
968
+ "Default strikethrough thickness"
969
+ ) ;
970
+ assert ! (
971
+ minimal_metrics. underline_position > 0 ,
972
+ "Default underline position"
973
+ ) ;
974
+ assert ! (
975
+ minimal_metrics. strikethrough_position > 0 ,
976
+ "Default strikethrough position"
977
+ ) ;
978
+ }
979
+
980
+ /// Test mixed script rendering (Latin + CJK + Emoji)
981
+ #[ test]
982
+ fn test_mixed_script_rendering ( ) {
983
+ let latin_font = TestFontData :: cascadia_code ( ) ;
984
+ let cjk_font = TestFontData :: noto_sans_cjk ( ) ;
985
+ let emoji_font = TestFontData :: noto_color_emoji ( ) ;
986
+
987
+ let latin_metrics = Metrics :: calc ( latin_font. face ) ;
988
+ let cjk_metrics =
989
+ Metrics :: calc_with_primary_cell_dimensions ( cjk_font. face , & latin_metrics) ;
990
+ let emoji_metrics =
991
+ Metrics :: calc_with_primary_cell_dimensions ( emoji_font. face , & latin_metrics) ;
992
+
993
+ // All fonts should have the same cell height for consistent rendering
994
+ assert_eq ! ( latin_metrics. cell_height, cjk_metrics. cell_height) ;
995
+ assert_eq ! ( latin_metrics. cell_height, emoji_metrics. cell_height) ;
996
+
997
+ // All fonts should have the same baseline
998
+ assert_eq ! ( latin_metrics. cell_baseline, cjk_metrics. cell_baseline) ;
999
+ assert_eq ! ( latin_metrics. cell_baseline, emoji_metrics. cell_baseline) ;
1000
+
1001
+ // Verify that a line containing all three scripts renders consistently
1002
+ let mixed_line_height = latin_metrics. cell_height ;
1003
+ let latin_only_height = latin_metrics. cell_height ;
1004
+ let cjk_only_height = cjk_metrics. cell_height ;
1005
+ let emoji_only_height = emoji_metrics. cell_height ;
1006
+
1007
+ assert_eq ! (
1008
+ mixed_line_height, latin_only_height,
1009
+ "Mixed script lines must have same height as single script lines"
1010
+ ) ;
1011
+ assert_eq ! ( mixed_line_height, cjk_only_height) ;
1012
+ assert_eq ! ( mixed_line_height, emoji_only_height) ;
1013
+ }
869
1014
}
0 commit comments