diff options
author | Liang Qi <liang.qi@qt.io> | 2017-11-03 07:31:53 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-11-03 07:31:53 +0100 |
commit | b045cf0ab9756a67a5a1037c231199ee9bf2d074 (patch) | |
tree | 43831df602905b64552cf31a233127bed9904fc8 /src | |
parent | 0bbaf0d5d7b2d406eda57d40370b00fb79cc0aeb (diff) | |
parent | 7f7af6290a63bdab76855da5866881c8a53f045c (diff) |
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts:
src/3rdparty
Change-Id: Ie6b1922db2269e0e0561022162228a7c8609c9ba
Diffstat (limited to 'src')
29 files changed, 332 insertions, 60 deletions
diff --git a/src/3rdparty b/src/3rdparty -Subproject 04cd5620124dc05c019a582363a93a78665b181 +Subproject 0c43a097b39603be90162b519927a7e47f15ae9 diff --git a/src/buildtools/gn.pro b/src/buildtools/gn.pro index 02d3df652..9d9af9eb8 100644 --- a/src/buildtools/gn.pro +++ b/src/buildtools/gn.pro @@ -4,7 +4,7 @@ option(host_build) !debug_and_release: CONFIG += release include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) -QT_FOR_CONFIG += webengine-private +QT_FOR_CONFIG += webengine webengine-private build_pass|!debug_and_release { !qtConfig(system-gn): CONFIG(release, debug|release) { diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index 05166536e..270595378 100644 --- a/src/core/api/core_api.pro +++ b/src/core/api/core_api.pro @@ -55,3 +55,11 @@ unix:!isEmpty(QMAKE_LFLAGS_VERSION_SCRIPT):!static { SOURCES += qtbug-60565.cpp \ qtbug-61521.cpp } + +msvc { + # Create a list of object files that can be used as response file for the linker. + # This is done to simulate -whole-archive on MSVC. + QMAKE_POST_LINK = \ + "if exist $(DESTDIR_TARGET).objects del $(DESTDIR_TARGET).objects$$escape_expand(\\n\\t)" \ + "for %%a in ($(OBJECTS)) do echo $$shell_quote($$shell_path($$OUT_PWD))\\%%a >> $(DESTDIR_TARGET).objects" +} diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index 720db77bf..359e0b3d9 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -40,19 +40,23 @@ #include "content_main_delegate_qt.h" #include "base/command_line.h" +#include <base/i18n/rtl.h> #include "base/logging.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" +#include <chrome/grit/generated_resources.h> #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_paths.h" #include "ui/base/resource/resource_bundle.h" +#include <ui/base/webui/jstemplate_builder.h> #include "net/grit/net_resources.h" #include "net/base/net_module.h" #include "content_client_qt.h" #include "renderer/content_renderer_client_qt.h" +#include "type_conversion.h" #include "web_engine_library_info.h" #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) @@ -63,12 +67,38 @@ #include "ui/base/ui_base_switches.h" #endif +#include <QtCore/qcoreapplication.h> + namespace QtWebEngineCore { +// The logic of this function is based on chrome/common/net/net_resource_provider.cc +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE.Chromium file. +static std::string constructDirHeaderHTML() +{ + base::DictionaryValue dict; + dict.SetString("header", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_HEADER)); + dict.SetString("parentDirText", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_PARENT)); + dict.SetString("headerName", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_NAME)); + dict.SetString("headerSize", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_SIZE)); + dict.SetString("headerDateModified", + l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_DATE_MODIFIED)); + dict.SetString("language", l10n_util::GetLanguage(base::i18n::GetConfiguredLocale())); + dict.SetString("listingParsingErrorBoxText", + l10n_util::GetStringFUTF16(IDS_DIRECTORY_LISTING_PARSING_ERROR_BOX_TEXT, + toString16(QCoreApplication::applicationName()))); + dict.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr"); + std::string html = webui::GetI18nTemplateHtml( + ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_DIR_HEADER_HTML), + &dict); + return html; +} + static base::StringPiece PlatformResourceProvider(int key) { if (key == IDR_DIR_HEADER_HTML) { - base::StringPiece html_data = ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_DIR_HEADER_HTML); - return html_data; + static std::string html_data = constructDirHeaderHTML(); + return base::StringPiece(html_data); } return base::StringPiece(); } diff --git a/src/core/core_module.pro b/src/core/core_module.pro index 55b20cda2..78bb8baee 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -61,7 +61,9 @@ osx { QMAKE_LFLAGS_DEBUG -= /DEBUG QMAKE_LFLAGS_DEBUG += /DEBUG:FASTLINK } - QMAKE_LFLAGS += /WHOLEARCHIVE:$${api_library_path}$${QMAKE_DIR_SEP}$${api_library_name}.lib + # Simulate -whole-archive by passing the list of object files that belong to the public + # API library as response file to the linker. + QMAKE_LFLAGS += @$${api_library_path}$${QMAKE_DIR_SEP}$${api_library_name}.lib.objects } else { LIBS_PRIVATE += -Wl,-whole-archive -l$$api_library_name -Wl,-no-whole-archive } diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index d0d840ecb..d6ee87950 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -849,8 +849,8 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // countering the scale of devicePixel-scaled tiles when rendering them // to the final surface. QMatrix4x4 matrix; - matrix.scale(1 / m_chromiumCompositorData->frameDevicePixelRatio, - 1 / m_chromiumCompositorData->frameDevicePixelRatio); + const float devicePixelRatio = m_chromiumCompositorData->frameDevicePixelRatio; + matrix.scale(1 / devicePixelRatio, 1 / devicePixelRatio); if (QSGTransformNode::matrix() != matrix) setMatrix(matrix); @@ -872,11 +872,19 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, frameData->resource_list.clear(); QScopedPointer<DelegatedNodeTreeHandler> nodeHandler; + const QSizeF viewportSizeInPt = apiDelegate->screenRect().size(); + const QSize viewportSize = (viewportSizeInPt * devicePixelRatio).toSize(); + // We first compare if the render passes from the previous frame data are structurally // equivalent to the render passes in the current frame data. If they are, we are going // to reuse the old nodes. Otherwise, we will delete the old nodes and build a new tree. - cc::CompositorFrame *previousFrameData = &m_chromiumCompositorData->previousFrameData; - const bool buildNewTree = !areRenderPassStructuresEqual(frameData, previousFrameData) || m_sceneGraphNodes.empty(); + // + // Additionally, because we clip (i.e. don't build scene graph nodes for) quads outside + // of the visible area, we also have to rebuild the tree whenever the window is resized. + const bool buildNewTree = + !areRenderPassStructuresEqual(frameData, &m_chromiumCompositorData->previousFrameData) || + m_sceneGraphNodes.empty() || + viewportSize != m_previousViewportSize; m_chromiumCompositorData->previousFrameData = cc::CompositorFrame(); SGObjects previousSGObjects; @@ -904,10 +912,7 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // All RenderPasses except the last one are rendered to an FBO. cc::RenderPass *rootRenderPass = frameData->render_pass_list.back().get(); - QRectF screenRectQt = apiDelegate->screenRect(); - gfx::Size thisSize(int(screenRectQt.width() * m_chromiumCompositorData->frameDevicePixelRatio), - int(screenRectQt.height() * m_chromiumCompositorData->frameDevicePixelRatio)); - + gfx::Rect viewportRect(toGfx(viewportSize)); for (unsigned i = 0; i < frameData->render_pass_list.size(); ++i) { cc::RenderPass *pass = frameData->render_pass_list.at(i).get(); @@ -939,12 +944,14 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, scissorRect = pass->output_rect; } else { renderPassParent = this; - scissorRect = gfx::Rect(thisSize); + scissorRect = viewportRect; scissorRect += rootRenderPass->output_rect.OffsetFromOrigin(); } - if (scissorRect.IsEmpty()) + if (scissorRect.IsEmpty()) { + holdResources(pass, resourceCandidates); continue; + } QSGNode *renderPassChain = nullptr; if (buildNewTree) @@ -967,8 +974,10 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, if (quadState->is_clipped) targetRect.Intersect(quadState->clip_rect); targetRect.Intersect(scissorRect); - if (targetRect.IsEmpty()) + if (targetRect.IsEmpty()) { + holdResources(quad, resourceCandidates); continue; + } if (quadState->sorting_context_id != currentSortingContextId) { flushPolygons(&polygonQueue, renderPassChain, @@ -1007,6 +1016,8 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, ResourceHolderIterator end = resourceCandidates.constEnd(); for (ResourceHolderIterator it = resourceCandidates.constBegin(); it != end ; ++it) resourcesToRelease->push_back((*it)->returnResource()); + + m_previousViewportSize = viewportSize; } void DelegatedFrameNode::flushPolygons( @@ -1224,6 +1235,18 @@ ResourceHolder *DelegatedFrameNode::findAndHoldResource(unsigned resourceId, QHa return resource.data(); } +void DelegatedFrameNode::holdResources(const cc::DrawQuad *quad, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +{ + for (auto resource : quad->resources) + findAndHoldResource(resource, candidates); +} + +void DelegatedFrameNode::holdResources(const cc::RenderPass *pass, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +{ + for (const auto &quad : pass->quad_list) + holdResources(quad, candidates); +} + QSGTexture *DelegatedFrameNode::initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate) { // QSGTextures must be destroyed in the scene graph thread as part of the QSGNode tree, diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h index b83f4682a..c627cdf95 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/delegated_frame_node.h @@ -126,6 +126,8 @@ private: static void fenceAndUnlockQt(DelegatedFrameNode *frameNode); ResourceHolder *findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); + void holdResources(const cc::DrawQuad *quad, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); + void holdResources(const cc::RenderPass *pass, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); QSGTexture *initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; @@ -143,6 +145,7 @@ private: bool m_contextShared; QScopedPointer<QOffscreenSurface> m_offsurface; #endif + QSize m_previousViewportSize; }; } // namespace QtWebEngineCore diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro index c565b99a4..a9089c569 100644 --- a/src/core/gn_run.pro +++ b/src/core/gn_run.pro @@ -1,5 +1,5 @@ include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) -QT_FOR_CONFIG += webengine-private +QT_FOR_CONFIG += webengine webengine-private TEMPLATE = aux diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 7ce71a81d..a12dea6ad 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -282,6 +282,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget , m_cursorPositionWithinSelection(-1) , m_cursorPosition(0) , m_emptyPreviousSelection(true) + , m_wheelAckPending(false) { m_host->SetView(this); #ifndef QT_NO_ACCESSIBILITY @@ -1315,7 +1316,28 @@ void RenderWidgetHostViewQt::accessibilityActiveChanged(bool active) void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev) { - m_host->ForwardWheelEvent(WebEventFactory::toWebWheelEvent(ev, dpiScale())); + if (!m_wheelAckPending) { + Q_ASSERT(m_pendingWheelEvents.isEmpty()); + m_wheelAckPending = true; + m_host->ForwardWheelEvent(WebEventFactory::toWebWheelEvent(ev, dpiScale())); + return; + } + if (!m_pendingWheelEvents.isEmpty()) { + // Try to combine with this wheel event with the last pending one. + if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), ev, dpiScale())) + return; + } + m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(ev, dpiScale())); +} + +void RenderWidgetHostViewQt::WheelEventAck(const blink::WebMouseWheelEvent &/*event*/, content::InputEventAckState /*ack_result*/) +{ + m_wheelAckPending = false; + if (!m_pendingWheelEvents.isEmpty()) { + m_wheelAckPending = true; + m_host->ForwardWheelEvent(m_pendingWheelEvents.takeFirst()); + } + // TODO: We could forward unhandled wheelevents to our parent. } void RenderWidgetHostViewQt::clearPreviousTouchMotionState() diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 74f14d0d4..c896cf058 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -153,6 +153,7 @@ public: bool HasAcceleratedSurface(const gfx::Size&) override; void DidCreateNewRendererCompositorFrameSink(cc::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) override; void SubmitCompositorFrame(const viz::LocalSurfaceId&, cc::CompositorFrame) override; + void WheelEventAck(const blink::WebMouseWheelEvent &event, content::InputEventAckState ack_result) override; void GetScreenInfo(content::ScreenInfo* results); gfx::Rect GetBoundsInRootWindow() override; @@ -274,6 +275,9 @@ private: QString m_surroundingText; bool m_imeHasHiddenTextCapability; + + bool m_wheelAckPending; + QList<blink::WebMouseWheelEvent> m_pendingWheelEvents; }; } // namespace QtWebEngineCore diff --git a/src/core/surface_factory_qt.cpp b/src/core/surface_factory_qt.cpp index d0741506a..c976e8b04 100644 --- a/src/core/surface_factory_qt.cpp +++ b/src/core/surface_factory_qt.cpp @@ -56,7 +56,13 @@ #if defined(USE_OZONE) #include <EGL/egl.h> -#include <dlfcn.h> + +#ifndef QT_LIBDIR_EGL +#define QT_LIBDIR_EGL "/usr/lib" +#endif +#ifndef QT_LIBDIR_GLES2 +#define QT_LIBDIR_GLES2 QT_LIBDIR_EGL +#endif namespace QtWebEngineCore { @@ -92,21 +98,29 @@ base::NativeLibrary LoadLibrary(const base::FilePath& filename) { bool GLOzoneQt::LoadGLES2Bindings(gl::GLImplementation /*implementation*/) { - base::NativeLibrary eglgles2Library = dlopen(NULL, RTLD_LAZY); - if (!eglgles2Library) { - LOG(ERROR) << "Failed to open EGL/GLES2 context " << dlerror(); + base::FilePath libEGLPath = QtWebEngineCore::toFilePath(QT_LIBDIR_EGL); + libEGLPath = libEGLPath.Append("libEGL.so.1"); + base::NativeLibrary eglLibrary = LoadLibrary(libEGLPath); + if (!eglLibrary) + return false; + + base::FilePath libGLES2Path = QtWebEngineCore::toFilePath(QT_LIBDIR_GLES2); + libGLES2Path = libGLES2Path.Append("libGLESv2.so.2"); + base::NativeLibrary gles2Library = LoadLibrary(libGLES2Path); + if (!gles2Library) return false; - } - gl::GLGetProcAddressProc get_proc_address = reinterpret_cast<gl::GLGetProcAddressProc>(base::GetFunctionPointerFromNativeLibrary(eglgles2Library, "eglGetProcAddress")); + gl::GLGetProcAddressProc get_proc_address = reinterpret_cast<gl::GLGetProcAddressProc>(base::GetFunctionPointerFromNativeLibrary(eglLibrary, "eglGetProcAddress")); if (!get_proc_address) { LOG(ERROR) << "eglGetProcAddress not found."; - base::UnloadNativeLibrary(eglgles2Library); + base::UnloadNativeLibrary(eglLibrary); + base::UnloadNativeLibrary(gles2Library); return false; } gl::SetGLGetProcAddressProc(get_proc_address); - gl::AddGLNativeLibrary(eglgles2Library); + gl::AddGLNativeLibrary(eglLibrary); + gl::AddGLNativeLibrary(gles2Library); return true; } diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index d9ba735bd..eb7c9d48b 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -142,6 +142,11 @@ inline QRectF toQt(const gfx::RectF &rect) return QRectF(rect.x(), rect.y(), rect.width(), rect.height()); } +inline gfx::Size toGfx(const QSize &size) +{ + return gfx::Size(size.width(), size.height()); +} + inline QSize toQt(const gfx::Size &size) { return QSize(size.width(), size.height()); diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index 4f30881c8..b77cd50f9 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -59,6 +59,8 @@ #include "net/dns/mapped_host_resolver.h" #include "net/extras/sqlite/sqlite_channel_id_store.h" #include "net/http/http_auth_handler_factory.h" +#include "net/http/http_auth_preferences.h" +#include "net/http/http_auth_scheme.h" #include "net/http/http_cache.h" #include "net/http/http_network_session.h" #include "net/http/http_server_properties_impl.h" @@ -209,6 +211,13 @@ void URLRequestContextGetterQt::generateAllStorage() m_updateAllStorage = false; } +static const char* const kDefaultAuthSchemes[] = { net::kBasicAuthScheme, + net::kDigestAuthScheme, +#if defined(USE_KERBEROS) && !defined(OS_ANDROID) + net::kNegotiateAuthScheme, +#endif + net::kNtlmAuthScheme }; + void URLRequestContextGetterQt::generateStorage() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); @@ -251,7 +260,15 @@ void URLRequestContextGetterQt::generateStorage() m_storage->set_ssl_config_service(new net::SSLConfigServiceDefaults); m_storage->set_transport_security_state(std::unique_ptr<net::TransportSecurityState>(new net::TransportSecurityState())); - m_storage->set_http_auth_handler_factory(net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get())); + if (!m_httpAuthPreferences) { + std::vector<std::string> auth_types(std::begin(kDefaultAuthSchemes), std::end(kDefaultAuthSchemes)); + m_httpAuthPreferences.reset(new net::HttpAuthPreferences(auth_types +#if defined(OS_POSIX) && !defined(OS_ANDROID) + , std::string() /* gssapi library name */ +#endif + )); + } + m_storage->set_http_auth_handler_factory(net::HttpAuthHandlerRegistryFactory::Create(m_httpAuthPreferences.get(), host_resolver.get())); m_storage->set_http_server_properties(std::unique_ptr<net::HttpServerProperties>(new net::HttpServerPropertiesImpl)); // Give |m_storage| ownership at the end in case it's |mapped_host_resolver|. diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h index 511d9eb04..495c9eb28 100644 --- a/src/core/url_request_context_getter_qt.h +++ b/src/core/url_request_context_getter_qt.h @@ -62,6 +62,7 @@ #include <QtCore/qsharedpointer.h> namespace net { +class HttpAuthPreferences; class MappedHostResolver; class ProxyConfigService; } @@ -126,6 +127,7 @@ private: scoped_refptr<CookieMonsterDelegateQt> m_cookieDelegate; content::URLRequestInterceptorScopedVector m_requestInterceptors; std::unique_ptr<net::HttpNetworkSession> m_httpNetworkSession; + std::unique_ptr<net::HttpAuthPreferences> m_httpAuthPreferences; QList<QByteArray> m_installedCustomSchemes; QWebEngineUrlRequestInterceptor* m_requestInterceptor; diff --git a/src/core/url_request_custom_job.cpp b/src/core/url_request_custom_job.cpp index 47c9b3b4c..b49135f79 100644 --- a/src/core/url_request_custom_job.cpp +++ b/src/core/url_request_custom_job.cpp @@ -56,6 +56,9 @@ URLRequestCustomJob::URLRequestCustomJob(URLRequest *request, , m_proxy(new URLRequestCustomJobProxy(this, scheme, adapter)) , m_device(nullptr) , m_error(0) + , m_pendingReadSize(0) + , m_pendingReadPos(0) + , m_pendingReadBuffer(nullptr) { } @@ -83,6 +86,12 @@ void URLRequestCustomJob::Kill() DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (m_device && m_device->isOpen()) m_device->close(); + if (m_pendingReadBuffer) { + m_pendingReadBuffer->Release(); + m_pendingReadBuffer = nullptr; + m_pendingReadSize = 0; + m_pendingReadPos = 0; + } m_device = nullptr; content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind(&URLRequestCustomJobProxy::release, @@ -127,13 +136,64 @@ int URLRequestCustomJob::ReadRawData(IOBuffer *buf, int bufSize) if (m_error) return m_error; qint64 rv = m_device ? m_device->read(buf->data(), bufSize) : -1; - if (rv >= 0) { + if (rv > 0) { return static_cast<int>(rv); + } else if (rv == 0) { + // Returning zero is interpreted as EOF by Chromium, so only + // return zero if we are the end of the file. + if (m_device->atEnd()) + return 0; + // Otherwise return IO_PENDING and call ReadRawDataComplete when we have data + // for them. + buf->AddRef(); + m_pendingReadPos = 0; + m_pendingReadSize = bufSize; + m_pendingReadBuffer = buf; + return ERR_IO_PENDING; } else { // QIODevice::read might have called fail on us. if (m_error) return m_error; + if (m_device && m_device->atEnd()) + return 0; return ERR_FAILED; } } + +void URLRequestCustomJob::notifyReadyRead() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (!m_device) + return; + if (!m_pendingReadSize) + return; + Q_ASSERT(m_pendingReadBuffer); + if (!m_pendingReadBuffer) + return; + + qint64 rv = m_device->read(m_pendingReadBuffer->data() + m_pendingReadPos, m_pendingReadSize - m_pendingReadPos); + if (rv == 0) + return; + if (rv < 0) { + if (m_error) + rv = m_error; + else if (m_device->atEnd()) + rv = 0; + else + rv = ERR_FAILED; + } else { + m_pendingReadPos += rv; + if (m_pendingReadPos < m_pendingReadSize && !m_device->atEnd()) + return; + rv = m_pendingReadPos; + } + // killJob may be called from ReadRawDataComplete + net::IOBuffer *buf = m_pendingReadBuffer; + m_pendingReadBuffer = nullptr; + m_pendingReadSize = 0; + m_pendingReadPos = 0; + ReadRawDataComplete(rv); + buf->Release(); +} + } // namespace diff --git a/src/core/url_request_custom_job.h b/src/core/url_request_custom_job.h index 68a834d48..021cf3204 100644 --- a/src/core/url_request_custom_job.h +++ b/src/core/url_request_custom_job.h @@ -70,12 +70,16 @@ protected: virtual ~URLRequestCustomJob(); private: + void notifyReadyRead(); scoped_refptr<URLRequestCustomJobProxy> m_proxy; std::string m_mimeType; std::string m_charset; GURL m_redirect; QIODevice *m_device; int m_error; + int m_pendingReadSize; + int m_pendingReadPos; + net::IOBuffer *m_pendingReadBuffer; friend class URLRequestCustomJobProxy; diff --git a/src/core/url_request_custom_job_delegate.cpp b/src/core/url_request_custom_job_delegate.cpp index 14de9a812..6b82cebb5 100644 --- a/src/core/url_request_custom_job_delegate.cpp +++ b/src/core/url_request_custom_job_delegate.cpp @@ -73,16 +73,23 @@ QByteArray URLRequestCustomJobDelegate::method() const void URLRequestCustomJobDelegate::reply(const QByteArray &contentType, QIODevice *device) { + if (device) + QObject::connect(device, &QIODevice::readyRead, this, &URLRequestCustomJobDelegate::slotReadyRead); content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJobProxy::reply, m_proxy,contentType.toStdString(),device)); } +void URLRequestCustomJobDelegate::slotReadyRead() +{ + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestCustomJobProxy::readyRead, m_proxy)); +} + void URLRequestCustomJobDelegate::abort() { content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::abort, - m_proxy)); + base::Bind(&URLRequestCustomJobProxy::abort, m_proxy)); } void URLRequestCustomJobDelegate::redirect(const QUrl &url) diff --git a/src/core/url_request_custom_job_delegate.h b/src/core/url_request_custom_job_delegate.h index eb99f3576..3f5e6d591 100644 --- a/src/core/url_request_custom_job_delegate.h +++ b/src/core/url_request_custom_job_delegate.h @@ -74,6 +74,9 @@ public: void abort(); void fail(Error); +private Q_SLOTS: + void slotReadyRead(); + private: URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy, const QUrl &url, diff --git a/src/core/url_request_custom_job_proxy.cpp b/src/core/url_request_custom_job_proxy.cpp index d53602c85..832d3d11e 100644 --- a/src/core/url_request_custom_job_proxy.cpp +++ b/src/core/url_request_custom_job_proxy.cpp @@ -144,6 +144,13 @@ void URLRequestCustomJobProxy::fail(int error) // else we fail on the next read, or the read that might already be in progress } +void URLRequestCustomJobProxy::readyRead() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (m_job) + m_job->notifyReadyRead(); +} + void URLRequestCustomJobProxy::initialize(GURL url, std::string method) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); diff --git a/src/core/url_request_custom_job_proxy.h b/src/core/url_request_custom_job_proxy.h index df7171f5e..3ea30a4e1 100644 --- a/src/core/url_request_custom_job_proxy.h +++ b/src/core/url_request_custom_job_proxy.h @@ -63,6 +63,7 @@ public: QWeakPointer<const BrowserContextAdapter> adapter); ~URLRequestCustomJobProxy(); + // Called from URLRequestCustomJobDelegate via post: //void setReplyCharset(const std::string &); void reply(std::string mimeType, QIODevice *device); void redirect(GURL url); @@ -70,12 +71,13 @@ public: void fail(int error); void release(); void initialize(GURL url, std::string method); + void readyRead(); - //IO thread owned + // IO thread owned: URLRequestCustomJob *m_job; bool m_started; - //UI thread owned + // UI thread owned: std::string m_scheme; URLRequestCustomJobDelegate *m_delegate; QWeakPointer<const BrowserContextAdapter> m_adapter; diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index b785adec0..2e0323f6d 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -1289,38 +1289,56 @@ WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev, doub } #endif -blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, double dpiScale) +static void setBlinkWheelEventDelta(blink::WebMouseWheelEvent &webEvent) { - WebMouseWheelEvent webEvent; - webEvent.delta_x = 0; - webEvent.delta_y = 0; - webEvent.wheel_ticks_x = 0; - webEvent.wheel_ticks_y = 0; - webEvent.SetType(webEventTypeForEvent(ev)); - webEvent.SetModifiers(modifiersForEvent(ev)); - webEvent.SetTimeStampSeconds(currentTimeForEvent(ev)); - - webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; - webEvent.wheel_ticks_y = static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep; - // 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; #if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) - const int wheelScrollLines = QGuiApplication::styleHints()->wheelScrollLines(); + static const int wheelScrollLines = QGuiApplication::styleHints()->wheelScrollLines(); #else - const int wheelScrollLines = 3; + static const int wheelScrollLines = 3; #endif webEvent.delta_x = webEvent.wheel_ticks_x * wheelScrollLines * cDefaultQtScrollStep; webEvent.delta_y = webEvent.wheel_ticks_y * wheelScrollLines * cDefaultQtScrollStep; +} + +blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, double dpiScale) +{ + WebMouseWheelEvent webEvent; + webEvent.SetType(webEventTypeForEvent(ev)); + webEvent.SetModifiers(modifiersForEvent(ev)); + webEvent.SetTimeStampSeconds(currentTimeForEvent(ev)); webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); + webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; + webEvent.wheel_ticks_y = static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep; + setBlinkWheelEventDelta(webEvent); + return webEvent; } +bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, QWheelEvent *ev, double dpiScale) +{ + if (webEventTypeForEvent(ev) != webEvent.GetType()) + return false; + if (modifiersForEvent(ev) != webEvent.GetModifiers()) + return false; + + webEvent.SetTimeStampSeconds(currentTimeForEvent(ev)); + webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); + webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); + + webEvent.wheel_ticks_x += static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; + webEvent.wheel_ticks_y += static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep; + setBlinkWheelEventDelta(webEvent); + + return true; +} + content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *ev) { content::NativeWebKeyboardEvent webKitEvent(reinterpret_cast<gfx::NativeEvent>(ev)); diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h index c9ae86a73..ca0f6035f 100644 --- a/src/core/web_event_factory.h +++ b/src/core/web_event_factory.h @@ -70,6 +70,7 @@ public: static blink::WebGestureEvent toWebGestureEvent(QNativeGestureEvent *, double dpiScale); #endif static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent*, double dpiScale); + static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent*, double dpiScale); static content::NativeWebKeyboardEvent toWebKeyboardEvent(QKeyEvent*); }; diff --git a/src/src.pro b/src/src.pro index 1cd23f9fa..76d342c8d 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,5 +1,5 @@ include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) -QT_FOR_CONFIG += webengine-private +QT_FOR_CONFIG += webengine webengine-private TEMPLATE = subdirs diff --git a/src/tools/qwebengine_convert_dict/main.cpp b/src/tools/qwebengine_convert_dict/main.cpp index e7dcc22d9..3a1a1ff64 100644 --- a/src/tools/qwebengine_convert_dict/main.cpp +++ b/src/tools/qwebengine_convert_dict/main.cpp @@ -30,6 +30,7 @@ #include <QTextStream> #include <QLibraryInfo> #include <QDir> +#include <QCoreApplication> // see also src/core/type_conversion.h inline base::FilePath::StringType toFilePathString(const QString &str) @@ -117,6 +118,11 @@ QString frameworkIcuDataPath() int main(int argc, char *argv[]) { + // Required only for making QLibraryInfo::location() return a valid path, when the application + // picks up a qt.conf file (which is the case for official Qt packages). + QCoreApplication app(argc, argv); + Q_UNUSED(app); + QTextStream out(stdout); if (argc != 3) { diff --git a/src/webengine/api/qquickwebenginefaviconprovider.cpp b/src/webengine/api/qquickwebenginefaviconprovider.cpp index b5ad6960a..3255f22be 100644 --- a/src/webengine/api/qquickwebenginefaviconprovider.cpp +++ b/src/webengine/api/qquickwebenginefaviconprovider.cpp @@ -70,7 +70,11 @@ QUrl QQuickWebEngineFaviconProvider::faviconProviderUrl(const QUrl &url) QUrl providerUrl; providerUrl.setScheme(QStringLiteral("image")); providerUrl.setHost(identifier()); - providerUrl.setPath(QStringLiteral("/%1").arg(url.toString())); + providerUrl.setPath(QStringLiteral("/%1").arg(url.toString(QUrl::RemoveQuery | QUrl::RemoveFragment))); + if (url.hasQuery()) + providerUrl.setQuery(url.query(QUrl::FullyDecoded)); + if (url.hasFragment()) + providerUrl.setFragment(url.fragment(QUrl::FullyDecoded)); return providerUrl; } diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 4b2170cbc..24fa2d9d8 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -1,5 +1,5 @@ include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) -QT_FOR_CONFIG += webengine-private +QT_FOR_CONFIG += webengine webengine-private TARGET = QtWebEngine diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index f844ddcd6..c4de46b67 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -145,24 +145,35 @@ using QtWebEngineCore::BrowserContextAdapter; \sa QWebEngineDownloadItem, QWebEnginePage::download() */ -QWebEngineProfilePrivate::QWebEngineProfilePrivate(QSharedPointer<BrowserContextAdapter> browserContext) +QWebEngineBrowserContext::QWebEngineBrowserContext(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext, QWebEngineProfilePrivate *profile) + : QObject(BrowserContextAdapter::globalQObjectRoot()) + , browserContextRef(browserContext) + , m_profile(profile) +{ + browserContextRef->addClient(m_profile); +} + +QWebEngineBrowserContext::~QWebEngineBrowserContext() +{ + Q_ASSERT(m_profile); + // In the case the user sets this profile as the parent of the interceptor + // it can be deleted before the browser-context still referencing it is. + browserContextRef->setRequestInterceptor(nullptr); + browserContextRef->removeClient(m_profile); +} + +QWebEngineProfilePrivate::QWebEngineProfilePrivate(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext) : m_settings(new QWebEngineSettings()) , m_scriptCollection(new QWebEngineScriptCollection(new QWebEngineScriptCollectionPrivate(browserContext->userResourceController()))) - , m_browserContextRef(browserContext) + , m_browserContext(new QWebEngineBrowserContext(browserContext, this)) { - m_browserContextRef->addClient(this); m_settings->d_ptr->initDefaults(); } QWebEngineProfilePrivate::~QWebEngineProfilePrivate() { - // In the case the user sets this profile as the parent of the interceptor - // it can be deleted before the browser-context still referencing it is. - m_browserContextRef->setRequestInterceptor(nullptr); - delete m_settings; m_settings = 0; - m_browserContextRef->removeClient(this); Q_FOREACH (QWebEngineDownloadItem* download, m_ongoingDownloads) { if (download) @@ -172,6 +183,11 @@ QWebEngineProfilePrivate::~QWebEngineProfilePrivate() m_ongoingDownloads.clear(); } +QSharedPointer<QtWebEngineCore::BrowserContextAdapter> QWebEngineProfilePrivate::browserContext() const +{ + return m_browserContext->browserContextRef; +} + void QWebEngineProfilePrivate::downloadDestroyed(quint32 downloadId) { m_ongoingDownloads.remove(downloadId); diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h index ffb28ec6d..8cbf241f3 100644 --- a/src/webenginewidgets/api/qwebengineprofile_p.h +++ b/src/webenginewidgets/api/qwebengineprofile_p.h @@ -65,15 +65,30 @@ class BrowserContextAdapter; QT_BEGIN_NAMESPACE +class QWebEngineProfilePrivate; class QWebEngineSettings; +// This is a wrapper class for BrowserContextAdapter. BrowserContextAdapter must be destructed before WebEngineContext +// is destructed. Therefore access it via the QWebEngineBrowserContext which parent is the WebEngineContext::globalQObject. +// This guarantees the destruction together with the WebEngineContext. +class QWebEngineBrowserContext : public QObject { +public: + QWebEngineBrowserContext(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext, QWebEngineProfilePrivate *profile); + ~QWebEngineBrowserContext(); + + QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContextRef; + +private: + QWebEngineProfilePrivate *m_profile; +}; + class QWebEngineProfilePrivate : public QtWebEngineCore::BrowserContextAdapterClient { public: Q_DECLARE_PUBLIC(QWebEngineProfile) QWebEngineProfilePrivate(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext); ~QWebEngineProfilePrivate(); - QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext() const { return m_browserContextRef; } + QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext() const; QWebEngineSettings *settings() const { return m_settings; } void downloadDestroyed(quint32 downloadId); @@ -85,7 +100,7 @@ private: QWebEngineProfile *q_ptr; QWebEngineSettings *m_settings; QScopedPointer<QWebEngineScriptCollection> m_scriptCollection; - QSharedPointer<QtWebEngineCore::BrowserContextAdapter> m_browserContextRef; + QPointer<QWebEngineBrowserContext> m_browserContext; QMap<quint32, QPointer<QWebEngineDownloadItem> > m_ongoingDownloads; }; diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index 29c961c80..958dec07b 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -1,4 +1,3 @@ -include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) QT_FOR_CONFIG += webengine-private TARGET = QtWebEngineWidgets |