@@ -21,6 +21,7 @@ let fntCodes = { // sorted
21
21
}
22
22
23
23
let fntData = { } ,
24
+ fntFaceData = { } ,
24
25
fntSize = '512px' ,
25
26
fntString = '-\uffff' ,
26
27
fntBtn = '' ,
@@ -122,12 +123,12 @@ let fntMaster = {
122
123
'Times New Roman Greek' , 'Times New Roman TUR' , 'Tms Rmn' , 'MS Serif Greek' , 'Small Fonts Greek' ,
123
124
'標準ゴシック' , 'ゴシック' , 'ゴシック' , // MS ゴシック -> MS Gothic
124
125
'ヘルベチカ' , 'タイムズロマン' , 'クーリエ' , // Arial, TNR, Courier - >Courier New
125
- /* variants
126
- 'Arial Black','Arial Narrow','Segoe UI Light','Segoe UI Semibold', // 7
127
- ' Segoe UI Semilight', // 8
128
- 'Microsoft JhengHei Light','Microsoft YaHei Light',' Segoe UI Black ', // 8.1
129
- 'Malgun Gothic Semilight', // 10
130
- */
126
+ ] ,
127
+ windowsface : [
128
+ 'Arial Black' , ' Segoe UI Light' , 'Segoe UI Semibold' , // 7
129
+ ' Segoe UI Semilight ', // 8
130
+ 'Microsoft JhengHei Light' , 'Microsoft YaHei Light' , 'Segoe UI Black' , // 8.1
131
+ 'Malgun Gothic Semilight' , // 10
131
132
] ,
132
133
} ,
133
134
// TB unexpected
@@ -151,6 +152,12 @@ let fntMaster = {
151
152
'Gill Sans' , 'Gill Sans MT' , // MS bundled
152
153
'Noto Serif Hmong Nyiakeng' , // 'Noto Sans Symbols2', // TB12 fontnames
153
154
] ,
155
+ windowsface : [
156
+ // 'Arial Narrow', // ToDo: uncomment once we block it
157
+ 'Calibri Light' , // 8
158
+ 'Microsoft JhengHei UI Light' , 'Nirmala UI Semilight' , // 8.1
159
+ 'Candara Light' , 'Corbel Light' , 'Yu Gothic UI Light' , // 10
160
+ ] ,
154
161
} ,
155
162
// kBaseFonts: https://searchfox.org/mozilla-central/search?path=StandardFonts*.inc
156
163
base : {
@@ -259,18 +266,22 @@ let fntMaster = {
259
266
// system aliases: should always be the same AFAICT
260
267
// https://searchfox.org/mozilla-central/source/gfx/thebes/gfxDWriteFontList.cpp#1990
261
268
'MS Sans Serif','MS Serif','Courier','Small Fonts','Roman', // Microsoft Sans Serif, TNR, Courier New, Arial, TNR
262
- // variants
263
- 'Arial Black','Arial Narrow','Segoe UI Light','Segoe UI Semibold', // 7
264
- 'Franklin Gothic Medium', // 7 not detected if font-vis < 3: 1720408
265
- 'Calibri Light','Calibri Light Italic','Segoe UI Semilight', // 8
266
- // 8.1
267
- 'Leelawadee UI Semilight','Microsoft JhengHei Light','Microsoft JhengHei UI Light',
268
- 'Microsoft YaHei Light','Microsoft YaHei UI Light','Nirmala UI Semilight','Segoe UI Black','Yu Gothic Light',
269
- // 10
270
- 'Bahnschrift Light','Bahnschrift SemiBold','Bahnschrift SemiLight','Candara Light','Corbel Light',
271
- 'Malgun Gothic Semilight','Yu Gothic Medium','Yu Gothic UI Light','Yu Gothic UI Semilight','Yu Gothic UI Semibold',
272
- */
269
+ //'Franklin Gothic Medium', // 7 not detected if font-vis < 3: 1720408
270
+ //*/
273
271
] ,
272
+ windowsface :[
273
+ 'Arial Black' , 'Arial Narrow' , 'Segoe UI Light' , 'Segoe UI Semibold' , // 7
274
+ 'Calibri Light' , 'Segoe UI Semilight' , // 8
275
+ // 8.1
276
+ 'Leelawadee UI Semilight' , 'Microsoft JhengHei Light' , 'Microsoft JhengHei UI Light' ,
277
+ 'Microsoft YaHei Light' , 'Microsoft YaHei UI Light' , 'Nirmala UI Semilight' , 'Segoe UI Black' , 'Yu Gothic Light' ,
278
+ // 10
279
+ 'Candara Light' , 'Corbel Light' , 'Malgun Gothic Semilight' ,
280
+ 'Yu Gothic Medium' , 'Yu Gothic UI Light' , 'Yu Gothic UI Semilight' , 'Yu Gothic UI Semibold' ,
281
+ /* ignore: not detected by font face
282
+ 'Bahnschrift Light','Bahnschrift SemiBold','Bahnschrift SemiLight',
283
+ //*/
284
+ ]
274
285
} ,
275
286
// kLangPackFonts
276
287
baselang : {
@@ -302,6 +313,9 @@ let fntMaster = {
302
313
// '標準明朝', // MS 明朝 -> MS Mincho
303
314
// 'FangSong_GB2312',
304
315
] ,
316
+ windowsface : [
317
+ 'BIZ UDMincho Medium' , 'BIZ UDPMincho Medium' , 'DengXian Light' , 'Yu Mincho Demibold' , 'Yu Mincho Light'
318
+ ] ,
305
319
} ,
306
320
system : {
307
321
android : [
@@ -434,6 +448,17 @@ let fntMaster = {
434
448
// MS downloads
435
449
'Cascadia Code' , 'Cascadia Mono' , // 11
436
450
] ,
451
+ windowsface : [
452
+ 'Arial Nova Cond' , 'Arial Nova Light' ,
453
+ 'Georgia Pro Black' , 'Georgia Pro Cond' , 'Georgia Pro Light' , 'Georgia Pro Semibold' ,
454
+ 'Gill Sans Nova Cond' , 'Gill Sans Nova Light' ,
455
+ //'Neue Haas Grotesk Text Pro UltraThin','Neue Haas Grotesk Text Pro Light',
456
+ 'Rockwell Nova Cond' , 'Rockwell Nova Extra Bold' , 'Rockwell Nova Light' ,
457
+ 'Verdana Pro Black' , 'Verdana Pro Light' ,
458
+ // the above are all supplemental, so to properly test font face is not leaking
459
+ // we need to add some non-weighted fonts: not much to work with :-(
460
+ 'Ink Free'
461
+ ] ,
437
462
} ,
438
463
// isOS
439
464
mini : [
@@ -450,9 +475,11 @@ function set_fntList() {
450
475
if ( build ) {
451
476
isFontSizesPrevious = isFontSizesMore
452
477
fntData = {
453
- system : [ ] , bundled : [ ] , base : [ ] , baselang : [ ] , fpp : [ ] , unexpected : [ ] , full : [ ] ,
454
- control : [ ] , 'control_name' : [ ] , generic : [ ] , 'generic_name' : [ ]
478
+ bundled : [ ] , base : [ ] , baselang : [ ] ,
479
+ control : [ ] , 'control_name' : [ ] , generic : [ ] , 'generic_name' : [ ] ,
480
+ fpp : [ ] , full : [ ] , system : [ ] , unexpected : [ ] ,
455
481
}
482
+ fntFaceData = { base : [ ] , baselang : [ ] , fpp : [ ] , full : [ ] , unexpected : [ ] }
456
483
457
484
// fntString
458
485
if ( isTB || 'android' == isOS || 'linux' == isOS ) {
@@ -507,7 +534,7 @@ function set_fntList() {
507
534
// lists
508
535
if ( isOS !== undefined ) {
509
536
fntFake = '--00' + rnd_string ( )
510
- let array = [ ]
537
+ let array = [ ] , osface = isOS + 'face'
511
538
if ( 'android' == isOS ) {
512
539
// notos
513
540
fntMaster . android . notoboth . forEach ( function ( fnt ) { array . push ( 'Noto Sans ' + fnt , 'Noto Serif ' + fnt ) } )
@@ -533,6 +560,14 @@ function set_fntList() {
533
560
fntData . unexpected = fntMaster . blocklist [ isOS ]
534
561
array = array . concat ( fntMaster . blocklist [ isOS ] )
535
562
fntData . full = array
563
+ // faces
564
+ array = fntMaster . allowlist [ osface ]
565
+ if ( undefined !== array ) {
566
+ fntFaceData . base = array . sort ( )
567
+ let aUnexpected = fntMaster . blocklist [ osface ]
568
+ fntFaceData . unexpected = aUnexpected . sort ( )
569
+ fntFaceData . full = array . concat ( aUnexpected ) . sort ( )
570
+ }
536
571
} else {
537
572
// desktop FF
538
573
array = fntMaster . base [ isOS ]
@@ -544,6 +579,19 @@ function set_fntList() {
544
579
array = array . concat ( fntMaster . system [ isOS ] )
545
580
fntData . unexpected = fntMaster . system [ isOS ]
546
581
fntData . full = array
582
+ // faces
583
+ array = fntMaster . base [ osface ]
584
+ if ( undefined !== array ) {
585
+ fntFaceData . base = array . sort ( )
586
+ let aBaseLang = fntMaster . baselang [ osface ]
587
+ fntFaceData . baselang = aBaseLang . sort ( )
588
+ array = array . concat ( aBaseLang )
589
+ fntFaceData . fpp = array . sort ( )
590
+ let aUnexpected = fntMaster . system [ osface ]
591
+ fntFaceData . unexpected = aUnexpected . sort ( )
592
+ array = array . concat ( aUnexpected )
593
+ fntFaceData . full = array . sort ( )
594
+ }
547
595
}
548
596
// -control from lists
549
597
if ( fntPlatformFont !== undefined ) {
@@ -626,6 +674,69 @@ function get_document_fonts(METRIC) {
626
674
return
627
675
}
628
676
677
+ const get_fontfaces = ( METRIC ) => new Promise ( resolve => {
678
+ // testing non regular fonts + font face leaks
679
+ // it is problematic to test weighted fonts because you don't know
680
+ // if it's synthesized, a variable font, or an actual font(name)
681
+ // blocking document fonts does not affect this test
682
+
683
+ let t0 = nowFn ( )
684
+ // start with a letter or it throws "SyntaxError: An invalid or illegal string was specified"
685
+ let fntFaceFake = 'a' + rnd_string ( )
686
+ async function testLocalFontFamily ( font ) {
687
+ try {
688
+ const fontFace = new FontFace ( font , `local("${ font } ")` )
689
+ await fontFace . load ( )
690
+ return fntFaceFake
691
+ } catch ( e ) {
692
+ return e + ''
693
+ }
694
+ }
695
+ function getLocalFontFamily ( font ) {
696
+ return new FontFace ( font , `local("${ font } ")` )
697
+ . load ( )
698
+ . then ( ( font ) => font . family )
699
+ . catch ( ( ) => null )
700
+ }
701
+ function loadFonts ( fonts ) {
702
+ return Promise . all ( fonts . map ( getLocalFontFamily ) )
703
+ . then ( list => list . filter ( font => font !== null ) )
704
+ }
705
+ function exit ( value , btn , notation , data , isLies ) {
706
+ addBoth ( 12 , METRIC , value , btn , notation , data , isLies )
707
+ log_perf ( 12 , METRIC , t0 )
708
+ return resolve ( )
709
+ }
710
+
711
+ Promise . all ( [
712
+ testLocalFontFamily ( fntFaceFake ) ,
713
+ ] ) . then ( function ( res ) {
714
+ let value = '' , data = '' , btn = '' , notation = '' , isLies = false
715
+ try {
716
+ let test = res [ 0 ]
717
+ let fntList = fntFaceData . full
718
+ if ( fntFaceFake == test ) { throw zErrInvalid + 'fake font detected'
719
+ } else if ( 'NetworkError: A network error occurred.' !== test ) { throw test
720
+ } else if ( 0 == fntList . length ) {
721
+ exit ( zNA , btn , notation , data , isLies )
722
+ } else {
723
+ loadFonts ( fntFaceData . full ) . then ( function ( results ) {
724
+ if ( results . length ) {
725
+ if ( results . includes ( fntFaceFake ) ) { isLies = true }
726
+ data = results , value = mini ( results )
727
+ btn = addButton ( 12 , METRIC , results . length )
728
+ } else {
729
+ value = 'none'
730
+ }
731
+ exit ( value , btn , notation , data , isLies )
732
+ } )
733
+ }
734
+ } catch ( e ) {
735
+ exit ( log_error ( 12 , METRIC , e ) , btn , notation , zErr , false )
736
+ }
737
+ } )
738
+ } )
739
+
629
740
function get_fonts_base ( METRICB , selected ) {
630
741
// selected can be: 'unknown', 'n/a' or any of the domrect or perspective or pixel
631
742
@@ -698,14 +809,12 @@ function get_fonts_base(METRICB, selected) {
698
809
let btn = addButton ( 12 , METRICB , Object . keys ( selectBase ) . length + '/' + fntData . generic_name . length )
699
810
addBoth ( 12 , METRICB , hash , btn , '' , newobj )
700
811
} else {
701
- //function addBoth(section, metric, str, btn =''
702
812
addBoth ( 12 , METRICB , selected )
703
813
}
704
814
}
705
815
706
816
const get_fonts_size = ( isMain = true , METRIC = 'font_sizes' ) => new Promise ( resolve => {
707
817
/* getDimensions code based on https://github.com/abrahamjuliot/creepjs */
708
- //let t0 = nowFn()
709
818
// reset
710
819
fntBaseInvalid = { }
711
820
fntBaseMin = [ ]
@@ -970,7 +1079,6 @@ const get_fonts_size = (isMain = true, METRIC = 'font_sizes') => new Promise(res
970
1079
}
971
1080
}
972
1081
973
- //console.log(nowFn() - t0 +' ms')
974
1082
removeElementFn ( id )
975
1083
return resolve ( oTests )
976
1084
} catch ( e ) {
@@ -987,9 +1095,9 @@ const get_fonts_size = (isMain = true, METRIC = 'font_sizes') => new Promise(res
987
1095
function get_fonts ( METRIC ) {
988
1096
/*
989
1097
- only notate font_names == not a metric but is picked up health
990
- - sizes we record all errors and lies per method. This is all we need for method
991
- results/entropy - sizes is either something or unknown: so never notate or zLIES
992
- - sizes_base + sizes_methos : never notate or zLIES : it is simply a reflection
1098
+ - sizes we record all errors + lies per method. This is all we need for method
1099
+ results/entropy - sizes is either something or unknown: so never notate or lies
1100
+ - sizes_base + sizes_methods : never notate or lies : it is simply a reflection
993
1101
of what happened in sizes
994
1102
*/
995
1103
@@ -1753,8 +1861,9 @@ const outputFonts = () => new Promise(resolve => {
1753
1861
] ) . then ( function ( ) {
1754
1862
// allow more time for font async fallback
1755
1863
Promise . all ( [
1864
+ get_fontfaces ( 'font_faces' ) ,
1756
1865
get_glyphs ( 'glyphs' ) ,
1757
- get_textmetrics ( 'textmetrics' )
1866
+ get_textmetrics ( 'textmetrics' ) ,
1758
1867
] ) . then ( function ( ) {
1759
1868
if ( fntBtn . length ) { addDisplay ( 12 , 'fntBtn' , fntBtn ) }
1760
1869
return resolve ( )
0 commit comments