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`
`)
// 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)}
`
}