Source

Target

Commits (14)
Showing with 156 additions and 35 deletions
......@@ -50,8 +50,11 @@
\skipto #include
\printto main
In the main function we first instantiate a QGuiApplication object.
We then call \l{QtWebEngine::initialize}, which makes sure that OpenGL
In the \c main function we first set the Qt::AA_EnableHighDpiScaling
attribute. This lets the web view automatically scale on high-dpi displays.
Then we instantiate a QGuiApplication object.
Next, we call \l{QtWebEngine::initialize}, which makes sure that OpenGL
contexts can be shared between the main process and the dedicated renderer
process (\c QtWebEngineProcess). This method needs to be called before
any OpenGL context is created.
......
......@@ -44,7 +44,9 @@
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QtWebEngine::initialize();
QQmlApplicationEngine engine;
......
......@@ -78,6 +78,8 @@ static QUrl startupUrl()
int main(int argc, char **argv)
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
Application app(argc, argv);
QtWebEngine::initialize();
......
......@@ -54,6 +54,7 @@
int main(int argc, char * argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
QUrl url;
......
......@@ -45,6 +45,7 @@
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
MainWindow window(QUrl("http://qt.io"));
window.show();
......
......@@ -137,7 +137,7 @@ void HistoryManager::setHistory(const QList<HistoryItem> &history, bool loadedAn
if (!loadedAndSorted)
qSort(m_history.begin(), m_history.end());
checkForExpired();
checkForExpired(loadedAndSorted);
if (loadedAndSorted) {
m_lastSavedUrl = m_history.value(0).url;
......@@ -163,7 +163,7 @@ HistoryTreeModel *HistoryManager::historyTreeModel() const
return m_historyTreeModel;
}
void HistoryManager::checkForExpired()
void HistoryManager::checkForExpired(bool removeEntriesDirectly)
{
if (m_historyLimit < 0 || m_history.isEmpty())
return;
......@@ -185,7 +185,11 @@ void HistoryManager::checkForExpired()
const HistoryItem& item = m_history.last();
// remove from saved file also
m_lastSavedUrl = QString();
emit entryRemoved(item);
if (removeEntriesDirectly)
m_history.takeLast();
else
emit entryRemoved(item);
}
if (nextTimeout > 0)
......
......@@ -126,7 +126,7 @@ public slots:
private slots:
void save();
void checkForExpired();
void checkForExpired(bool removeExpiredEntriesDirectly = false);
protected:
void addHistoryItem(const HistoryItem &item);
......
......@@ -54,6 +54,7 @@
int main(int argc, char **argv)
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
Q_INIT_RESOURCE(data);
BrowserApplication application(argc, argv);
if (!application.isTheOnlyBrowser())
......
......@@ -56,6 +56,7 @@
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication a(argc, argv);
MainWindow window;
......
......@@ -42,7 +42,10 @@
\section1 The Code
In \c main.cpp we instantiate a QApplication and a QWebEngineView. The URL
In the \c main function we first set the Qt::AA_EnableHighDpiScaling.
This lets the web view automatically scale on high-dpi displays.
Next, we instantiate a QApplication and a QWebEngineView. The URL
to load is set by calling \l QWebEngineView::setUrl. The view widget is
given a reasonable default size, and shown.
Finally, QApplication::exec() launches the main event loop.
......
......@@ -43,6 +43,7 @@
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
QWebEngineView view;
......
......@@ -57,6 +57,8 @@ QString getCommandLineUrlArgument()
int main(int argc, char **argv)
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
app.setWindowIcon(QIcon(QLatin1String(":simplebrowser.svg")));
......
......@@ -89,9 +89,16 @@ contains(QT_ARCH, "arm") {
contains(QT_ARCH, "mips") {
GYP_CONFIG += target_arch=mipsel
contains(QMAKE_CFLAGS, "mips32r6"): mips_arch_variant=\"r6\"
else: contains(QMAKE_CFLAGS, "mips32r2"): mips_arch_variant=\"r2\"
else: contains(QMAKE_CFLAGS, "mips32"): mips_arch_variant=\"r1\"
MARCH = $$extractCFlag("-march=.*")
!isEmpty(MARCH) {
equals(MARCH, "mips32r6"): GYP_CONFIG += mips_arch_variant=\"r6\"
else: equals(MARCH, "mips32r2"): GYP_CONFIG += mips_arch_variant=\"r2\"
else: equals(MARCH, "mips32"): GYP_CONFIG += mips_arch_variant=\"r1\"
} else {
contains(QMAKE_CFLAGS, "mips32r6"): GYP_CONFIG += mips_arch_variant=\"r6\"
else: contains(QMAKE_CFLAGS, "mips32r2"): GYP_CONFIG += mips_arch_variant=\"r2\"
else: contains(QMAKE_CFLAGS, "mips32"): GYP_CONFIG += mips_arch_variant=\"r1\"
}
contains(QMAKE_CFLAGS, "-mdsp2"): GYP_CONFIG += mips_dsp_rev=2
else: contains(QMAKE_CFLAGS, "-mdsp"): GYP_CONFIG += mips_dsp_rev=1
......
......@@ -239,6 +239,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget
, m_didFirstVisuallyNonEmptyLayout(false)
, m_adapterClient(0)
, m_imeInProgress(false)
, m_receivedEmptyImeText(false)
, m_anchorPositionWithinSelection(0)
, m_cursorPositionWithinSelection(0)
, m_initPending(false)
......@@ -949,6 +950,19 @@ void RenderWidgetHostViewQt::handleMouseEvent(QMouseEvent* event)
QCursor::setPos(m_lockedMousePosition);
}
if (m_imeInProgress && event->type() == QMouseEvent::MouseButtonPress) {
m_imeInProgress = false;
// Tell input method to commit the pre-edit string entered so far, and finish the
// composition operation.
#ifdef Q_OS_WIN
// Yes the function name is counter-intuitive, but commit isn't actually implemented
// by the Windows QPA, and reset does exactly what is necessary in this case.
qApp->inputMethod()->reset();
#else
qApp->inputMethod()->commit();
#endif
}
m_host->ForwardMouseEvent(webEvent);
}
......@@ -957,15 +971,16 @@ void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev)
if (IsMouseLocked() && ev->key() == Qt::Key_Escape && ev->type() == QEvent::KeyRelease)
UnlockMouse();
if (m_imeInProgress) {
if (m_receivedEmptyImeText) {
// IME composition was not finished with a valid commit string.
// We're getting the composition result in a key event.
if (ev->key() != 0) {
// The key event is not a result of an IME composition. Cancel IME.
m_host->ImeCancelComposition();
m_imeInProgress = false;
m_receivedEmptyImeText = false;
} else {
if (ev->type() == QEvent::KeyRelease) {
m_receivedEmptyImeText = false;
m_host->ImeConfirmComposition(toString16(ev->text()), gfx::Range::InvalidRange(),
false);
m_imeInProgress = false;
......@@ -1005,6 +1020,25 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev)
const QList<QInputMethodEvent::Attribute> &attributes = ev->attributes();
std::vector<blink::WebCompositionUnderline> underlines;
auto ensureValidSelectionRange = [&]() {
if (!selectionRange.IsValid()) {
// We did not receive a valid selection range, hence the range is going to mark the
// cursor position.
int newCursorPosition =
(cursorPositionInPreeditString < 0) ? preeditString.length()
: cursorPositionInPreeditString;
selectionRange.set_start(newCursorPosition);
selectionRange.set_end(newCursorPosition);
}
};
auto setCompositionForPreEditString = [&](){
ensureValidSelectionRange();
m_host->ImeSetComposition(toString16(preeditString),
underlines,
selectionRange.start(),
selectionRange.end());
};
Q_FOREACH (const QInputMethodEvent::Attribute &attribute, attributes) {
switch (attribute.type) {
......@@ -1018,8 +1052,11 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev)
break;
}
case QInputMethodEvent::Cursor:
if (attribute.length)
cursorPositionInPreeditString = attribute.start;
// Always set the position of the cursor, even if it's marked invisible by Qt, otherwise
// there is no way the user will know which part of the composition string will be
// changed, when performing an IME-specific action (like selecting a different word
// suggestion).
cursorPositionInPreeditString = attribute.start;
break;
case QInputMethodEvent::Selection:
selectionRange.set_start(qMin(attribute.start, (attribute.start + attribute.length)));
......@@ -1034,16 +1071,42 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev)
gfx::Range replacementRange = (replacementLength > 0) ? gfx::Range(replacementStart, replacementStart + replacementLength)
: gfx::Range::InvalidRange();
m_host->ImeConfirmComposition(toString16(commitString), replacementRange, false);
m_imeInProgress = false;
} else if (!preeditString.isEmpty()) {
if (!selectionRange.IsValid()) {
// We did not receive a valid selection range, hence the range is going to mark the cursor position.
int newCursorPosition = (cursorPositionInPreeditString < 0) ? preeditString.length() : cursorPositionInPreeditString;
selectionRange.set_start(newCursorPosition);
selectionRange.set_end(newCursorPosition);
// We might get a commit string and a pre-edit string in a single event, which means
// we need to confirm the last composition, and start a new composition.
if (!preeditString.isEmpty()) {
setCompositionForPreEditString();
m_imeInProgress = true;
} else {
m_imeInProgress = false;
}
m_host->ImeSetComposition(toString16(preeditString), underlines, selectionRange.start(), selectionRange.end());
m_receivedEmptyImeText = false;
} else if (!preeditString.isEmpty()) {
setCompositionForPreEditString();
m_imeInProgress = true;
m_receivedEmptyImeText = false;
} else {
// There are so-far two known cases, when an empty QInputMethodEvent is received.
// First one happens when backspace is used to remove the last character in the pre-edit
// string, thus signaling the end of the composition.
// The second one happens (on Windows) when a Korean char gets composed, but instead of
// the event having a commit string, both strings are empty, and the actual char is received
// as a QKeyEvent after the QInputMethodEvent is processed.
// In lieu of the second case, we can't simply cancel the composition on an empty event,
// and then add the Korean char when QKeyEvent is received, because that leads to text
// flickering in the textarea (or any other element).
// Instead we postpone the processing of the empty QInputMethodEvent by posting it
// to the same focused object, and cancelling the composition on the next event loop tick.
if (!m_receivedEmptyImeText && m_imeInProgress) {
m_receivedEmptyImeText = true;
m_imeInProgress = false;
QInputMethodEvent *eventCopy = new QInputMethodEvent(*ev);
QGuiApplication::postEvent(qApp->focusObject(), eventCopy);
} else {
m_receivedEmptyImeText = false;
m_host->ImeCancelComposition();
}
}
}
......
......@@ -241,6 +241,7 @@ private:
ui::TextInputType m_currentInputType;
bool m_imeInProgress;
bool m_receivedEmptyImeText;
QRect m_cursorRect;
size_t m_anchorPositionWithinSelection;
size_t m_cursorPositionWithinSelection;
......
......@@ -659,14 +659,11 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, doub
webEvent.modifiers = modifiersForEvent(ev);
webEvent.timeStampSeconds = currentTimeForEvent(ev);
if (ev->orientation() == Qt::Horizontal)
webEvent.wheelTicksX = ev->delta() / 120.0f;
else
webEvent.wheelTicksY = ev->delta() / 120.0f;
webEvent.wheelTicksX = ev->angleDelta().x() / QWheelEvent::DefaultDeltasPerStep;
webEvent.wheelTicksY = ev->angleDelta().y() / QWheelEvent::DefaultDeltasPerStep;
// Since we report the scroll by the pixel, convert the delta to pixel distance using standard scroll step.
// Use the same single scroll step as QTextEdit (in QTextEditPrivate::init [h,v]bar->setSingleStep)
// We can't use the device specific QWheelEvent::pixelDelta(), so we calculate
// a pixel delta based on ticks and scroll per line.
static const float cDefaultQtScrollStep = 20.f;
webEvent.deltaX = webEvent.wheelTicksX * wheelScrollLines * cDefaultQtScrollStep;
......
......@@ -93,6 +93,27 @@
QT_BEGIN_NAMESPACE
using namespace QtWebEngineCore;
QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event)
{
static struct {
QKeySequence::StandardKey standardKey;
QQuickWebEngineView::WebAction action;
} editorActions[] = {
{ QKeySequence::Cut, QQuickWebEngineView::Cut },
{ QKeySequence::Copy, QQuickWebEngineView::Copy },
{ QKeySequence::Paste, QQuickWebEngineView::Paste },
{ QKeySequence::Undo, QQuickWebEngineView::Undo },
{ QKeySequence::Redo, QQuickWebEngineView::Redo },
{ QKeySequence::SelectAll, QQuickWebEngineView::SelectAll },
{ QKeySequence::UnknownKey, QQuickWebEngineView::NoWebAction }
};
for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i)
if (event == editorActions[i].standardKey)
return editorActions[i].action;
return QQuickWebEngineView::NoWebAction;
}
#ifndef QT_NO_ACCESSIBILITY
static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *object)
{
......@@ -343,7 +364,8 @@ void QQuickWebEngineViewPrivate::allowCertificateError(const QSharedPointer<Cert
Q_Q(QQuickWebEngineView);
QQuickWebEngineCertificateError *quickController = new QQuickWebEngineCertificateError(errorController);
QQmlEngine::setObjectOwnership(quickController, QQmlEngine::JavaScriptOwnership);
// mark the object for gc by creating temporary jsvalue
qmlEngine(q)->newQObject(quickController);
Q_EMIT q->certificateError(quickController);
if (!quickController->deferred() && !quickController->answered())
quickController->rejectCertificate();
......@@ -526,6 +548,18 @@ void QQuickWebEngineViewPrivate::focusContainer()
void QQuickWebEngineViewPrivate::unhandledKeyEvent(QKeyEvent *event)
{
Q_Q(QQuickWebEngineView);
#ifdef Q_OS_OSX
if (event->type() == QEvent::KeyPress) {
QQuickWebEngineView::WebAction action = editorActionForKeyEvent(event);
if (action != QQuickWebEngineView::NoWebAction) {
// Try triggering a registered short-cut
if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(event))
return;
q->triggerWebAction(action);
return;
}
}
#endif
if (q->parentItem())
q->window()->sendEvent(q->parentItem(), event);
}
......
......@@ -73,6 +73,8 @@ class QQmlContext;
class QQuickWebEngineSettings;
class QQuickWebEngineFaviconProvider;
QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event);
#ifdef ENABLE_QML_TESTSUPPORT_API
class QQuickWebEngineTestSupport;
#endif
......
......@@ -38,10 +38,6 @@
\annotatedlist qtwebengine-modules
For Qt Quick applications, Qt WebEngine provides the following QML modules:
\annotatedlist qtwebengine-qmlmodules
\section1 Articles and Guides
\list
......
......@@ -27,7 +27,7 @@
\qmlmodule QtWebEngine 1.3
\title Qt WebEngine QML Types
\brief Provides QML types for rendering web content within a QML application
\ingroup qtwebengine-qmlmodules
\ingroup qtwebengine-modules
The QML types can be imported into your application using the following import statements in
your .qml file:
......