View Single Post
Old 04-04-2017, 12:27 PM   #1
KevinH
Sigil Developer
KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.
 
Posts: 8,859
Karma: 6120478
Join Date: Nov 2009
Device: many
Pick your brain on QtWebEngine

Hi Kovid,

I wanted to pick your brain a bit. I am playing around with a port our Preview Window (not BookView) to QWebEngine to see if it is possible and what performance is like. I have been trying to figure out a good way to synchronously wait for a return value from running a Javascript. I saw your PyQt5 post on the subject and so tried a Functor approach and ended up with the overly elaborate approach for C++ as follows:

Code:
struct JSResult {
  QVariant res;
  bool     finished;
  JSResult() : res(QVariant("")), finished(false) {}
  JSResult(JSResult * pRes) : res(pRes->res),  finished(pRes->finished) {}
  bool isFinished() { return finished; }
};

struct SetJavascriptResultFunctor {
    JSResult * pres;
    SetJavascriptResultFunctor(JSResult * pres) : pres(pres) {}
    void operator()(const QVariant &result) {
        pres->res.setValue(result);
        pres->finished = true;
    }
};

QVariant ViewPreview::EvaluateJavascript(const QString &javascript)
{
    JSResult * pres = new JSResult();
    page()->runJavaScript(javascript,SetJavascriptResultFunctor(pres));
    while(!pres->isFinished()) {
        qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers, 100;
    }
    QVariant res = pres->res;
    delete pres;
    return res;
}
This basically followed your recommended PyQt5 idea but since a QVariant does not have a "None" value and C++ does not support internal functions, I needed added a structure to keep a boolean finished flag. That grew things considerably. It does seem to work but the code is ugly.

So I have been looking for a simpler approach and found the following in QupZilla 2.1.2 code which is a full browser that supports QWebEngine:

Code:
QVariant WebPage::execJavaScript(const QString &scriptSource, quint32 worldId, int timeout)
{
    QPointer<QEventLoop> loop = new QEventLoop;
    QVariant result;
    QTimer::singleShot(timeout, loop.data(), &QEventLoop::quit);

    runJavaScript(scriptSource, worldId, [loop, &result](const QVariant &res) {
        if (loop && loop->isRunning()) {
            result = res;
            loop->quit();
        }
    });

    loop->exec();
    delete loop;

    return result;
}
It does not use the main app event loop and instead uses a separate QEventLoop.

I was wondering what you thought of this approach.

To me it seems to have an inherent race in that a truly asynchronous javascript run could complete and make the callback in the interval after runJavascript and before loop->exec() is invoked. Doesn't the loop->IsRunning() test in the callback return false if loop.exec() has not been called yet?

Also, I was wondering about your experiences with QtWebEngine.

For what it is worth, I have found that QWebEngine in Qt 5.6.2 is really slow to load almost everything (at least on my Mac) - very slow as in 3 to 5 seconds to load a display a simple xhtml page with a single image link in it. I do not think the xhtml code paths have been tested much as it seems to be highly prone to segfaults when loading incorrect "xhtml" documents using setContent with an xhtml mimetype (something editing in CodeView will make happen easily). I am hoping that things are much much improved in Qt 5.8.0 when it comes to QtWebEngine.

Aside from the insecure WebInspector issues (I saw your bug report), what have your experiences been with QtWebEngine?

Thanks,

KevinH
KevinH is offline   Reply With Quote