import { captureError } from '../errors' import { documentLie, lieProps, PHANTOM_DARKNESS } from '../lies' import { hashMini } from '../utils/crypto' import { createTimer, queueEvent, CSS_FONT_FAMILY, EMOJIS, logTestResult, performanceLogger, hashSlice, formatEmojiSet } from '../utils/helpers' import { patch, html, HTMLNote } from '../utils/html' export default async function getSVG() { try { const timer = createTimer() await queueEvent(timer) let lied = ( lieProps['SVGRect.height'] || lieProps['SVGRect.width'] || lieProps['SVGRect.x'] || lieProps['SVGRect.y'] || lieProps['String.fromCodePoint'] || lieProps['SVGRectElement.getBBox'] || lieProps['SVGTextContentElement.getExtentOfChar'] || lieProps['SVGTextContentElement.getSubStringLength'] || lieProps['SVGTextContentElement.getComputedTextLength'] ) || false const doc = ( PHANTOM_DARKNESS && PHANTOM_DARKNESS.document && PHANTOM_DARKNESS.document.body ? PHANTOM_DARKNESS.document : document ) const divElement = document.createElement('div') doc.body.appendChild(divElement) // patch div patch(divElement, html`
${ EMOJIS.map((emoji) => { return `${emoji}` }).join('') }
`) // SVG const reduceToObject = (nativeObj) => { const keys = Object.keys(nativeObj.__proto__) return keys.reduce((acc, key) => { const val = nativeObj[key] const isMethod = typeof val == 'function' return isMethod ? acc : {...acc, [key]: val} }, {}) } const reduceToSum = (nativeObj) => { const keys = Object.keys(nativeObj.__proto__) return keys.reduce((acc, key) => { const val = nativeObj[key] return isNaN(val) ? acc : (acc += val) }, 0) } const getObjectSum = (obj) => !obj ? 0 : Object.keys(obj).reduce((acc, key) => acc += Math.abs(obj[key]), 0) // SVGRect const svgBox = doc.getElementById('svgBox') const bBox = reduceToObject(svgBox.getBBox()) // compute SVGRect emojis const pattern = new Set() const svgElems = [...svgBox.getElementsByClassName('svgrect-emoji')] await queueEvent(timer) const emojiSet = svgElems.reduce((emojiSet, el, i) => { const emoji = EMOJIS[i] const dimensions = ''+el.getComputedTextLength() if (!pattern.has(dimensions)) { pattern.add(dimensions) emojiSet.add(emoji) } return emojiSet }, new Set()) // svgRect System Sum const svgrectSystemSum = 0.00001 * [...pattern].map((x) => { return x.split(',').reduce((acc, x) => acc += (+x||0), 0) }).reduce((acc, x) => acc += x, 0) // detect failed shift calculation const svgEmojiEl = svgElems[0] as SVGTextContentElement const initial = svgEmojiEl.getComputedTextLength() svgEmojiEl.classList.add('shift-svg') const shifted = svgEmojiEl.getComputedTextLength() svgEmojiEl.classList.remove('shift-svg') const unshifted = svgEmojiEl.getComputedTextLength() if ((initial - shifted) != (unshifted - shifted)) { lied = true documentLie('SVGTextContentElement.getComputedTextLength', 'failed unshift calculation') } const data = { bBox: getObjectSum(bBox), extentOfChar: reduceToSum(svgElems[0].getExtentOfChar(EMOJIS[0])), subStringLength: svgElems[0].getSubStringLength(0, 10), computedTextLength: svgElems[0].getComputedTextLength(), emojiSet: [...emojiSet], svgrectSystemSum, lied, } doc.body.removeChild(doc.getElementById('svg-container')) logTestResult({ time: timer.stop(), test: 'svg', passed: true }) return data } catch (error) { logTestResult({ test: 'svg', passed: false }) captureError(error) return } } export function svgHTML(fp) { if (!fp.svg) { return `
SVGRect
bBox: ${HTMLNote.BLOCKED}
char: ${HTMLNote.BLOCKED}
subs: ${HTMLNote.BLOCKED}
text: ${HTMLNote.BLOCKED}
${HTMLNote.BLOCKED}
` } const { svg: { $hash, bBox, subStringLength, extentOfChar, computedTextLength, emojiSet, svgrectSystemSum, lied, }, } = fp const divisor = 10000 const helpTitle = `SVGTextContentElement.getComputedTextLength()\nhash: ${hashMini(emojiSet)}\n${emojiSet.map((x, i) => i && (i % 6 == 0) ? `${x}\n` : x).join('')}` return `
${performanceLogger.getLog().svg} SVGRect${hashSlice($hash)}
bBox: ${bBox ? (bBox/divisor) : HTMLNote.BLOCKED}
char: ${extentOfChar ? (extentOfChar/divisor) : HTMLNote.BLOCKED}
subs: ${subStringLength ? (subStringLength/divisor) : HTMLNote.BLOCKED}
text: ${computedTextLength ? (computedTextLength/divisor) : HTMLNote.BLOCKED}
${svgrectSystemSum || HTMLNote.UNSUPPORTED} ${formatEmojiSet(emojiSet)}
` }