whoami

  • Nokia Digia The Qt Company
  • Based in Oslo, Norway
  • Open-source enthusiast
  • Loves cooking & climbing

What are we doing here?

Quick recap

  • Blink: an earthquake in QtWebKit land
  • Talk here last year ( youtu.be/Pc5zKGmeYN0)
  • Promising yet very experimental at the time
  • Shorter release cycle for 5.3
  • 1.0 is coming

Agenda

  • Overview
  • Integration considerations
  • Forecast

Overview

What it does

Purpose

“Who needs a web engine?”

  • Integrate web content
  • Not intended as a Web Runtime
  • Does the platform already have one?

The ideal

Chromium window screenshot

The ideal (slight simplification)

Just the contents

A word on complexity

 
Totals grouped by language (dominant language first):
cpp:        4754146 (52.93%)
ansic:      3293012 (36.66%)
asm:         446223 (4.97%)
python:      276758 (3.08%)
(...)

Total Physical Source Lines of Code (SLOC)                = 8,981,788
Development Effort Estimate, Person-Years (Person-Months) = 2,831.79 (33,981.47)
Schedule Estimate, Years (Months)                         = 10.98 (131.77)
Estimated Average Number of Developers (Effort/Schedule)  = 257.89
Total Estimated Cost to Develop                           = $ 382,536,221
 (average salary = $56,286/year, overhead = 2.40).
      
generated using David A. Wheeler’s ‘SLOCCount’.

Somebody call the plumber!

© BrokenSphere / Wikimedia Commons

Architecture

Application process
Widgets
QT += webenginewidgets
Qt Quick
import QtWebEngine 1.0
Render Process
QtWebEngineProcess
QtWebEngineCore
Chromium
  • Widgets C++ library
  • QtQuick plugin

Widgets example

TEMPLATE = app
TARGET = mycoolexample
QT += webenginewidgets
SOURCES = main.cpp
      
#include <QtWebEngineWidgets>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QUrl url = (argc > 1) ? QUrl::fromUserInput(argv[1]) : QUrl("http://qt.io");
    QWebEngineView view;
    view.load(url);
    view.show();
    return app.exec();
}
      

QtQuick example

Enabling context sharing

#include <QtWebEngine/qtwebengineglobal.h>

int main(int argc, char **argv)
{
    QGuiApplication app(argc, argv);
    QtWebEngine::initialize();
    QQmlApplicationEngine appEngine;
    appEngine.load(QUrl("qrc:/ui.qml"));
    return app.exec();
}
      

QtQuick example

import QtWebEngine 1.0
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.1

ApplicationWindow {
    width: 800
    height: 600
    ColumnLayout {
        anchors.fill: parent
        TextField {
            id: addressBar
            focus: true
            Layout.fillWidth: true
            text: webView.url
            onAccepted: webView.url = text
        }
        WebEngineView {
            id: webView
            url: "http://www.qt.io"
            Layout.fillWidth: true
            Layout.fillHeight: true
        }
    }
}
      

Which one can/should I use?

WidgetsQt Quick
No OpenGL
Porting (maintenance)
Porting (long term)
New project

Integration with Qt

How it’s done

Does it matter?

Visualizing it

Visualizing it

Visualizing it

Enter Übercompositor

  • Similar problem on Chromium’s side
  • Übercompositor project
  • Excellent timing

Scene graph integration walkthrough


void RenderWidgetHostViewQt::OnSwapCompositorFrame(uint32 surface_id
                      , scoped_ptr<cc::CompositorFrame> frame)
{
    m_needsDelegatedFrameAck = true;
    m_pendingOutputSurfaceId = output_surface_id;
    // ...

    m_frameNodeData->frameData = frame->delegated_frame_data.Pass();

    // ...

    m_delegate->update();

    // ...
}
      

Scene graph integration walkthrough


QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode)
{
    DelegatedFrameNode *frameNode = static_cast<DelegatedFrameNode *>(oldNode);
    if (!frameNode)
        frameNode = new DelegatedFrameNode;

    frameNode->commit(m_frameNodeData.data(), &m_resourcesToRelease);

    // This is possibly called from the Qt render thread, post the ack back to the UI
    // to tell the child compositors to release resources and trigger a new frame.
    if (m_needsDelegatedFrameAck) {
        m_needsDelegatedFrameAck = false;
        content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
            base::Bind(&RenderWidgetHostViewQt::sendDelegatedFrameAck, AsWeakPtr()));
    }

    return frameNode;
}
      

Scene graph integration walkthrough


void DelegatedFrameNode::commit(DelegatedFrameNodeData* data
                                       , cc::ReturnedResourceArray *resourcesToRelease)
//...
    for (; it != end; ++it) {
        cc::DrawQuad *quad = *it;
//...
        switch (quad->material) {
//...
        case cc::DrawQuad::RENDER_PASS: {
           const cc::RenderPassDrawQuad *renderPass = cc::RenderPassDrawQuad::MaterialCast(quad);
           QSGTexture *texture = findRenderPassTexture(renderPass->render_pass_id, m_renderPassTextures).data();
           // cc::GLRenderer::DrawRenderPassQuad silently ignores missing render passes.
           if (!texture)
               continue;

           QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode;
           textureNode->setRect(toQt(quad->rect));
           textureNode->setTexture(texture);
           currentLayerChain->appendChildNode(textureNode);
           break;
       }
//...
       

Other integration aspects

  • API "speaks" Qt types
    • Apparent in Widgets (e.g. load(const QUrl & url))
    • Transparent in QtQuick
  • QtWebChannel as a way to expose QObjects to JS
    • Which underlying transport mechanism?

Forecast

When to expect what

First things first

1.0 with 5.4

What’s next?

  • Software compositor
  • WebChannel integration
  • Invisible things
    • Better test coverage
    • Build system changes up ahead

Ideas floating around

  • User script mechanism
  • Someone said PPAPI support?
  • <place your contribution here>

<Thank You!>