From a27d3e8eb69cfe491b021719871cfbba9495c377 Mon Sep 17 00:00:00 2001
From: Christoph Reiter <reiter.christoph@gmail.com>
Date: Thu, 22 Oct 2020 14:52:41 +0200
Subject: [PATCH] Move the QR detection out of the redraw loop

We now queue it and in the callback check if the scan is still active,
and go from there. This means we redraw all the time and detect mostly
in the background.

This results in worse perf with the old library since that isn't async, but
we can always revert if needed.
---
 .../qr-code-scanner/src/qr-code-scanner.js    | 51 ++++++++++---------
 1 file changed, 26 insertions(+), 25 deletions(-)

diff --git a/packages/qr-code-scanner/src/qr-code-scanner.js b/packages/qr-code-scanner/src/qr-code-scanner.js
index 5b7e42f2..21f8ce48 100644
--- a/packages/qr-code-scanner/src/qr-code-scanner.js
+++ b/packages/qr-code-scanner/src/qr-code-scanner.js
@@ -248,13 +248,13 @@ export class QrCodeScanner extends ScopedElementsMixin(DBPLitElement) {
         let video = await createVideoElement(this._activeCamera);
         this._askPermission = false;
 
-        let lastVideoScanTime = -1;
         let lastCode = null;
         let lastSentData = null;
 
         let detector = new QRScanner();
+        let detectorRunning = false;
 
-        const tick = async () => {
+        const tick = () => {
             this._requestID = null;
             if (video.readyState === video.HAVE_ENOUGH_DATA) {
                 this._loading = false;
@@ -277,18 +277,31 @@ export class QrCodeScanner extends ScopedElementsMixin(DBPLitElement) {
                 maskStartX = canvasElement.width/2 - maskWidth/2;
                 maskStartY = canvasElement.height/2 - maskHeight/2;
 
-                let code = null;
-                // We only check for QR codes 5 times a second to improve performance
-                let shouldAnalyze = Math.abs(lastVideoScanTime - video.currentTime) >= 1/3;
-                if (shouldAnalyze) {
-                    lastVideoScanTime = video.currentTime;
-                    code = await detector.scan(canvasElement, maskStartX, maskStartY, maskWidth, maskHeight);
-                    lastCode = code;
-                } else {
-                    code = lastCode;
+                let lastVideo = video;
+                if (!detectorRunning) {
+                    detectorRunning = true;
+                    detector.scan(canvasElement, maskStartX, maskStartY, maskWidth, maskHeight).then((code) => {
+                        detectorRunning = false;
+                        // if we got restarted then the video element is new, so stop then.
+                        if (lastVideo !== this._videoElement)
+                            return;
+                        lastCode = code;
+
+                        if (code) {
+                            if (lastSentData !== code.data) {
+                                this._outputData = code.data;
+                                this.dispatchEvent(new CustomEvent("code-detected",
+                                    {bubbles: true, composed: true, detail: {'code': code.data}}));
+                            }
+                            lastSentData = code.data;
+                        } else {
+                            this._outputData = null;
+                            lastSentData = null;
+                        }
+                    });
                 }
 
-                let matched = code ? code.data.match(this.matchRegex) !== null : false;
+                let matched = lastCode ? lastCode.data.match(this.matchRegex) !== null : false;
 
                 //draw mask
                 canvas.beginPath();
@@ -301,7 +314,7 @@ export class QrCodeScanner extends ScopedElementsMixin(DBPLitElement) {
                 canvas.fill();
 
                 canvas.beginPath();
-                if (code) {
+                if (lastCode) {
                     let okColor = getComputedStyle(this).getPropertyValue('--dbp-success-bg-color');
                     let notOkColor = getComputedStyle(this).getPropertyValue('--dbp-danger-bg-color');
                     canvas.fillStyle = matched ? okColor : notOkColor;
@@ -329,18 +342,6 @@ export class QrCodeScanner extends ScopedElementsMixin(DBPLitElement) {
                     this.dispatchEvent(new CustomEvent("scan-started", {bubbles: true, composed: true}));
                     firstDrawDone = true;
                 }
-
-                if (code) {
-                    if (lastSentData !== code.data) {
-                        this._outputData = code.data;
-                        this.dispatchEvent(new CustomEvent("code-detected",
-                            {bubbles: true, composed: true, detail: {'code': code.data}}));
-                    }
-                    lastSentData = code.data;
-                } else {
-                    this._outputData = null;
-                    lastSentData = null;
-                }
             }
             console.assert(this._requestID === null);
             this._requestID = requestAnimationFrame(tick);
-- 
GitLab