From eba8d8d4b8db665520e693e40f79b58b8d2d1f3a Mon Sep 17 00:00:00 2001 From: Evan Hahn <69474926+EvanHahn-Signal@users.noreply.github.com> Date: Fri, 14 Jan 2022 10:45:05 -0600 Subject: [PATCH] Render QR code with SVG, not canvas --- ts/components/QrCode.stories.tsx | 3 +- ts/components/QrCode.tsx | 62 ++++++------------- .../InstallScreenQrCodeNotScannedStep.tsx | 5 +- ts/util/lint/exceptions.json | 4 +- 4 files changed, 24 insertions(+), 50 deletions(-) diff --git a/ts/components/QrCode.stories.tsx b/ts/components/QrCode.stories.tsx index 118c02bb91..88ce6f458e 100644 --- a/ts/components/QrCode.stories.tsx +++ b/ts/components/QrCode.stories.tsx @@ -10,8 +10,7 @@ const story = storiesOf('Components/QrCode', module); story.add('Default', () => ( )); diff --git a/ts/components/QrCode.tsx b/ts/components/QrCode.tsx index 173e659988..aeb7304eb0 100644 --- a/ts/components/QrCode.tsx +++ b/ts/components/QrCode.tsx @@ -2,53 +2,33 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { ReactElement } from 'react'; -import React, { useEffect, useMemo, useRef } from 'react'; +import React, { useMemo, useRef } from 'react'; import qrcode from 'qrcode-generator'; import { getEnvironment, Environment } from '../environment'; -import { strictAssert } from '../util/assert'; -import { useDevicePixelRatio } from '../hooks/useDevicePixelRatio'; const AUTODETECT_TYPE_NUMBER = 0; const ERROR_CORRECTION_LEVEL = 'L'; type PropsType = Readonly<{ - 'aria-label': string; + alt: string; className?: string; data: string; - size: number; }>; export function QrCode(props: PropsType): ReactElement { - // I don't think it's possible to destructure this. - // eslint-disable-next-line react/destructuring-assignment - const ariaLabel = props['aria-label']; - const { className, data, size } = props; + const { alt, className, data } = props; - const qrCode = useMemo(() => { - const result = qrcode(AUTODETECT_TYPE_NUMBER, ERROR_CORRECTION_LEVEL); - result.addData(data); - result.make(); - return result; + const elRef = useRef(null); + + const src = useMemo(() => { + const qrCode = qrcode(AUTODETECT_TYPE_NUMBER, ERROR_CORRECTION_LEVEL); + qrCode.addData(data); + qrCode.make(); + + const svgData = qrCode.createSvgTag({ cellSize: 1, margin: 0 }); + return `data:image/svg+xml;utf8,${svgData}`; }, [data]); - const canvasRef = useRef(null); - const dpi = useDevicePixelRatio(); - const canvasSize = size * dpi; - - useEffect(() => { - const canvas = canvasRef.current; - if (!canvas) { - return; - } - - const context = canvas.getContext('2d'); - strictAssert(context, 'Expected a canvas context'); - - const cellSize = canvasSize / qrCode.getModuleCount(); - context.clearRect(0, 0, canvasSize, canvasSize); - qrCode.renderTo2dContext(context, cellSize); - }, [canvasSize, qrCode]); - // Add a development-only feature to copy a QR code to the clipboard by double-clicking. // This can be used to quickly inspect the code, or to link this Desktop with an iOS // simulator primary, which has a debug-only option to paste the linking URL instead of @@ -60,25 +40,23 @@ export function QrCode(props: PropsType): ReactElement { navigator.clipboard.writeText(data); - const canvas = canvasRef.current; - if (!canvas) { + const el = elRef.current; + if (!el) { return; } - canvas.style.filter = 'brightness(50%)'; + el.style.filter = 'brightness(50%)'; window.setTimeout(() => { - canvas.style.filter = ''; + el.style.filter = ''; }, 150); }; return ( - ); } diff --git a/ts/components/installScreen/InstallScreenQrCodeNotScannedStep.tsx b/ts/components/installScreen/InstallScreenQrCodeNotScannedStep.tsx index 84ddd9a939..360a19e97b 100644 --- a/ts/components/installScreen/InstallScreenQrCodeNotScannedStep.tsx +++ b/ts/components/installScreen/InstallScreenQrCodeNotScannedStep.tsx @@ -25,8 +25,6 @@ type PropsType = { provisioningUrl: Loadable; }; -// This should match the size in the CSS. -const QR_CODE_SIZE = 256; const QR_CODE_FAILED_LINK = 'https://support.signal.org/hc/articles/360007320451#desktop_multiple_device'; @@ -113,10 +111,9 @@ function InstallScreenQrCode( case LoadingState.Loaded: contents = ( ); break; diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index b5bcd92745..c1a1f5cf76 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -7527,10 +7527,10 @@ { "rule": "React-useRef", "path": "ts/components/QrCode.tsx", - "line": " const canvasRef = useRef(null);", + "line": " const elRef = useRef(null);", "reasonCategory": "usageTrusted", "updated": "2022-01-04T21:43:17.517Z", - "reasonDetail": "Used to draw on the canvas." + "reasonDetail": "Used to change the style in non-production builds." }, { "rule": "React-createRef",