diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/gyp_run.pro | 13 | ||||
-rw-r--r-- | src/core/render_widget_host_view_qt.cpp | 87 | ||||
-rw-r--r-- | src/core/render_widget_host_view_qt.h | 1 | ||||
-rw-r--r-- | src/core/web_event_factory.cpp | 11 | ||||
-rw-r--r-- | src/webengine/api/qquickwebengineview.cpp | 36 | ||||
-rw-r--r-- | src/webengine/api/qquickwebengineview_p_p.h | 2 | ||||
-rw-r--r-- | src/webengine/doc/src/qtwebengine-index.qdoc | 4 | ||||
-rw-r--r-- | src/webengine/doc/src/qtwebengine-qmlmodule.qdoc | 2 | ||||
-rw-r--r-- | src/webengine/render_widget_host_view_qt_delegate_quick.cpp | 12 | ||||
-rw-r--r-- | src/webengine/render_widget_host_view_qt_delegate_quick.h | 1 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebenginepage.cpp | 36 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebenginepage_p.h | 2 | ||||
-rw-r--r-- | src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp | 7 |
13 files changed, 186 insertions, 28 deletions
diff --git a/src/core/gyp_run.pro b/src/core/gyp_run.pro index a1b33e258..8c4aeb163 100644 --- a/src/core/gyp_run.pro +++ b/src/core/gyp_run.pro @@ -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 diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 99e4da27e..f45db6bf4 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -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(); + } } } diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 67e7461b3..523d1c49d 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -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; diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index 505a684eb..10809a764 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -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; diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index ac25cd4d2..ced8c1452 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -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); } diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 1b5198110..f13bfd09a 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -73,6 +73,8 @@ class QQmlContext; class QQuickWebEngineSettings; class QQuickWebEngineFaviconProvider; +QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event); + #ifdef ENABLE_QML_TESTSUPPORT_API class QQuickWebEngineTestSupport; #endif diff --git a/src/webengine/doc/src/qtwebengine-index.qdoc b/src/webengine/doc/src/qtwebengine-index.qdoc index e7314fcf9..fd7fe2351 100644 --- a/src/webengine/doc/src/qtwebengine-index.qdoc +++ b/src/webengine/doc/src/qtwebengine-index.qdoc @@ -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 diff --git a/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc b/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc index 954562e38..87022262d 100644 --- a/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc +++ b/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc @@ -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: diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index 5e39cc2b3..d0bd67e6a 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -210,6 +210,18 @@ void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVis } +bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event) +{ + if (event->type() == QEvent::ShortcutOverride) { + if (editorActionForKeyEvent(static_cast<QKeyEvent*>(event)) != QQuickWebEngineView::NoWebAction) { + event->accept(); + return true; + } + } + + return QQuickItem::event(event); +} + void RenderWidgetHostViewQtDelegateQuick::focusInEvent(QFocusEvent *event) { m_client->forwardEvent(event); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h index 66bc63732..c51ca3408 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -77,6 +77,7 @@ public: virtual void setClearColor(const QColor &) Q_DECL_OVERRIDE { } protected: + virtual bool event(QEvent *event) Q_DECL_OVERRIDE; virtual void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE; virtual void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE; virtual void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index bb0db402b..db1915b9f 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -83,6 +83,8 @@ #include <QStyle> #include <QUrl> +#include <private/qguiapplication_p.h> + QT_BEGIN_NAMESPACE using namespace QtWebEngineCore; @@ -103,6 +105,27 @@ static QWebEnginePage::WebWindowType toWindowType(WebContentsAdapterClient::Wind } } +QWebEnginePage::WebAction editorActionForKeyEvent(QKeyEvent* event) +{ + static struct { + QKeySequence::StandardKey standardKey; + QWebEnginePage::WebAction action; + } editorActions[] = { + { QKeySequence::Cut, QWebEnginePage::Cut }, + { QKeySequence::Copy, QWebEnginePage::Copy }, + { QKeySequence::Paste, QWebEnginePage::Paste }, + { QKeySequence::Undo, QWebEnginePage::Undo }, + { QKeySequence::Redo, QWebEnginePage::Redo }, + { QKeySequence::SelectAll, QWebEnginePage::SelectAll }, + { QKeySequence::UnknownKey, QWebEnginePage::NoWebAction } + }; + for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i) + if (event == editorActions[i].standardKey) + return editorActions[i].action; + + return QWebEnginePage::NoWebAction; +} + QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) : adapter(new WebContentsAdapter) , history(new QWebEngineHistory(new QWebEngineHistoryPrivate(this))) @@ -244,6 +267,19 @@ void QWebEnginePagePrivate::focusContainer() void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event) { +#ifdef Q_OS_OSX + Q_Q(QWebEnginePage); + if (event->type() == QEvent::KeyPress) { + QWebEnginePage::WebAction action = editorActionForKeyEvent(event); + if (action != QWebEnginePage::NoWebAction) { + // Try triggering a registered short-cut + if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(event)) + return; + q->triggerAction(action); + return; + } + } +#endif if (view && view->parentWidget()) QGuiApplication::sendEvent(view->parentWidget(), event); } diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index c0b1b9a4e..fb0b85268 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -71,6 +71,8 @@ class QWebEngineProfile; class QWebEngineSettings; class QWebEngineView; +QWebEnginePage::WebAction editorActionForKeyEvent(QKeyEvent* event); + class QWebEnginePagePrivate : public QtWebEngineCore::WebContentsAdapterClient { public: diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index 99621b602..f0385a252 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -326,6 +326,13 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) } } + if (event->type() == QEvent::ShortcutOverride) { + if (editorActionForKeyEvent(static_cast<QKeyEvent*>(event)) != QWebEnginePage::NoWebAction) { + event->accept(); + return true; + } + } + if (event->type() == QEvent::MouseButtonDblClick) { // QWidget keeps the Qt4 behavior where the DblClick event would replace the Press event. // QtQuick is different by sending both the Press and DblClick events for the second press |