diff options
31 files changed, 487 insertions, 75 deletions
diff --git a/.cmake.conf b/.cmake.conf index 2991fa83b..185995ba1 100644 --- a/.cmake.conf +++ b/.cmake.conf @@ -1,4 +1,4 @@ -set(QT_REPO_MODULE_VERSION "6.5.5") +set(QT_REPO_MODULE_VERSION "6.5.6") set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_WEBENGINE "3.19") set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1") diff --git a/CHROMIUM_VERSION b/CHROMIUM_VERSION index 76c045625..0361e1449 100644 --- a/CHROMIUM_VERSION +++ b/CHROMIUM_VERSION @@ -1,3 +1,3 @@ Based on Chromium version: 112.0.5615.213 -Patched with security patches up to Chromium version: 121.0.6167.160 +Patched with security patches up to Chromium version: 124.0.6367.208 diff --git a/cmake/Functions.cmake b/cmake/Functions.cmake index f22e96056..40554ad6b 100644 --- a/cmake/Functions.cmake +++ b/cmake/Functions.cmake @@ -458,8 +458,10 @@ function(add_linker_options target buildDir completeStatic) target_link_options(${cmakeTarget} PRIVATE /DELAYLOAD:mf.dll /DELAYLOAD:mfplat.dll /DELAYLOAD:mfreadwrite.dll /DELAYLOAD:winmm.dll ) - # enable larger PDBs - target_link_options(${cmakeTarget} PRIVATE "/pdbpagesize:8192") + # enable larger PDBs if webenginecore debug build + if(cmakeTarget STREQUAL "WebEngineCore") + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:Debug>:/pdbpagesize:8192>") + endif() endif() target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${objects_rsp}>") if(NOT completeStatic) @@ -1192,6 +1194,15 @@ function(add_gn_build_artifacts_to_target) endforeach() list(GET archs 0 arch) set(target ${arg_NINJA_TARGET}_${config}_${arch}) + # Work around for broken builds with new Apple linker ld_prime. Force + # use of the classic linker until this has been fixed. + # TODO: remove once this has been fixed by Apple. See issue FB13667242 + # or QTBUG-122655 for details. + if(APPLECLANG) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "15.0.0") + target_link_options(${arg_CMAKE_TARGET} PRIVATE -ld_classic) + endif() + endif() if(QT_IS_MACOS_UNIVERSAL) add_lipo_command(${target} ${arg_BUILDDIR}/${config}) endif() diff --git a/coin/module_config.yaml b/coin/module_config.yaml index f1d69a277..61ce9a525 100644 --- a/coin/module_config.yaml +++ b/coin/module_config.yaml @@ -1,4 +1,5 @@ version: 2 +alias: qtwebengine accept_configuration: condition: property property: features diff --git a/dependencies.yaml b/dependencies.yaml index 5803efcaf..21b73a6c7 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -1,13 +1,13 @@ dependencies: ../tqtc-qtdeclarative: - ref: 3760c04fdea95b6e6d6ccac7c594993f063096fd + ref: 0bbb1c4e12e7d027b452a946652049f353a41132 required: true ../tqtc-qtpositioning: - ref: 90db41d5271c38c141fef3deb8012469279a83db + ref: 384e6155a739c96be5f07a29ac4953463405d960 required: false ../tqtc-qttools: - ref: 8923c9a51e2b1da324d6d02235a1c37f2e59f669 + ref: b4920210050c18913531ac237f294e2632a2edda required: false ../tqtc-qtwebchannel: - ref: 588848bb0bfe4fff393d7a1eca27cf253ac6c59a + ref: 951929518a183f9dd254603140a33be1fc9f35f6 required: false diff --git a/src/3rdparty b/src/3rdparty -Subproject 707f4e7c0110c33df3d36a1942ad1b0ea2cb997 +Subproject be3ba7a0ebb340b9498e82c3506cf46ec5ddbee diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 20ef91637..3b2e21d9b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -356,9 +356,14 @@ foreach(arch ${archs}) ) extend_gn_list(gnArgArg ARGS enable_plugins - CONDITION QT_FEATURE_webengine_pepper_plugins + CONDITION QT_FEATURE_webengine_printing_and_pdf OR + QT_FEATURE_webengine_pepper_plugins ) extend_gn_list(gnArgArg + ARGS enable_ppapi + CONDITION QT_FEATURE_webengine_pepper_plugins + ) + extend_gn_list(gnArgArg ARGS enable_spellcheck CONDITION QT_FEATURE_webengine_spellchecker ) diff --git a/src/core/api/Qt6WebEngineCoreMacros.cmake b/src/core/api/Qt6WebEngineCoreMacros.cmake index 6c335aad1..8bb731548 100644 --- a/src/core/api/Qt6WebEngineCoreMacros.cmake +++ b/src/core/api/Qt6WebEngineCoreMacros.cmake @@ -29,7 +29,7 @@ function(qt6_add_webengine_dictionary) set(copyCommand COMMAND ${CMAKE_COMMAND} -E copy_directory ${ARGS_OUTPUT_DIRECTORY}/dict ${ARGS_OUTPUT_DIRECTORY}/$<CONFIG> ) - elseif((MACOS OR IOS) AND isBundle) + elseif(APPLE AND isBundle) get_target_property(outputName ${ARGS_TARGET} OUTPUT_NAME) if(NOT outputName) set(outputName ${ARGS_TARGET}) diff --git a/src/core/api/configure.cmake b/src/core/api/configure.cmake index 48f7cacc0..49ad00ed8 100644 --- a/src/core/api/configure.cmake +++ b/src/core/api/configure.cmake @@ -13,7 +13,7 @@ if(NOT QT_CONFIGURE_RUNNING) pkg_check_modules(XDAMAGE xdamage) pkg_check_modules(POPPLER_CPP poppler-cpp IMPORTED_TARGET) pkg_check_modules(GBM gbm) - pkg_check_modules(LIBVA libva) + pkg_check_modules(LIBVA libva>=1.14) if(NOT GIO_FOUND) pkg_check_modules(GIO gio-2.0) endif() @@ -66,7 +66,7 @@ qt_feature("webengine-system-alsa" PRIVATE ) qt_feature("webengine-v8-context-snapshot" PRIVATE LABEL "Use v8 context snapshot" - CONDITION NOT CMAKE_CROSSCOMPILING + AUTODETECT NOT CMAKE_CROSSCOMPILING ) qt_feature("webengine-geolocation" PUBLIC LABEL "Geolocation" diff --git a/src/core/configure/BUILD.root.gn.in b/src/core/configure/BUILD.root.gn.in index 7b61ff4ef..fe4f306b0 100644 --- a/src/core/configure/BUILD.root.gn.in +++ b/src/core/configure/BUILD.root.gn.in @@ -356,20 +356,24 @@ source_set("qtwebengine_sources") { "//components/embedder_support/user_agent_utils.cc", "//components/embedder_support/user_agent_utils.h", ] - if (use_ozone && use_vaapi) { + if (use_vaapi_x11) { deps += [ "//ui/base/x:gl", "//ui/gfx/linux:gpu_memory_buffer_support_x11", ] sources += [ - "//ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc", - "//ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h", "//ui/ozone/platform/x11/gl_egl_utility_x11.cc", "//ui/ozone/platform/x11/gl_egl_utility_x11.h", "//ui/ozone/platform/x11/native_pixmap_glx_binding.cc", "//ui/ozone/platform/x11/native_pixmap_glx_binding.h", ] } + if (use_vaapi) { + sources += [ + "//ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc", + "//ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h", + ] + } if (enable_extensions) { deps += [ ":qtwebengine_extensions_features", diff --git a/src/core/doc/src/qwebenginepage_lgpl.qdoc b/src/core/doc/src/qwebenginepage_lgpl.qdoc index 8f8f50968..a8a31da11 100644 --- a/src/core/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/core/doc/src/qwebenginepage_lgpl.qdoc @@ -710,6 +710,7 @@ is empty, it is assumed that the content is \c{text/plain,charset=US-ASCII}. External objects referenced in the content are located relative to \a baseUrl. + For external objects with relative URLs to be loaded, \c baseUrl cannot be empty. The \a data is loaded immediately; external objects are loaded asynchronously. diff --git a/src/core/doc/src/qwebenginesettings_lgpl.qdoc b/src/core/doc/src/qwebenginesettings_lgpl.qdoc index 63e9c9710..d98cef8c9 100644 --- a/src/core/doc/src/qwebenginesettings_lgpl.qdoc +++ b/src/core/doc/src/qwebenginesettings_lgpl.qdoc @@ -15,8 +15,8 @@ \inmodule QtWebEngineCore QWebEngineSettings allows configuration of browser properties, such as font sizes and - families, the location of a custom style sheet, and generic attributes, such as JavaScript - support. Individual attributes are set using the setAttribute() function. The + families, and generic attributes, such as JavaScript support. + Individual attributes are set using the setAttribute() function. The \l{QWebEngineSettings::WebAttribute}{WebAttribute} enum further describes each attribute. Each QWebEnginePage object has its own QWebEngineSettings object, which configures the diff --git a/src/core/ozone/ozone_platform_qt.cpp b/src/core/ozone/ozone_platform_qt.cpp index 8dcb56446..12a204f20 100644 --- a/src/core/ozone/ozone_platform_qt.cpp +++ b/src/core/ozone/ozone_platform_qt.cpp @@ -70,13 +70,14 @@ public: static OzonePlatform::PlatformRuntimeProperties properties; #if BUILDFLAG(USE_VAAPI) if (has_initialized_gpu()) { +#if BUILDFLAG(USE_VAAPI_X11) if (GetQtXDisplay()) { // This property is set when the GetPlatformRuntimeProperties is // called on the gpu process side. properties.supports_native_pixmaps = ui::GpuMemoryBufferSupportX11::GetInstance()->has_gbm_device(); - } else { + } else +#endif properties.supports_native_pixmaps = true; // buffer_manager_->GetGbmDevice() != nullptr - } } #endif return properties; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 64ccd529d..d00f66335 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -311,6 +311,9 @@ void WebContentsDelegateQt::RenderViewHostChanged(content::RenderViewHost *, con Q_ASSERT(rwhv->delegate()); rwhv->delegate()->adapterClientChanged(m_viewClient); m_viewClient->zoomUpdateIsNeeded(); + auto backgroundColor = m_viewClient->backgroundColor(); + if (backgroundColor != Qt::white) + m_viewClient->webContentsAdapter()->setBackgroundColor(backgroundColor); } } diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index ae85bb2d6..81de7833f 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -601,9 +601,6 @@ const static char kDisableInProcGpuThread[] = "QTWEBENGINE_DISABLE_GPU_THREAD"; bool WebEngineContext::isGpuServiceOnUIThread() { static bool threadedGpu = -#if QT_CONFIG(opengl) && !defined(Q_OS_MACOS) - QOpenGLContext::supportsThreadedOpenGL() && -#endif !qEnvironmentVariableIsSet(kDisableInProcGpuThread); return !threadedGpu; } @@ -985,7 +982,7 @@ const char *qWebEngineChromiumVersion() noexcept const char *qWebEngineChromiumSecurityPatchVersion() noexcept { - return "121.0.6167.160"; // FIXME: Remember to update + return "124.0.6367.208"; // FIXME: Remember to update } QT_END_NAMESPACE diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index c03c9a3b2..e71153899 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -284,6 +284,12 @@ QString dictionariesPath() break; } } + + if (potentialDictionariesPath.isEmpty()) { + // return path for error message + potentialDictionariesPath = QCoreApplication::applicationDirPath() % QDir::separator() + % QLatin1String("qtwebengine_dictionaries"); + } } return potentialDictionariesPath; diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp index 6de2fbc6c..17fdb29b9 100644 --- a/src/pdf/qpdfdocument.cpp +++ b/src/pdf/qpdfdocument.cpp @@ -446,7 +446,7 @@ void QPdfDocumentPrivate::fpdf_AddSegment(_FX_DOWNLOADHINTS *pThis, size_t offse Q_UNUSED(size); } -QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int count) +QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int count) const { QList<ushort> buf(count + 1); // TODO is that enough space in case one unicode character is more than one in utf-16? @@ -455,23 +455,73 @@ QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int return QString::fromUtf16(reinterpret_cast<const char16_t *>(buf.constData()), len - 1); } -QPointF QPdfDocumentPrivate::getCharPosition(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex) +QPointF QPdfDocumentPrivate::getCharPosition(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const { double x, y; - int count = FPDFText_CountChars(textPage); - bool ok = FPDFText_GetCharOrigin(textPage, qMin(count - 1, charIndex), &x, &y); - if (!ok) - return QPointF(); - return QPointF(x, pageHeight - y); + const int count = FPDFText_CountChars(textPage); + if (FPDFText_GetCharOrigin(textPage, qMin(count - 1, charIndex), &x, &y)) + return mapPageToView(pdfPage, x, y); + return {}; } -QRectF QPdfDocumentPrivate::getCharBox(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex) +QRectF QPdfDocumentPrivate::getCharBox(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const { double l, t, r, b; - bool ok = FPDFText_GetCharBox(textPage, charIndex, &l, &r, &b, &t); - if (!ok) - return QRectF(); - return QRectF(l, pageHeight - t, r - l, t - b); + if (FPDFText_GetCharBox(textPage, charIndex, &l, &r, &b, &t)) + return mapPageToView(pdfPage, l, t, r, b); + return {}; +} + +/*! \internal + Convert the point \a x , \a y to the usual 1x (pixels = points) + 4th-quadrant "view" coordinate system relative to the top-left corner of + the rendered page. Some PDF files have internal transforms that make this + coordinate system different from "page coordinates", so we cannot just + subtract from page height to invert the y coordinates, in general. + */ +QPointF QPdfDocumentPrivate::mapPageToView(FPDF_PAGE pdfPage, double x, double y) const +{ + const auto pageHeight = FPDF_GetPageHeight(pdfPage); + const auto pageWidth = FPDF_GetPageWidth(pdfPage); + int rx, ry; + if (FPDF_PageToDevice(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, x, y, &rx, &ry)) + return QPointF(rx, ry); + return {}; +} + +/*! \internal + Convert the bounding box defined by \a left \a top \a right and \a bottom + to the usual 1x (pixels = points) 4th-quadrant "view" coordinate system + that we use for rendering things on top of the page image. + Some PDF files have internal transforms that make this coordinate + system different from "page coordinates", so we cannot just + subtract from page height to invert the y coordinates, in general. + */ +QRectF QPdfDocumentPrivate::mapPageToView(FPDF_PAGE pdfPage, double left, double top, double right, double bottom) const +{ + const auto pageHeight = FPDF_GetPageHeight(pdfPage); + const auto pageWidth = FPDF_GetPageWidth(pdfPage); + int xfmLeft, xfmTop, xfmRight, xfmBottom; + if ( FPDF_PageToDevice(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, left, top, &xfmLeft, &xfmTop) && + FPDF_PageToDevice(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, right, bottom, &xfmRight, &xfmBottom) ) + return QRectF(xfmLeft, xfmTop, xfmRight - xfmLeft, xfmBottom - xfmTop); + return {}; +} + +/*! \internal + Convert the point \a x , \a y \a from the usual 1x (pixels = points) + 4th-quadrant "view" coordinate system relative to the top-left corner of + the rendered page, to "page coordinates" suited to the given \a pdfPage, + which may have arbitrary internal transforms. + */ +QPointF QPdfDocumentPrivate::mapViewToPage(FPDF_PAGE pdfPage, QPointF position) const +{ + const auto pageHeight = FPDF_GetPageHeight(pdfPage); + const auto pageWidth = FPDF_GetPageWidth(pdfPage); + double rx, ry; + if (FPDF_DeviceToPage(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, position.x(), position.y(), &rx, &ry)) + return QPointF(rx, ry); + return {}; } QPdfDocumentPrivate::TextPosition QPdfDocumentPrivate::hitTest(int page, QPointF position) @@ -480,14 +530,14 @@ QPdfDocumentPrivate::TextPosition QPdfDocumentPrivate::hitTest(int page, QPointF TextPosition result; FPDF_PAGE pdfPage = FPDF_LoadPage(doc, page); - double pageHeight = FPDF_GetPageHeight(pdfPage); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); - int hitIndex = FPDFText_GetCharIndexAtPos(textPage, position.x(), pageHeight - position.y(), + const QPointF pagePos = mapViewToPage(pdfPage, position); + int hitIndex = FPDFText_GetCharIndexAtPos(textPage, pagePos.x(), pagePos.y(), CharacterHitTolerance, CharacterHitTolerance); if (hitIndex >= 0) { - QPointF charPos = getCharPosition(textPage, pageHeight, hitIndex); + QPointF charPos = getCharPosition(pdfPage, textPage, hitIndex); if (!charPos.isNull()) { - QRectF charBox = getCharBox(textPage, pageHeight, hitIndex); + QRectF charBox = getCharBox(pdfPage, textPage, hitIndex); // If the given position is past the end of the line, i.e. if the right edge of the found character's // bounding box is closer to it than the left edge is, we say that we "hit" the next character index after if (qAbs(charBox.right() - position.x()) < qAbs(charPos.x() - position.x())) { @@ -931,11 +981,12 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end) { const QPdfMutexLocker lock; FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); - double pageHeight = FPDF_GetPageHeight(pdfPage); + const QPointF pageStart = d->mapViewToPage(pdfPage, start); + const QPointF pageEnd = d->mapViewToPage(pdfPage, end); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); - int startIndex = FPDFText_GetCharIndexAtPos(textPage, start.x(), pageHeight - start.y(), + int startIndex = FPDFText_GetCharIndexAtPos(textPage, pageStart.x(), pageStart.y(), CharacterHitTolerance, CharacterHitTolerance); - int endIndex = FPDFText_GetCharIndexAtPos(textPage, end.x(), pageHeight - end.y(), + int endIndex = FPDFText_GetCharIndexAtPos(textPage, pageEnd.x(), pageEnd.y(), CharacterHitTolerance, CharacterHitTolerance); QPdfSelection result; @@ -946,7 +997,7 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end) // If the given end position is past the end of the line, i.e. if the right edge of the last character's // bounding box is closer to it than the left edge is, then extend the char range by one - QRectF endCharBox = d->getCharBox(textPage, pageHeight, endIndex); + QRectF endCharBox = d->getCharBox(pdfPage, textPage, endIndex); if (qAbs(endCharBox.right() - end.x()) < qAbs(endCharBox.x() - end.x())) ++endIndex; @@ -958,7 +1009,7 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end) for (int i = 0; i < rectCount; ++i) { double l, r, b, t; FPDFText_GetRect(textPage, i, &l, &t, &r, &b); - QRectF rect(l, pageHeight - t, r - l, t - b); + const QRectF rect = d->mapPageToView(pdfPage, l, t, r, b); if (hull.isNull()) hull = rect; else @@ -988,7 +1039,6 @@ QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int ma return {}; const QPdfMutexLocker lock; FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); - double pageHeight = FPDF_GetPageHeight(pdfPage); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); int pageCount = FPDFText_CountChars(textPage); if (startIndex >= pageCount) @@ -1003,7 +1053,7 @@ QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int ma for (int i = 0; i < rectCount; ++i) { double l, r, b, t; FPDFText_GetRect(textPage, i, &l, &t, &r, &b); - QRectF rect(l, pageHeight - t, r - l, t - b); + const QRectF rect = d->mapPageToView(pdfPage, l, t, r, b); if (hull.isNull()) hull = rect; else @@ -1012,7 +1062,7 @@ QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int ma } } if (bounds.isEmpty()) - hull = QRectF(d->getCharPosition(textPage, pageHeight, startIndex), QSizeF()); + hull = QRectF(d->getCharPosition(pdfPage, textPage, startIndex), QSizeF()); qCDebug(qLcDoc) << "on page" << page << "at index" << startIndex << "maxLength" << maxLength << "got" << text.size() << "chars," << rectCount << "rects within" << hull; @@ -1029,7 +1079,6 @@ QPdfSelection QPdfDocument::getAllText(int page) { const QPdfMutexLocker lock; FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); - double pageHeight = FPDF_GetPageHeight(pdfPage); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); int count = FPDFText_CountChars(textPage); if (count < 1) @@ -1041,7 +1090,7 @@ QPdfSelection QPdfDocument::getAllText(int page) for (int i = 0; i < rectCount; ++i) { double l, r, b, t; FPDFText_GetRect(textPage, i, &l, &t, &r, &b); - QRectF rect(l, pageHeight - t, r - l, t - b); + const QRectF rect = d->mapPageToView(pdfPage, l, t, r, b); if (hull.isNull()) hull = rect; else diff --git a/src/pdf/qpdfdocument_p.h b/src/pdf/qpdfdocument_p.h index 4adbf695e..12092c4ad 100644 --- a/src/pdf/qpdfdocument_p.h +++ b/src/pdf/qpdfdocument_p.h @@ -78,9 +78,12 @@ public: static int fpdf_GetBlock(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); static void fpdf_AddSegment(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size); void updateLastError(); - QString getText(FPDF_TEXTPAGE textPage, int startIndex, int count); - QPointF getCharPosition(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex); - QRectF getCharBox(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex); + QString getText(FPDF_TEXTPAGE textPage, int startIndex, int count) const; + QPointF getCharPosition(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const; + QRectF getCharBox(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const; + QPointF mapPageToView(FPDF_PAGE pdfPage, double x, double y) const; + QRectF mapPageToView(FPDF_PAGE pdfPage, double left, double top, double right, double bottom) const; + QPointF mapViewToPage(FPDF_PAGE pdfPage, QPointF position) const; // FPDF takes the rotation parameter as an int. // This enum is mapping the int values defined in fpdfview.h:956. diff --git a/src/pdf/qpdflinkmodel.cpp b/src/pdf/qpdflinkmodel.cpp index 366b77344..645dff21a 100644 --- a/src/pdf/qpdflinkmodel.cpp +++ b/src/pdf/qpdflinkmodel.cpp @@ -179,7 +179,6 @@ void QPdfLinkModelPrivate::update() qCWarning(qLcLink) << "failed to load page" << page; return; } - double pageHeight = FPDF_GetPageHeight(pdfPage); q->beginResetModel(); links.clear(); @@ -204,8 +203,7 @@ void QPdfLinkModelPrivate::update() std::swap(rect.bottom, rect.top); QPdfLink linkData; - linkData.d->rects << QRectF(rect.left, pageHeight - rect.top, - rect.right - rect.left, rect.top - rect.bottom); + linkData.d->rects << document->d->mapPageToView(pdfPage, rect.left, rect.top, rect.right, rect.bottom); FPDF_DEST dest = FPDFLink_GetDest(doc, linkAnnot); FPDF_ACTION action = FPDFLink_GetAction(linkAnnot); switch (FPDFAction_GetType(action)) { @@ -224,7 +222,7 @@ void QPdfLinkModelPrivate::update() break; // at least we got a page number, so the link will jump there } if (hasX && hasY) - linkData.d->location = QPointF(x, pageHeight - y); + linkData.d->location = document->d->mapPageToView(pdfPage, x, y); if (hasZoom) linkData.d->zoom = zoom; break; @@ -287,7 +285,7 @@ void QPdfLinkModelPrivate::update() double left, top, right, bottom; bool success = FPDFLink_GetRect(webLinks, i, r, &left, &top, &right, &bottom); if (success) { - linkData.d->rects << QRectF(left, pageHeight - top, right - left, top - bottom); + linkData.d->rects << document->d->mapPageToView(pdfPage, left, top, right, bottom); links << linkData; } } diff --git a/src/pdf/qpdfsearchmodel.cpp b/src/pdf/qpdfsearchmodel.cpp index 78dfe06fa..abe0122bf 100644 --- a/src/pdf/qpdfsearchmodel.cpp +++ b/src/pdf/qpdfsearchmodel.cpp @@ -3,12 +3,11 @@ #include "qpdfdocument_p.h" #include "qpdflink.h" -#include "qpdflink_p.h" #include "qpdfsearchmodel.h" #include "qpdfsearchmodel_p.h" -#include "third_party/pdfium/public/fpdf_doc.h" #include "third_party/pdfium/public/fpdf_text.h" +#include "third_party/pdfium/public/fpdfview.h" #include <QtCore/qelapsedtimer.h> #include <QtCore/qloggingcategory.h> @@ -251,7 +250,6 @@ bool QPdfSearchModelPrivate::doSearch(int page) qWarning() << "failed to load page" << page; return false; } - double pageHeight = FPDF_GetPageHeight(pdfPage); FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); if (!textPage) { qWarning() << "failed to load text of page" << page; @@ -269,9 +267,12 @@ bool QPdfSearchModelPrivate::doSearch(int page) int startIndex = -1; int endIndex = -1; for (int r = 0; r < rectCount; ++r) { + // get bounding box of search result in page coordinates double left, top, right, bottom; FPDFText_GetRect(textPage, r, &left, &top, &right, &bottom); - rects << QRectF(left, pageHeight - top, right - left, top - bottom); + // deal with any internal PDF transforms and + // convert to the 1x (pixels = points) 4th-quadrant coordinate system + rects << document->d->mapPageToView(pdfPage, left, top, right, bottom); if (r == 0) { startIndex = FPDFText_GetCharIndexAtPos(textPage, left, top, CharacterHitTolerance, CharacterHitTolerance); @@ -280,7 +281,8 @@ bool QPdfSearchModelPrivate::doSearch(int page) endIndex = FPDFText_GetCharIndexAtPos(textPage, right, top, CharacterHitTolerance, CharacterHitTolerance); } - qCDebug(qLcS) << rects.last() << "char idx" << startIndex << "->" << endIndex; + qCDebug(qLcS) << rects.last() << "char idx" << startIndex << "->" << endIndex + << "from page rect" << left << top << right << bottom; } QString contextBefore, contextAfter; if (startIndex >= 0 || endIndex >= 0) { diff --git a/src/process/CMakeLists.txt b/src/process/CMakeLists.txt index bbe47431f..630ba42a8 100644 --- a/src/process/CMakeLists.txt +++ b/src/process/CMakeLists.txt @@ -25,7 +25,7 @@ if(WIN32) set_property(TARGET ${qtWebEngineProcessName} PROPERTY WIN32_EXECUTABLE TRUE) # get libs rsp file, since cmake is not aware of PUBLIC libs for WebEngineCore get_target_property(libs_rsp WebEngineCore LIBS_RSP) - target_link_options(${qtWebEngineProcessName} PRIVATE "@${libs_rsp}") + target_link_options(${qtWebEngineProcessName} PRIVATE "@${libs_rsp}" "/STACK:0x800000") endif() if(MACOS) diff --git a/src/webenginequick/api/qtwebenginequickglobal.cpp b/src/webenginequick/api/qtwebenginequickglobal.cpp index f8f520a05..e24ef643b 100644 --- a/src/webenginequick/api/qtwebenginequickglobal.cpp +++ b/src/webenginequick/api/qtwebenginequickglobal.cpp @@ -37,16 +37,19 @@ namespace QtWebEngineQuick { */ void initialize() { + auto api = QQuickWindow::graphicsApi(); if (!QCoreApplication::startingUp()) { - qWarning("QtWebEngineQuick::initialize() called with QCoreApplication object already created and should be call before. "\ - "This is depreciated and may fail in the future."); + if (api == QSGRendererInterface::OpenGL || (api != QSGRendererInterface::Vulkan + && api != QSGRendererInterface::Metal && api != QSGRendererInterface::Direct3D11)) { + qWarning("QtWebEngineQuick::initialize() called with QCoreApplication object already created and should be call before. "\ + "This is depreciated and may fail in the future."); + } QtWebEngineCore::initialize(); return; } // call initialize the same way as widgets do qAddPreRoutine(QtWebEngineCore::initialize); - auto api = QQuickWindow::graphicsApi(); if (api != QSGRendererInterface::OpenGL && api != QSGRendererInterface::Vulkan && api != QSGRendererInterface::Metal && api != QSGRendererInterface::Direct3D11) QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); diff --git a/src/webenginequick/doc/src/webengineview_lgpl.qdoc b/src/webenginequick/doc/src/webengineview_lgpl.qdoc index 5f4297cb8..cbbec9fd8 100644 --- a/src/webenginequick/doc/src/webengineview_lgpl.qdoc +++ b/src/webenginequick/doc/src/webengineview_lgpl.qdoc @@ -356,9 +356,8 @@ This method offers a lower-level alternative to the \c{url} property, which references HTML pages via URL. - External objects, such as stylesheets or images referenced in the HTML - document, should be located relative to \a baseUrl. For external objects to - be loaded, \c baseUrl cannot be empty. For example, if \a html + \a baseUrl is optional and used to resolve relative URLs in the document, + such as referenced images or stylesheets. For example, if \a html is retrieved from \c http://www.example.com/documents/overview.html, which is the base URL, then an image referenced with the relative URL, \c diagram.png, should be at \c{http://www.example.com/documents/diagram.png}. diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index c4a0da4d9..e28f70b5f 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#include "qapplication.h" #include "qwebenginenotificationpresenter_p.h" #include "qwebengineview.h" #include "qwebengineview_p.h" @@ -156,6 +157,7 @@ public: } void SetClearColor(const QColor &color) override { + setUpdatesEnabled(false); QQuickWidget::setClearColor(color); // QQuickWidget is usually blended by punching holes into widgets // above it to simulate the visual stacking order. If we want it to be @@ -164,7 +166,8 @@ public: bool isTranslucent = color.alpha() < 255; setAttribute(Qt::WA_AlwaysStackOnTop, isTranslucent); setAttribute(Qt::WA_OpaquePaintEvent, !isTranslucent); - update(); + setUpdatesEnabled(true); + window()->update(); } void MoveWindow(const QPoint &screenPos) override { @@ -441,6 +444,8 @@ void QWebEngineViewPrivate::widgetChanged(QtWebEngineCore::WebEngineQuickWidget #endif q->layout()->addWidget(newWidget); q->setFocusProxy(newWidget); + if (oldWidget && oldWidget == QApplication::focusWidget()) + newWidget->setFocus(); newWidget->show(); } } diff --git a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc index 03489640a..3153ec952 100644 --- a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc @@ -108,9 +108,8 @@ \fn void QWebEngineView::setHtml(const QString &html, const QUrl &baseUrl) Sets the content of the web view to the specified \a html content. - External objects, such as stylesheets or images referenced in the HTML - document, are located relative to \a baseUrl. For external objects to - be loaded, \c baseUrl cannot be empty. For example, if \a html + \a baseUrl is optional and used to resolve relative URLs in the document, + such as referenced images or stylesheets. For example, if \a html is retrieved from \c http://www.example.com/documents/overview.html, which is the base URL, then an image referenced with the relative URL, \c diagram.png, should be at \c{http://www.example.com/documents/diagram.png}. @@ -144,7 +143,7 @@ is empty, it is assumed that the content is \c{text/plain,charset=US-ASCII}. External objects referenced in the content are located relative to \a baseUrl. - For external objects to be loaded, \c baseUrl cannot be empty. + For external objects with relative URLs to be loaded, \c baseUrl cannot be empty. The data is loaded immediately; external objects are loaded asynchronously. diff --git a/tests/auto/pdf/qpdfdocument/CMakeLists.txt b/tests/auto/pdf/qpdfdocument/CMakeLists.txt index aadc192b3..b8300ef27 100644 --- a/tests/auto/pdf/qpdfdocument/CMakeLists.txt +++ b/tests/auto/pdf/qpdfdocument/CMakeLists.txt @@ -12,5 +12,7 @@ qt_internal_add_test(tst_qpdfdocument TESTDATA pdf-sample.protected.pdf pdf-sample.metadata.pdf + rotated_text.pdf + tagged_mcr_multipage.pdf test.pdf ) diff --git a/tests/auto/pdf/qpdfdocument/rotated_text.pdf b/tests/auto/pdf/qpdfdocument/rotated_text.pdf new file mode 100644 index 000000000..d6d8db84e --- /dev/null +++ b/tests/auto/pdf/qpdfdocument/rotated_text.pdf @@ -0,0 +1,70 @@ +%PDF-1.7 +%��� +1 0 obj << + /Type /Catalog + /Pages 2 0 R +>> +endobj +2 0 obj << + /Type /Pages + /MediaBox [ 0 0 200 200 ] + /Count 1 + /Kids [ 3 0 R ] +>> +endobj +3 0 obj << + /Type /Page + /Parent 2 0 R + /Resources << + /Font << + /F1 4 0 R + >> + >> + /Contents 5 0 R +>> +endobj +4 0 obj << + /Type /Font + /Subtype /Type1 + /BaseFont /Times-Roman +>> +endobj +5 0 obj << + /Length 406 +>> +stream +BT +0 0 Td +/F1 12 Tf +0.70710678118 -0.70710678118 0.70710678118 0.70710678118 100 100 Tm +(Hello,) Tj +0 0 Td +/F1 12 Tf +-0.70710678118 -0.70710678118 0.70710678118 -0.70710678118 100 100 Tm +( world!\r\n) Tj +0 0 Td +/F1 12 Tf +-0.70710678118 0.70710678118 -0.70710678118 -0.70710678118 100 100 Tm +(Goodbye,) Tj +0 0 Td +/F1 12 Tf +0.70710678118 0.70710678118 -0.70710678118 0.70710678118 100 100 Tm +( world!) Tj +ET +endstream +endobj +xref +0 6 +0000000000 65535 f +0000000015 00000 n +0000000068 00000 n +0000000161 00000 n +0000000287 00000 n +0000000365 00000 n +trailer << + /Root 1 0 R + /Size 6 +>> +startxref +823 +%%EOF diff --git a/tests/auto/pdf/qpdfdocument/tagged_mcr_multipage.pdf b/tests/auto/pdf/qpdfdocument/tagged_mcr_multipage.pdf new file mode 100644 index 000000000..fcc5fafda --- /dev/null +++ b/tests/auto/pdf/qpdfdocument/tagged_mcr_multipage.pdf @@ -0,0 +1,136 @@ +%PDF-1.7 +%��� +1 0 obj << + /Type /Catalog + /MarkInfo << + /Type /MarkInfo + /Marked true + >> + /Pages 2 0 R + /StructTreeRoot 8 0 R +>> +endobj +2 0 obj << + /Type /Pages + /CropBox [ 10.8197 8.459 605.705 801.639 ] + /MediaBox [ 0.0 0.0 616.721 809.902 ] + /Count 2 + /Kids [ + 4 0 R + 6 0 R + ] +>> +endobj +3 0 obj << + /Type /Font + /Subtype /Type1 + /BaseFont /Times-Roman +>> +endobj +4 0 obj << + /Type /Page + /Tabs /S + /Parent 2 0 R + /StructParents 0 + /Contents 5 0 R + /Resources << + /ProcSet [/PDF /Text] + /Font << + /F1 3 0 R + >> + >> +>> +endobj +5 0 obj << + /Length 83 +>> +stream +BT +/Document <</MCID 0 >>BDC +0 i +/F1 1 Tf +12 0 0 12 43.073 771.625 Tm +(1)Tj +EMC +ET +endstream +endobj +6 0 obj << + /Type /Page + /Tabs /S + /Parent 2 0 R + /StructParents 1 + /Contents 7 0 R + /Resources << + /ProcSet [/PDF /Text] + /Font << + /F1 3 0 R + >> + >> +>> +endobj +7 0 obj << + /Length 83 +>> +stream +BT +/Document <</MCID 0 >>BDC +0 i +/F1 1 Tf +12 0 0 12 43.073 771.625 Tm +(2)Tj +EMC +ET +endstream +endobj +8 0 obj << + /Type /StructTreeRoot + /K 10 0 R + /ParentTree 9 0 R + /ParentTreeNextKey 2 +>> +endobj +9 0 obj << + /Nums [ + 0 + [10 0 R] + 1 + [10 0 R] + ] +>> +endobj +10 0 obj << + /T () + /S /Document + /P 8 0 R + /Pg 4 0 R + /K [ + 0 + << + /MCID 0 + /Pg 6 0 R + /Type /MCR + >> + ] +>> +%endobj +xref +0 11 +0000000000 65535 f +0000000015 00000 n +0000000149 00000 n +0000000315 00000 n +0000000393 00000 n +0000000575 00000 n +0000000709 00000 n +0000000891 00000 n +0000001025 00000 n +0000001125 00000 n +0000001198 00000 n +trailer << + /Root 1 0 R + /Size 11 +>> +startxref +1345 +%%EOF diff --git a/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp b/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp index 6bb007e7f..d222bff0c 100644 --- a/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp +++ b/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp @@ -36,6 +36,10 @@ private slots: void passwordClearedOnClose(); void metaData(); void pageLabels(); + void getSelection_data(); + void getSelection(); + void getSelectionAtIndex_data(); + void getSelectionAtIndex(); private: void consistencyCheck(QPdfDocument &doc) const; @@ -394,6 +398,86 @@ void tst_QPdfDocument::pageLabels() QCOMPARE(doc.pageLabel(2), "i"); // i of the tiger! } +void tst_QPdfDocument::getSelection_data() +{ + QTest::addColumn<QString>("pdfPath"); + QTest::addColumn<int>("page"); + QTest::addColumn<QPointF>("start"); + QTest::addColumn<QPointF>("end"); + QTest::addColumn<QString>("expectedText"); + QTest::addColumn<int>("expectedStartIndex"); + QTest::addColumn<int>("expectedEndIndex"); + QTest::addColumn<QRect>("expectedBounds"); + QTest::addColumn<int>("expectedPolygonCount"); + + QTest::newRow("raid") << QFINDTESTDATA("test.pdf") + << 1 << QPointF(316.4, 206) << QPointF(339, 201) + << "raid" << 80 << 84 << QRect(316, 201, 21, 12) << 1; + QTest::newRow("rotated text") << QFINDTESTDATA("rotated_text.pdf") + << 0 << QPointF(102, 94) << QPointF(125, 73) + << "world!" << 25 << 31 << QRect(98, 70, 26, 28) << 1; +} + +void tst_QPdfDocument::getSelection() +{ + QFETCH(QString, pdfPath); + QFETCH(int, page); + QFETCH(QPointF, start); + QFETCH(QPointF, end); + QFETCH(QString, expectedText); + QFETCH(int, expectedStartIndex); + QFETCH(int, expectedEndIndex); + QFETCH(QRect, expectedBounds); + QFETCH(int, expectedPolygonCount); + + QPdfDocument doc; + QCOMPARE(doc.load(pdfPath), QPdfDocument::Error::None); + + QPdfSelection sel = doc.getSelection(page, start, end); + QCOMPARE(sel.text(), expectedText); + QCOMPARE(sel.startIndex(), expectedStartIndex); + QCOMPARE(sel.endIndex(), expectedEndIndex); + QCOMPARE(sel.boundingRectangle().toRect(), expectedBounds); + QCOMPARE(sel.bounds().size(), expectedPolygonCount); +} + +void tst_QPdfDocument::getSelectionAtIndex_data() +{ + QTest::addColumn<QString>("pdfPath"); + QTest::addColumn<int>("page"); + QTest::addColumn<int>("start"); + QTest::addColumn<int>("maxLen"); + QTest::addColumn<QString>("expectedText"); + QTest::addColumn<QRect>("expectedBounds"); + QTest::addColumn<int>("expectedPolygonCount"); + + QTest::newRow("raid") << QFINDTESTDATA("test.pdf") + << 1 << 80 << 4 << "raid" << QRect(316, 201, 21, 12) << 1; + QTest::newRow("rotated text") << QFINDTESTDATA("rotated_text.pdf") + << 0 << 7 << 6 << "world!" << QRect(76, 102, 26, 28) << 1; + QTest::newRow("displaced text") << QFINDTESTDATA("tagged_mcr_multipage.pdf") + << 0 << 0 << 10 << "1" << QRect(34, 22, 3, 8) << 1; +} + +void tst_QPdfDocument::getSelectionAtIndex() +{ + QFETCH(QString, pdfPath); + QFETCH(int, page); + QFETCH(int, start); + QFETCH(int, maxLen); + QFETCH(QString, expectedText); + QFETCH(QRect, expectedBounds); + QFETCH(int, expectedPolygonCount); + + QPdfDocument doc; + QCOMPARE(doc.load(pdfPath), QPdfDocument::Error::None); + + QPdfSelection sel = doc.getSelectionAtIndex(page, start, maxLen); + QCOMPARE(sel.text(), expectedText); + QCOMPARE(sel.boundingRectangle().toRect(), expectedBounds); + QCOMPARE(sel.bounds().size(), expectedPolygonCount); +} + QTEST_MAIN(tst_QPdfDocument) #include "tst_qpdfdocument.moc" diff --git a/tests/auto/pdfquick/multipageview/tst_multipageview.cpp b/tests/auto/pdfquick/multipageview/tst_multipageview.cpp index b64cd47b1..c5e0b30db 100644 --- a/tests/auto/pdfquick/multipageview/tst_multipageview.cpp +++ b/tests/auto/pdfquick/multipageview/tst_multipageview.cpp @@ -62,7 +62,7 @@ void tst_MultiPageView::internalLink_data() QTest::addColumn<qreal>("expectedZoom"); QTest::addColumn<QPoint>("expectedScroll"); - QTest::newRow("first link") << 0 << 1 << qreal(1) << QPoint(134, 1276); + QTest::newRow("first link") << 0 << 1 << qreal(1) << QPoint(134, 1286); // TODO fails because it zooms out, and the view leaves gaps between pages currently // QTest::newRow("second link") << 1 << 2 << qreal(0.5) << QPoint(0, 717); } diff --git a/tests/auto/quick/qmltests/BLACKLIST b/tests/auto/quick/qmltests/BLACKLIST index fc8f9f0d8..ef580a636 100644 --- a/tests/auto/quick/qmltests/BLACKLIST +++ b/tests/auto/quick/qmltests/BLACKLIST @@ -4,6 +4,39 @@ macos [WebEngineViewContextMenu::test_contextMenuLinkAndSelectedText] macos +[WebEngineFavicon::test_bestFavicon] +macos + +[WebEngineFavicon::test_dynamicFavicon] +macos + +[WebEngineFavicon::test_faviconLoad] +macos + +[WebEngineFavicon::test_faviconLoadAfterHistoryNavigation] +macos + +[WebEngineFavicon::test_faviconLoadEncodedUrl] +macos + +[WebEngineFavicon::test_faviconLoadPushState] +macos + +[WebEngineFavicon::test_multiIcon] +macos + +[WebEngineFavicon::test_touchIcon] +macos + +[WebEngineFavicon::test_touchIconWithSameURL] +macos + +[WebEngineFaviconDatabase::test_iconDatabase] +macos + +[WebEngineFaviconDatabase::test_iconDatabaseMultiView] +macos + [CertificateError::test_fatalError] * |