Skip to content

Commit 3ac0b7a

Browse files
add font faces [WIP] (#372)
1 parent 8d2795e commit 3ac0b7a

File tree

4 files changed

+144
-34
lines changed

4 files changed

+144
-34
lines changed

js/fonts.js

+136-27
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ let fntCodes = { // sorted
2121
}
2222

2323
let fntData = {},
24+
fntFaceData = {},
2425
fntSize = '512px',
2526
fntString = '-\uffff',
2627
fntBtn ='',
@@ -122,12 +123,12 @@ let fntMaster = {
122123
'Times New Roman Greek','Times New Roman TUR','Tms Rmn','MS Serif Greek','Small Fonts Greek',
123124
'標準ゴシック','ゴシック','ゴシック', // MS ゴシック -> MS Gothic
124125
'ヘルベチカ','タイムズロマン','クーリエ', // 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
131132
],
132133
},
133134
// TB unexpected
@@ -151,6 +152,12 @@ let fntMaster = {
151152
'Gill Sans','Gill Sans MT', // MS bundled
152153
'Noto Serif Hmong Nyiakeng', // 'Noto Sans Symbols2', // TB12 fontnames
153154
],
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+
],
154161
},
155162
// kBaseFonts: https://searchfox.org/mozilla-central/search?path=StandardFonts*.inc
156163
base: {
@@ -259,18 +266,22 @@ let fntMaster = {
259266
// system aliases: should always be the same AFAICT
260267
// https://searchfox.org/mozilla-central/source/gfx/thebes/gfxDWriteFontList.cpp#1990
261268
'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+
//*/
273271
],
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+
]
274285
},
275286
// kLangPackFonts
276287
baselang: {
@@ -302,6 +313,9 @@ let fntMaster = {
302313
// '標準明朝', // MS 明朝 -> MS Mincho
303314
// 'FangSong_GB2312',
304315
],
316+
windowsface: [
317+
'BIZ UDMincho Medium','BIZ UDPMincho Medium','DengXian Light','Yu Mincho Demibold','Yu Mincho Light'
318+
],
305319
},
306320
system: {
307321
android: [
@@ -434,6 +448,17 @@ let fntMaster = {
434448
// MS downloads
435449
'Cascadia Code','Cascadia Mono', // 11
436450
],
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+
],
437462
},
438463
// isOS
439464
mini: [
@@ -450,9 +475,11 @@ function set_fntList() {
450475
if (build) {
451476
isFontSizesPrevious = isFontSizesMore
452477
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: [],
455481
}
482+
fntFaceData = {base: [], baselang: [], fpp: [], full: [], unexpected: []}
456483

457484
// fntString
458485
if (isTB || 'android' == isOS || 'linux' == isOS) {
@@ -507,7 +534,7 @@ function set_fntList() {
507534
// lists
508535
if (isOS !== undefined) {
509536
fntFake = '--00'+ rnd_string()
510-
let array = []
537+
let array = [], osface = isOS +'face'
511538
if ('android' == isOS) {
512539
// notos
513540
fntMaster.android.notoboth.forEach(function(fnt) {array.push('Noto Sans '+ fnt, 'Noto Serif '+ fnt)})
@@ -533,6 +560,14 @@ function set_fntList() {
533560
fntData.unexpected = fntMaster.blocklist[isOS]
534561
array = array.concat(fntMaster.blocklist[isOS])
535562
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+
}
536571
} else {
537572
// desktop FF
538573
array = fntMaster.base[isOS]
@@ -544,6 +579,19 @@ function set_fntList() {
544579
array = array.concat(fntMaster.system[isOS])
545580
fntData.unexpected = fntMaster.system[isOS]
546581
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+
}
547595
}
548596
// -control from lists
549597
if (fntPlatformFont !== undefined) {
@@ -626,6 +674,69 @@ function get_document_fonts(METRIC) {
626674
return
627675
}
628676

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+
629740
function get_fonts_base(METRICB, selected) {
630741
// selected can be: 'unknown', 'n/a' or any of the domrect or perspective or pixel
631742

@@ -698,14 +809,12 @@ function get_fonts_base(METRICB, selected) {
698809
let btn = addButton(12, METRICB, Object.keys(selectBase).length +'/'+ fntData.generic_name.length)
699810
addBoth(12, METRICB, hash, btn,'', newobj)
700811
} else {
701-
//function addBoth(section, metric, str, btn =''
702812
addBoth(12, METRICB, selected)
703813
}
704814
}
705815

706816
const get_fonts_size = (isMain = true, METRIC = 'font_sizes') => new Promise(resolve => {
707817
/* getDimensions code based on https://github.com/abrahamjuliot/creepjs */
708-
//let t0 = nowFn()
709818
// reset
710819
fntBaseInvalid = {}
711820
fntBaseMin = []
@@ -970,7 +1079,6 @@ const get_fonts_size = (isMain = true, METRIC = 'font_sizes') => new Promise(res
9701079
}
9711080
}
9721081

973-
//console.log(nowFn() - t0 +' ms')
9741082
removeElementFn(id)
9751083
return resolve(oTests)
9761084
} catch(e) {
@@ -987,9 +1095,9 @@ const get_fonts_size = (isMain = true, METRIC = 'font_sizes') => new Promise(res
9871095
function get_fonts(METRIC) {
9881096
/*
9891097
- 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
9931101
of what happened in sizes
9941102
*/
9951103

@@ -1753,8 +1861,9 @@ const outputFonts = () => new Promise(resolve => {
17531861
]).then(function(){
17541862
// allow more time for font async fallback
17551863
Promise.all([
1864+
get_fontfaces('font_faces'),
17561865
get_glyphs('glyphs'),
1757-
get_textmetrics('textmetrics')
1866+
get_textmetrics('textmetrics'),
17581867
]).then(function(){
17591868
if (fntBtn.length) {addDisplay(12, 'fntBtn', fntBtn)}
17601869
return resolve()

js/globals.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const btnList = ['alerts', 'errors', 'lies']
1919

2020
const jsFilesExpected = 14,
2121
gSectionsExpected = 16,
22-
expectedMetrics = 144
22+
expectedMetrics = 145
2323
let jsFiles = 0, gCount = 0, gCountTiming = 0
2424

2525
// global
@@ -67,8 +67,8 @@ const zD = 'disabled',
6767
zLIE = 'untrustworthy',
6868
zSKIP = 'skipped'
6969

70-
let zErrLog = '', // log error in addBoth
71-
zErrShort = '' // log error in addBoth but display zErr in addDisplay
70+
let zErrLog = '', // log error in add/Both
71+
zErrShort = '' // log error in add/Both but display zErr in add/Display
7272

7373
// grab as soon as possible
7474
let isInitial = {height: {}, width: {}}

js/storage.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ function test_idb(log = false) {
248248
}
249249

250250
const test_worker_service = (log = false) => new Promise(resolve => {
251-
let t0 = performance.now()
251+
let t0 = nowFn()
252252
const METRIC = 'service_worker_test'
253253
function exit(value) {
254254
dom[METRIC] = value
@@ -266,7 +266,7 @@ const test_worker_service = (log = false) => new Promise(resolve => {
266266
})
267267

268268
const test_worker_shared = (log = false) => new Promise(resolve => {
269-
let t0 = performance.now()
269+
let t0 = nowFn()
270270
const METRIC = 'shared_worker_test'
271271
function exit(value) {
272272
dom[METRIC] = value
@@ -290,7 +290,7 @@ const test_worker_shared = (log = false) => new Promise(resolve => {
290290
})
291291

292292
const test_worker_web = (log = false) => new Promise(resolve => {
293-
let t0 = performance.now()
293+
let t0 = nowFn()
294294
const METRIC = 'web_worker_test'
295295
function exit(value) {
296296
dom[METRIC] = value

tzp.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,8 @@
729729
<span id="cssWoff2"></span> | <span class="c" id="woff2">
730730
</span>
731731
</td></tr>
732-
<!--fontsizes-->
732+
<!--fonts-->
733+
<tr><td>[faces] fonts</td><td class="mono" id="font_faces"></td></tr>
733734
<tr><td>[methods] fonts <sup>3</sup></td>
734735
<td class="c mono" id="font_sizes_methods"></td></tr>
735736
<tr><td><span id="labelFS" class="btn btn0" onClick="togglerows('FS','btn')">[+]</span>

0 commit comments

Comments
 (0)