From 58e642df5d036459a0f991381c55705efaea3c4e Mon Sep 17 00:00:00 2001 From: Thorin-Oakenpants Date: Fri, 13 Oct 2023 05:47:56 +0000 Subject: [PATCH] lotsa stuff (#251) --- css/index.css | 8 +- css/media.css | 6 +- js/audio.js | 2 +- js/css.js | 54 ++- js/devices.js | 89 ++-- js/elements.js | 2 +- js/fonts.js | 67 +-- js/generic.js | 149 +++--- js/globals.js | 12 +- js/media.js | 2 +- js/misc.js | 53 +- js/region.js | 70 ++- js/screen.js | 1266 ++++++++++++++++++++++++------------------------ js/storage.js | 7 +- js/webgl.js | 2 +- tzp.html | 86 ++-- 16 files changed, 947 insertions(+), 928 deletions(-) diff --git a/css/index.css b/css/index.css index eeb341c0..40603c3b 100644 --- a/css/index.css +++ b/css/index.css @@ -56,10 +56,6 @@ code { background: rgba(142, 142, 145, 0.25) !important; padding: 2px 6px; /* top+bottom | left+ right */ } -code.lies { - background-color: rgba(255, 79, 79, 0.6) !important; - color: white; -} #modaloverlay { position: fixed; @@ -122,6 +118,10 @@ a.return {color: var(--test12); text-decoration: none; font-size: 14px; line-he .strike {text-decoration: line-through;} .spaces {white-space: pre-wrap;} .perf {font-family: monospace, "Courier New"; font-size: 12px; white-space: pre-wrap;} +.lies { + color: var(--test99); + text-decoration: underline; /*var(--test0);*/ +} .cursive {font-family: cursive;} .emoji {font-family: emoji;} diff --git a/css/media.css b/css/media.css index 3673a5d8..f51bd478 100644 --- a/css/media.css +++ b/css/media.css @@ -58,7 +58,11 @@ @media (color:18){#cssC:after{content:"18";}} @media (color:19){#cssC:after{content:"19";}} @media (color:20){#cssC:after{content:"20";}} -@media (color:21){#cssC:after{content:"";}} +@media (color:21){#cssC:after{content:"21";}} +@media (color:22){#cssC:after{content:"22";}} +@media (color:23){#cssC:after{content:"23";}} +@media (color:24){#cssC:after{content:"24";}} +@media (color:25){#cssC:after{content:"";}} #cssP:after{content:"n/a";} @media (pointer:fine){#cssP:after{content:"fine";}} diff --git a/js/audio.js b/js/audio.js index 4f1e8a1f..14e57411 100644 --- a/js/audio.js +++ b/js/audio.js @@ -73,7 +73,7 @@ const get_audio2_context = (os = isOS) => new Promise(resolve => { // ac-outputLatency is variable per tab and even on page load // so on non RFP hashes, change it to variable and display the original on screen - if (note !== rfp_green) { + if (isGecko && note !== rfp_green) { latencynote = " [" + objnew["ac-outputLatency"]+ " latency]" objnew["ac-outputLatency"] = "variable" hash = mini(objnew) diff --git a/js/css.js b/js/css.js index cb5c97fa..24bd7d6f 100644 --- a/js/css.js +++ b/js/css.js @@ -19,20 +19,22 @@ function get_colors() { 'InfoText','Menu','MenuText','Scrollbar','ThreeDDarkShadow','ThreeDFace','ThreeDHighlight', 'ThreeDLightShadow','ThreeDShadow','Window','WindowFrame','WindowText', ], - "moz": [ // FF117+: + "moz": [ // FF120+: '-moz-buttonhoverface','-moz-buttonhovertext','-moz-cellhighlight','-moz-cellhighlighttext', '-moz-combobox','-moz-comboboxtext','-moz-dialog','-moz-dialogtext','-moz-eventreerow','-moz-field', '-moz-fieldtext','-moz-html-cellhighlight','-moz-html-cellhighlighttext','-moz-mac-active-menuitem', '-moz-mac-active-source-list-selection','-moz-mac-defaultbuttontext','-moz-mac-disabledtoolbartext', - '-moz-mac-focusring','-moz-mac-menuitem','-moz-mac-menupopup','-moz-mac-menutextdisable', - '-moz-mac-menutextselect','-moz-mac-source-list','-moz-mac-source-list-selection','-moz-mac-tooltip', - '-moz-menubarhovertext','-moz-menuhover','-moz-menuhovertext','-moz-nativehyperlinktext','-moz-oddtreerow', + '-moz-mac-focusring','-moz-mac-menuitem','-moz-mac-menupopup','-moz-mac-source-list', + '-moz-mac-source-list-selection','-moz-mac-tooltip','-moz-menubarhovertext','-moz-menuhover', + '-moz-menuhovertext','-moz-nativehyperlinktext','-moz-oddtreerow', ], } - if (isVer < 117) { + if (isVer < 120) { // ToDo: change to < 119 once beta backport confirmed let aTmp = oList["moz"] aTmp.push ( + // removed/backported FF119 1857695 + '-moz-mac-menutextdisable','-moz-mac-menutextselect', // removed FF117 "-moz-buttondefault","-moz-dragtargetzone","-moz-mac-chrome-active","-moz-mac-chrome-inactive", "-moz-mac-menuselect","-moz-mac-menushadow","-moz-mac-secondaryhighlight","-moz-menubartext", @@ -85,9 +87,10 @@ function get_colors() { let btn = addButton(14, METRIC, Object.keys(newobj).length +"/"+ count) addData(14, METRIC, newobj, hash) if (isSmart && type == "moz") { - let check = "5a00aa84" // FF117+ - if (isVer < 103) {check = "c0df6598"} else if (isVer < 117) {check = "788e7d22"} - notation = hash == check ? rfp_green : rfp_red // 1734115 + let check = "47538602" // FF119+ + if (isVer < 117) {check = "788e7d22" // 115-116 + } else if (isVer < 119) {check = "5a00aa84"} // 117-118 + notation = hash == check ? rfp_green : rfp_red } log_display(14, METRIC, hash + btn + notation) } catch(e) { @@ -118,7 +121,7 @@ function get_computed_styles() { const names = ["styles_cssrulelist","styles_getcomputed","styles_htmlelement"] let aErr = [false, false, false], isLies = false let aHashes = [], intHashes = [], oDisplay = {} - let check = (isSmart && isTB && isVer > 114) + let check = (isSmart && isTB) let notation = check ? tb_red : "" let styleVersion = type => { @@ -297,12 +300,17 @@ function get_computed_styles() { log_known(SECT14, METRIC) } else { if (check) { - /* win diff - layout.css.font-variations.enabled = locked false on win 7 - fontOpticalSizing, font-optical-sizing, fontVariationSettings, font-variation-settings - */ - if (hash === "e32d06bd") {notation = tb_green // TB/MB win11 + linux, TB android: 1102 - } else if (hash === "e14684e7") {notation = tb_green} // TB/MB win7 1098 + if (isOS == "mac") { + /* mac 1102 vs win 1102: mac has: MozOsxFontSmoothing, -moz-osx-font-smoothing */ + if (hash === "75600d93") {notation = tb_green} // TB 1102 + } else { + /* win diff + layout.css.font-variations.enabled = locked false on win 7 + fontOpticalSizing, font-optical-sizing, fontVariationSettings, font-variation-settings + */ + if (hash === "e32d06bd") {notation = tb_green // TB/MB win11 + linux, TB android: 1102 + } else if (hash === "e14684e7") {notation = tb_green} // TB/MB win7 1098 + } } addData(14, METRIC, res[lookup]["keys"], hash) } @@ -343,7 +351,7 @@ function get_computed_styles() { const get_mm_css = () => new Promise(resolve => { function get_mm(type, id, rfpvalue, minVer) { - const METRIC = type + const METRIC = type, METRIC2 = type +"_css" let value = zNA, display = value, q = type, isErr = false try { if (window.matchMedia("("+ q +":no-preference)").matches) {value = "no-preference" @@ -362,24 +370,26 @@ const get_mm_css = () => new Promise(resolve => { display = log_error(SECT14, METRIC, e) value = zErr } + let cssvalue = getElementProp(SECT14, "#css"+ id, METRIC2) + let isErrCss = cssvalue == zErr if (isSmart) { - let cssvalue = getElementProp(SECT14, "#css"+ id) - if (value !== cssvalue && cssvalue !== "x") { - if (!isErr) { + if (!isErr && !isErrCss) { + if (value !== cssvalue) { display = colorFn(display) value = zLIE log_known(SECT14, METRIC) } } if (rfpvalue !== undefined) { - // notate: only apply notation from when it was flipped + // notate from when it was flipped if (minVer == undefined || minVer < isVer) { - display += display == rfpvalue ? rfp_green : rfp_red + display += display == rfpvalue ? rfp_green : rfp_red // mm + log_display(14, type +"_css", (cssvalue == rfpvalue ? rfp_green : rfp_red)) // css } } } log_display(14, type, display) - res.push([METRIC, value]) + res.push([METRIC, value], [METRIC2, cssvalue]) } let res = [] diff --git a/js/devices.js b/js/devices.js index 81c69bd4..0478e27a 100644 --- a/js/devices.js +++ b/js/devices.js @@ -66,11 +66,7 @@ const get_maxtouch = () => new Promise(resolve => { }) const get_mm_color = () => new Promise(resolve => { - const METRIC = "color" - function exit(value, display) { - log_display(7, METRIC, display) - return resolve([METRIC, value]) - } + const METRIC = "color", METRIC2 = METRIC +"_css" let isErr = false, value, display try { if (runSE) {foo++} @@ -85,61 +81,57 @@ const get_mm_color = () => new Promise(resolve => { } catch(e) { isErr = true; value = zErr; display = log_error(SECT7, METRIC, e) } + let cssvalue = getElementProp(SECT7, "#cssC", METRIC2) + let isErrCss = cssvalue == zErr if (isSmart) { - let cssvalue = getElementProp(SECT7, "#cssC") - if (value !== cssvalue && cssvalue !== "x") { - if (!isErr) { + if (!isErr && !isErrCss) { + if (value !== cssvalue) { display = colorFn(display) value = zLIE log_known(SECT7, METRIC) } } - display += display === 8 ? rfp_green : rfp_red + display += display === 8 ? rfp_green : rfp_red // mm + log_display(7, METRIC2, (cssvalue === 8 ? rfp_green : rfp_red)) // css } - exit(value, display) + log_display(7, METRIC, display) + return resolve([[METRIC, value], [METRIC2, cssvalue]]) }) const get_mm_colorgamut = () => new Promise(resolve => { - const METRIC = "color-gamut" - function exit(value, display) { - log_display(7, METRIC, display) - return resolve([METRIC, value]) - } + const METRIC = "color-gamut", METRIC2 = METRIC +"_css" + let value = zNA, display = value, isErr = false try { if (runSE) {foo++} - let value = zNA, display = value let q = "(color-gamut: " if (window.matchMedia(q +"srgb)").matches) {value = "srgb"} if (window.matchMedia(q +"p3)").matches) {value = "p3"} if (window.matchMedia(q +"rec2020)").matches) {value = "rec2020"} if (runSL) {value = "p3"} display = value - if (isSmart) { - let cssvalue = getElementProp(SECT7, "#cssCG") - if (value !== cssvalue && cssvalue !== "x") { + } catch(e) { + isErr = true; value = zErr; display = log_error(SECT7, METRIC, e) + } + let cssvalue = getElementProp(SECT7, "#cssCG", METRIC2) + let isErrCss = cssvalue == zErr + if (isSmart) { + if (!isErr && !isErrCss) { + if (value !== cssvalue) { display = colorFn(display) value = zLIE log_known(SECT7, METRIC) } - // FF110+: 1422237 - if (isVer > 109) { - display += display === "srgb" ? rfp_green : rfp_red - } } - exit(value, display) - } catch(e) { - log_error(SECT7, METRIC, e) - log_display(7, METRIC, zErr + (isSmart ? rfp_red : "")) - return resolve([METRIC, zErr]) + // FF110+: 1422237 + display += display === "srgb" ? rfp_green : rfp_red // mm + log_display(7, METRIC2, (cssvalue === "srgb" ? rfp_green : rfp_red)) // css } + log_display(7, METRIC, display) + return resolve([[METRIC, value], [METRIC2, cssvalue]]) }) const get_mm_pointer = (group, type, id, rfpvalue) => new Promise(resolve => { - const METRIC = type - function exit(value, display) { - log_display(7, type, display) - return resolve([METRIC, value]) - } + const METRIC = type, METRIC2 = type +"_css" let value = zNA, display = value, isErr = false try { if (runSE) {foo++} @@ -168,14 +160,15 @@ const get_mm_pointer = (group, type, id, rfpvalue) => new Promise(resolve => { display = log_error(SECT7, METRIC, e) isErr = true; value = zErr } + let cssvalue = getElementProp(SECT7, id, METRIC2) + let isErrCss = cssvalue == zErr if (isSmart) { if (value !== zErr) { - let cssvalue = getElementProp(SECT7, id) - if (group == 2 && cssvalue !== "x") { - let cssvalue2 = getElementProp(SECT7, id, ":before") + if (group == 2 && !isErrCss) { + let cssvalue2 = getElementProp(SECT7, id, METRIC2, ":before") cssvalue = cssvalue2 + cssvalue } - if (value !== cssvalue && cssvalue !== "x") { + if (value !== cssvalue && !isErrCss) { display = colorFn(display) value = zLIE log_known(SECT7, METRIC) @@ -183,12 +176,15 @@ const get_mm_pointer = (group, type, id, rfpvalue) => new Promise(resolve => { } // notate: FF74+ 1607316 if (type == "any-pointer" && isOS !== "android") { - display += display === "fine + fine" ? rfp_green : rfp_red + display += display === "fine + fine" ? rfp_green : rfp_red // mm + log_display(7, METRIC2, (cssvalue === "fine + fine" ? rfp_green : rfp_red)) // css } else if (isOS == "android") { - display += display === rfpvalue ? rfp_green : rfp_red + display += display === rfpvalue ? rfp_green : rfp_red // mm + log_display(7, METRIC2, (cssvalue === rfpvalue ? rfp_green : rfp_red)) // css } } - exit(value, display) + log_display(7, type, display) + return resolve([[METRIC, value], [METRIC2, cssvalue]]) }) const get_media_devices = () => new Promise(resolve => { @@ -202,10 +198,14 @@ const get_media_devices = () => new Promise(resolve => { return value == "TypeError: navigator.mediaDevices is undefined" ? tb_green : tb_red } else { // RFP if (isLies) {return (isMullvad ? tb_red : rfp_red)} - let rfplegacy = "02ab1e4c", rfpnew = "7a2e5d0c" - if (isVer < 115) {rfpnew = rfplegacy - } else if (isMullvad) {rfplegacy = rfpnew} // tor-browser#42043 - return ((value == rfplegacy || value == rfpnew) ? rfp_green : (isMullvad ? tb_red : rfp_red)) + legacy + let rfplegacy = "02ab1e4c", rfpnew = "7a2e5d0c" + if (isMullvad) { + // tor-browser#42043 + return (value == rfpnew ? tb_green : tb_red) + legacy + } else { + // FF: ToDo: 1843434: add version check when flipped + return ((value == rfplegacy || value == rfpnew) ? rfp_green : rfp_red) + legacy + } } } return "" + legacy @@ -403,7 +403,6 @@ function get_plugins_mimetypes() { get_mimetypes(), ]).then(function(results){ - return resolve() }) }) diff --git a/js/elements.js b/js/elements.js index b9ca8bec..f683cd0e 100644 --- a/js/elements.js +++ b/js/elements.js @@ -3,7 +3,7 @@ const get_element_keys = () => new Promise(resolve => { const METRIC = "htmlelement_keys" const id = "html-element-version" - let check = (isSmart && isTB && isVer > 114) + let check = (isSmart && isTB) let notation = check ? tb_red : "" function cleanup() { diff --git a/js/fonts.js b/js/fonts.js index 6534fc59..d6a5ecbb 100644 --- a/js/fonts.js +++ b/js/fonts.js @@ -97,9 +97,19 @@ let fntMaster = { 'Cantarell','DejaVu Sans','DejaVu Serif','Droid Sans','STIX', // fedora 'Dingbats','FreeMono','Ubuntu', // ubuntu 'Liberation Mono','Liberation Sans','Liberation Serif', // popular + // TB12 fontnames, should have been removed + 'Noto Serif Hmong Nyiakeng','Noto Sans Symbols2','STIX Math', + ], + 'mac': [ + 'Apple Symbols','Avenir','Charter','Impact','Palatino','Rockwell', + // TB12 fontnames, should have been removed + 'Noto Serif Hmong Nyiakeng','Noto Sans Symbols2','STIX Math', + ], + 'windows': [ + 'Calibri','Candara','Corbel','Impact','Ebrima','Gabriola', + // TB12 fontnames, should have been removed + 'Noto Serif Hmong Nyiakeng','Noto Sans Symbols2', ], - 'mac': ['Apple Symbols','Avenir','Charter','Impact','Palatino','Rockwell',], - 'windows': ['Calibri','Candara','Corbel','Impact','Ebrima','Gabriola',], }, // kBaseFonts: https://searchfox.org/mozilla-central/search?path=StandardFonts*.inc 'base': { @@ -120,6 +130,8 @@ let fntMaster = { 'Microsoft Sans Serif','Microsoft Tai Le','Microsoft YaHei','Microsoft Yi Baiti','MingLiU-ExtB','MingLiU_HKSCS-ExtB', 'Mongolian Baiti','NSimSun','PMingLiU-ExtB','Palatino Linotype','Segoe Print','Segoe Script','Segoe UI','Segoe UI Symbol', 'SimSun','SimSun-ExtB','Sylfaen','Symbol','Tahoma','Times New Roman','Trebuchet MS','Verdana','Webdings','Wingdings', + // 7 but not detected if font-vis < 3: 1720408 + 'Franklin Gothic Medium', // 8 'Gadugi','Nirmala UI','Microsoft JhengHei UI','Microsoft YaHei UI','Myanmar Text', // 8.1 @@ -127,21 +139,19 @@ let fntMaster = { 'Sitka Heading','Sitka Small','Sitka Subheading','Sitka Text','Yu Gothic', // 10 'Bahnschrift','HoloLens MDL2 Assets','Segoe MDL2 Assets','Segoe UI Historic','Yu Gothic UI', - // FontSubstitutes - // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes - 'MS Shell Dlg','MS Shell Dlg \\32', // might differ based on system locale/install - 'Helv','Helvetica','Times','Tms Rmn', // seems stable - - // localized: kBase: detected FF120+: 1850672 + // localized: kBase: detected FF119+: 1850672 '微软雅黑', // Microsoft YaHei 'MS ゴシック', // MS Gothic 'MS Pゴシック', // MS PGothic '宋体', // SimSun '游ゴシック', // Yu Gothic - /* ignore: https://searchfox.org/mozilla-central/source/gfx/thebes/gfxDWriteFontList.cpp#1990 'MS Sans Serif','MS Serif','Courier','Small Fonts','Roman', */ + // FontSubstitutes + // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes + 'MS Shell Dlg','MS Shell Dlg \\32', // might differ based on system locale/install + 'Helv','Helvetica','Times','Tms Rmn', // seems stable /* variants // 7 @@ -236,6 +246,8 @@ let fntMaster = { 'Simplified Arabic Fixed','Traditional Arabic','Tunga','UD Digi Kyokasho N-B','UD Digi Kyokasho N-R', 'UD Digi Kyokasho NK-B','UD Digi Kyokasho NK-R','UD Digi Kyokasho NP-B','UD Digi Kyokasho NP-R','Urdu Typesetting', 'Utsaah','Vani','Verdana Pro','Vijaya','Vrinda','Yu Mincho', + // win11 + 'Sans Serif Collection', // localized ^ '바탕', // Batang 'BIZ UDPゴシック', // BIZ UDPGothic @@ -247,8 +259,6 @@ let fntMaster = { 'MS P明朝', // MS PMincho '新細明體', // PMingLiU - // kBase but broken: 1720408 - 'Franklin Gothic Medium', // MS products 'Arial Unicode MS','MS Reference Specialty','MS Outlook', // MS downloads @@ -287,34 +297,6 @@ function set_fntList(os = isOS) { "generic": [], } - // diffs fom TB13 - if (isTB) { - if (isVer < 115) { - // ToDo: isSmartMin=115 remove - // renamed: Noto Sans Symbols 2 (new) vs Noto Sans Symbols2 (old) - let tmpArray = fntMaster["bundled"]["allnotosans"] - tmpArray.push("Symbols2") - tmpArray = tmpArray.filter(x => !["Symbols 2"].includes(x)) - fntMaster["bundled"]["allnotosans"] = tmpArray.sort() - // renamed: Noto Serif NP Hmong (new) vs Noto Serif Hmong Nyiakeng (old) - tmpArray = fntMaster["bundled"]["allnotoserif"] - tmpArray.push("Hmong Nyiakeng") - tmpArray = tmpArray.filter(x => !["NP Hmong"].includes(x)) - fntMaster["bundled"]["allnotoserif"] = tmpArray.sort() - // mac/linux: STIX Two Math (new) vs STIX Math (old) - tmpArray = fntMaster["bundled"]["linux"] - tmpArray.push("STIX Math") - tmpArray = tmpArray.filter(x => !["STIX Two Math"].includes(x)) - fntMaster["bundled"]["linux"] = tmpArray.sort() - fntMaster["bundled"]["mac"] = ['Noto Sans Armenian','Noto Sans Hebrew','Noto Serif Armenian','Noto Serif Hebrew','STIX Math',] - } else { - // make sure old fonts + font names were removed - fntMaster.blocklist.windows.push("Noto Serif Hmong Nyiakeng","Noto Sans Symbols2") - fntMaster.blocklist.linux.push("Noto Serif Hmong Nyiakeng","Noto Sans Symbols2","STIX Math") - fntMaster.blocklist.mac.push("Noto Serif Hmong Nyiakeng","Noto Sans Symbols2","STIX Math") - } - } - // baseSize: add fallback for misconfigured/missing // isPlatformFont: expected + can't be blocked + differs vs most fonts // no entropy loss: size collisions of expected system fonts e.g. Tahoma @@ -992,6 +974,7 @@ const get_system_fonts = (os = isOS) => new Promise(resolve => { ] let aProps = ['font-size','font-style','font-weight','font-family'] let oRes = {}, notation = "" + let check = (isSmart && isTB) try { if (runSE) {foo++} let el = dom.sysFont @@ -1005,14 +988,14 @@ const get_system_fonts = (os = isOS) => new Promise(resolve => { let newobj = {}, count = 0 for (const k of Object.keys(oRes).sort()) {newobj[k] = oRes[k]; count += newobj[k].length} let hash = mini(newobj) - if (isSmart && isTB && isVer > 114) { + if (check) { // https://gitlab.torproject.org/tpo/applications/tor-browser/-/issues/41646 notation = tb_red if (os == "windows") { /* "12px normal 400 sans-serif" */ if (hash == "c89fb033") {notation = tb_green} } else if (os == "mac") { - if (hash == "") {notation = tb_green} + if (hash == "1dc326ac") {notation = tb_green} } else if (os == "linux") { /* "15px normal 400 sans-serif" */ if (hash == "7b469d36") {notation = tb_green} @@ -1025,7 +1008,7 @@ const get_system_fonts = (os = isOS) => new Promise(resolve => { log_display(12, METRIC, hash + addButton(12, METRIC, Object.keys(newobj).length +"/"+ count) + notation) return resolve() } catch(e) { - notation = (isSmart && isTB && isVer > 14) ? tb_red : "" + notation = check ? tb_red : "" log_display(12, METRIC, log_error(SECT12, METRIC, e) + notation) return resolve([METRIC, zErr]) } diff --git a/js/generic.js b/js/generic.js index 2cab1885..4875f5c9 100644 --- a/js/generic.js +++ b/js/generic.js @@ -121,7 +121,7 @@ function json_stringify(passedObj, options = {}) { const newFn = x => typeof x != 'string' ? x : new Function(x)() function nowFn() {if (isPerf) {return performance.now()}; return} -function colorFn(str) {return ""+ str +""} +function colorFn(str) {return ""+ str +""} function rnd_string() {return Math.random().toString(36).substring(2, 15)} function rnd_number() {return Math.floor((Math.random() * (99999-10000))+10000)} @@ -158,19 +158,45 @@ function run_basic() { } } -function getElementProp(SECT, id, pseudo = ":after") { - if (runPS) {return "x"} +function getElementProp(SECT, id, name, pseudo = ":after") { + // default none: https://www.w3.org/TR/CSS21/generate.html#content try { + if (runSE) {foo++} let item = window.getComputedStyle(document.querySelector(id), pseudo) item = item.getPropertyValue("content") - if (item == "none") {item = "x"} - item = item.replace(/"/g,"") + if (runPS) {item = "none"} + let originalitem = item + item = item.replace(/"/g,"") // trim quote marks + //console.log(SECT, id, name, pseudo, "~"+ item +"~", "~"+ originalitem +"~") + + // out of range: screen/window returns "none" + if (id == "#S" || id == "#D") { + if (item == "none") { + item = "?" + } else if (pseudo == ":after") { + item = item.slice(3) + } + } else if (id == "#P") { + // out of range: dpi returns "" + if (item == "") {item = "?"} + } if (!isNaN(item * 1)) {item = item * 1} // number - if (item == "") {item = "x"} // blanks + + // fuckery + if (item == "") { + log_error(SECT, name, zErrInvalid +"got ''") + item = zErr + } else if (originalitem == "none") { + // ignore screen/window + if (id !== "#S" && id !== "#D") { + log_error(SECT, name, zErrInvalid +"got 'none'") + item = zErr + } + } return item } catch(e) { - log_error(SECT, id, e) - return "x" + log_error(SECT, name, e) + return zErr } } @@ -272,6 +298,9 @@ function get_isGecko() { } const get_isOS = () => new Promise(resolve => { + if (!isGecko) { + return resolve() + } let t0 = nowFn() setTimeout(() => resolve(zErrTime), 100) const METRIC = "isOS" @@ -356,6 +385,9 @@ const get_isSystemFont = () => new Promise(resolve => { }) const get_isTB = () => new Promise(resolve => { + if (!isGecko) { + return resolve(false) + } let t0 = nowFn() setTimeout(() => resolve(t0), 150) const METRIC = "isTB" @@ -388,13 +420,11 @@ const get_isTB = () => new Promise(resolve => { }) const get_isVer = () => new Promise(resolve => { + if (!isGecko) { + return resolve() + } let t0 = nowFn() function output(verNo) { - if (!Number.isInteger(verNo)) { - log_perf(SECTG, "isVer", t0, "", verNo) - isVer = 0 - return resolve() - } isVer = verNo if (verNo < 102) {isVerExtra = " or lower" } else if (verNo == 120) {isVerExtra = "+"} @@ -428,7 +458,8 @@ const get_isVer = () => new Promise(resolve => { } return 101 } catch(e) { - return zErr + console.error(e) + return 0 } } }) @@ -436,6 +467,9 @@ const get_isVer = () => new Promise(resolve => { /*** PREREQ ***/ const get_isClientRect = () => new Promise(resolve => { + if (!isGecko) { + return resolve() + } // determine valid domrect methods let t0 = nowFn() let aNames = ["Element.getBoundingClientRect", "Element.getClientRects", @@ -547,17 +581,20 @@ function showMetrics(name, scope, isConsole = false) { let data, showhash = true, results, color = 99 if (name == SECT98 || name == SECT99) { data = gData[name] - } else if (name == "fingerprint" || name == "errors" || name == "health") { + } else if (name == "fingerprint" || name == "errors" || name == "health" || name == "lies") { data = gData[name][scope] } else if (name == "fingerprint_summary") { data = gData[zFP][scope+"_summary"] - } else if (name == "untrustworthy") {data = gKnown - } else if (name == "known methods") {data = gMethods } else if (name == "alerts") {data = gAlert; showhash = false } else if (name.slice(0,6) == "errors") { name = name.slice(6) data = sData["errors"][scope][name] name = name.toUpperCase() +": errors" showhash = false + } else if (name.slice(0,4) == "lies") { + name = name.slice(4) + data = sData["lies"][scope][name] + name = name.toUpperCase() +": lies" + showhash = false } else if (sectionNames.includes(name)) { data = sData[zFP][scope][name]; name = name.toUpperCase() } else { @@ -611,7 +648,13 @@ function output_health(scope) { } else if (metric == "fontnames") { data = sDetail[scope]["fontnames_health"] } else if (metric == "letterboxing" || metric == "new_window") { - data = gData[zFP][scope]["screen"]["metrics"]["window_inner"] + data = gData[zFP][scope]["screen"]["metrics"]["window_sizes"]["metrics"]["innerWidth"] + +" x "+ gData[zFP][scope]["screen"]["metrics"]["window_sizes"]["metrics"]["innerHeight"] + } else { + let aList = ["devicePixelRatio", "-moz-device-pixel-ratio", "dpi", "dpcm", "dppx", "dpi_css"] + if (aList.includes(metric)) { + data = gData[zFP][scope]["screen"]["metrics"]["pixels"]["metrics"][metric] + } } // handle non data so at least it shows in JSON display if (data == undefined) { data =""} @@ -731,7 +774,7 @@ function output_section(section, scope) { try { btnList.forEach(function(item) { let once = item+"once" - if (gData[once][scope] !== undefined) { + if (gData[once] !== undefined && gData[once][scope] !== undefined) { for (const s of Object.keys(gData[once][scope])) { if (!sectionNames.includes(s)) { // non-section: straight to sData: sorted @@ -823,12 +866,19 @@ function output_section(section, scope) { btnList.forEach(function(item) { let btn = "", source = {}, target = {} if (sDataTemp[item][scope] !== undefined && sDataTemp[item][scope][name] !== undefined) { - if (sData[item][scope] == undefined) {sData[item][scope] = {}} - if (sData[item][scope][name] == undefined) {sData[item][scope][name] = {}} - for (const m of Object.keys(sDataTemp[item][scope][name]).sort()) { - sData[item][scope][name][m] = sDataTemp[item][scope][name][m] + let len = 0 + if (sData[item][scope] == undefined) {sData[item][scope] = {}} + if (sData[item][scope][name] == undefined) {sData[item][scope][name] = {}} + if (item == "errors") { + for (const m of Object.keys(sDataTemp[item][scope][name]).sort()) { + sData[item][scope][name][m] = sDataTemp[item][scope][name][m] + } + len = Object.keys(sData[item][scope][name]).length + } else { + let array = sDataTemp[item][scope][name].sort() + sData[item][scope][name] = array + len = array.length } - let len = Object.keys(sData[item][scope][name]).length // catch zero length: e.g. object cleared not deleted if (len > 0) { let btnText = len + " "+ (len == 1 ? item.slice(0,-1) : item) // single/plural @@ -846,10 +896,8 @@ function output_section(section, scope) { /*** INCOMING ***/ -function addButton(color, name, text = "details", btn = "btnc", scope = isScope, color2 = undefined) { - text = "["+ text +"]" - if (color2 !== undefined) {text = colorFn(text)} - return " "+ text +"" +function addButton(color, name, text = "details", btn = "btnc", scope = isScope) { + return " ["+ text +"]" } function addData(section, metric, data, hash = undefined, includeDetail = true) { @@ -954,8 +1002,11 @@ function log_health(scope, type, section, metric, h = "health") { } } -function log_known(section, metric) { - if (gRun) {gKnown.push(section +":" + metric)} +function log_known(section, metric, scope = isScope) { + let obj = "lies" + if (sDataTemp[obj][scope] == undefined) {sDataTemp[obj][scope] = {}} + if (sDataTemp[obj][scope][section] == undefined) {sDataTemp[obj][scope][section] = []} + sDataTemp[obj][scope][section].push(metric) } function log_perf(section, metric = "", time1, time2, extra) { @@ -1051,27 +1102,6 @@ function log_section(name, time, scope = isScope) { gAlert = gAlert.concat(gAlertOnce) gAlert = gAlert.filter(function(item, position) {return gAlert.indexOf(item) === position}) gAlert.sort() - gKnown = gKnown.filter(function(item, position) {return gKnown.indexOf(item) === position}) - gKnown.sort() - gMethods = gMethods.filter(function(item, position) {return gMethods.indexOf(item) === position}) - gMethods.sort() - // known - let knownStr = "" - if (gKnown.length) { - let knownText = gKnown.length +" lie"+ (gKnown.length > 1 ? "s" : "") - knownStr = mini(gKnown) + addButton(0, "untrustworthy", knownText, "btnc", zDOC, 1) - } else { - knownStr = isSmart ? "none" : zNA - } - dom.knownhash.innerHTML = knownStr - // methods - if (gMethods.length) { - let methodStr = gMethods.length +" noted" - let methodBtn = addButton(0, "known methods", methodStr) - dom.knownmethods.innerHTML = mini(gMethods) + methodBtn - } else { - dom.knownmethods = isSmart ? "none" : zNA - } // alerts dom.allcheck = (gAlert.length ? "[ alerts ]" : "") @@ -1087,19 +1117,18 @@ function log_section(name, time, scope = isScope) { /*** RUN ***/ function countJS(filename) { - if (!isGecko) { + if (!isGecko && !isAllowNonGecko) { isBlock = true run_block() // non-gecko return } - jsFiles++ if (jsFiles === 1) { get_isVer() // as long as don't touch the dom this is fine here: required for isTB get_isSystemFont() return } else if (jsFiles === jsFilesExpected) { - gData["perf"].push([1, "RUN ONCE", nowFn()]) + if (isGecko) {gData["perf"].push([1, "RUN ONCE", nowFn()])} let t0 = nowFn() Promise.all([ get_isTB() @@ -1110,7 +1139,13 @@ function countJS(filename) { log_perf(SECTG, METRIC, results[0], "", zErrTime) log_alert(SECTG, METRIC +": "+ zErrTime, true) } - isBlock = isVer < isBlockMin[0] + // might allow non-Gecko later + if (isGecko) { + isBlock = isVer < isBlockMin[0] + } else { + isBlock = false // allow non-gecko + isSmart = false // force basic mode + } if (isBlock) { run_block() // old gecko return @@ -1232,6 +1267,7 @@ function outputSection(id, cls) { //*/ gData[zFP] = {"document":{}, "document_summary": {}} gData["errors"] = {} + gData["lies"] = {} if (!gLoad) { // don't wipe gLoad perf gData["perf"] = [] } @@ -1240,12 +1276,14 @@ function outputSection(id, cls) { "errors": {}, "fingerprint": {"document":{}}, "health": {}, + "lies": {}, } // sDataTemp sDataTemp = { "display": {"document":{}}, "errors": {}, "fingerprint": {"document":{}}, + "lies": {}, "perf": [], } sDetail = {} @@ -1272,7 +1310,6 @@ function outputSection(id, cls) { gCount = 0 gAlert = [] gKnown = [] - gMethods = [] // reset section sDetail = {} get_isDevices() diff --git a/js/globals.js b/js/globals.js index 25d2cf75..8d9708af 100644 --- a/js/globals.js +++ b/js/globals.js @@ -4,7 +4,7 @@ var dom; const SECTG = "_global", SECTP = "_prereq", SECTNF = "NON-FP", SECT1 = "screen", SECT2 = "ua", SECT3 = "feature", SECT4 = "region", - SECT5 = "network", SECT6 = "storage", SECT7 = "devices", SECT9 = "canvas", + SECT5 = "headers", SECT6 = "storage", SECT7 = "devices", SECT9 = "canvas", SECT10 = "webgl", SECT11 = "audio", SECT12 = "fonts", SECT13 = "media", SECT14 = "css", SECT15 = "elements", SECT18 = "misc", SECT98 = "prototype", SECT99 = "proxy" @@ -17,7 +17,7 @@ const sectionMap = { let sectionOrder = [], sectionNames = [] -const btnList = ["errors"] // ToDo: expand e.g alerts, lies +const btnList = ["errors", "lies"] // ToDo: expand e.g alerts const jsFilesExpected = 14 let gCountExpected = 15 @@ -29,7 +29,6 @@ let gData = { // from sData "perf": [], }, gKnown = [], // known, methods, alerts - gMethods = [], gAlert = [], gAlertOnce = [] @@ -134,12 +133,12 @@ let isArch = true, isOSErr, isSystemFont = [], isTB = false, - isVer, + isVer = 0, isVerExtra = "", isWordmark // other -let isClientRect = 1, +let isClientRect = 0, isPerf = false // runtypes @@ -147,8 +146,9 @@ let gt0, gt1, gLoad = true, gRun = true, gClick = true, + isAllowNonGecko = false, // not supported: to see what other engines return isBlock = true, - isBlockMin = [115, 13], // [FF, equivalent TB version] + isBlockMin = [102, 12], // [FF, equivalent TB version] isSmart = false, isSmartMin = 115 // we can't treat TB differently as we haven't gotten isMullvad yet which if true then sets isTB diff --git a/js/media.js b/js/media.js index d2cb5002..af1f9194 100644 --- a/js/media.js +++ b/js/media.js @@ -237,7 +237,7 @@ const get_midi = () => new Promise(resolve => { let notation = "", count = 0 function exit(name, value) { count++ - if (isSmart && isVer > 109) { + if (isSmart) { notation = value == "prompt" ? default_green : default_red } addData(13, name, value) diff --git a/js/misc.js b/js/misc.js index d1eaa798..a2b88c91 100644 --- a/js/misc.js +++ b/js/misc.js @@ -11,7 +11,6 @@ function check_mathLies() { } const get_component_shims = () => new Promise(resolve => { - // ToDo: 1448046: isSmartMin=115 ? remove this metric const METRIC = "component_interfaces" let notation = "" try { @@ -207,22 +206,23 @@ function get_navigator() { display = colorFn(display) log_known(SECT18, METRIC) } - // health: only do TB/MB as ESR is stable + // health: 115+ only do TB/MB as ESR is stable // otherwise it's way too much work to track OSes/releases and beta/early etc - if (isSmart && isTB && isVer > 114) { + if (isSmart && isTB) { notation = tb_red if (!isLies) { if (isMullvad) { - // MB + // MB13 desktop if (hash === "1bfbd5d3") {notation = tb_green} // 37: mediaDevices, mediaSession } else { - // TB - if (isOS == "android") { - if (hash === "3b7f79c3") {notation = tb_green} // 37: share, canShare (dom.webshare.enabled) - } else { - if (hash === "1054f985") {notation = tb_green} // 35 - } + if (isOS == "android") { + // TBA13 + if (hash === "3b7f79c3") {notation = tb_green} // 37: share, canShare (dom.webshare.enabled) + } else { + // TB13 desktop + if (hash === "1054f985") {notation = tb_green} // 35 } + } } } log_display(18, METRIC, display + addButton(18, METRIC, keys.length) + tamperBtn + notation) @@ -257,10 +257,9 @@ function get_recursion(log = false) { } function get_perf_mark_entries() { - // ToDo: isSmartMin=115 remove this metric + // FF111+ 1811567: no longer a health metric, but keep to detect timing fuckery const METRIC = "perf_mark_entries" - let entries = "", valueEntries = "", ctrlEntries = "0, 0, 0, 0" - let measure = "", notation = "" + let entries = "", valueEntries = "", ctrlEntries = "0, 0, 0, 0", measure = "" try { if (runSE) {foo++} performance.mark("a") @@ -291,15 +290,10 @@ function get_perf_mark_entries() { // cleanup performance.clearMarks() performance.clearMeasures() - // FF111+ 811567 - if (isSmart && isVer < 111) { - notation = entries == ctrlEntries && measure == 0 ? rfp_green : rfp_red - } - log_display(18, METRIC, entries +" | "+ measure + notation) + log_display(18, METRIC, entries +" | "+ measure) return [METRIC, valueEntries +" | "+ measure] } catch(e) { - if (isSmart && isVer < 111) {notation = rfp_red} - log_display(18, METRIC, log_error(SECT18, METRIC, e) + notation) + log_display(18, METRIC, log_error(SECT18, METRIC, e)) return [METRIC, zErr] } } @@ -323,8 +317,8 @@ function get_perf_now(log = false) { } // analyse function output() { - let isMatch = true, - goodRFP = [0, 16.7, 16.6, 33.3, 33.4, 50, 66.6, 66.7] + let isMatch = true + let goodRFP = [0, 16.6, 16.7, 33.3, 33.4, 50, 66.6, 66.7, 83.3, 83.4, 100, 116.6, 116.7] // tidy times for (let i=0; i < aData.length ; i++) { let time = aData[i] - p0 @@ -392,7 +386,7 @@ const get_window_props = () => new Promise(resolve => { /* https://github.com/abrahamjuliot/creepjs */ let t0 = nowFn(), iframe const METRIC = "window_properties" - let check = (isSmart && isTB && isVer > 114) + let check = (isSmart && isTB) let notation = check ? tb_red : "" try { @@ -416,10 +410,6 @@ const get_window_props = () => new Promise(resolve => { // cleanup iframe.parentNode.removeChild(iframe) - // ToDo: isSmartMin=115 remove this metric - let perf = aProps.includes("PerformanceNavigationTiming") ? zE : zD - if (isSmart && isVer < 111) {perf += (perf == zD ? rfp_green : rfp_red)} // 78-110: 1511941 - 1811567 - log_display(18, "perf_navigation", perf) // wasm let wasm = aProps.includes("WebAssembly") ? zE : zD if (isSmart && isTB) {wasm += (wasm == zE ? tb_standard : tb_safer)} @@ -464,11 +454,17 @@ const get_window_props = () => new Promise(resolve => { display += addButton(18, METRIC, aProps.length) + tamperBtn // health if (check && fpvalue !== zLIE) { + // ToDo: touch devices + // "Touch", "TouchEvent", "TouchList","ontouchcancel", "ontouchend", "ontouchmove", "ontouchstart" + // e.g. is not in my windows touch-capable laptop but may be present in a tablet + // dom.w3c_touch_events.enabled: 0=disabled (macOS) 1=enabled 2=autodetect (linux/win/android) + // autodetection is currently only supported on Windows and GTK3 (and assumed on Android) + // on touch devices: 0 (all false) 1 or 2 (all true) if (isMullvad) { if (fpvalue == "0d0dd5d5" || fpvalue == "8815bd33") {notation = tb_green} // 823 standard | 822 safer } else { if (isOS == "android") { - notation = sbx +" TBv13 "+ fpvalue +"]"+sc + if (fpvalue == "c70d9b44" || fpvalue == "6623eaa2") {notation = tb_green} // 783 standard | 782 safer } else { if (fpvalue == "226bc5ca" || fpvalue == "df3d8de8") {notation = tb_green} // 774 standard | 773 safer } @@ -498,7 +494,6 @@ const get_window_props = () => new Promise(resolve => { try {iframe.parentNode.removeChild(iframe)} catch(err) {} let eMsg = log_error(SECT18, METRIC, e) let note = (isSmart && isTB) ? rfp_red : "" - log_display(18, "perf_navigation", eMsg + note) // ToDo: 1448046: isSmartMin=115 ? remove this metric log_display(18, "wasm", eMsg + (isSmart && isTB ? tb_slider_red : "")) log_display(18, "webgpu", eMsg + note) diff --git a/js/region.js b/js/region.js index 14948530..8c3c4647 100644 --- a/js/region.js +++ b/js/region.js @@ -2,7 +2,6 @@ const get_geo = () => new Promise(resolve => { const METRIC = "geolocation" - // nav let value, display try { @@ -25,7 +24,6 @@ const get_geo = () => new Promise(resolve => { value = zErr, display = value log_error(SECT4, METRIC +"_navigator", e) } - // window let geoWin try { @@ -87,7 +85,7 @@ const get_nav_connection = () => new Promise(resolve => { if (isSmart && sData[SECT99].includes("Navigator.connection")) { nav = zLIE display = colorFn(display) - log_known(METRIC) + log_known(SECT5, METRIC) } finish(nav, display) } else { @@ -144,20 +142,22 @@ const get_nav_dnt = () => new Promise(resolve => { // expected nav: i.e you can't remove it const METRIC = "doNotTrack" function exit(value, display) { - log_display(5, METRIC, display) + log_display(5, METRIC, display +"") return resolve([METRIC, value]) } try { let value = navigator[METRIC] if (runST) {value = 1} let display = value - if ("1" !== value && "unspecified" !== value) { - if ("string" === typeof value) { - display = log_error(SECT5, METRIC, zErrInvalid + cleanFn(value)) - } else { - display = log_error(SECT5, METRIC, zErrType + typeof value) + if (isGecko) { + if ("1" !== value && "unspecified" !== value) { + if ("string" === typeof value) { + display = log_error(SECT5, METRIC, zErrInvalid + cleanFn(value)) + } else { + display = log_error(SECT5, METRIC, zErrType + typeof value) + } + value = zErr } - value = zErr } exit(value, display) } catch(e) { @@ -171,7 +171,14 @@ const get_nav_gpc = () => new Promise(resolve => { // privacy.globalprivacycontrol.enabled = true/false const METRIC = "globalPrivacyControl" function exit(value, display) { - log_display(5, METRIC, display) + let notation = "" + if (isSmart) { + notation = default_red + if (isVer > 119 && value === false) {notation = default_green + } else if (isVer < 120 && value == "undefined") {notation = default_green + } + } + log_display(5, METRIC, display + notation) return resolve([METRIC, value]) } try { @@ -185,7 +192,7 @@ const get_nav_gpc = () => new Promise(resolve => { } else if (isSmart && sData[SECT99].includes("Navigator."+ METRIC)) { value = zLIE display = colorFn(display) - log_known(SECT4, METRIC) + log_known(SECT5, METRIC) } exit(value, display) } catch(e) { @@ -241,12 +248,6 @@ function get_lang() { "second": {"long": [1], "narrow": [1], "short": [987654]}, "terabyte": optL, } - // ToDo: isSmartMin=115 remove FF < 110 tweak - if (isVer < 110) { - tests["unit"]["month"] = {"narrow": [1], "short": [987654]} - tests["unit"]["day"] = optL - tests["unit"]["gallon"] = {"short": [987654]} - } } set_tests() @@ -503,7 +504,7 @@ function get_lang() { // LANGUAGES METRIC = "languages" data = oTempData[METRIC] - let langcheck = (isSmart && isTB && isOS !== "android" && isVer > 114) // ToDo: android may differ, ignore for now + let langcheck = (isSmart && isTB && isOS !== "android") // ToDo: android may differ, ignore for now Object.keys(data).forEach(function(item){ METRIC = item if (langcheck) { @@ -551,11 +552,14 @@ function get_lang() { } else if (res.length == 0) { value = zErr fpvalue = zErr - } else { + } else { value = "mixed" - fpvalue = zLIE - value = colorFn(value) - log_known(SECT4, METRIC) + fpvalue = "mixed" + if (isSmart) { + fpvalue = zLIE + value = colorFn(value) + log_known(SECT4, METRIC) + } } addData(4, METRIC, fpvalue) if (langcheck) { @@ -695,21 +699,11 @@ function get_lang() { let period2 = dteL.format(hr08) // long08 if (period1 == period2) {res.push(period1)} else {res.push(period1 +" / "+ period2)} res.push( dteS.format(hr12)) // short12 - - // ToDo: isSmartMin=115 remove FF < 110 tweak - if (isVer > 109) { - // FF110+: assuming ICU 72: 1792775 - period1 = dteN.format(hr15) // narrow15 - period2 = dteS.format(hr15) // short15 - if (period1 == period2) {res.push(period1)} else {res.push(period1 +" / "+ period2)} - res.push( dteS.format(hr18)) // short18 - res.push( dteL.format(hr22)) // long22 - } else { - // FF109 or lower - res.push( dteN.format(hr15)) // narrow15 - res.push( dteS.format(hr18)) // short18 - res.push( dteS.format(hr22)) // short22 - } + period1 = dteN.format(hr15) // narrow15 + period2 = dteS.format(hr15) // short15 + if (period1 == period2) {res.push(period1)} else {res.push(period1 +" / "+ period2)} + res.push( dteS.format(hr18)) // short18 + res.push( dteL.format(hr22)) // long22 return res.join(" | ") } else if (item == 24) { // ListFormat: 5 tests max required diff --git a/js/screen.js b/js/screen.js index 5c26eb52..52267495 100644 --- a/js/screen.js +++ b/js/screen.js @@ -25,11 +25,13 @@ function return_nw(w,h, isNew) { return (bw && bh) ? nw_green : nw_red } -const get_scr_fullscreen = () => new Promise(resolve => { +const get_scr_fullscreen = (runtype) => new Promise(resolve => { let oRes = {} + let cssvalue = getElementProp(SECT1, "#cssDM", "display-mode_css") + let isErrCss = cssvalue == zErr function get_display_mode() { - const METRIC = "display-mode" + const METRIC = "display-mode", METRIC2 = METRIC +"_css" let value, display try { let q = "(display-mode:" @@ -37,9 +39,8 @@ const get_scr_fullscreen = () => new Promise(resolve => { if (window.matchMedia(q +"browser)").matches) {value = "browser"} if (window.matchMedia(q +"minimal-ui)").matches) {value = "minimal-ui"} display = value - if (isSmart) { - let cssCheck = getElementProp(SECT1, "#cssDM") - if (value !== cssCheck && cssCheck !== "x") { + if (isSmart && !isErrCss) { + if (value !== cssvalue) { value = zLIE display = colorFn(display) log_known(SECT1, METRIC) @@ -52,6 +53,41 @@ const get_scr_fullscreen = () => new Promise(resolve => { } log_display(1, METRIC, display) oRes[METRIC] = value + oRes[METRIC2] = cssvalue + } + + // fullScreen + function get_fullScreen() { + const METRIC = "fullScreen" + let value, display + if (isGecko) { + try { + // ToDo: shouldn't this be a standard and work in blink etc? + value = window.fullScreen + if (runSE) {foo++} else if (runST) {value = undefined} + display = value + if ("boolean" !== typeof value) { + log_error(SECT1, METRIC, zErrType + typeof value) + value = zErr + display = zErr + } else if (isSmart && !isErrCss) { + let boolCss = cssvalue == "fullscreen" ? true : false + if (boolCss !== value) { + value = zLIE + display = colorFn(display) + log_known(SECT1, METRIC) + } + } + } catch(e) { + log_error(SECT1, METRIC, e) + value = zErr + display = value + } + } else { + value = zNA; display = value + } + log_display(1, METRIC, display) + oRes[METRIC] = value } // full-screen-api.enabled @@ -69,64 +105,397 @@ const get_scr_fullscreen = () => new Promise(resolve => { oRes[METRIC] = r } - // fullScreen - function get_fullScreen() { - const METRIC = "fullScreen" - let value, display - try { - value = window.fullScreen - if (runSE) {foo++} else if (runST) {value = undefined} - display = value - if ("boolean" !== typeof value) { - log_error(SECT1, METRIC, zErrType + typeof value) - value = zErr - display = zErr - } else if (isSmart) { - let cssCheck = getElementProp(SECT1, "#cssDM") - if (cssCheck !== "x") { - cssCheck = cssCheck == "fullscreen" ? true : false - if (cssCheck !== value) { - value = zLIE - display = colorFn(display) - log_known(SECT1, METRIC) - } + // do in order so oRes keys = sorted + get_display_mode() + get_fullScreen() + get_mozFullScreenEnabled() + if (runtype !== "resize") { + addData(1, "fullscreen", oRes, mini(oRes)) + } + return resolve() +}) + +const get_scr_measure = (runtype) => new Promise(resolve => { + let t0 = nowFn() + Promise.all([ + get_scr_mm(runtype, "measure"), + ]).then(function(mmres){ + let tmpScreen = {}, tmpWindow = {}, oScreen = {}, oWindow = {} + + // matchmedia + tmpScreen["device-height"] = mmres[0]["device-height"] + tmpScreen["device-width"] = mmres[0]["device-width"] + tmpWindow["window_height"] = mmres[0]["window_height"] + tmpWindow["window_width"] = mmres[0]["window_width"] + // screen/window + let aList = [ + "width","height","availWidth","availHeight", // scr + "outerWidth","outerHeight","innerWidth","innerHeight", // window + ] + for (let i=0; i < 8; i++) { + let x + let prefix = (i < 2) ? "screen_" : "" // width/height is ambiguous: also clashes with matchmedia inner + try { + if (i < 4) {x = screen[aList[i]] + } else {x = window[aList[i]] + } + if (typeof x !== "number") { + log_error(SECT1, prefix + aList[i], zErrType + typeof x) + x = "NaN" } + } catch (e) { + log_error(SECT1, prefix + aList[i], e) + x = zErr } - } catch(e) { - log_error(SECT1, METRIC, e) + if (i < 4) {tmpScreen[prefix + aList[i]] = x + } else {tmpWindow[aList[i]] = x + } + } + // css + let cList = [ + ["#S", "device-width_css", ":before"], + ["#S", "device-height_css", ":after"], + ["#D", "window_width_css", ":before"], + ["#D", "window_height_css", ":after"], + ] + cList.forEach(function(array) { + let value = getElementProp(SECT1, array[0], array[1], array[2]) + if ("number" !== typeof value && value !== "?") { + log_error(SECT1, array[1], zErrType + typeof value) + value = "NaN" + } + // NaNs + if (array[0] == "#S") { + tmpScreen[array[1]] = value + } else { + tmpWindow[array[1]] = value + } + }) + + // reorder object + if (runtype !== "resize") { + for (const h of Object.keys(tmpScreen).sort()) { + oScreen[h] = tmpScreen[h] + } + for (const k of Object.keys(tmpWindow).sort()) { + oWindow[k] = tmpWindow[k] + } + } + + // just display it for now + log_display(1, "mAvailable", tmpScreen.availWidth +" x "+ tmpScreen.availHeight) + log_display(1, "mmScreen", tmpScreen["device-width"] +" x "+ tmpScreen["device-height"]) + log_display(1, "mScreen", tmpScreen.screen_width +" x "+ tmpScreen.screen_height) + addData(1, "screen_sizes", oScreen, mini(oScreen)) + + log_display(1, "mOuter", tmpWindow.outerWidth +" x "+ tmpWindow.outerHeight) + log_display(1, "mmInner", tmpWindow.window_width +" x "+ tmpWindow.window_height) + log_display(1, "mInner", tmpWindow.innerWidth +" x "+ tmpWindow.innerHeight) + addData(1, "window_sizes", oWindow, mini(oWindow)) + + // inner: LB/NW + if (isSmart) { + if (isOS !== "android") { + // TB13 changes newwin to max 1400x900, and aligns LB to match NW steps + log_display(1, "letterboxing", return_lb(tmpWindow.innerWidth, tmpWindow.innerHeight, isTB)) + log_display(1, "new_window", return_nw(tmpWindow.innerWidth, tmpWindow.innerHeight, isTB)) + } + } + + }) + return resolve() + + /* + // notate + let match = true, r = "" + if (mScreen !== mAvailable) {match = false + } else if (mAvailable !== mOuter) {match = false + } else if (mOuter !== mInner) {match = false + } else { + aMeasures.forEach(function(value) { + if (isNaN(value)) {match = false} + }) + } + r = match ? screen_green : screen_red + dom.scrmatch.innerHTML = r + */ + + // inner + let newW = getElementProp(SECT1, "#D",":before"), + newH = getElementProp(SECT1, "#D"), + isLies = 0, oldW = w4, oldH = h4 + if (newW !== "?") { + newW = newW * 1 + if (newW == oldW-1) {newW = oldW} + if (newW !== oldW) {isLies++} + } + if (newH !== "?") { + newH = newH.slice(3) * 1 + if (newH == oldH-1) {newH = oldH} + if (newH !== oldH) {isLies++} + } + if (isLies > 0) { + dom.mInner.innerHTML = colorFn(mInner) + log_known(SECT1, "window inner") + } + res["window_inner"] = (isLies > 0 ? zLIE : mInner) + + // screen + newW = getElementProp(SECT1, "#S",":before") + newH = getElementProp(SECT1, "#S") + isLies = 0, oldW = w1, oldH = h1 + if (newW !== "?") { + newW = newW * 1 + if (newW == oldW-1) {newW = oldW} + if (newW !== oldW) {isLies++} + } + if (newH !== "?") { + newH = newH.slice(3) * 1 + if (newH == oldH-1) {newH = oldH} + if (newH !== oldH) {isLies++} + } + if (["Screen.width","Screen.height"].some(lie => sData[SECT99].indexOf(lie) >= 0)) {isLies++} + if (isLies > 0) { + dom.mScreen.innerHTML = colorFn(mScreen) + log_known(SECT1, "screen") + } + res["screen"] = (isLies > 0 ? zLIE : mScreen) + + // screen available + isLies = false + if (["Screen.availWidth","Screen.availHeight"].some(lie => sData[SECT99].indexOf(lie) >= 0)) { + isLies = true + dom.mAvailable.innerHTML = colorFn(mAvailable) + log_known(SECT1, "screen available") + } + res["screen_available"] = (isLies > 0 ? zLIE : mAvailable) + + // outer + res["window_outer"] = mOuter + if (runtype !== "resize") {log_perf(SECT1, "scr/win",t0)} + // resolve + return resolve(res) + +}) + +const get_scr_mm = (runtype, datatype) => new Promise(resolve => { + const unable = "unable to find upper bound" + const oList = { + "measure": [ + ["device-width", "device-width", "max-device-width", "px", 512, 0.01], + ["device-height", "device-height", "max-device-height", "px", 512, 0.01], + ["window_width", "width", "max-width", "px", 512, 0.01], + ["window_height", "height", "max-height", "px", 512, 0.01], + ], + "pixels": [ + ["-moz-device-pixel-ratio", "-moz-device-pixel-ratio", "max--moz-device-pixel-ratio", "", 4, 0.0000001], + ["-webkit-min-device-pixel-ratio", "-webkit-min-device-pixel-ratio", "-webkit-max-device-pixel-ratio", "", 4, 0.01], + // webkit seems limited to and rounds down to 0.25, 0.5, 1, 2, 4 + ["dpcm", "resolution", "max-resolution", "dpcm", 1e-5, 0.0000001], + ["dpi", "resolution", "max-resolution", "dpi", 1e-5, 0.0000001], + ["dppx", "resolution", "max-resolution", "dppx", 1e-5, 0.0000001], + ] + } + let list = oList[datatype], maxCount = oList[datatype].length, count = 0, oData = {} + function exit(id, value) { + if (value == unable) { + log_error(SECT1, id, unable) value = zErr - display = value } - log_display(1, METRIC, display) - oRes[METRIC] = value + oData[id] = value + count++ + if (count == maxCount) { + return resolve(oData) + } } + function runTest(callback){ + list.forEach(function(k){ + let metric = k[0], lower = k[1], upper = k[2], suffix = k[3], epsilon = k[4], precision = k[5] + Promise.all([ + callback(lower, upper, suffix, epsilon, precision), + ]).then(function(result){ + exit(metric, result[0]) + }).catch(function(err){ + exit(metric, err) + }) + }) + } + function searchValue(tester, maxValue, precision){ + let minValue = 0 + let ceiling = Math.pow(2, 32) + function stepUp(){ + if (maxValue > ceiling || runST){ + return Promise.reject(unable) + } + return tester(maxValue).then(function(testResult){ + if (testResult === searchValue.isEqual){ + return maxValue + } + else if (testResult === searchValue.isBigger){ + minValue = maxValue + maxValue *= 2 + return stepUp() + } + else { + return false + } + }) + } + function binarySearch() { + if (maxValue - minValue < precision) { + return tester(minValue).then(function(testResult) { + if (testResult.isEqual) {return minValue + } else { + return tester(maxValue).then(function(testResult) { + if (testResult.isEqual) {return maxValue + } else { + return Promise.resolve(minValue) // +" to "+ maxValue // just return min + } + }) + } + }) + } else { + let pivot = (minValue + maxValue) / 2 + return tester(pivot).then(function(testResult) { + if (testResult === searchValue.isEqual) {return pivot + } else if (testResult === searchValue.isBigger) { + minValue = pivot + return binarySearch() + } else { + maxValue = pivot + return binarySearch() + } + }) + } + } + return stepUp().then(function(stepUpResult) { + if (stepUpResult){return stepUpResult + } else {return binarySearch()} + }) + } + searchValue.isSmaller = -1 + searchValue.isEqual = 0 + searchValue.isBigger = 1 - get_display_mode() - get_mozFullScreenEnabled() - get_fullScreen() - return resolve(oRes) + runTest(function(prefix, maxPrefix, suffix, maxValue, precision) { + return searchValue(function(valueToTest) { + try { + if (runSE) {foo++} + if (window.matchMedia("("+ prefix +": "+ valueToTest + suffix+")").matches){ + return Promise.resolve(searchValue.isEqual) + } else if (window.matchMedia("("+ maxPrefix +": "+ valueToTest + suffix+")").matches){ + return Promise.resolve(searchValue.isSmaller) + } else { + return Promise.resolve(searchValue.isBigger) + } + } catch(e) { + log_error(SECT1, prefix, e, isScope, 40) + return Promise.reject(zErr) + } + }, maxValue, precision) + }) }) -const get_scr_subpixels = (runtype) => new Promise(resolve => { - function return_mm_dpi(type, denominator) { - const METRIC = "max-resolution_"+ type - let r = "" +const get_scr_orientation = (type) => new Promise(resolve => { + let oScreen = {}, oWindow = {} + // matchmedia: sorted names + let names = [ + ["-moz-device-orientation", "#cssOm"], + ["device-aspect-ratio", "#cssDAR"], + ["aspect-ratio", "#cssAR"], + ["orientation", "#cssO"], + ] + let l = "landscape", p = "portrait", q = "(orientation: ", s = "square", a = "aspect-ratio" + let aWindow = [], aScreen = [] + for (let i=0; i < names.length; i++) { + let value, isErr = false + let METRIC = names[i][0], METRIC2 = METRIC +"_css" try { - r = (function() { - let i = 1 - for (1; i < 3001; i++) { - let n = i/denominator - if (matchMedia("(max-resolution:"+ n + type +")").matches === true) {return n} - } - log_error(SECT1, METRIC, zErrInvalid +"> "+ ((i-1)/denominator)) - return zErr - })() + if (runSE) {foo++} + if (i == 0) { + if (window.matchMedia("(-moz-device-orientation:"+ l +")").matches) value = l + if (window.matchMedia("(-moz-device-orientation:"+ p +")").matches) value = p + } else if (i == 1) { + if (window.matchMedia("(device-"+ a +":1/1)").matches) value = s + if (window.matchMedia("(min-device-"+ a +":10000/9999)").matches) value = l + if (window.matchMedia("(max-device-"+ a +":9999/10000)").matches) value = p + } else if (i == 2) { + if (window.matchMedia("("+ a +":1/1)").matches) value = s + if (window.matchMedia("(min-"+ a +":10000/9999)").matches) value = l + if (window.matchMedia("(max-"+ a +":9999/10000)").matches) value = p + } else { + if (window.matchMedia(q + p +")").matches) value = p + if (window.matchMedia(q + l +")").matches) value = l + } + if (value == undefined) {value = zU} } catch(e) { log_error(SECT1, METRIC, e) - return zErr + value = zErr + isErr = true + } + if (runSL) {value += "_fake"} + let display = value + // css + let isLies = false + let cssvalue = getElementProp(SECT1, names[i][1], METRIC2) + let isErrCss = cssvalue == zErr + if (isSmart && !isErr && !isErrCss) { + if (value !== cssvalue) { + display = colorFn(display) + value = zLIE + log_known(SECT1, names[i][0]) + } + } + if (i < 2) { + aScreen.push(display) + oScreen[METRIC] = value + oScreen[METRIC2] = cssvalue + } else { + aWindow.push(display) + oWindow[METRIC] = value + oWindow[METRIC2] = cssvalue + } + } + log_display(1, "screen_mmorientation", aScreen.join(" | ")) + log_display(1, "window_mmorientation", aWindow.join(" | ")) + + // screen + names = ["mozOrientation", "orientation.angle", "orientation.type"], aScreen = [] + for (let i=0; i < 3; i++) { + let value + try { + if (runSE) {foo++} + if (i == 0) {value = screen.mozOrientation + } else if (i == 1) {value = screen.orientation.angle + } else {value = screen.orientation.type + } + if (value == undefined) {value = zU} + } catch(e) { + log_error(SECT1, names[i], e) + value = zErr } - return r + aScreen.push(value) + oScreen[names[i]] = value } + let display = aScreen.join(" | ") + if (isSmart) { + // does this makes sense? e.g. we control the screen, based on inner, so it should reflect + // that, not sure about angle. i.e this is just lying about equivalency of already protected values? + // ... BUT we should continue to protect -primary vs -secondary + // ... AND we should make sure subpixels round up (e.g min) + display += (display == "landscape-primary | 0 | landscape-primary" ? rfp_green : rfp_red) + } + log_display(1, "screen_orientation", display) + + if (type !== "resize") { + // objects are already sorted + addData(1, "screen_orientation", oScreen, mini(oScreen)) + addData(1, "window_orientation", oWindow, mini(oWindow)) + } + return resolve() +}) + +const get_scr_pixels = (runtype) => new Promise(resolve => { function get_dpr() { const METRICw = "devicePixelRatio", METRICb = "devicePixelRatio_border" // DPR window @@ -148,11 +517,10 @@ const get_scr_subpixels = (runtype) => new Promise(resolve => { } let notation = "" if (isSmart) { - let rfpvalue = isTB && isVer > 102 ? 2 : 1 - notation = value === rfpvalue ? rfp_green : rfp_red + notation = value === (isTB ? 2 : 1) ? rfp_green : rfp_red } log_display(1, METRICw, display + notation) - oSubpixels[METRICw] = value + oData[METRICw] = value // DPR border: 477157: don't notate this for health value = undefined, display = undefined @@ -183,18 +551,14 @@ const get_scr_subpixels = (runtype) => new Promise(resolve => { display = zErr } log_display(1, METRICb, display) - oSubpixels[METRICb] = value + oData[METRICb] = value return } - // DPI x 3 methods, DPPX, DPCM + // DPI function get_dpi() { - const METRIC = "dpi" - let mmDPPX = return_mm_dpi("dppx",100), - mmDPCM = return_mm_dpi("dpcm",10) - mmDPI = return_mm_dpi("dpi",1) + const METRIC = "dpi_div", METRIC2 = "dpi_css" //note: divDPI relies on css: if css is blocked (dpi_y = 0) this causes issues - // measure div try {dpi_x = Math.round(dom.divDPI.offsetWidth * varDPR)} catch(e) {dpi_x = zErr} try {dpi_y = Math.round(dom.divDPI.offsetHeight * varDPR)} catch(e) {dpi_y = zErr} @@ -205,16 +569,18 @@ const get_scr_subpixels = (runtype) => new Promise(resolve => { if (dpi_y !== 0 && !isNaN(dpi_y)) { // this is the one: RFP spoofs cssDPI and mmDPI varDPI = dpi_y - } else if (cssDPI !== "x" && mmDPI !== zErr) { + } else if ("number" == typeof cssDPI && mmDPI !== zErr) { diffDPI = Math.abs(mmDPI - cssDPI) varDPI = (diffDPI == 1 ? mmDPI : cssDPI) } else if (mmDPI !== zErr) { varDPI = mmDPI } + // notate css + log_display(1, METRIC2, (cssDPI == 96 ? rfp_green : rfp_red)) } - log_display(1, "mmDPI", mmDPI +" | "+ mmDPPX +" | "+ mmDPCM) log_display(1, METRIC, varDPI) - oSubpixels[METRIC] = varDPI + oData[METRIC2] = cssDPI + oData[METRIC] = varDPI return } @@ -238,123 +604,59 @@ const get_scr_subpixels = (runtype) => new Promise(resolve => { value = zErr } log_display(1, METRIC, display) - oSubpixels[METRIC] = value + if (runtype !== "resize") { + oData[METRIC] = value + } return } // run // if dpi_x/y stay at 0 = css blocked or offsetWidth blocked let t0 = nowFn() - let oSubpixels = {} + let oData = {} let varDPR, varDPI, mmDPI, dpi_x = 0, dpi_y = 0 - let cssDPI = getElementProp(SECT1, "#P",":before") - // get - get_dpr() - get_dpi() - get_vv_scale() - if (runtype !== "resize") { - log_perf(SECT1, "dpi/dpr", t0, "", varDPI +" "+ cssDPI +" "+ mmDPI +" "+ dpi_x +" "+ dpi_y) + let cssDPI = getElementProp(SECT1, "#P", "dpi_css", ":before") + if (cssDPI !== "?" && cssDPI !== zErr) { + if ("number" !== typeof cssDPI) { + cssDPI = "NaN" + log_error(SECT1, "dpi_css", zErrType + typeof cssDPI) + } } - return resolve(oSubpixels) -}) -const get_scr_orientation = (type) => new Promise(resolve => { - let oScreen = {}, oWindow = {} - // matchmedia: sorted names - let names = [ - ["-moz-device-orientation", "#cssOm"], - ["device-aspect-ratio", "#cssDAR"], - ["aspect-ratio", "#cssAR"], - ["orientation", "#cssO"], - ] - let l = "landscape", p = "portrait", q = "(orientation: ", s = "square", a = "aspect-ratio" - let aWindow = [], aScreen = [] - for (let i=0; i < names.length; i++) { - let value - try { - if (runSE) {foo++} - if (i == 0) { - if (window.matchMedia("(-moz-device-orientation:"+ l +")").matches) value = l - if (window.matchMedia("(-moz-device-orientation:"+ p +")").matches) value = p - } else if (i == 1) { - if (window.matchMedia("(device-"+ a +":1/1)").matches) value = s - if (window.matchMedia("(min-device-"+ a +":10000/9999)").matches) value = l - if (window.matchMedia("(max-device-"+ a +":9999/10000)").matches) value = p - } else if (i == 2) { - if (window.matchMedia("("+ a +":1/1)").matches) value = s - if (window.matchMedia("(min-"+ a +":10000/9999)").matches) value = l - if (window.matchMedia("(max-"+ a +":9999/10000)").matches) value = p - } else { - if (window.matchMedia(q + p +")").matches) value = p - if (window.matchMedia(q + l +")").matches) value = l + // get + Promise.all([ + get_scr_mm(runtype, "pixels") + ]).then(function(results){ + + for (const k of Object.keys(results[0])) { + // expected 100% zoom values + let oMatch = { + "-moz-device-pixel-ratio": 1, + "-webkit-min-device-pixel-ratio": 1, + "dpcm": 37.79527499999999, + "dpi": 96.00000000000003, + "dppx": 1, } - if (value == undefined) {value = zU} - } catch(e) { - log_error(SECT1, names[i][0], e) - value = zErr - } - if (runSL) {value += "_fake"} - let display = value - // css - let isLies = false - let cssvalue = getElementProp(SECT1, names[i][1]) - if (isSmart && value !== zErr && cssvalue !== "x") { - if (value !== cssvalue) { - display = colorFn(display) - value = zLIE - log_known(SECT1, names[i][0]) + let value = results[0][k], notation = "" + if (isSmart && oMatch[k] !== undefined) { + notation = value == oMatch[k] ? rfp_green : rfp_red } + oData[k] = value + log_display(1, k, value + notation) } - if (i < 2) { - aScreen.push(display) - oScreen[names[i][0]] = value - oScreen[names[i][0] +"_css"] = cssvalue - } else { - aWindow.push(display) - oWindow[names[i][0]] = value - oWindow[names[i][0] +"_css"] = cssvalue - } - } - log_display(1, "screen_mmorientation", aScreen.join(" | ")) - log_display(1, "window_mmorientation", aWindow.join(" | ")) - - // screen - names = ["mozOrientation", "orientation.angle", "orientation.type"], aScreen = [] - for (let i=0; i < 3; i++) { - let value - try { - if (runSE) {foo++} - if (i == 0) {value = screen.mozOrientation - } else if (i == 1) {value = screen.orientation.angle - } else {value = screen.orientation.type - } - if (value == undefined) {value = zU} - } catch(e) { - log_error(SECT1, names[i], e) - value = zErr + get_dpr() + get_dpi() + get_vv_scale() + if (runtype !== "resize") { + let newobj = {} + for (const k of Object.keys(oData).sort()) {newobj[k] = oData[k]} + addData(1, "pixels", newobj, mini(newobj)) + log_perf(SECT1, "pixels", t0, "", varDPI +" "+ cssDPI +" "+ oData["dpi"] +" "+ dpi_x +" "+ dpi_y) } - aScreen.push(value) - oScreen[names[i]] = value - } - let display = aScreen.join(" | ") - if (isSmart) { - // does this makes sense? e.g. we control the screen, based on inner, so it should reflect - // that, not sure about angle. i.e this is just lying about equivalency of already protected values? - // ... BUT we should continue to protect -primary vs -secondary - // ... AND we should make sure subpixels round up (e.g min) - display += (display == "landscape-primary | 0 | landscape-primary" ? rfp_green : rfp_red) - } - log_display(1, "screen_orientation", display) - - if (type !== "resize") { - // objects are already sorted - addData(1, "screen_orientation", oScreen, mini(oScreen)) - addData(1, "window_orientation", oWindow, mini(oWindow)) - } - return resolve() + return resolve() + }) }) - const get_scr_positions = (type) => new Promise(resolve => { const METRIC = type +"_positions" let oRes = {}, notation = "", aDisplay = [], aList, check, x @@ -393,21 +695,31 @@ const get_scr_positions = (type) => new Promise(resolve => { }) const get_scr_scrollbar = (runtype) => new Promise(resolve => { - // we need to wait for the viewport width + // ui.useOverlayScrollbars: 0 = no, 1 = yes use-overlays + // win11 = overlay = very thin scrollbar + + // https://bugzilla.mozilla.org/show_bug.cgi?id=1786665 + // widget.non-native-theme.scrollbar.style = values 1 to 5 + // widget.non-native-theme.scrollbar.size.override <-- non-overlay only? + Promise.all([ + // get the viewport width: we only return zErr or a number get_scr_viewport(runtype) - ]).then(function(res){ + ]).then(function(res) { let t0 = nowFn() + let oData = {}, aDisplay = [] + // css inner width - let cssW = getElementProp(SECT1, "#D",":before") + let cssW = getElementProp(SECT1, "#D", "innerWidth_css", ":before") - // element - function get_sb_element() { - const METRIC = "scollbar_element" + // scrollWidth + function get_scrollwidth(METRIC) { let value, display try { - value = (100 - dom.eScroll.scrollWidth) - if (runSE) {foo++} + let scrollWidth = dom.eScroll.scrollWidth + if ("number" !== typeof scrollWidth) {scrollWidth = "x"} + value = (100 - scrollWidth) + if (runSE) {foo++} else if (runST) {value = "x"} if ("number" !== typeof value) { log_error(SECT1, METRIC, zErrType + typeof value) value = zErr @@ -424,449 +736,132 @@ const get_scr_scrollbar = (runtype) => new Promise(resolve => { display = zErr log_error(SECT1, METRIC, e) } - return [display, value] + oData[METRIC] = value + aDisplay.push(display) } - // viewport - function get_sb_viewport() { - let eViewport = res[0][0] // calculated from element - - } - - - /* - let eViewport = res[0][0] // calculated from element - let eWidth, eValue, eLies = false - if (eViewport == zErr) { - eValue = eViewport - eWidth = eViewport - } else if (isSmart && "number" !== typeof eViewport) { - eWidth = "NaN"; eLies = true; eValue = zLIE - } else { - try { - eWidth = (window.innerWidth - eViewport) - eWidth = cleanFn(eWidth) - eValue = eWidth - if (isSmart) { - // leverage css value - let cssE = cssW - if (cssE !== "x" && "number" == typeof eWidth) { - if (cssE * 1 == eWidth - 1) {cssE = eWidth} // allow for min- - eWidth = cssE - eViewport - } - // lies - let eMin = -1 - if ("number" !== typeof eWidth) {eLies = true - } else if (eWidth < eMin) {eLies = true} - eValue = eLies ? zLIE : eWidth - } - } catch(e) { - eWidth = zErr; eValue = zErr - log_error(SECT1, "scrollbar_viewport", e) - } - } - if (eLies) { - eWidth = colorFn(eWidth); if (runtype !== "resize") {log_known(SECT1, "scrollbar_viewport")} - } - */ - - // visualViewport - function get_sb_visualviewport() { - - } - /* - let vViewport = res[0][1] - let vValue, vWidth, vLies = false - if (vViewport == eViewport) { - vValue = eValue - vWidth = eWidth - vLies = eLies - } else if (vViewport == zErr) { - vValue = vViewport - vWidth = vViewport - } else if ("number" !== typeof vViewport) { - vWidth = "NaN"; vLies = true; vValue = zLIE - } else { - try { - vWidth = (window.innerWidth - vViewport) - vWidth = cleanFn(vWidth) - vValue = vWidth - if (isSmart) { - // leverage css value - if (cssW !== "x" && "number" == typeof vWidth) { - if (cssW * 1 == vWidth - 1) {cssW = vWidth} // allow for min- - vWidth = cssW - vViewport + // viewport (calculated from element), visualViewport + function get_viewport(METRIC) { + let viewport = METRIC == "viewport" ? res[0][0] : res[0][1] + let value, display + if (viewport == zErr) { + value = zErr + display = zErr + } else { + try { + let innerwidth = window.innerWidth + if ("number" !== typeof innerwidth) { + log_error(SECT1, METRIC, zErrType + typeof value) + value = zErr + width = "NaN" + } else { + value = (innerWidth - viewport) + display = value + if (isSmart) { + // leverage css value + if (cssW !== "?") { + if (cssW * 1 == value - 1) {cssW = value} // allow for min- + value = cssW - viewport + display = value + } + // lies + if (value < -1) { + value = zLIE + display = colorFn(eWidth) + if (runtype !== "resize") {log_known(SECT1, METRIC)} + } + } } - // lies - let vMin = -1 - if ("number" !== typeof vWidth) {vLies = true - } else if (vWidth < vMin) {vLies = true} - vValue = vLies ? zLIE : vWidth + } catch(e) { + value = zErr; display = zErr + log_error(SECT1, METRIC, e) } - } catch(e) { - vWidth = zErr; vValue = zErr - log_error(SECT1, "scrollbar_visualViewport", e) } + oData[METRIC] = value + aDisplay.push(display) } - if (vLies) { - vWidth = colorFn(vWidth); if (runtype !== "resize") {log_known(SECT1, "scrollbar_visualViewport")} - } - */ - - get_sb_element() - get_sb_viewport() - get_sb_visualviewport() - - // display - //dom.mScrollbar.innerHTML = vWidth +" | "+ eWidth +" | "+ elWidth - if (runtype !== "resize") {log_perf(SECT1, "scrollbars", t0)} - return resolve(["scrollbars", "TBA"]) + get_scrollwidth("scrollWidth") + get_viewport("viewport") + get_viewport("visualViewport") + const METRIC = "scrollbar_widths" + log_display(1, METRIC, aDisplay.join(" | ")) + addData(1, METRIC, oData, mini(oData)) + if (runtype !== "resize") {log_perf(SECT1, METRIC, t0)} + return resolve() }) }) -function get_scr_viewport(runtype) { +const get_scr_viewport = (runtype) => new Promise(resolve => { let t0 = nowFn() - // element - let eViewport, evh, evw, eValue, eValid = false - try { - if (runSE) {foo++} - let e = document.createElement("div") - e.style.cssText = "position:fixed;top:0;left:0;bottom:0;right:0;" - document.documentElement.insertBefore(e,document.documentElement.firstChild) - evw = e.offsetWidth - evh = e.offsetHeight - document.documentElement.removeChild(e) - if (isSmart && "number" !== typeof evw || "number" !== typeof evh) { - eViewport = colorFn(cleanFn(evw) +" x "+ cleanFn(evh)) - eValue = "NaN" - log_known(SECT1, "viewport") - } else { - eValid = true; eValue = evw - if (avh == "") {avh = evh} // get android height once - eViewport = cleanFn(evw) +" x "+ cleanFn(evh) + let oData = {}, aDisplay = [] + + // viewport + // visualViewport: note: FF63+ dom.visualviewport.enabled FF91+ default true (desktop at least) + function get_viewport(type) { + let METRIC1 = "viewport_height", METRIC2 = "viewport_width" + if (type == "vViewport") { + METRIC1 = "visualViewport_height", METRIC2 = "visualViewport_width" } - } catch(e) { - eViewport = log_error(SECT1,"viewport", e) - eValue = zErr - } - - // visualViewport - // note: FF63+ dom.visualviewport.enabled FF91+ default true (desktop at least) - let vViewport, vvw, vvh, vValue, vValid = false - try { - if (runSE) {foo++} - vvw = window.visualViewport.width - vvh = window.visualViewport.height - if (isSmart && "number" !== typeof vvw || "number" !== typeof vvh) { - vViewport = colorFn(cleanFn(vvw) +" x "+ cleanFn(vvh)) - vValue = "NaN" - log_known(SECT1, "visualViewport size") - } else { - vValid = true; vValue = vvw - if (avh == "") {avh = vvh} // get android height once - vViewport = cleanFn(vvw) +" x "+ cleanFn(vvh) + let wValue, hValue, wDisplay = "", hDisplay + try { + if (runSE) {foo++} + if (type == "eViewport") { + let e = document.createElement("div") + e.style.cssText = "position:fixed;top:0;left:0;bottom:0;right:0;" + document.documentElement.insertBefore(e,document.documentElement.firstChild) + wValue = e.offsetWidth + hValue = e.offsetHeight + document.documentElement.removeChild(e) + } else { + wValue = window.visualViewport.width + hValue = window.visualViewport.height + } + if (runST) {hValue = undefined} + if ("number" !== typeof hValue) { + log_error(SECT1, METRIC1, zErrType + typeof hValue) + hValue = zErr + hDisplay = "NaN" + } else { + hDisplay = hValue + if (avh == "") {avh = hValue} // get android height once + } + if (runST) {wValue = ""} + if ("number" !== typeof wValue) { + log_error(SECT1, METRIC2, zErrType + typeof wValue) + wValue = zErr + wDisplay = "NaN" + } else { + wDisplay = wValue + } + } catch(e) { + hValue = zErr; wValue = zErr + hDisplay = log_error(SECT1, METRIC1, e); wDisplay = "" + log_error(SECT1, METRIC2, e) + } + oData[METRIC1] = hValue + oData[METRIC2] = wValue + if (runtype !== "height") { + log_display(1, type, (wDisplay == "" ? hDisplay : wDisplay +" x "+ hDisplay)) } - } catch(e) { - vViewport = log_error(SECT1, "visualViewport size", e) - vValue = zErr } - // get viewport height once on first load - if (avh == "") {avh = "undefined"} - + get_viewport("eViewport") + get_viewport("vViewport") + if (avh == "") {avh = "undefined"} // get viewport height once on first load // return if (runtype == "height") { - return vValid ? evh : vvh // android tests + let vvh = oData["visualViewport_height"] + return resolve(vvh !== zErr ? vvh : oData["viewport_height"]) // android tests } else { - dom.eViewport = eViewport - dom.vViewport.innerHTML = vViewport // perf if (runtype !== "resize") { - log_perf(SECT1, "viewport", t0, "", "e: "+ evh +" v: "+ vvh +" a: "+ avh) + addData(1, "viewport", oData, mini(oData)) + log_perf(SECT1, "viewport", t0, "", "e: "+ oData["viewport_height"] +" v: "+ oData["visualViewport_height"] +" a: "+ avh) } - return [eValue, vValue] // scrollbar + return resolve([oData["viewport_width"], oData["visualViewport_width"]]) // for scrollbar } -} - -function get_scr_window(runtype) { - return new Promise(resolve => { - let t0 = nowFn() - let res = {} - // MEASURE: ToDo: catch errors/undefined etc - let aMeasures = [] - let aPos = [] - let aList = [ - "screen.width","screen.height","screen.availWidth","screen.availHeight", - "window.outerWidth","window.outerHeight","window.innerWidth","window.innerHeight", - ] - for (let i=0; i < 8; i++) { - let x - try { - if (i == 0) {x = screen.width - } else if (i == 1) {x = screen.height - } else if (i == 2) {x = screen.availWidth - } else if (i == 3) {x = screen.availHeight - } else if (i == 4) {x = window.outerWidth - } else if (i == 5) {x = window.outerHeight - } else if (i == 6) {x = window.innerWidth - } else if (i == 7) {x = window.innerHeight - } - if (typeof x !== "number") { - log_error(SECT1, aList[i], zErrType + typeof x) - x = "NaN" - } - } catch (e) { - log_error(SECT1, aList[i], e) - x = zErr - } - aMeasures.push(x) - } - - let w1 = aMeasures[0], h1 = aMeasures[1], - w2 = aMeasures[2], h2 = aMeasures[3], - w3 = aMeasures[4], h3 = aMeasures[5], - w4 = aMeasures[6], h4 = aMeasures[7] - let mScreen = w1 +" x "+ h1, - mAvailable = w2 +" x "+ h2, - mOuter = w3 +" x "+ h3, - mInner = w4 +" x "+ h4 - // default display - dom.mScreen = mScreen - dom.mAvailable = mAvailable - dom.mOuter = mOuter - dom.mInner.innerHTML = mInner - - if (!isSmart) { - res["screen"] = mScreen - res["screen_available"] = mAvailable - res["window_inner"] = mInner - res["window_outer"] = mOuter - return resolve(res) - } - - /* - // notate - let match = true, r = "" - if (mScreen !== mAvailable) {match = false - } else if (mAvailable !== mOuter) {match = false - } else if (mOuter !== mInner) {match = false - } else { - aMeasures.forEach(function(value) { - if (isNaN(value)) {match = false} - }) - } - r = match ? screen_green : screen_red - dom.scrmatch.innerHTML = r - */ - - // inner: LB/NW - if (isOS !== "android") { - // TB changes newwin to max 1400x900, and aligns LB to match NW steps - let isNewSteps = (isTB && isVer > 102) - log_display(1, "letterboxing", return_lb(w4,h4, isNewSteps)) - log_display(1, "new_window", return_nw(w4,h4, isNewSteps)) - } - - // inner - let newW = getElementProp(SECT1, "#D",":before"), - newH = getElementProp(SECT1, "#D"), - isLies = 0, oldW = w4, oldH = h4 - if (newW !== "x") { - newW = newW * 1 - if (newW == oldW-1) {newW = oldW} - if (newW !== oldW) {isLies++} - } - if (newH !== "x") { - newH = newH.slice(3) * 1 - if (newH == oldH-1) {newH = oldH} - if (newH !== oldH) {isLies++} - } - if (isLies > 0) { - dom.mInner.innerHTML = colorFn(mInner) - log_known(SECT1, "window inner") - } - res["window_inner"] = (isLies > 0 ? zLIE : mInner) - - // screen - newW = getElementProp(SECT1, "#S",":before") - newH = getElementProp(SECT1, "#S") - isLies = 0, oldW = w1, oldH = h1 - if (newW !== "x") { - newW = newW * 1 - if (newW == oldW-1) {newW = oldW} - if (newW !== oldW) {isLies++} - } - if (newH !== "x") { - newH = newH.slice(3) * 1 - if (newH == oldH-1) {newH = oldH} - if (newH !== oldH) {isLies++} - } - if (["Screen.width","Screen.height"].some(lie => sData[SECT99].indexOf(lie) >= 0)) {isLies++} - if (isLies > 0) { - dom.mScreen.innerHTML = colorFn(mScreen) - log_known(SECT1, "screen") - } - res["screen"] = (isLies > 0 ? zLIE : mScreen) - - // screen available - isLies = false - if (["Screen.availWidth","Screen.availHeight"].some(lie => sData[SECT99].indexOf(lie) >= 0)) { - isLies = true - dom.mAvailable.innerHTML = colorFn(mAvailable) - log_known(SECT1, "screen available") - } - res["screen_available"] = (isLies > 0 ? zLIE : mAvailable) - - // outer - res["window_outer"] = mOuter - - if (runtype !== "resize") {log_perf(SECT1, "scr/win",t0)} - // resolve - return resolve(res) - }) -} - -function get_scr_window_mm(runtype) { - return new Promise(resolve => { - let t0 = nowFn() - let count = 0, res = [] - let unable = "unable to find upper bound" - // perf - function perf(id, str, type) { - if (runtype == "screen" && id == "devicePixelRatio_moz") { - addData(1, id, ("number" == typeof str ? str : zErr)) - } - document.getElementById(id).innerHTML = str //== unable ? zErr : str - if (str == unable) { - log_error(SECT1, "matchmedia "+ type, unable) - } - count++ - if (count == 3) { - if (runtype !== "resize") {log_perf(SECT1, "mm scr/win",t0)} - return resolve("skip") - } - } - - function runTest(callback){ - // screen - Promise.all([ - callback("device-width", "max-device-width", "px", 512, 0.01), // 0.01 - callback("device-height", "max-device-height", "px", 512, 0.01) // 0.01 - ]).then(function(device){ - perf("mmScreen", device.join(" x "), "screen") - }).catch(function(err){ - perf("mmScreen", err, "screen") - }) - // inner - Promise.all([ - callback("width", "max-width", "px", 512, 0.01), - callback("height", "max-height", "px", 512, 0.01) - ]).then(function(inner){ - perf("mmInner", inner.join(" x "), "inner") - }).catch(function(err){ - perf("mmInner", err, "inner") - }) - // moz - callback("-moz-device-pixel-ratio", "max--moz-device-pixel-ratio", "", 2, 0.0000001 - ).then(function(moz){ - perf("devicePixelRatio_moz", moz, "-moz-device-pixel-ratio") - }).catch(function(err){ - perf("devicePixelRatio_moz", err, "-moz-device-pixel-ratio") - }) - } - function searchValue(tester, maxValue, precision){ - let minValue = 0 - let ceiling = Math.pow(2, 32) - function stepUp(){ - if (maxValue > ceiling){ - return Promise.reject("unable to find upper bound") - } - return tester(maxValue).then(function(testResult){ - if (testResult === searchValue.isEqual){ - return maxValue - } - else if (testResult === searchValue.isBigger){ - minValue = maxValue - maxValue *= 2 - return stepUp() - } - else { - return false - } - }) - } - function binarySearch(){ - if (maxValue - minValue < precision){ - return tester(minValue).then(function(testResult){ - if (testResult.isEqual){ - return minValue - } - else { - return tester(maxValue).then(function(testResult){ - if (testResult.isEqual){ - return maxValue - } - else { - return Promise.resolve( - minValue // +" to "+ maxValue // just return min - ) - } - }) - } - }) - } - else { - let pivot = (minValue + maxValue) / 2 - return tester(pivot).then(function(testResult){ - if (testResult === searchValue.isEqual){ - return pivot - } - else if (testResult === searchValue.isBigger){ - minValue = pivot - return binarySearch() - } - else { - maxValue = pivot - return binarySearch() - } - }) - } - } - return stepUp().then(function(stepUpResult){ - if (stepUpResult){ - return stepUpResult - } - else { - return binarySearch() - } - }) - } - searchValue.isSmaller = -1 - searchValue.isEqual = 0 - searchValue.isBigger = 1 - - runTest(function(prefix, maxPrefix, suffix, maxValue, precision){ - return searchValue(function(valueToTest){ - try { - //if (runSE) {foo++} - if (window.matchMedia("("+ prefix +": "+ valueToTest + suffix+")").matches){ - return Promise.resolve(searchValue.isEqual) - } - else if (window.matchMedia("("+ maxPrefix +": "+ valueToTest + suffix+")").matches){ - return Promise.resolve(searchValue.isSmaller) - } - else { - return Promise.resolve(searchValue.isBigger) - } - } catch(e) { - if (prefix == "-moz-device-pixel-ratio") {prefix = "devicePixelRatio_moz"} - return Promise.reject(log_error("screen", prefix, e, isScope, 40)) - } - }, maxValue, precision) - }) - }) -} +}) /* UA */ @@ -1013,7 +1008,8 @@ function get_android_tap() { function goFS() { dom.fsLeak = "" - const initialState = getElementProp(SECT1, "#cssDM") + const initialState = getElementProp(SECT1, "#cssDM", "display-mode_css") + let ih1 = window.innerHeight, delay = 1, n = 1, sizeS = [], sizeE = [] @@ -1171,6 +1167,7 @@ function goNW_UA() { } /* OUTPUT */ + function outputUA(os = isOS) { let t0 = nowFn() let aReported = [], oComplex = {} @@ -1252,31 +1249,20 @@ function outputUA(os = isOS) { }, } if (isSmart && os !== undefined) { - // 1818889: RFP 115-119 freezes rv at 109 - let uaVer = isVer, rvVer = (isVer > 114 && isVer < 120 ? 109 : isVer) - let uaRFP = "Mozilla/5.0 (" + oRFP[os].ua_os +"; rv:" - let uaNext = isVerExtra === "+" ? uaRFP : undefined - if (os == "android") { - // android - if (isVer > 119) { - // 1806690: RFP 120+ drops matching ESR + frozen rv - uaRFP += uaVer +".0) Gecko/"+ isVer +".0 Firefox/"+ uaVer +".0" - if (isVerExtra === "+") { - // next: isVer is now at least 120 so we can ignore frozen rv - uaNext += (isVer + 1) +".0) Gecko/"+ (isVer + 1) +".0 Firefox/"+ (isVer + 1) +".0" - oRFP[os]["userAgentNext"] = uaNext - } - } else { - uaVer = isVer < 115 ? 102 : 115 - rvVer = (isVer < 114 && isVer > 120) ? uaVer : 109 - uaRFP += rvVer +".0) Gecko/"+ uaVer +".0 Firefox/"+ uaVer +".0" - } + let uaVer = isVer, isDroid = isOS == "android" + let uaRFP = "Mozilla/5.0 (" + oRFP[os].ua_os +"; rv:" // base + let uaNext = uaRFP // only used if ver+ + + if (uaVer < 120) { + // 1818889: RFP 115-119 rv=109, droid version = 115 + uaRFP += "109.0) Gecko/"+ (isDroid ? "115.0" : "20100101") +" Firefox/"+ (isDroid? "115" : uaVer) +".0" } else { - // desktop - uaRFP += rvVer +".0) Gecko/20100101 Firefox/"+ uaVer +".0" + // 1806690: RFP 120+ drops frozen rv + droid version spoof + uaRFP += uaVer +".0) Gecko/" + (isDroid ? uaVer +".0" : "20100101") +" Firefox/"+ uaVer +".0" + // next if (isVerExtra === "+") { - // next: isVer is now at least 120 so we can ignore frozen rv - uaNext += (uaVer + 1) +".0) Gecko/20100101 Firefox/"+ (uaVer + 1) +".0" + let nxtVer = uaVer + 1 + uaNext += nxtVer +".0) Gecko/"+ (isDroid ? nxtVer +".0" : "20100101") +" Firefox/"+ nxtVer +".0" oRFP[os]["userAgentNext"] = uaNext } } @@ -1323,6 +1309,19 @@ function outputUA(os = isOS) { function outputFD() { let t0 = nowFn() + + if (!isGecko) { + addData(3, "browser", "non-gecko") + log_display(3, "fdBrandingCss", zNA) + log_display(3, "fdResourceCss", zNA) + log_display(3, "browser", zNA) + log_display(3, "browser_architecture", zNA) + log_display(3, "os", zNA) + log_display(3, "version", zNA) + log_section(3, t0) + return + } + // logo if (gLoad || isLogo == zErr || runST || runSE) { try { @@ -1382,6 +1381,7 @@ function outputFD() { // browser let METRIC = "browser" let browser = (isMullvad ? "Mullvad Browser" : (isTB ? "Tor Browser" : "Firefox")) + log_display(3, METRIC, browser + " | "+ isLogo +" | "+ isWordmark) addData(3, METRIC, browser) addData(3, "logo", isLogo) @@ -1399,34 +1399,29 @@ function outputFD() { log_error(SECT3, METRIC, e) } - // version - let r = isVer - if (isVerExtra !== "") {r += isVerExtra} - addDataDisplay(3, "version", r) - // os METRIC = "os" let hasErr = isOSErr !== undefined log_display(3, METRIC, (hasErr ? isOSErr : isOS)) addData(3, METRIC, (hasErr ? zErr : isOS)) + // version + let ver = isVer + if (isVerExtra !== "") {ver += isVerExtra} + addDataDisplay(3, "version", ver) + // os arch: FF110+ pref removed: error means 32bit METRIC = "browser_architecture" - let notation = "" - let check = (isTB && isSmart && isVer < 110) // TB health check if (isArch === true) { - notation = check ? tb_red : "" - log_display(3, METRIC, "64bit" + notation) + log_display(3, METRIC, "64bit") addData(3, METRIC, 64) } else { let isMsg = isArch === "RangeError: invalid array length" - if (isVer > 109 && isMsg) { - if (check) {notation = tb_red} - log_display(3, METRIC, "32bit" + notation) + if (ver > 109 && isMsg) { + log_display(3, METRIC, "32bit") addData(3, METRIC, 32) } else { - if (check) {notation = (isMsg ? tb_green : tb_red)} - log_display(3, METRIC, isArch + notation) + log_display(3, METRIC, isArch) addData(3, METRIC, zErr) } } @@ -1440,15 +1435,14 @@ function outputScreenResize(runtype) { return new Promise(resolve => { Promise.all([ - get_scr_fullscreen(), + get_scr_fullscreen(runtype), get_scr_positions("screen"), get_scr_positions("window"), - get_scr_subpixels(runtype), + get_scr_pixels(runtype), get_scr_scrollbar(runtype), // gets viewport get_scr_orientation(runtype), - get_scr_window(runtype), - get_scr_window_mm(runtype), + get_scr_measure(runtype), ]).then(function(results){ if (runtype !== "screen") { diff --git a/js/storage.js b/js/storage.js index f66217ef..2574605b 100644 --- a/js/storage.js +++ b/js/storage.js @@ -119,7 +119,9 @@ const get_storage_manager = (delay = 170) => new Promise(resolve => { try { navigator.storage.persist().then(function(persistent) { navigator.storage.estimate().then(estimate => { - exit(`${estimate.usage} of ${estimate.quota} bytes`) + // we don't care about estimate.usage + let value = Math.floor(estimate.quota/(1073741824) * 10)/10 // round down + exit(value +"GB ["+ estimate.quota +" bytes]") }) }) } catch(e) { @@ -154,8 +156,9 @@ const get_storage_quota = () => new Promise(resolve => { const get_permissions = (item) => new Promise(resolve => { const METRIC = "permission_"+ item + let notation = "" function exit(value) { - let notation = value == "prompt" ? "" : default_red + if (isSmart) {notation = value == "prompt" ? "" : default_red} log_display(6, METRIC, value + notation) if (item == "persistent-storage" && value == "granted") { // silent run manager to force granted quota when run diff --git a/js/webgl.js b/js/webgl.js index 69901054..b258b045 100644 --- a/js/webgl.js +++ b/js/webgl.js @@ -342,7 +342,7 @@ function outputWebGL() { const [webGL2Data, webGL2Errors] = webGL2 const [experimentalWebGLData, experimentalWebGLErrors] = experimentalWebGL - //* + /* console.log('WebGLRenderingContext: ', mini(webGLData), webGLData) if (webGLErrors.length) {console.log('webGL Errors',webGLErrors)} console.log('WebGL2RenderingContext: ', webGL2Data) diff --git a/tzp.html b/tzp.html index 6a0f4727..62c20b87 100644 --- a/tzp.html +++ b/tzp.html @@ -31,7 +31,7 @@
- +
׆ ॿ @@ -117,10 +117,9 @@   document +
- untrustworthy - methods fingerprints are always loose @@ -187,8 +186,8 @@ viewport 4 visualViewport
[ i ] - visualViewport
viewport
element
-   scrollbars + scrollWidth
viewport
visualViewport
+   scrollbars
[ i ] mozInnerScreenX
mozInnerScreenY
screenX
screenY
@@ -215,20 +214,21 @@ attempts to open a new blank
window as big as possible
and grab the dimensions
  new window - - dpi + + [div] dpi
[ i ]range 40-400
-   [css min-resolution] dpi -
[ i ] - max-resolution
-   [matchMedia] dpi | dppx | dpcm - +   [css min-resolution] dpi + [matchMedia] dpi + + + [matchMedia] dppx | dpcm + | +
[ i ] - -moz-device-pixel-ratio
border width
-   devicePixelRatio - | - - [window] devicePixelRatio + -moz-device-pixel-ratio
-webkit-min-device-pixel-ratio
window
  devicePixelRatio + | | + + [border] devicePixelRatio visualViewport scale --- android --- @@ -321,8 +321,8 @@
[ re-run ]
- [css] branding - [css] browser + [css] branding + [css] browser [browser] architecture browser version @@ -343,9 +343,9 @@ +   timezonename @@ -444,18 +444,18 @@
-
@@ -407,7 +407,7 @@
[PoC]   sign
[PoC] -   timezonename
[PoC]   unit
- + - + @@ -468,7 +468,7 @@ @@ -496,10 +496,10 @@ --> @@ -523,24 +523,25 @@ - + - + - - + + - - + + - + + | + | + | + | -
-
[ re-run ]
- +
connection
doNotTrack
notifications |
[ i ] - notifications | push | persistent-storage
+ notifications | persistent-storage | push   permissions
- | | + |
[ click ] storage manager
color |
|
pixel depth | color depth |
color gamut |
|
[ i ] dom.maxHardwareConcurrency
  hardwareConcurrency
any-hover |
hover |
any-hover |
hover |
[ i ] media.navigator.enabled
media.peerconnection.enabled
  media devices
mimeTypes
plugins
pdfViewerEnabled
any-pointer |
pointer |
any-pointer + |
pointer |
[ mouse ]
[ i ] @@ -636,8 +637,8 @@
[ click ] hash
audioContext 2
OscillatorNode 2
OscillatorNode/DynamicsCompressor 2
OscillatorNode 2
audio code based on work by kkapsner & @@ -774,15 +775,15 @@
forced-colors |
inverted-colors - |
prefers-color-scheme - |
prefers-contrast - |
prefers-reduced-data |
prefers-reduced-motion - |
prefers-reduced-transparency |
code by @@ -869,7 +870,6 @@
[ i ] dom.enable_performance
  performance.timing
PerformanceNavigationTiming
stack depth | length
[ i ] svg.disabled