Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QByteArray seen as a String in Javascript via QWebChannel

Migrating from QtWebKit to QtWebEngine, using QWebChannel.

I have an invokable function that sends a QVariant Object to the Javascript, which is seen as a JSON object. So a QString becomes a string, a QInt an int, etc.

Using QtWebKit without QWebChannel, a QByteArray was seen as a Uint8ClampedArray, but is now directly transformed to a string using UTF-8 (Which my QByteArray is not :( )

Did I do something wrong ? What should I do ?

Here is the relevant code part :

//Qt Window class signal to javascript
void MyWindow::uplink(Response msg)
{
    emit _nativeToJs(msg->toJson());
}



//Response class toJson() method
QVariantMap Response::toJson() const
{
    QVariantMap map;

    map["id"] = m_id; //qulonglong
    map["src"] = QString(m_src);
    map["dst"] = QString(m_dst);
    map["status"] = m_status; //qint16
    map["result"] = m_result; //QVariant, can be a map of string, arrays, etc

    return map;
}


//Javascript 

var foo;
new QWebChannel(qt.webChannelTransport, function(channel) {
    //we connect the signal
    channel.objects.foo._nativeToJs.connect(function(msg){
        //msg is now a JSON object
    });
});

msg.result should contains a clamped array (msgpack data) that I later decode. Now I have an ugly string of not UTF-8 chars interpreted as UTF-8, which I can't do anything with.

like image 314
hereismass Avatar asked Apr 29 '16 09:04

hereismass


1 Answers

Not an answer at all, but a beginning of research, as it is a very interesting question.

In Qt versions < Qt5.6, you can find how the conversion is done by looking into Qt sources. In particular, I found this function in the file C:\Qt\5.5\Src\qtwebkit\Source\WebCore\bridge\qt\qt_runtime.cpp:

JSValueRef convertQVariantToValue(JSContextRef context, PassRefPtr<RootObject> root, const QVariant& variant, JSValueRef *exception)

and this piece of code inside it :

if (type == QMetaType::QByteArray) {
    QByteArray qtByteArray = variant.value<QByteArray>();
    WTF::RefPtr<WTF::Uint8ClampedArray> wtfByteArray = WTF::Uint8ClampedArray::createUninitialized(qtByteArray.length());
    memcpy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
    ExecState* exec = toJS(context);
    APIEntryShim entryShim(exec);
    return toRef(exec, toJS(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), wtfByteArray.get()));
}

which seems to be the processing of a QByteArray on the JS side.

I also believe that by migrating from Qt WebKit to Qt WebEngine, Qt uses now V8, whereas before it was WebCore and JavaScript Core (source : this thread). So, things might have changed but I don't know to what extent.

At the moment, I can't search further in the Qt sources for Qt5.6, and thus I can't provide a real answer, but I hope this will motivate you or anyone else to look into it and to clarify this behavior :-).

like image 81
IAmInPLS Avatar answered Nov 17 '22 16:11

IAmInPLS